首先先看这两个函数:
bind():
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 第一个参数sockfd使用的应该是服务器端的socket文件描述符。
- 第二个参数const struct sockaddr *addr是构造出的IP地址和端口号。
- 第三个参数是addr的长度。
- bind函数的返回值为“0”则创建成功。失败返回-1,设置errno。
accept():
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 第一个参数sockfd同bind也是服务器端的socket文件描述符。
- 第二个参数addr是传出参数,返回链接客户端的地址信息,其中包含IP地址和端口号。
- 第三个参数addrlen是一个传入传出参数,传入的,是sizeof(addr)的大小函数在返回时,则返回的是真正接收到地址结构体的大小
- accept函数的返回值则是创建结果,如果创建成功,返回的是新的客户端的socket文件描述符,用于和客户端通信,创建失败则返回-1,设置errno。
这里需要注意的是:
一、sockaddr的问题
在两个函数中,都是使用了struct sockaddr类型的参数。这个结构体的定义为:
struct sockaddr {
sa_family_t sa_family; //16位的地址类型
char sa_data[14]; //14字节的地址数据
};
但是在现代编程中sockaddr类型已经被废弃,取而代之的是struct sockaddr_in,定义为:
struct sockaddr_in {
__kernel_sa_family_t sin_family; /* Address family */ 地址结构类型
__be16 sin_port; /* Port number */ 端口号
struct in_addr sin_addr; /* Internet address */ IP地址
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
所以,我们需要在编程的过程中,使用scokaddr_in来传值,然后,在后续传参的时候,把sockaddr_in强制转换成sockaddr来使用。
比如:
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr= htonl(INADDR_ANY);
bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
cfd=accept(lfd,(struct sockaddr *)&clie_addr,&clie_addr_len);
二、传入传出参数的问题:
通过观察bind和accept函数的参数,可以发现:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
两个函数的定义中第三个参数,一个是socklen_t addrlen,一个是socklen_t *addrlen。
bind函数中soclen_t addr表示:这是一个传入参数,在使用的时候,可以像上文的程序中一样,直接sizeof(serv_addr)传值进去。
accpet函数中socklen_t *addr表示:这是一个传入传出参数,在使用的时候,必须先在socklen中声明之后,才可以使用。在accpet函数返回的时候,*addr也会被重新赋值。
总结一下传入传出参数的使用:
扫描二维码关注公众号,回复:
4902519 查看本文章
- 传入的参数,需要在传入之前,先初始化好一个实际值
- 传出的参数,要加“&”取地址。