套接字地址结构
参考书:《UNIX 网络编程 卷1:套接字互联网API(第三版)》pp56-76
1.为什么要使用套接字地址结构
大多数套接字韩式都需要一个指向套接字地址结构的指针作为参数。
struct in_addr{
in_addr_t s_addr;
};
struct sockaddr_in{
uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8]; //unused
}
2.目前来讲,我们有IPv4套接字地址结构,IPv6套接字地址结构,还有一套通用套接字地址结构(如下)。
struct sockaddr_storage{
uint8_t ss_len; // 该结构体的长度
sa_family_t ss_family; // AF_xxx value
}
3.内核 -- 进程 函数
- 内核 至 进程: accept, recvfrom,getsockname,getpeername(里面的len参数为“值-结果参数”)
- 进程 至 内核: bind, connect, sendto (里面的len参数为“值参数”)
4.字节排序
- 大端(大字节应该存储在起始位置):高序字节(地址A) -- 低序字节(地址A+1)
- 小端(小字节应该存储在起始位置):高序字节(地址A+1) -- 低序字节(地址A)
- 对于网际协议:使用大端字节序传递。
5.字节操纵函数
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *sest, size_t nbytes); // 即使dest与src有重叠部分也可以正确处理
int bcmp(const void *ptr1, const void *ptr2, size_t nbytes); // 相同return 0,否则return非零
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes); // 当dest与src有重叠部分的时候会出问题(结果未知)。需使用memmove。
int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
- inet_aton,inet_addr和inet_ntoa函数
-
int inet_aton(const char *strptr. struct in_addr *addrptr)
:讲一个C字符串转换成一个32
位的网络字节序二进制值。成功return 1,失败return 0。 -
in_addr_t inet_addr(const char *strptr)
:若字符串有效,则为32
为二进制字节序的IPv4地址,否则则返回INADDR_NONE。(注:in_addr_t等价于uint32_t)。 -
char *inet_ntoa(struct in_addr inaddr);
:返回一个点分十进制数串的指针(例:“x.x.x.x”)。
- inet_pton和inet_ntop函数:(p指presentation,n指numeric)
-
int inet_pton(int family, const char *strptr, void *addrptr)
:将strptr中的IP地址(ASCII字符串格式)转化为二进制数值存入addrptr中。成功return 1,若输入不是有效格式则return0,出错则return -1。 -
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len)
:将IP地址的二进制数值转化为ASCII字符串,成功则返回结果对应指针,失败则返回NULL。
注: a) inet_pton中的strptr不可以为空指针
b) inet_ntop中的len可以通过INET_ADDRSTRLEN, INET6_ADDRSTRLEN
来确保。如果len不够长,该函数会返回空指针,并且将errno设置为ENOSPC
sock_ntop及相关函数
char *sock_ntop(const struct sockaddr *sockaddr, socklen_t addrlen)
: 如果出错return NULL,若成功则返回inet_ntop
操作操作出的值。
用途:inet_ntop
需要调用者传一个指向二进制地址的指针,一般来说这种地址的指针包含在套接字的地址结构中。因此我们需要一个新的可以直接处理sockaddr地址的函数。以同样的思路,之前的关于inet的函数均可变为sock函数。readn,writen和readline函数(ssize_t:signed size_t)
ssize_t readn(int filedes, void *buff, size_t nbytes);
ssize_t written(int filedes, const void *buff, size_t nbytes);
ssize_t readline(int filedes, void *buff, size_t maxlen);
总结:
在这一章主要内容为:套接字地址结构,字节排序(大端小端),字节操作,数值地址和表达地址的互相转化以及sock包裹的转换函数(这个是书中自己引入的函数),还有readn,writen,readline这三个为防止因缓冲区不足而设立的函数。