简体   繁体   English

使用select()函数在C中进行套接字编程

[英]Socket programming in C, using the select() function

Based from the answers I got from this thread , I've created this: 根据从该线程获得的答案,我创建了以下代码:

    //Server 

    sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/

    timeout = 50000;

    serv_sock_input[0] = TCP(1234); 
    serv_sock_input[1] = UDP(9876);

    input_protocols[0] = "tcp";
    input_protocols[1] = "udp";

    while (1)
    {
        FD_ZERO(&sock_set);
        for (x = 0; x<number_of_inputs; x++)
        {
            FD_SET(serv_sock_input[x], &sock_set);
        }

        select_timeout.tv_sec = timeout;
        select_timeout.tv_usec = 0;

        if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
            printf("No requests");
        else
        {
            for (x = 0; x<number_of_inputs; x++)
            {
                if (FD_ISSET(serv_sock_input[x],&sock_set))
                {
                    printf("\nRequest on port %d: \n", x);
                    if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE
                    {
                        accept_socket(serv_sock_input[x]);
                        printf("Input TCP Port %d\n",x);
                        close_socket(serv_sock_input[x]);
                    }
                    else
                    {
                        printf("Input UDP Port %d\n",x);
                    }
                }
            }
        }
    }
    sock_term();
}

int TCP (unsigned short port)
{
    int sock;                        
    struct sockaddr_in servAddr; 

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        exit(1);

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;         
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(port);            

    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        exit(1);

    if (listen(sock, 5) < 0)
        exit(1);

    return sock;
}

int UDP (unsigned short port)
{
    int sock;                        /* socket to create */
    struct sockaddr_in servAddr; /* Local address */

    /* Create socket for sending/receiving datagrams */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        exit(1);

    /* Construct local address structure */
    memset(&servAddr, 0, sizeof(servAddr));   /* Zero out structure */
    servAddr.sin_family = AF_INET;                /* Internet address family */
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
    servAddr.sin_port = htons(port);      /* Local port */

    /* Bind to the local address */
    if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        exit(1);


    return sock;
}

//Client
sock_init();

    if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        exit(1);

    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family      = AF_INET;
    client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    client_addr.sin_port        = htons(1234);

    if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0)
        exit(1);

    closesocket(client_sock_output);

    sock_term();

When the server starts, the server gets blocked at the if(select(...)) statement. 服务器启动时,服务器在if(select(...))语句处被阻塞。

So when I run the Server, and then the client, the client connects to the server (sometimes it takes a couple times to run the client before they connect). 因此,当我先运行服务器,再运行客户端时,客户端将连接到服务器(有时,连接客户端之前,需要花费几次时间来运行客户端)。 Then the if(select...)) statement is no longer true and it proceeds to the else. 然后, if(select...))语句不再为真,并继续进行else。

After that, the client closes the connection, and the program. 之后,客户端关闭连接和程序。 However, and this is where my problem happens, the if(select(...)) statement is always false. 但是,这就是我的问题所在, if(select(...))语句始终为false。 I get this output: 我得到以下输出:

Request on port 0:  
Input TCP Port 0  

Request on port 1:  
Input UDP Port 1

This output repeats forever. 此输出将永远重复。 How come it doesn't get stuck at the if(select(...)) ? 它怎么不会卡在if(select(...))

You have two problems: you don't understand how accept() works in TCP, and you need to read the incoming data in UDP. 有两个问题:您不了解accept()在TCP中的工作方式,并且您需要在UDP中读取传入的数据。

select() tells you that a listening socket has connection to accept, or reading socket has data to read. select()告诉您侦听套接字具有要接受的连接,或者读取套接字具有要读取的数据。

For select to stop telling you this, you need to actually read the data or accept the connection. 若要选择停止告诉您,您需要实际读取数据或接受连接。

In your UDP branch, you need to call receiv to actually get the data. 在UDP分支中,您需要调用receiv才能实际获取数据。 If you don't, select will keep telling you that you have data. 如果没有,select将继续告诉您您有数据。

In your TCP branch, you call accept_socket. 在您的TCP分支中,您调用accept_socket。 I don't know what is your implementation of it, but it's most probably wrong to close the socket you just called accept() on. 我不知道它的实现是什么,但是关闭刚刚调用accept()的套接字很可能是错误的。 accept() returns a new socket for you - the one you should be using for IO. accept()为您返回一个新的套接字-您应该用于IO的套接字。 If anything needs to be closed, it's that new socket. 如果需要关闭任何东西,那就是新的套接字。

Please check why you have this in server. 请检查为什么在服务器中有此功能。

if ( select(0, &sock_set, NULL, NULL, &select_timeout) == 0) if( select(0, &sock_set,NULL,NULL,&select_timeout)== 0)

replace it with 替换为

if ( select( maxDescPlus1 , &sock_set, NULL, NULL, &select_timeout) == 0) if( select( maxDescPlus1 &sock_set,NULL,NULL,&select_timeout)== 0)

where maxDescPlus1 --> is number of descriptors to select plus 1 value. 其中maxDescPlus1->是要选择的描述符数量加1的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM