今天在《Linux高性能服务器编程》中看到:accept()函数是从监听队列中取出连接,于是自己使用书上的方法验证了一下,代码如下:
//accept_abnor_data.cpp#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>int main(int argc, char * argv[]) {if (argc <= 2) {printf("usage:%s ip_address port_number\n", argv[0]);return 1;}const char * ip = argv[1];int port = atoi(argv[2]);struct sockaddr_in address;bzero(&address, sizeof(address));address.sin_family = AF_INET;inet_pton(AF_INET, ip, &address.sin_addr);address.sin_port = htons(port);int sock = socket(PF_INET, SOCK_STREAM, 0);assert(sock >= 0);int ret = bind(sock, (struct sockaddr *)&address, sizeof(address));assert(ret != -1);ret = listen(sock, 5);assert(ret != -1);sleep(20); //睡眠20sstruct sockaddr_in client;socklen_t client_addrlength = sizeof(client);int connfd = accept(sock, (struct sockaddr *)&client, &client_addrlength); //accept()是从监听队列中取出连接,不论连接状态如何if (connfd < 0) {printf("errno is: %d\n", errno); }else {//接受成功打印客户端ip和端口号char remote[INET_ADDRSTRLEN];printf("connected with ip :%s and port :%d\n", inet_ntop(AF_INET, &client.sin_addr, remote, INET_ADDRSTRLEN), ntohs(client.sin_port));}return 0;
}
修改Makefile结果如下:
.PHONY:clean all
CC=gcc
GFLAGS=-Wall -g
BIN=accept_abnor_data
all:$(BIN)
%.0:%.c$(CC) $(GFLAGS) -c $< -o $@
clean:rm -f *.o $(BIN)
打开终端(1),执行下列命令:
make
./accept_abnor_data 192.168.1.104 12345
打开另一个终端(2),使用telnet命令进行登录:
telnet 192.168.1.104 12345
结果如下:
再打开一个终端终端,查看端口状态:
netstat -nt | grep 12345
查看到网络状态如下:
终端(1)中的./accept_abnor_data 192.168.1.104 12345
命令执行20后,即睡眠结束,终端(1)上会打印出:
终端(2)上会打印出:
以上是客户端正常退出的结果,下面我们来看一下客户端异常退出的情况:
操作与上面不同的是,我们在终端使用telnet远程登录时(测试是在本地进行的),登录成功后,键入ctrl+],强制退出到telnet命令界面,再键入quit命令,结果如下:
客户端已经退出,此时的端口状态为:
客户端和服务器端端口状态分别为:FIN_WAIT2 、CLOSE_WAIT
此时,你能以为服务器端不会接受客户端的本次连接了,可等到服务器端睡眠20s后,仍能接受客户端的请求,并打印客户端的ip和端口号:
由此可见,accept()函数只是从监听队列中取出连接,并不关心连接处于何种状态,更不关心任何网络状况的变化,只要监听队列中有请求连接,服务器端就可以进行连接。
注:测试是在本地进行的,本地ip为192.168.1.104
参考:
《高性能服务器编程》