先看下面的代码:
监听127.0.0.1 : 5563 ,如果有连接,就输出这个客户端的IP、端口和连接描述符。
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char** argv){
int _socket = 0 ;
struct sockaddr_in addr_server,addr_client;
_socket = socket(AF_INET, SOCK_STREAM, 0);
addr_server.sin_family = AF_INET;
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
addr_server.sin_port = htons(5563);
int ret = bind(_socket,(struct sockaddr *)&addr_server, sizeof(addr_server));
ret = listen(_socket, 16);
int length ;
while(1){
int fd = accept(_socket, (struct sockaddr *)&addr_client, &length);
if (fd == -1) {
break;
}
printf("IP:%s.Port:%d.Fd:%d Connect!\n",inet_ntoa(addr_client.sin_addr),addr_client.sin_port,fd);
}
return 0;
}
在执行gcc -o accept accept.c之后,分两次在客户端用telnet进行连接,输出如下:
[root@localhost network]# ./accept
IP:255.127.0.0.Port:22011.Fd:4 Connect!
IP:127.0.0.1.Port:25237.Fd:5 Connect!
accept定义如下:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
1)sockfd 。通过调用socket函数所返回的socket 文件描述符。
2)addr。sockaddr结构,这个参数在accept成功返回之后,将会被socket连接另一端的地址填充,也就是会包含客户端的IP和端口信息。
3)addrlen。这是一个引用类型的参数,调用accept的人必须要对这个值以初始为第二个参数addr的结构所包含的字节数大小。当accept返回之后,它将包含从另一端返回的实际字节数大小。
那么问题就出来了,在前面的代码中第一次调用 accept时,并没有指定length参数的值为addr结构体大小,这样内核就会以为这个结构大小为0,因此不足以存储将客户端的信息返回,但在第一次以后,length的值就被内核修改了,改成了真实的结构返回大小,而后每次调用就正常了。
修改如下:
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc,char** argv){
int _socket = 0 ;
struct sockaddr_in addr_server,addr_client;
_socket = socket(AF_INET, SOCK_STREAM, 0);
addr_server.sin_family = AF_INET;
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
addr_server.sin_port = htons(5563);
int ret = bind(_socket,(struct sockaddr *)&addr_server, sizeof(addr_server));
ret = listen(_socket, 16);
int length ;
while(1){
length = sizeof(struct sockaddr_in);
int fd = accept(_socket, (struct sockaddr *)&addr_client, &length);
if (fd == -1) {
break;
}
printf("IP:%s.Port:%d.Fd:%d %d Connect!\n",inet_ntoa(addr_client.sin_addr),addr_client.sin_port,fd,length);
}
return 0;
}
运行就正常了:
[root@localhost network]# ./accept
IP:127.0.0.1.Port:26005.Fd:4 16 Connect!
IP:127.0.0.1.Port:26261.Fd:5 16 Connect!
IP:127.0.0.1.Port:26517.Fd:6 16 Connect!
IP:127.0.0.1.Port:26773.Fd:7 16 Connect!