listen和accept函数解析

来源:互联网 发布:linux ubuntu 服务器版 编辑:程序博客网 时间:2024/05/21 09:10

函数原型:

#include <sys/socket.h>

int listen(int s, int backlog);

函数功能:listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

参数:

S: 用于标识一个已捆绑为未连接套接口的描述字。

backlog:等待连接队列的最大长度。

返回值:若无错误发生,返回0,否则返回-1(SOCKET_ERROR).

下面写个人对这个函数的一些理解:

     当调用这个函数后,s即变为监听套接字,即此时如果客户端对目的ip和端口进行connect操作,才可以进行三次握手操作,在未调用listen时,客户端是进行不了三从握手操作的,具体细节请参考http://blog.csdn.net/junjun150013652/article/details/37966901?utm_source=tuicool&utm_medium=referral这篇文章。

     内核为任何一个给定的监听套接字维护两个队列:

     (1) 未完成连接队列(incomplete connection queue),当服务器接收到客户端发来三次握手的第一个SYN分片,此时对应套接字处于SYN_RECV状态,服务器会给对应客户端回复一个ACK+SYNC包,并把对应套接字放到未完成连接队列中。

     (2) 已完成队列(completed connection queue),当客户端对服务器发来的SYNC包回复ACK确认包后,此时即完成三次握手过程,此时对应套接字处于ESTABLISHED状态,把对应套接字从未完成连接队列移到已完成连接队列中。

      关于backlog,这个参数争议比较大,《UNIX网络编程》一书中表达了类似以下的说法:backlog参数决定了未完成队列和已完成队列中连接数目之和的最大值,晚上有人对此进行了验证,地址是http://blog.csdn.net/ordeder/article/details/21551567。

    咱又观摩了很多其他文章,有一些观点是在最新的Linux版本中,backlog的大小并不是已完成和未完成队列中的连接数之和了,而是已完成连接数(completed connection queue).


函数原型:

#include <sys/types.h>

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);

功能:accept()系统调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。它提取出所监听套接字的等待连接队列中第一个连接请求创建一个新的套接字,并返回指向该套接字的文件描述符。新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。

参数:

sockfd,    利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接

addr,    指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写,返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL;

addrlen,    一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;

如果队列中没有等待的连接,套接字也没有被标记为Non-blocking,accept()会阻塞调用函数直到连接出现;如果套接字被标记为Non-blocking,队列中也没有等待的连接,accept()返回错误EAGAINEWOULDBLOCK

备注:一般来说,实现时accept()为阻塞函数,当监听socket调用accept()时,它先到自己的receive_buf中查看是否有连接数据包;

若有,把数据拷贝出来,删掉接收到的数据包,创建新的socket与客户发来的地址建立连接;

若没有,就阻塞等待;

为了在套接字中有到来的连接时得到通知,可以使用select()或poll()。当尝试建立新连接时,系统发送一个可读事件,然后调用accept()为该连接获取套接字。另一种方法是,当套接字中有连接到来时设定套接字发送SIGIO信号。

返回值:成功时,返回非负整数,该整数是接收到套接字的描述符;出错时,返回-1(INVALID_SOCKET),相应地设定全局变量errno。

例子:

sockaddr_in caddr;socklen_t len = sizeof(caddr);int fd = accept(listenfd, (sockaddr*)&caddr, &len);if (INVALID_SOCKET == fd)     return -1;

accept部分来自http://blog.csdn.net/david_xtd/article/details/7087843



1 0
原创粉丝点击