日记(16)-20140928
昨天看了电影《亲爱的》,很真实。
---------------------------------------华丽分割线----------------------------------------------
好了,说说今天。
简单谈一下我对listen函数,及其背后机制的理解。
1,内核为每个监听套接字维护2个队列: 未完成连接队列, 已完成连接队列。
2,建立三次握手后,sockfd从未完成连接队列加入已完成连接队列。
3,accept()函数不参与三次握手,而只负责从已建立连接队列中取出一个连接和本地连接 进行绑定;
4,backlog参数决定了未完成队列和已完成队列中连接数目之和的最大值
5,accept()函数调用,会从已连接队列中取出一个“连接”。 未完成队列和已完成队列中连接数目之和将减少1。
6,监听套接字的已完成队列中的元素个数大于0,那么该套接字是可读的。
7,当程序调用accept的时候(设置阻塞参数),那么判定该套接字是否可读,不可读则进入睡眠,直至已完成队列中的元素个数大于0(监听套接字可读)而唤起监听进程。
从网上找了一段验证该机制的代码:额,结果,我不能理解。。。
#include <stdio.h> #include<unistd.h> #include<sys/types.h> /* basic system data types */ #include<sys/socket.h> /* basic socket definitions */ #include<netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include<arpa/inet.h> /* inet(3) functions */ // #include<sys/epoll.h> /* epoll function */ #include<fcntl.h> #include<stdlib.h> #include<errno.h> #include<stdio.h> #include<string.h> int main(int argc,char*argv[]) { int listenfd,connfd; struct sockaddr_in cliaddr,servaddr; int queuelen; if(argc!=2){ puts("usage# ./aworker listenqueuelen"); exit(0); } queuelen=atoi(argv[1]); listenfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(12989); bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); listen(listenfd,queuelen); sleep(60); //将这个注释,会出现另一种情况哟~~ while(1) { connfd = accept(listenfd,NULL,0); if(connfd == -1) { perror("accept error"); continue; } puts("new connection..."); } return 0; } ----------------------------------------华丽分割线--------------------------------------------------- #include <stdio.h> #include<unistd.h> #include<sys/types.h> /* basic system data types */ #include<sys/socket.h> /* basic socket definitions */ #include<netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include<arpa/inet.h> /* inet(3) functions */ // #include<sys/epoll.h> /* epoll function */ #include<fcntl.h> #include<stdlib.h> #include<errno.h> #include<stdio.h> #include<string.h> //void cli_hander(int sockfd,) int main() { int sockfd; int rc; int cpid; struct sockaddr_in servaddr; bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr); servaddr.sin_port = htons(12989); int i; for(i=0;i<20;i++) { cpid = fork(); if(cpid == 0) { sockfd = socket(AF_INET,SOCK_STREAM,0); rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); if(rc == -1) { perror("connect error"); exit(0); } printf("pid#%d connected...\n",getpid()); sleep(3); close(sockfd); exit(0); } } while(1) { cpid = wait(NULL); if(cpid==-1){ perror("end of wait"); break; } printf("pid#%d exit...\n",cpid); } return 0; }
上部分是服务端,下部分是客户端。
服务端执行: ./server 2
客户端执行: ./client
执行结果:
pid#1962174 connected... pid#1871924 connected... pid#1146952 connected... pid#1585294 connected... pid#1962174 exit... pid#1146952 exit... pid#1871924 exit... pid#1585294 exit... connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out connect error: Connection timed out pid#2064532 exit... pid#1749096 exit... pid#1052892 exit... pid#1077410 exit... pid#782454 exit... pid#1261572 exit... pid#602162 exit... pid#1761490 exit... pid#1409108 exit... pid#1687662 exit... pid#897224 exit... pid#1720342 exit... pid#1765402 exit... pid#1830952 exit... pid#2019546 exit... pid#2085100 exit... end of wait: No child processes
立刻建立了4个连接。
怎么理解呢?
我的执行环节为AIX 6.1.0.0