1. sockaddr 和 sockaddr_in
struct sockaddr 这个结构体是linux的网络编程接口中用来表示IP地址的标准结构体,bind、connect等函数中都需要这个结构体,这个结构体是兼容IPV4和IPV6的。在实际编程中这个结构体会被一个 struct sockaddr_in 所填充。
struct sockaddr {
sa_family_t sa_family; //所选协议族AF_INET
char sa_data[14]; //ip地址及端口号, 14字节的协议地址
};
sockaddr的缺陷: sa_data 把目标地址和端口信息混在一起了。 sockaddr_in 解决了这一缺陷,将端口号和IP地址分开存储。

struct sockaddr_in {
short int sin_family; //地址族,AF_xxx 在socket编程中只能是AF_INET
unsigned short int sin_port; //端口号 (使用网络字节顺序)
struct in_addr sin_addr; //存储IP地址 4字节
unsigned char sin_zero[8]; //总共8个字节,实际上没有什么用,只是为了和struct sockaddr保持一样的
};

虽然是两个结构体,可是二者占用的内存是一致的,因此可以互相转化。
sockaddr 常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息。是一种通用的套接字地址。
而 sockaddr_in 一般是储存地址和端口的。用于信息的显示及存储使用。

我们在为bind()函数准备ip、port值时,可以直接将值赋给结构体: sockaddr_in ,请看下面的例子:
int serverfd = -1;
struct sockaddr_in sin; //本地地址、端口赋值
sin.sin_family = PF_INET; //PROTOCL FAMILY 协议族, 使用AF_INET、PF_INET都可以

sin.sin_port = htons(atoi("8183")); //htons()函数将一个16位的无符号短整型数据由主机分列体式格式转换成收集分列体式格式
sin.sin_addr.s_addr = inet_addr("192.168.0.1"); //inet_addr()函数将网络地址转化为二进制数字
serverfd = socket(sin.sin_family,SOCK_STREAM,IPPROTO_TCP);
if(serverfd < 0){
printf("创建server的socket套接字失败");
return -1;
}

bzero(&(sin.sin_zero), 8); // zero the rest of the struct
ret = bind(serverfd,(const struct sockaddr*)&sin,sizeof(sin));
if(ret){
printf("绑定本地地址、端口失败");
return -1;
}
inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。
填值的时候使用 sockaddr_in 结构,而作为函数(如socket, listen, bind等)的参数传入的时候转换成 sockaddr 结构就行了,因为两个结构体都是16个字符长,可以相互转换。

2. AF_INET 和 SOCK_STREAM
AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型;
AF_INET6 则是 IPv6 的;
AF_UNIX 则是 Unix 系统本地通信。

SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送。
SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,主要用于在网络上发广播信息。

posted on 2018-08-23 17:33  Garnett21  阅读(322)  评论(0编辑  收藏  举报