sockaddr结构体和sockaddr_in结构体
1 2 3 4
| struct sockaddr { unsigned short sa_family; char sa_data[14]; };
|
存放协议族、端口和地址信息。客户端的 connect 函数和服务端的 bind 函数需要这个结构体。
sockaddr 结构体是为了统一地址结构的表示方法,统一接口函数,但是这个结构体并不方便使用,因此定义了等价的 sockaddr_in 结构体,它的大小和 sockaddr 结构体相同,可以强制转换成 sockaddr。
1 2 3 4 5 6 7 8 9 10
| struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; };
struct in_addr { unsigned long s_addr; };
|
因此,在实际的网络编程中,先定义 sockaddr_in结构体把相关信息存储之后,再强制转换成 sockaddr,毕竟提供的API接受的类型是 sockaddr。
gethostbyname函数
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <netdb.h>
struct hostent *gethostbyname(const char *name);
struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; };
#define h_addr h_addr_list[0]
|
这个函数的优点就是不仅可以直接传递IP地址(字符串类型或字符数组类型),还支持传递域名。根据返回的hostent结构体中的成员,添加到所需的其它结构体中。
如下是部分应用核心代码:
1 2 3 4 5 6 7 8 9 10 11 12
| const char* hostname = "www.example.com";
struct hostent* host_info = gethostbyname(hostname);
struct sockaddr_in server_addr; std::memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(80); std::memcpy(&server_addr.sin_addr, host_info->h_addr_list[0], host_info->h_length);
|
字符串IP与大端序IP地址的转换
C语言提供几个库函数,用于字符串格式的IP和大端序IP的相互转换,用于网络通讯的服务端程序中。
inet_addr
:将字符串形式的 IP 地址转换为 in_addr_t
1 2 3 4 5 6
| in_addr_t inet_addr(const char *cp);
|
inet_aton
:将字符串形式的 IP 地址转换为 in_addr
结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int inet_aton(const char *cp, struct in_addr *inp);
cp: 指向一个以点分十进制表示的IPv4地址的字符串 inp: 指向一个 in_addr 结构体,用于存储转换后的IP地址
|
inet_ntoa
:将 in_addr
结构体中的 IP 地址转换为字符串形式
1 2 3 4 5 6 7 8 9 10 11 12 13
| char *inet_ntoa(struct in_addr in);
|
注:typedef unsigned int in_addr_t 代表32位大端序的IP地址。