tcp连接中的listen()与accept()

int listen(int sockfd, int backlog);

作用:通知服务端准备接受套结字上的连接请求。<>364页原话.

感觉说的很浅,具体是怎么准备的呢?

先说结论:  listen()调用完毕,生成一个大小为backlog*3/2的等待队列(队列的长度,不同内核版本,系数(这个3/2)可能会有差异),这时客户端如果调用connect()并且队列没满则TCP连接直接就建立好了(三次握手建立双向连接).如果队列已经满了则服务段拒绝建立新的TCP连接. 实际上调用一次accept()是从该队列取出一个客户端的socketfd返回,同时队列的容量也会减一,如果队列为空,则accept()就会阻塞.


demo代码证明结论!

#服务端:server.c

#include    //该头文件是我自己封装并放到/usr/include下的一个头文件
#define PORT         9898
#define LOCAL_IP     "127.0.0.1"

int main(int argc,char **argv)
{
    struct sockaddr_in local;
    int sockfd;
    int on=1;
    socklen_t   len;
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))){
        perror("error in setsockopt()!");
        return -1;
    }
    len = sizeof(struct sockaddr_in);
    memset(&local,0,len);
    local.sin_family = AF_INET;
    local.sin_port = htons(PORT);
    inet_aton(LOCAL_IP,&local.sin_addr);
    if(-1 == (bind(sockfd,(struct sockaddr *)&local,len))){
        perror("error in bind()!");
        return -1;
    }
    if(-1 == (listen(sockfd,2))){
        perror("error in listen()!");
        return -1;
    }
    pause();
    return 0;
}

#客户端:client.c

#include
int main()
{
    struct sockaddr_in  cli;
    int sockfd;
    head_inf   inf;
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    memset(&cli,0,sizeof(cli));
    cli.sin_family = AF_INET;
    cli.sin_port = htons(9898);
    cli.sin_addr.s_addr = inet_addr("127.0.0.1");

    if(-1 == connect(sockfd,(struct sockaddr *)&cli,sizeof(cli))){
        printf("%s\n",strerror(errno));
        return 2;
    }
    pause();
    return 0;
}

#编译

gcc client.c -o client

gcc server.c -o server


listen的第二个参数是2,则队列容量最大为3.开启3个bash并执行 ./client  执行netstat -nt查看tcp连接的状态

tcp连接中的listen()与accept()_第1张图片


当开启第4个client时

tcp连接中的listen()与accept()_第2张图片


我们发现第四个TCP连接没有成功建立,只是一个半连接的状态(SYN_RECV)。


    另外再说一下accept(),该函数仅仅是从已连接队列中取出客户端的socket描述符.<>上也给出了一个例子:

服务端server.c

......

listen(sockfd,2);

sleep(20);

int new_sockfd = accept(sockfd,(struct sockaddr_in *)&client,&sockaddr_length);

......

现在让客户端在服务端sleep(20)期间 断开网线或关闭客户端程序,结果丝毫不影响服务端accept并获取客户端的socket描述符.


你可能感兴趣的:(C/C++套结字编程)