1、socket编程
TCP协议作为传输层的主要协议,不仅可以支持本地的数据通信,还可以支持跨网络的进程间通信。在互联网中,我们可以通过“IP地址+端口号”标识唯一的一个进程,“IP地址+端口号”被称为socket,这就是网络socket编程。在TCP协议中建立连接的两个进程各有个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。socket本身是“插座”的意思,因此用来描述网络连接的一对一关系。TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。这里在socket API中主要介绍TCP协议的函数接口。
我们知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如UDP段格式, 16位的源端口号1000(0x3e8),则先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址 存0xe8。但是,如果发送主机是小端字节序的,这16位仍被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的, 接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序。
2、socket地址的数据类型及相关函数
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,然而,各种网络协议的地址格式并不相同,如下图所示:
各种socket地址结构体的开头都是相同的,前16位表示整个结构体的长度,后16位表示地址类型。
IPv4、IPv6和UNIX Domain Socket的地址类型分别定义为常数AF_INET、AF_INET6、AF_UNIX。这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中