网络编程之listen的那点屁事

写在前面

    我们知道在网络编程中,listen接口是用来建立socket监听的,其参数只有两个。我们就listen展开说明。

函数原型

    int listen(int sockfd, int backlog);

函数作用

    当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。根据TCP状态转换图,调用listen导致套接字从CLOSED状态转换成LISTEN状态。

案列分析


server.c

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>

static bool stop = false;
/*SIGTERM 信号的处理函数,触发时结束主进程中的循环*/
static void handle_term(int sig)
{
	sig=0;
    stop = true;
}

int main(int argc, char* argv[])
{
    signal(SIGTERM, handle_term);

    if(argc <= 3)
    {
        printf("usage: %s ip_address port_number backlog\n", basename(argv[0]));
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);
    int backlog = atoi(argv[3]);

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    assert(sock >= 0);

    struct sockaddr_in address;
    bzero(&address, sizeof(address));
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>

static bool stop = false;
/*SIGTERM 信号的处理函数,触发时结束主进程中的循环*/
static void handle_term(int sig)
{
	sig=0;
    stop = true;
}

int main(int argc, char* argv[])
{
    signal(SIGTERM, handle_term);

    if(argc <= 3)
    {
        printf("usage: %s ip_address port_number count\n", basename(argv[0]));
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);
    int count= atoi(argv[3]);
    
    struct sockaddr_in server_address;
    bzero(&server_address, sizeof(server_address));
    server_address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &server_address.sin_addr);
    server_address.sin_port = htons(port);

    int sockfd[count];
    for(int i = 0; i < count; i++)
    {
        sockfd[i] = socket(AF_INET, SOCK_STREAM,0);
        assert(sockfd[i] >= 0);
        if(connect(sockfd[i],(struct sockaddr*)&server_address,sizeof(server_address)) < 0)
        {
            printf("connection failed\n");
        }
    }

    /*循环等待连接,直到有SIGTERM信号将它中断*/
    while(!stop)
    {
        sleep(1);
    }
    for(int j = 0; j < count; j++)
    {
        close(sockfd[j]);
    }

    return 0;
}

address.sin_family = AF_INET; inet_pton(AF_INET, ip, &address.sin_addr); address.sin_port = htons(port); int ret = bind(sock, (struct sockaddr*)&address, sizeof(address)); assert(ret != -1); ret = listen(sock, backlog); assert( ret != -1); /*循环等待连接,直到有SIGTERM信号将它中断*/ while(!stop) { sleep(1); } /*关闭socket*/ close(sock); return 0;}

client.c

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>

static bool stop = false;
/*SIGTERM 信号的处理函数,触发时结束主进程中的循环*/
static void handle_term(int sig)
{
	sig=0;
    stop = true;
}

int main(int argc, char* argv[])
{
    signal(SIGTERM, handle_term);

    if(argc <= 3)
    {
        printf("usage: %s ip_address port_number count\n", basename(argv[0]));
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);
    int count= atoi(argv[3]);
    
    struct sockaddr_in server_address;
    bzero(&server_address, sizeof(server_address));
    server_address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &server_address.sin_addr);
    server_address.sin_port = htons(port);

    int sockfd[count];
    for(int i = 0; i < count; i++)
    {
        sockfd[i] = socket(AF_INET, SOCK_STREAM,0);
        assert(sockfd[i] >= 0);
        if(connect(sockfd[i],(struct sockaddr*)&server_address,sizeof(server_address)) < 0)
        {
            printf("connection failed\n");
        }
    }

    /*循环等待连接,直到有SIGTERM信号将它中断*/
    while(!stop)
    {
        sleep(1);
    }
    for(int j = 0; j < count; j++)
    {
        close(sockfd[j]);
    }

    return 0;
}

启动server

./server 12.7.0.0.1 6666 5

启动client客户端程序,接收3个参数:IP地址、端口和count连接数。我们在Linux另外一个终端上运行(建立10个连接):

./client myself 6666 9

启动listen监听队列内容

netstat -nt|grep 6666


结论:

其中处于LISTEN状态的为建立监听的服务端程序,在监听队里中,处于ESTABLISHED状态的连接有6个(backlog值加1),其他的连接都处于SYN_RCVD状态。我们改变服务端与客户端程序的第3个参数并重新运行之,能发现同样的规律,即完成连接最多有(backlog+1)个。在不同的系统上,运行结果会有些差别,不过监听队列中已完成连接的上限通常比backlog值略大。



猜你喜欢

转载自blog.csdn.net/jiaochiwuzui/article/details/80668392