Программирование сокетов на C с использованием функции select () - PullRequest
2 голосов
/ 30 июля 2010

Основываясь на ответах, которые я получил от этой темы , я создал это:

    //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();

Когда сервер запускается, он блокируется в операторе if(select(...)).

Поэтому, когда я запускаю Сервер, а затем клиента, клиент подключается к серверу (иногда для запуска клиента требуется несколько раз, прежде чем они подключаются). Тогда оператор if(select...)) больше не верен и переходит к другому.

После этого клиент закрывает соединение и программу. Однако, и здесь возникает моя проблема, оператор if(select(...)) всегда ложен. Я получаю этот вывод:

Request on port 0:  
Input TCP Port 0  

Request on port 1:  
Input UDP Port 1

Этот вывод повторяется навсегда. Почему это не застревает на if(select(...))?

Ответы [ 2 ]

5 голосов
/ 30 июля 2010

У вас есть две проблемы: вы не понимаете, как accept () работает в TCP, и вам нужно прочитать входящие данные в UDP.

select () сообщает вам, что прослушивающий сокет имеет соединение спринять или прочитать сокет, в котором есть данные для чтения.

Для того, чтобы прекратить рассказывать вам об этом, вам нужно фактически прочитать данные или принять соединение.

В вашей ветви UDP вам необходимовызов получен, чтобы фактически получить данные.Если вы этого не сделаете, select будет постоянно сообщать вам, что у вас есть данные.

В вашей ветке TCP вы вызываете accept_socket.Я не знаю, какова ваша реализация, но, скорее всего, неправильно закрывать сокет, который вы только что вызвали accept ().accept () возвращает новый сокет для вас - тот, который вы должны использовать для ввода-вывода.Если что-то нужно закрыть, это новый сокет.

1 голос
/ 25 октября 2013

Пожалуйста, проверьте, почему у вас это на сервере.

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

замените его на

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

где maxDescPlus1 -> - количество дескрипторов для выбора плюс значение 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...