套接字编程
1. 套接字地址结构
1.1 IPv4套接字地址结构
<netinet/in.h>
struct in_addr
{
in_addr_t s_addr; /* 32-bit IPv4 address */
/* network byte ordered */
};
struct sockaddr_in
{
uint8_t sin_len; /* length of struct */
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* 16-bit TCP or UDP port number */
/* network byte ordered */
struct in_addr sin_addr; /* 32-bit IPv4 address */
/* network byte ordered */
char sin_zero[8]; /* unused */
};
1.2 通用套接字地址结构
当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递。
通用套接字地址结构
#include <sys/socket.h>
struct sockaddr
{
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_XXX value */
char sa_data[14]; /* protocol-specific address */
};
1.3 IPv6 套接字地址结构
#include <netinet/in.h>
struct in6_addr
{
unit8_t s6_addr[16]; /* 128-bit IPv6 address */
/* network byte ordered */
};
#define SIN6_LEN /* required for compile-time tests */
struct sockaddr_in6
{
uint8_t sin6_len; /* length of this struct (28) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* transport layer port# */
/* network byte ordered */
uint32_t sin6_flowinfo; /* flow information, undefined */
struct in6_addr sin6_addr; /* IPv6 address */
/* network byte ordered */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
};
1.4 新的通用套接字地址结构
#include <sys/in.h>
struct sockaddr_storage
{
uint8_t ss_len; /* length of this struct */
sa_family_t ss_family; /* address family: AF_xxx value */
...
};
2. 值-结果参数
当往一个套接字函数传递一个套接字地址结构时,该结构总是以引用形式来传递,也就是说传递的是指向该结构的一个指针。该结构的长度也作为一个参数来传递。
- 从进程到内核传递套接字地址结构的函数有 3 个:bind、connect、sendto 。
- 从内核到进程传递套接字地址结构的函数有 4 个:accept、recvfrom、getsockname、getpeername 。
当函数被调用时,结构大小是一个值,它告诉内核该结构的大小,这样内核在写该结构时不至于越界;当函数返回时,结构大小又是一个结果,它告诉进程内核在该结构中究竟存储了多少信息。
这种类型的参数称为 值-结果 参数。
3. 字节排序函数
小端和大端表示多个字节值的哪一端(小端或大端)存储在该值的起始地址。
把某个给定系统所用的字节序称为主机字节序。
网路协议必须指定一个网络字节序。网际协议使用大端字节序来传送这些多字节整数。
使用如下 4 个函数,在主机字节序和网络字节序之间相互转换。
#include <netinet/in.h>
//返回:网络字节序的值
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
//返回:主机字节序的值
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
h 代表 host,n 代表 netwok,s 代表 short,l 代表 long。
4. inet_aton、inet_ntoa 函数
在点分十进制数串(例 206.168.112.96)与它长度为 32 位的网络字节序二进制值间转换 IP 地址。
#include <arpa/inet.h>
//返回:若字符串有效则为 1,否则为 0
int inet_aton(const char *strptr, struct in_addr *addrptr);
//返回:指向一个点分十进制数串的指针
char *inet_ntoa(struct in_addr inaddr);
inet_aton 将 strptr 所指 C 字符串转换成一个 32 位的网络字节序二进制值。
inet_ntoa 将一个 32 位的网络字节序二进制 IPv4 地址转换成相应的点分十进制数串。
5. inet_pton、inet_ntop 函数
这两个函数是随 IPv6 出现的新函数,对于 IPv4 和 IPv6 都适用。
函数名中 p 和 n 分别代表 表达(presentation)和 数值(numeric)。地址的表达格式通常是 ASCII 字符串,数值格式则是存放到套接字地址结构中的二进制值。
#include <arpa/inet.h>
//返回:若成功则为 1 ;若输入不是有效的表达格式则为 0;若出错则为 -1
int inet_pton(int family, const char *strptr, void *addrptr);
//返回:若成功则为指向结果的指针;若出错则为 NULL
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
family 参数既可以是 AF_INET,也可以是 AF_INET6 。
inet_pton 函数尝试转换由 strptr 指针所指向的字符串,并通过 addrptr 指针存放二进制结果。
inet_ntop 函数进行相反的转换,从数值格式转换到表达格式。len参数是目标存储单元的大小。