使用Unix和C / C ++帮助阻止套接字

时间:2011-03-31 00:27:30

标签: c sockets posix blocking

我正在试图弄清楚什么阻碍了我的程序。我正在运行使用POSIX线程的服务器。我必须为我的计算机编程实验室。 main函数侦听新连接。一旦接受连接,它就会通过将FD传递给线程来创建新线程。我能够使用多个telnet /客户端连接成功连接到服务器。我可以成功地将数据发送到服务器一次,但如果我再次尝试发送,服务器将不会执行任何操作。

主要功能的一部分

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
    }  
}  

我认为它阻止接受或接受。我听说过select()和其他各种方法,但是我很难尝试实现它们。谢谢!

2 个答案:

答案 0 :(得分:2)

您的问题的根本原因似乎是您无条件地在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 :(得分:1)

默认情况下,网络套接字是阻塞的。您需要在套接字上设置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)。最后,除了等待I / O之外,您还需要使用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%正确,但应该是一个良好的开端。此外,我倾向于在处理SOCK_DGRAM套接字时保留使用send *()和recv *(),并在SOCK_STREAM套接字上使用read(),write()。