Question

I need this server to be able to listen for and establish new connections with clients while simultaneously writing to existing connections.. ie. Asynchronous non-blocking i/o. I've been told to use poll() but after spending an inordinate amount of time simply trying to grasp socket programming, I'm still unsure how implement the poll() function.

int sockfd; 

int main(int argc, char *argv[])
{
 int newsockfd, portno; 
 socklen_t clilen;  
 char buffer[256];       
 struct sockaddr_in serv_addr, cli_addr;  
 int n;             

 if (argc < 2) {         
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1);
 }

 sockfd = socket(AF_INET, SOCK_STREAM, 0);      
 if (sockfd < 0)                    
    error("ERROR opening socket");          

 bzero((char *) &serv_addr, sizeof(serv_addr));     

 portno = atoi(argv[1]);            
 serv_addr.sin_family = AF_INET;        
 serv_addr.sin_addr.s_addr = INADDR_ANY;    
 serv_addr.sin_port = htons(portno);    

 if (bind(sockfd, (struct sockaddr *) &serv_addr, 
          sizeof(serv_addr)) < 0) 
          error("ERROR on binding");        
 listen(sockfd,5);                  

 clilen = sizeof(cli_addr);     

 while(1){          
     newsockfd = accept(sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);              
     if (newsockfd < 0)                 
          error("ERROR on accept");

     // READ READ READ READ READ READ READ READ READ READ READ READ READ READ READ READ 
     bzero(buffer,256);
     n = read(newsockfd,buffer,255);    


     if (n < 0) error("ERROR reading from socket");
     printf("Here is the message: %s\n",buffer);

     // WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE 
     n = write(newsockfd,"I got your message",18); 
     if (n < 0) error("ERROR writing to socket");
     close(newsockfd);  
 }

 return 0; 

}

My understanding is that I need to build something like this:

//  Set up array of file descriptors for polling
struct pollfd ufds[2];
ufds[0].fd = sockfd;    
ufds[0].events = POLLIN; 

ufds[1].fd = newsockfd;
ufds[1].events = POLLOUT;

and use poll(ufds,2,2000); inside the loop to check whether sockfd or newsockfd have any activity, in which case I use the appropriate read or write.. If anybody could give me some guidance I'd be very appreciative.

Was it helpful?

Solution

The kernel will fill in the events that occurred in the revents field of your struct pollfd array.

From the manual page:

The field revents is an output parameter, filled by the kernel with the events that actually occurred. The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are meaningless in the events field, and will be set in the revents field whenever the corresponding condition is true.)

If you want event notifications for accepted connections, then you need to either reserve space in advance or resize the struct pollfd array for every connection.

You'll need some way to differentiate the listening socket. You could store it in index zero of your array.

int i, n;

n = poll(ufds, num_fds_in_array, timeout_value);

/* errors or timeout? */
if (n < 1)
    ;

for (i = 0; i < num_fds_in_array; i++) {
    /* were there any events for this socket? */
    if (!ufds[i].revents)
        continue;

    /* is it our listening socket? */
    if (!i) {
         if (ufds[0].revents & POLLIN)
             /* call accept() and add the new socket to ufds */
         else
             /* error */

         continue;
    }

    /* is there incoming data on the socket? */
    if (ufds[i].revents & POLLIN)
        /* call recv() on the socket and decide what to do from there */
}

The POLLOUT flag is used to signal when the sending data on the socket will not block the caller.

For non-blocking I/O, I'd use a more powerful API since it requires more bookkeeping to do reliably. See the next paragraph.

Unfortunately, there's no room for auxiliary per-connection data to store state when using poll. There are alternatives available depending on your platform, e. g. epoll for Linux, kqueue for *BSD, and a handful of options for Windows. If you want to use poll with context data, you'd have to use a data structure that can be searched using the file descriptor or array index.

OTHER TIPS

Why don't u use libevent? It totally asynchronous and non-blocking. http://libevent.org/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top