网络编程-listen函数
来源:互联网 发布:知乎 股市入门书籍 编辑:程序博客网 时间:2024/06/14 10:38
listen()函数
假如你不希望与远程的一个地址相连,或者说, 仅仅是将它踢开,那你就需要等待接入请求并且用各种方法处理它们。处 理过程分两步:首先,你听--listen(),然后,你接受--accept() (请看下面的 内容)。
除了要一点解释外,系统调用 listen 也相当简单。
int listen(int sockfd, int backlog);
sockfd 是调用 socket() 返回的套接字文件描述符。backlog 是在进入 队列中允许的连接数目。什么意思呢? 进入的连接是在队列中一直等待直 到你接受 (accept() 请看下面的文章)连接。它们的数目限制于队列的允许。 大多数系统的允许数目是20,你也可以设置为5到10。
和别的函数一样,在发生错误的时候返回-1,并设置全局错误变量 errno。
你可能想象到了,在你调用 listen() 前你或者要调用 bind() 或者让内 核随便选择一个端口。如果你想侦听进入的连接,那么系统调用的顺序可 能是这样的:
socket();
bind();
listen();
/* accept() 应该在这 */
client代码
实验结果:
客户端显示:
结果分析:
同样的运行,结果如下:
客户端:
结果分析:
假如你不希望与远程的一个地址相连,或者说, 仅仅是将它踢开,那你就需要等待接入请求并且用各种方法处理它们。处 理过程分两步:首先,你听--listen(),然后,你接受--accept() (请看下面的 内容)。
除了要一点解释外,系统调用 listen 也相当简单。
int listen(int sockfd, int backlog);
sockfd 是调用 socket() 返回的套接字文件描述符。backlog 是在进入 队列中允许的连接数目。什么意思呢? 进入的连接是在队列中一直等待直 到你接受 (accept() 请看下面的文章)连接。它们的数目限制于队列的允许。 大多数系统的允许数目是20,你也可以设置为5到10。
和别的函数一样,在发生错误的时候返回-1,并设置全局错误变量 errno。
你可能想象到了,在你调用 listen() 前你或者要调用 bind() 或者让内 核随便选择一个端口。如果你想侦听进入的连接,那么系统调用的顺序可 能是这样的:
socket();
bind();
listen();
/* accept() 应该在这 */
因为它相当的明了,我将在这里不给出例子了。(在 accept() 那一章的 代码将更加完全。)真正麻烦的部分在 accept()。
Unix网络编程描述如下:
总结
0. accept()函数不参与三次握手,而只负责从已建立连接队列中取出一个连接和sockfd进行绑定;
1. backlog参数决定了未完成队列和已完成队列中连接数目之和的最大值(从内核角度看,是否这个和就是等于sock->recv_queue ?);
2. accept()函数调用,会从已连接队列中取出一个“连接”(可以是一个描述连接的数据结构,listensocket->sock->recv_queue[sk_buff] ? ),未完成队列和已完成队列中连接数目 之和将减少1;即accept将监听套接字对应的sock的接收队列中的已建立连接的sk_buff取下(从该sk_buff中可以获得对端主机的发送过来的tcp/ip数据包)
3. 监听套接字的已完成队列中的元素个数大于0,那么该套接字是可读的。
4. 当程序调用accept的时候(设置阻塞参数),那么判定该套接字是否可读,不可读则进入睡眠,直至已完成队列中的元素个数大于0(监听套接字可读)而唤起监听进程。
实例分析1
将服务器端的listen函数backlog设置为2,用20个客户端与服务器建立连接,查看连接的建立情况。
服务器代码:
- #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=5;
- 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(2989);
- 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;
- }
client代码
- #include "client.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(2989);
- for(int 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;
- }
实验结果:
服务器端显示:
- root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
客户端显示:
- root@cloud2:~/slp/NetWrokProgram/client# ./a.out
- pid#16697 connected...
- pid#16699 connected...
- pid#16698 connected...
- pid#16697 exit...
- pid#16699 exit...
- pid#16698 exit...
- pid#16700 connected...
- pid#16701 connected...
- pid#16700 exit...
- pid#16701 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
- pid#16702 exit...
- pid#16703 exit...
- pid#16704 exit...
- pid#16705 exit...
- pid#16706 exit...
- pid#16707 exit...
- pid#16708 exit...
- pid#16709 exit...
- pid#16710 exit...
- pid#16711 exit...
- pid#16712 exit...
- pid#16713 exit...
- pid#16714 exit...
- pid#16715 exit...
- pid#16716 exit...
- end of wait: No child processes
结果分析:
同时建立连接的客户端进程共有20个,可是只有5个完成了连接的建立,其他15个没有成功。有趣的是,建立的5个链接中有3个是马上建立的,2个是过了一段时间后后来才建立的。
实例分析2
将server端的代码中的sleep(60)注释,即服务端listen即开始进入while循环中的accept阻塞:
- ...
- listen(listenfd,queuelen);
- sleep(60); //将这个注释,会出现另一种情况哟~~
- while(1)
- {
- connfd = accept(listenfd,NULL,0);
- ....
同样的运行,结果如下:
- root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
客户端:
- root@cloud2:~/slp/NetWrokProgram/client# ./a.out
- pid#16736 connected...
- pid#16737 connected...
- pid#16738 connected...
- pid#16739 connected...
- pid#16740 connected...
- pid#16741 connected...
- pid#16742 connected...
- pid#16743 connected...
- pid#16744 connected...
- pid#16745 connected...
- pid#16746 connected...
- pid#16747 connected...
- pid#16748 connected...
- pid#16749 connected...
- pid#16750 connected...
- pid#16751 connected...
- pid#16752 connected...
- pid#16753 connected...
- pid#16755 connected...
- pid#16754 connected...
- pid#16736 exit...
- pid#16737 exit...
- pid#16738 exit...
- pid#16739 exit...
- pid#16740 exit...
- pid#16741 exit...
- pid#16742 exit...
- pid#16743 exit...
- pid#16744 exit...
- pid#16745 exit...
- pid#16746 exit...
- pid#16747 exit...
- pid#16748 exit...
- pid#16749 exit...
- pid#16750 exit...
- pid#16751 exit...
- pid#16752 exit...
- pid#16753 exit...
- pid#16755 exit...
- pid#16754 exit...
- end of wait: No child processes
结果分析:
由于每个连接在建立之后,已完成队列中的连接马上就被accept给读取了,所以已完成和未完成队列中的连接数之和根本不可能超过backlog限定的个数。
原文链接:
http://blog.csdn.net/ordeder/article/details/21551567 0 0
- 网络编程-listen函数
- 网络编程socket之listen函数
- linux网络编程之listen函数
- 网络编程socket之listen函数
- 网络编程socket之listen函数
- 网络编程socket之listen函数
- UNIX网络编程-listen函数及其包裹函数介绍
- 网络监听函数listen()
- 网络socket编程指南 4 listen accept send recv 函数
- linux网络编程之Listen函数参数介绍
- TCP网络编程中的listen
- Socket编程:listen()函数英文翻译
- unix网络编程bind函数listen函数和accept函数详解
- C++ tcp/ip网络编程中listen函数和accept函数详解和区别
- linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)
- linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)
- linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)
- linux网络编程常用函数详解与实例(socket-->bind-->listen-->accept)
- presentModalViewController的使用
- Leetcode---Unique Binary Search Trees II
- jQuery ajax提交
- uml
- 原android 涂鸦(清屏,画笔,粗细,保存)以及canvas源码学习
- 网络编程-listen函数
- hdu5114 Collision [模拟]
- #import 指令
- Canvas标签学习总结
- elastic编译
- Android的SharedPreference中putStringSet存取数据
- 【SVN】团队项目出现The project cannot be built until build path errors are resolved的解决方法与.classpath文件
- duilib编译错误解决方法整理 (含VS2013)
- 为什么要使用反射机制