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 structure (16) */
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 */
}
IPv6套接字地址结构
头文件<netinet/in.h>
struct in6_addr{
uint8_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 */
unit32_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 */
}
注意 :如果系统支持套接字地址结构中的长度字段,那么SIN6_LEN常值必须定义
字节排序函数
小端:将低序字节存储在起始地址
大端:将高序字节存储在起始地址
主机字节序:某个给定系统所用的字节序
当今有不少系统能够在系统复位时(如MIPS 2000),或者在运行时(例如Intel i860)在大小端之间切换。
主机字节序和网络字节序之间的相互转换:
#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);
在那些与网际协议所用字节序(大端)相同的系统中,这四个函数通常被定义为空宏。
字节操纵函数
4.2BSD Berkeley
#include <strings.h>
void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, size_t nbytes);
int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
ANSI C
void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes);
int memcpy(const void *ptr1, const void *ptr2, size_t nbytes);
memcpy与bcopy类似,不过两个指针参数的顺序相反,当源字节串与目的字节串重叠时,bcopy能够正常处理,但memcpy操作结果却不可知,这种情况必须改用ANSI C的memmove函数。
地址转换函数——在ASCII字符串(人们偏爱使用的格式 192.168.0.1)与网络字节序的二进制值(存放在套接字地址结构中的值 0xC 0xA8 0x0 0x1)之间转换网际地址
#include <arpa/inet.h>
//将字符串转换成32位的网络字节序二进制值,成功返回1,否则返回0
int inet_aton(const char *strptr, struct in_addr *addrptr);
//进行相同的转换,只是返回值为32位的网络字节序二进制值,出错时返回INADDR_NONE常值(通常是32位均为1的值),因此255.255.255.255不能由该函数处理
//还有一个问题,有些手册声明该函数出错时返回-1而不是INADDR_NONE,这样该函数的返回值和-1进行比较时可能会发生问题,具体取决于C编译器
//如今已经被废弃。新的代码应该使用inet_aton函数,更好的办法是使用新函数inet_pton(兼容IPv4和IPv6)
in_addr_t inet_addr(const char *strptr);
//将32位的网络字节序二进制ipv4地址转换成相应的点分十进制串,返回指向点分十进制数串的指针
//返回值所指向的字符串驻留在静态内存中,这意味着函数不可重入,另外要注意参数是一个结构体
char *inet_ntoa(struct in_addr inaddr);
IPv6出现后新的兼容性转换函数
//函数名字p和n分别代表 表达(presentation) 和 数值(numeric)
#include <arpa/inet.h>
//返回,若成功则为1,若输入不是有效的格式则为0,若出错则为-1
int inet_pton(int family, const char *strptr, void *addrptr);
//返回:若成功则为指向结果的指针,若出错则为NULL
//如果len太小,不足以容纳表达式格式结果(包括结尾的空字符),那么返回一个空指针,置errno为ENOSPC
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
这两个函数的family参数既可以是AF_INET,也可以是AF_INET6,如果以不被支持的地址族作为family参数,这两个函数都返回一个错误,errno置为EAFNOSUPPORT。
#define INET_ADDRSTRLEN 16 /* for ipv4 dotted-decimal */
#define INET6_ADDRSTRLEN 46 /* for ipv6 hex string */
TCP套接字为应用进程提供了一个字节流,它们没有记录标记,从TCP套接字read的返回值可能比我们请求的数量少,但是这不表示发生了错误(改进后的readn,writen和readline函数可解决此问题,实现见3.9节)。