Блочный сокет с Unix и C / C ++ Help - PullRequest
0 голосов
/ 31 марта 2011

Я пытаюсь выяснить, что блокирует мою программу. Я использую сервер, который использует потоки POSIX. Я должен для моей лаборатории компьютерного программирования. Основная функция прослушивает новые соединения. Как только он принимает соединение, он создает новый поток, передавая поток данных в поток. Я могу успешно подключиться к серверу, используя несколько соединений telnet / client. Я могу один раз успешно отправить данные на сервер, но если я попытаюсь отправить их снова, сервер ничего не сделает.

Часть основной функции

int active_thread = 0;  
    //The Running loop  
while(running)  
{ 
    if(active_thread > NUMBTHREADS)
    {
        printf("Unable to accept client connection!  Threads are all used up");
        running = false;
    }
    else
    {
        if(FD_ISSET(sockfd, &readfds))
        {
            if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
            {
                fprintf(stderr, "Unable to accept client \n");
                perror("What");
                break;
            }

            activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
            //close(bindfd[active_thread]);
            //pthread_join( threads[active_thread], NULL);
            active_thread++;
            //running = false;
            }       
        }
    }
    close(sockfd);
    return 0;
}

Часть кода резьбы POSIX

void *server_handler( void *sockfd)  
{  
    int bindfd = *( (int *) sockfd);  
    char buffer[MESSAGELENGTH];  
    bool running = true;  
    printf("Thread was created successfully\n");  
    char intro[] = "Successfully Connected to server!\n";  
    struct pollfd pfd;  
    pfd.fd = bindfd;  
    pfd.events = POLLIN;  

    if ( (send(bindfd, intro, strlen(intro), 0)) < 0)  
    {  
        perror("Unable to send");  
    }  

    while(running){  
    char msg[] = "\nYou have the following options!\n1) Insert an integer:  insert <integer>\n2) Remove An Integer:  remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer:  get_first\n5) Get last integer:  get_last\n6) Quit program:  quit\n ";  
    if ( (send(bindfd, msg, strlen(msg), 0)) < 0)  
    {  
        perror("Unable to send");  
    }  
    memset(&buffer, 0, MESSAGELENGTH);  
    if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0)  
    {
        //SOme other code
    }  
}  

Я думаю, что это блокировка при принятии или recv. Я слышал о select () и различных других методах, но мне трудно их реализовать. Спасибо!

Ответы [ 2 ]

2 голосов
/ 31 марта 2011

Основная причина вашей проблемы заключается в том, что вы безоговорочно выполняете close(sockfd); return 0; в нижней части цикла while (running), что означает, что цикл выполняется только один раз.

Кроме того, вы не должны использовать FD_ISSET(), если вы также не используете select(). Ваш основной цикл должен выглядеть примерно так:

int active_thread = 0;  

while (active_thread < NUMBTHREADS)  
{ 
    if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
    {
        fprintf(stderr, "Unable to accept client \n");
        perror("What");
        break;
    }

    activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
    active_thread++;
}

if (active_thread >= NUMBTHREADS)
{
    printf("Unable to accept client connection!  Threads are all used up.\n");
}
running = false;
close(sockfd);
return 0;
1 голос
/ 31 марта 2011

По умолчанию сетевые сокеты блокируются.Вам необходимо установить флаг O_NONBLOCK на сокете.

if(fcntl(fd, F_GETFL, &flags) < 0 ||
   fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
        perror("Failed to set socket as non-blocking");

Теперь вместо блокировки, когда нет ввода (или буферного пространства для хранения вывода), возвращается ошибка EAGAIN (или EWOUDLBLOCK).Наконец, вам нужно будет использовать select () или poll (), когда вам больше нечего делать, кроме как ждать ввода-вывода.Эти вызовы будут вызывать процесс только тогда, когда будет либо вход, либо пространство для вывода, либо, возможно, истечет время ожидания.

int maxFd;
fdset fds;

FD_ZERO(&fds);
FD_SET(listenFd, &fds);
FD_SET(sockFd1, &fds);
FD_SET(sockFd2, &fds);
maxFd = listenFd+1;
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd;
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd;
if(select(maxFd, &fds, &fds, &fds,  NULL) < 0) {
        perror("Failed on select()");
        exit(1);
}
if(FD_ISSET(listenFd, &fds))
    ...

Этот пример не завершен или не обязательно на 100% правильный, но должен бытьхорошее начало.Кроме того, я склонен резервировать с помощью send * () и recv * () при работе с сокетами SOCK_DGRAM и просто использовать read (), write () на сокетах SOCK_STREAM.

...