2011-03-31 22 views
0

我想弄清楚什麼是阻止我的程序。我正在運行一個使用POSIX線程的服務器。我必須爲我的計算機編程實驗室。主函數監聽新的連接。一旦它接受了連接,它就會通過將FD傳遞給該線程來創建一個新線程。我能夠使用多個telnet /客戶端連接成功連接到服務器。我可以成功地將數據發送到服務器一次,但如果我嘗試再次發送服務器將不會執行任何操作。主要功能使用Unix和C/C++的塊套接字幫助

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()和其他各種方法,但我很難實現它們。謝謝!

+0

你真的需要使用select(或輪詢,而是選擇更容易IMO),以確保您的套接字fd的準備讀或寫。對不起,我沒有時間atm提供一個真正的答案,但谷歌周圍的例子與選擇,我相信你會最好的。 – 2011-03-31 01:01:33

+0

在幾個打印語句中添加應該知道它阻塞的位置。如果您在撥打'recv'時阻止,則可能等待您發送數據。作爲一個方面說明,看起來你在'server_handler'中的'while'循環中有大括號的不匹配 – Jeff 2011-03-31 01:17:11

回答

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)阻擋。最後,當你沒有別的事要做時,你需要使用select()或poll(),但是在I/O上等待。這些調用只會在有輸入,輸出空間或可能超時時間的情況下喚醒進程。

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

這個例子是不完整的或neccessarily 100%正確的,但應該是一個良好的開端。另外,我傾向於在處理SOCK_DGRAM套接字時使用send *()和recv *()並在SOCK_STREAM套接字上使用read(),write()。

2

您的問題的根本原因似乎是您無條件在while (running)循環的底部執行close(sockfd); return 0;,這意味着該循環只執行一次。

此外,除非您還使用select(),否則不應使用FD_ISSET()。你的主循環看起來應該更像:

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;