字节序
如果处理器架构支持大端(big-endian)字节序,那么最大字节地址出现在最低有效字节(Least Significant Byte, LSB)上。小端(little-dndian)字节序相反,最大字节地址出现在最低有效字节上。
下图显示了一个32位整数的字节是如何排序的:
网络协议指定了字节序,因此异构计算机系统能够交换协议信息而不会被字节序所混淆。
TCP/IP协议栈使用大端字节序。
对于TCP/IP应用程序,由4个用来在处理器字节序和网络字节序之间实施转换的函数。
#include <arpa/inet.h> uint32_t htonl(uint32_t hostint32); 返回值:以网络字节序表示的32位整数 uint16_t htons(uint16_t hostint16); 返回值:以网络字节序表示的16位整数 uint32_t ntohl(uint32_t netint32); 返回值:以主机字节序表示的32位整数 uint16_t ntohs(uint16_t netint16); 返回值:以主机字节序表示的16位整数 |
---|
地址格式
一个地址表示一个特定通信域的套接字端点,地址格式与这个特定的通信域相关。为了使不同的格式地址能够传入到套接字函数,地址会被强转成一个通用的地址结构sockaddr。
套接字实现可以自由的添加额外的成员并且定义sa_data成员的大小。在linux中,sockaddr的结构定义为:
struct sockaddr {
sa_family_t sa_family; /* address family */
char sa_data[14]; /* variable-length address */
};
因特网地址定义在<netinet/in.h>头文件中。在IPv4因特网域(AF_INET)中,套接字地址用结构sockaddr_in表示:
struct in_addr {
in_addr_t s_addr; /* IPv4 address */
};
struct sockaddr_in {
sa_family_t sin_family; /* address family */
in_port_t sin_port; /* port number */
struct in_addr sin_addr; /* IPv4 address */
};
inet_addr和inet_ntoa函数用于二进制地址格式和点分十进制之间的转换。
将套接字与地址关联
对于服务器,需要给一个接收客户端请求的服务器套接字关联上一个众所周知的地址。
使用bind函数来关联地址和套接字。
#include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t len); 返回值:若成功,返回0;若出错,返回-1 |
---|
对于使用的地址有以下一些限制:
● 在进程正在运行的计算机上,指定的地址必须有效;不能指定一个其他机器的地址。
● 地址必须和创建检套接字时的地址簇所支持的格式相匹配。
● 地址中的端口号必须不小于1024,除非改建成具有相应的特权(即超级用户)。
● 一般只能将一个套接字端点绑定到一个给定地址上,尽管有些协议允许多重绑定。
对于因特网域,如果指定IP地址为INADDR_ANY(<netinet/in.h>中定义的),套接字端点可以被绑定到所有的系统网络接口上。这意味着可以接受这个系统所安装的任何一个网卡的数据包。
可以调用getsockname函数来发现绑定到套接字上的地址。
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp); 返回值:若成功,返回0;若出错,返回-1 |
---|
调用getsockname之前,将alenp设置为一个指向整数的指针,该整数指定缓冲区sockaddr的长度。返回值,该整数会被设置成返回地址的大小。
如果套接字已经和对等方连接,可以调用getpeername函数来找到对方的地址。
#include <sys/socket.h> int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp); 返回值:若成功,返回0;若出错,返回-1 |
---|
除了返回对等方的地址,函数getpeername和getsockname一样。