2012-07-17 35 views
2

我正在通過UNIX網絡編程中的示例工作,並在此處將「daytimeclientserv.c」修改爲此代碼。服務器按照預期向客戶端發送日期/時間字符串,除了啓動時收到的第一個請求。當我第一次運行服務器程序(在局域網中的另一臺計算機上)時,它會創建監聽套接字,將其綁定,然後等待連接。在收到第一個請求時,它將日期/時間字符串打印到它自己的stdout(終端)而不是套接字,並且客戶端程序永遠掛起等待。但是,所有後續請求都會正確發送到客戶端。使用gdb,我注意到connfd總是被設置爲零。它在第一次請求時以及在將來的所有時間都設置爲零。服務器打印到標準輸出而不是套接字

我也有與此相關的一些其他問題:

  • 如果服務器偵聽一個插座(listenfd),然後用連接()重新連接在另一個(connfd),客戶如何交易隨着插座的變化?這是我的理解是一個套接字由四個部分標識:servIPaddr,servPort,clientIPaddr,CLIENTPORT

  • 我怎麼可以運行服務器(在Linux上)而不被根

  • 我怎樣才能乾淨地關閉監聽套接字,以便我可以再次使用它。如果我使用SIGINT(Ctrl-C)退出服務器程序,則會出現綁定錯誤。到目前爲止,我一直在使用gdb,並使用「call close(listenfd)」來手動調用該函數。但有沒有辦法做到這一點,如果我不使用GDB(即只調試客戶端應用程序)。

任何幫助,非常感謝。

#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <time.h> 

#define BUFFER 80 
int main(int argc, char **argv) { 
    int listenfd, connfd; 
    char buf[BUFFER]; 
    struct sockaddr_in servaddr; 
    time_t ticks; 
    struct sockaddr *ptr; 
    char *ret; 

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
    perror("socket error"); 
    return 1; 
    } 

    memset(&servaddr, 0, sizeof(servaddr)); 
    memset(buf, 0, BUFFER); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(13); 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    ptr = (struct sockaddr*) &servaddr; 
    if (bind(listenfd, ptr ,sizeof(servaddr)) < 0) { 
    perror("bind error"); 
    return 2; 
    } 

    if (listen(listenfd, 128) < 0) { 
    perror("listen error"); 
    return 3; 
    } 

    ptr = NULL; 
    while (1) { 
    if (connfd = accept(listenfd, ptr, NULL) < 0) { 
     perror("accept error"); 
     return 4; 
    } else { 
     ticks = time(NULL); 
     ret = ctime(&ticks); 
     sprintf(buf, "%.24s\n", ret); 
     if (write(connfd, buf, strlen(buf)) < 0) { 
     perror("write error"); 
     close(connfd); 
    } 
    } 

    return 0; 
} 

回答

4

在這裏是我的預感:在終端(TTY),stdout和標準輸入是相同的物理設備。因此寫入filedescriptor 0(stdin)可能實際上工作並導致終端輸出。

您需要括號解決此

if (connfd = accept(listenfd, ptr, NULL) < 0) { 

像這樣

if ((connfd = accept(listenfd, ptr, NULL)) < 0) { 

或者connfd將被分配 '0'

更新剛剛進行了測試,這的確是罪魁禍首。下一次,編譯gcc -Wall和編譯器會告訴你這個(和其他一些好的表單/樣式)。這樣,你就不必依靠預感找到錯誤。

修正版本:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <time.h> 

#define BUFFER 80 
int main(int argc, char **argv) { 
    int listenfd, connfd; 
    char buf[BUFFER]; 
    struct sockaddr_in servaddr; 
    time_t ticks; 
    struct sockaddr *ptr; 
    char *ret; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (listenfd < 0) { 
     perror("socket error"); 
     return 1; 
    } 

    memset(&servaddr, 0, sizeof(servaddr)); 
    memset(buf, 0, BUFFER); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(13); 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    ptr = (struct sockaddr*) &servaddr; 
    if (bind(listenfd, ptr ,sizeof(servaddr)) < 0) { 
     perror("bind error"); 
     return 2; 
    } 

    if (listen(listenfd, 128) < 0) { 
     perror("listen error"); 
     return 3; 
    } 

    ptr = NULL; 
    while (1) { 
     connfd = accept(listenfd, ptr, NULL); 
     if (connfd < 0) { 
      perror("accept error"); 
      return 4; 
     } else { 
      ticks = time(NULL); 
      ret = ctime(&ticks); 
      sprintf(buf, "%.24s\n", ret); 
      if (write(connfd, buf, strlen(buf)) < 0) { 
       perror("write error"); 
       close(connfd); 
      } 
     } 
    } 

    return 0; 
} 
+0

我使用-pedantic-錯誤,-Wfatal-錯誤,它編譯罰款 – xst 2012-07-17 19:39:55

+0

好吧,這仍然是錯誤,我的編譯器'-Wall'報告它:_'warning :建議用作真值的賦值周圍的圓括號[-Wparentheses]'_ – sehe 2012-07-17 19:41:53

+1

好的,現在我將使用'-pedantic-errors -Wall -Werror -Wfatal-errors' – xst 2012-07-17 19:47:16

相關問題