Block Socket with Unix and C/C++ Help

痴心易碎 提交于 2019-12-13 03:34:46

问题


I'm trying to figure out what is blocking my program. I'm running a server that uses POSIX threads. I have to for my computer programming lab. The main function listens for new connections. Once it accepts a connection, it creates a new thread by passing the FD to the thread. I'm able to successfully connect to the server using multiple telnet/client connections. I can send data to the server successfully once, but if I try sending again the server won't do anything.

Part of the main function

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

Part of the POSIX THREAD CODE

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

I think its blocking at either the accept or recv. I've heard of select() and various other methods, but I'm having difficulty trying to implement them. Thanks!


回答1:


The root cause of your issue appears to be that you are unconditionally executing close(sockfd); return 0; at the bottom of your while (running) loop, which means that the loop only ever executes once.

Additionally, you should not be using FD_ISSET() unless you are also using select(). Your main loop should look something more like:

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;



回答2:


By default network sockets are blocking. You need to set the O_NONBLOCK flag on the socket.

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

Now, instead of blocking when there is no input (or buffer space to store output), the error EAGAIN (or EWOUDLBLOCK) is returned. Lastly, you will need to use select() or poll() when you have nothing else to do but wait on I/O. These calls will only wake the process when either there is input, room for output, or possibly a time-out period passes.

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

This example is not complete or neccessarily 100% correct, but should be a good start. Also, I tend to reserve using send*() and recv*() when dealing with SOCK_DGRAM sockets and just use read(), write() on SOCK_STREAM sockets.



来源:https://stackoverflow.com/questions/5494052/block-socket-with-unix-and-c-c-help

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