Socket programming in C, using the select() function

梦想的初衷 提交于 2021-01-28 01:10:54

问题


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.

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.

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. 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(...))?


回答1:


You have two problems: you don't understand how accept() works in TCP, and you need to read the incoming data in UDP.

select() tells you that a listening socket has connection to accept, or reading socket has data to read.

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. If you don't, select will keep telling you that you have data.

In your TCP branch, you call 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() returns a new socket for you - the one you should be using for IO. If anything needs to be closed, it's that new socket.




回答2:


Please check why you have this in server.

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

replace it with

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

where maxDescPlus1 --> is number of descriptors to select plus 1 value.



来源:https://stackoverflow.com/questions/3372605/socket-programming-in-c-using-the-select-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!