2013-10-24 39 views
5

Potrzebuję tego serwera, aby móc nasłuchiwać i nawiązywać nowe połączenia z klientami, jednocześnie zapisując do istniejących połączeń. Asynchroniczne nieblokujące wejścia/wyjścia. Powiedziano mi, aby używać poll(), ale po spędzeniu nadmiernej ilości czasu po prostu próbując uchwycić programowanie gniazd, wciąż nie jestem pewien, jak zaimplementować funkcję poll().Wdrażanie ankiety() na serwerze TCP odczytu/zapisu

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; 

}

Moje zrozumienie jest, że trzeba zbudować coś takiego:

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

i wykorzystanie dysków flash, poll (2,2000); wewnątrz pętli, aby sprawdzić, czy sockfd lub newsockfd mają jakąkolwiek aktywność, w takim przypadku używam odpowiedniego odczytu lub zapisu. Jeśli ktoś mógłby dać mi wskazówki, byłbym bardzo wdzięczny.

+1

Czy czytasz o "wybierz"? – NiRR

Odpowiedz

3

Jądro wypełnia zdarzenia, które wystąpiły w polu revents swojej tablicy struct pollfd.

Od strony man:

W revents pole jest parametr wyjściowy, wypełniona przez jądro z wydarzeń, które miały miejsce w rzeczywistości. Zwracane bity mogą zawierać dowolne z podanych zdarzeń lub jedną z wartości: POLLERR, POLLHUP lub POLLNVAL. (Te trzy bity są bez znaczenia w polu zdarzeń i zostaną ustawione w polu Ponowne wychodzenie, gdy odpowiedni warunek będzie prawdziwy.)

Jeśli chcesz otrzymywać powiadomienia o wydarzeniach dla zaakceptowanych połączeń, musisz zarezerwować miejsce w przesuń lub zmień rozmiar tablicy struct pollfd dla każdego połączenia.

Będziesz potrzebował sposobu na rozróżnienie gniazda nasłuchującego. Możesz przechowywać go w indeksie zero swojej tablicy.

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

POLLOUT flaga służy do sygnalizowania gdy wysyłanie danych na gnieździe nie będzie blokować rozmówcę.

Dla niezablokowanych operacji we/wy używałbym bardziej wydajnego interfejsu API, ponieważ wymaga to więcej księgowości, aby działał niezawodnie. Zobacz następny akapit.

Niestety, nie ma miejsca na dane pomocnicze dla połączenia do stanu przechowywania przy użyciu poll. W zależności od platformy dostępne są rozwiązania alternatywne, np. sol. epoll dla Linux, kino dla * BSD i garść opcji dla Windows. Jeśli chcesz użyć wartości poll z danymi kontekstowymi, musisz użyć struktury danych, którą można przeszukać za pomocą deskryptora pliku lub indeksu tablicy.

+0

Byłbym bardzo szczęśliwy, gdybyś pokazał, jak ten kod można zastosować do kodu OP. Mam dokładnie ten sam problem, który mam polecenia read(), które blokują poprawnie, ale chcę mieć limit czasu połączenia. Próbowałem tak wielu rzeczy, ale to nie działa. Nie rozumiem twojego kodu ... co to jest ufds? Czy to newsockfd? –