表示IPv4地址的结构体
| 12
 3
 4
 5
 6
 
 | struct sockaddr_in {sa_family_t    sin_family;
 uint16_t       sin_port;
 struct in_addr sin_addr;
 char           sin_zero[8];
 };
 
 | 
其中的struct in_addr里面为一个32位整型
| 12
 3
 
 | struct in_addr {In_addr_t s_addr;
 };
 
 | 
sockaddr_in的成员分析
sin_family
| 地址族 | 含义 | 
| AF_INET | IPv4网络协议中使用的地址族 | 
| AF_INET6 | IPv6网络协议中使用的地址族 | 
| AF_LOCAL | 本地通信中采用的UNIX协议的地址族 | 
sin_port
保存16位端口号,且以网络字节序保存。
sin_addr
保存32位IP地址信息,也以网络字节序保存。
sin_zero
无特殊含义。方便结构体sockaddr_in的大小与sockaddr结构体保持一致。必须填充0。
sockaddr
| 12
 3
 4
 
 | struct sockaddr {sa_family_t family;
 char        sa_data[14];
 };
 
 | 
字节序与网络字节序
CPU像内存保存数据的方式有2种
- 大端序:高位字节存放到低位地址。
- 小端序:高位字节存放到高位地址。
对于网络字节序,统一采用大端序。
字节序转换
| 12
 3
 4
 
 | unsigned short htons(unsigned short);unsigned short ntohs(unsigned short);
 unsigned long  htonl(unsigned long);
 unsigned long  ntohl(unsigned long);
 
 | 
htons中的h代表主机字(host)节序,n代表网络(network)字节序。
将字符串信息转换为网络字节序的整数型
| 12
 3
 4
 
 | #include <arpa/inet.h>
 
 in_adddr_t inet_addr(const char* string);
 
 | 
可以向该函数传递类似"xxx.xxx.xxx.xxx"十进制格式的字符串。
| 12
 3
 4
 
 | #include <arpa/inet.h>
 
 int inet_aton(const char* string, struct in_addr* addr);
 
 | 
inet_aton函数和inet_addr函数功能完全相同,但inet_aton可以自动填入in_addr的结构体。
| 12
 3
 4
 
 | #include <arpa/inet.h>
 
 char* inet_ntoa(struct in_addr adr);
 
 | 
该函数将整数型IP地址转换为字符串格式并返回。
网络地址初始化
套接字常见的初始化方式。
| 12
 3
 4
 5
 6
 7
 
 | struct sockaddr_in addr;char* serv_ip = "123.124.1.23";
 char* serv_port = "9190";
 memset(&addr, 0, sizeof(addr));
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = inet_addr(serv_ip);
 addr.sin_port = htons(atoi(serv_port));
 
 | 
INADDR_ANY
每次创建套接字都要输入IP会很繁琐,所以可以利用INADDR_ANY
| 12
 3
 4
 5
 6
 
 | struct sockaddr_in addr;char* serv_port = "9190";
 memset(&addr, 0, sizeof(addr));
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 addr.sin_port = htons(atoi(serv_port));
 
 | 
该方式可自动获取运行服务器端的计算机IP地址。
向套接字分配网络地址
| 12
 3
 4
 5
 6
 
 | #include <sys/socket.h>
 
 
 
 int bind(int sockfd, struct sockaddr* myaddr, socklen_t addrlen);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | int serv_sock;struct sockaddr_in serv_addr;
 char* serv_port = "9190";
 
 
 serv_sock = socket(PF_INET, SOCK_STREAM, 0);
 
 
 memset(&serv_addr, 0, sizeof(serv_addr));
 serv_addr.sin_family = AF_INET;
 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 serv_addr.sin_port = htons(atoi(serv_port));
 
 
 bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
 ...
 
 | 
基于UDP的数据I/O函数
由于UDP套接字不会保持连接状态,因此每次传输数据都需要添加目标地址信息。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | #include <sys/socket.h>
 
 
 
 
 
 
 ssize_t sendto(int sock, void* buff, size_t nbytes,
 int flags, struct sockaddr* to, socklen_t addrken);
 
 
 ssize_t recvfrom(int sock, void* buff, size_t nbytes,
 struct sockaddr* from, socklen_t* addrlen);
 
 | 
断开连接的shutdown函数
shutdown函数用来关闭其中的一个流。
| 12
 3
 4
 5
 
 | #include <sys/socket.h>
 
 
 int shutdown(int sock, int howto);
 
 | 
对于第二个参数有:
- SHUT_RD:断开输入流。
- SHUT_WR:断开输出流。
- SHUT_RDWR:同时断开I/O流。