Linux高性能服务器编程第五章Linux网络编程基础API
Linux高性能服务器编程第五章Linux网络编程基础API
Hoshea Zhang本章节主要从三个方面讨论Linux网络API:
- socket地址API。socket最开始的含义是一个IP地址和端口对(ip,port)。它唯一地表示了使用TCP通信的一端。本书称其为socket地址。
- socket基础API。socket的主要API都定义在sys/socket.h头文件中,包括创建socket、命名socket、监听socket、接受连接、发起连接、读写数据、获取地址信息、检测带外标记,以及读取和设置socket选项。
- 网络信息API。Linux提供了一套网络信息API,以实现主机名和IP地址之间的转换,以及服务名称和端口号之间的转换。这些API都定义在netdb.h头文件中,我们将讨论其中几个主要的函数。
socket地址API
主机字节序和网络字节序
现在CPU一次都能装载4字节(至少),那么这四个字节排列顺序将影响他被累加器装载成的整数值。
字节序分为大端字节序和小端字节序,大端序指的是一个整数的高位字节在内存的低地址处,低位字节在高地址处,小端序则相反。现代PC都用小端序,所以小端序又称主机字节序,与此同时发送端总是将发送端数据转化为大端字节序再发送,因此大端字节序又叫网络字节序。
Linux提供了四个函数完成主机字节序和网络字节序的转换:
1 |
|
它们的含义很明确,比如htonl表示“host to network long”,即将长整型(32 bit)的主机字节序数据转化为网络字节序数据。这4个函数中,长整型函数通常用来转换IP地址,短整型函数用来转换端口号(当然不限于此。任何格式化的数据通过网络传输时,都应该使用这些函数来转换字节序)。
通用socket地址
1 |
|
专用socket地址
这里只看IPV4的结构体
1 | struct sockaddr_in{ |
所有专用socket地址类型的变量在实际使用的时候都需要转化为通用sockaddr(强制转换即可)。
IP地址转换函数
通常用可读性好的字符串来表示IP地址,比如用点分十进制来表示IPV4地址,编程中我们需要先把他们转化为整数(二进制)
1 |
|
inet_addr
函数将用点分十进制字符串表示的IPV4地址,转化为网络字节序整数表示的IPv4地址
inet_aton
完成和上面函数一样的功能,但是将值保存在第二个参数代表的结构体中
inet_ntoa
是将整数表示转化为点分十进制的IPv4地址
创建socket
UNIX/Linux的一个哲学是万物皆文件,socket也不例外,他就是可读可写可控制可关闭的文件描述符,下面的系统调用可创建一个socket:
1 |
|
domain参数告诉系统使用哪个底层协议族,TCP/IP应该设置为PF_INET
type参数指定服务类型。服务类型主要有SOCK_STREAM服务(流服务)和SOCK_UGRAM(数据报)服务。对TCP/IP协议族而言,其值取SOCK_STREAM表示传输层使用TCP协议,取SOCK_DGRAM表示传输层使用UDP协议。
protocol参数是在前两个参数构成的协议集合下,再选择一个具体的协议,通常这个值都是唯一的,几乎在所有情况下,我们都应该把这个值设为0,表示默认协议
调用成功返回一个socket文件描述符,失败返回-1设置errno
命名socket
我们创建socket的时候指定了地址族,但是没有指定使用该地址族的哪个具体地址,只有将一个socket和socket地址绑定才能命名。在服务器程序中,我们需要给socket命名,客户端才知道该如何连接他,客户端不需要命名,而是采用匿名方式,即使用操作系统自动分配的socket地址
1 |
|
bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数指出该socket 地址的长度。
监听socket
被命名后还不能马上接收客户连接,我们需要使用如下系统调用:
1 |
|
backlog提示内核监听队列的最大长度,一般设置为5
接受连接
1 |
|
sockfd参数是执行过listen系统调用的监听socket。addr参数用来获取被接受连接的远端socket地址,该socket地址的长度由addrlen参数指出。accept成功时返回—个新的连接socket,该socket唯一地标识了被接受的这个连接,服务器可通过读写该socket来与被接受连接对应的客户端通信。accept失败时返回-1并设置errno。
经过实验,accept只是从监听队列中取出连接,而不论连接处与何种状态,也不关心任何网络变化
发起连接
1 |
|
fd参数是待关闭的socket,但是他不是总是立即关闭一个连接,而是将fd的引用计数-1,当引用计数为0时才关闭。
多进程程序中,一次fork系统调用都将使父进程打开的socket的引用计数+1.
后面的具体方法不再赘述,如果有用到了再提