sockaddr介绍
sockaddr是存储socket结构信息的结构体,它具有通用性。
sockaddr在后来ipv4出现之后进化成了sockaddr_in,其在结构体上已与sockaddr不同,而在ipv4用完之后,ipv6出现并产生了ipv6的衍生版本sockaddr_in6。然而为了兼容性,我们无论在使用ipv4还是ipv6进行通信时,都要将结构体强转为sockaddr类型,详见如下。
sockaddr
sockaddr_in – ipv4
需要注意的是结构体in_addr的结构
sockaddr_in6 – ipv6
sockaddr使用
这个sockaddr数据结构在服务端bind时,accept时,客户端connect时都有用,而且使用它的时候也比较不一样。
仅有的accept
extern int accept (int __fd, __SOCKADDR_ARG __addr,
socklen_t *__restrict __addr_len);
在连接过程中需要用到三个sockaddr_in,而仅有accept()函数的第二个参数__SOCKADDR_ARG __addr参数是传出参数,socklen_t *__restrict __addr_len是传入传出参数。
sockaddr定义 – ipv4为例
struct sockaddr_in serv_addr;
作为函数参数
struct sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons(PORT);
listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr))
//由于client_len是一个传入传出参数,必须有初始值
int client_len = sizeof(accept_addr);
int accept_fd = accept(listen_fd, (struct sockaddr *)&accept_addr, &client_len)
accept返回的accept_fd 包含了客户端的ip和port信息
//但是需要注意的是这些信息都是以网络字节序的形式传输过来的,需要进行转换
accept_addr.sin_addr.s_addr
accept_addr.sin_port)
struct sockaddr_in connect_addr;
inet_pton(AF_INET,"127.0.0.1",&connect_addr.sin_addr.s_addr);
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = htons(PORT);
connect(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr))
那之所以要将sockaddr_in 强转为sockaddr原因之一是为了兼容ipv6,当然ipv6也同样需要强转,互相兼容。
sockaddr成员初始化
服务端
bind()
服务端在bind时,必须给sockaddr_in的成员赋值
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//服务端不需要ip地址,INADDR_ANY可以自动取出系统有效的任意ip,取出来默认是int型
serv_addr.sin_port = htons(PORT);
accept()
accept不需要初始化,因为它是用来接收connect的信息的 ,但是一定要复制。
客户端
客户端在connect时,也必须给sockaddr_in的成员赋值,规定连接的协议族和服务端ip与port,否则就不能能连接上服务端,这是显而易见的。
client_sockaddr.sin_port = htons(port);
// 设置端口号
client_sockaddr.sin_family = AF_INET;
// 设置地址族为IPv4
client_sockaddr.sin_addr.s_addr = inet_addr(ip_str);
// 设置IP地址
注:关于sockaddr这个结构体还有什么需要注意的点我也不清楚,就比如下面这个
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
/* This macro is used to declare the initial common members
of the data types used for socket addresses, `struct sockaddr',
`struct sockaddr_in', `struct sockaddr_un', etc. */
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family