2013-09-24 19 views
0

我有兩個服務器代碼:什麼是使用tcp socket的數據轉換模式?

  1. 的第一臺服務器:直到串完成每次向客戶端發送一個char

    int 
    main(int argc, char **argv) 
    { 
        int     listenfd, connfd; 
        struct sockaddr_in servaddr; 
        char    buff[MAXLINE]; 
        time_t    ticks; 
         char       temp[1]; 
         int        i = 0; 
    
        listenfd = Socket(AF_INET, SOCK_STREAM, 0); 
    
        bzero(&servaddr, sizeof(servaddr)); 
        servaddr.sin_family  = AF_INET; 
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
        servaddr.sin_port  = htons(9999); /* daytime server */ 
    
        Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 
    
        Listen(listenfd, LISTENQ); 
    
        for (; ;) { 
         connfd = Accept(listenfd, (SA *) NULL, NULL); 
    
         ticks = time(NULL); 
         snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); 
    
         for(i = 0; i < strlen(buff); i++) 
         { 
          temp[0] = buff[i]; 
          Write(connfd, temp, strlen(temp)); 
         } 
    
         Close(connfd); 
        } 
    } 
    
  2. 第二服務器:向客戶端發送一個字符串

    int 
    main(int argc, char **argv) 
    { 
        int     listenfd, connfd; 
        struct sockaddr_in servaddr; 
        char    buff[MAXLINE]; 
        time_t    ticks; 
         char       temp[1]; 
         int        i = 0; 
    
        listenfd = Socket(AF_INET, SOCK_STREAM, 0); 
    
        bzero(&servaddr, sizeof(servaddr)); 
        servaddr.sin_family  = AF_INET; 
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
        servaddr.sin_port  = htons(9999); /* daytime server */ 
    
        Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 
    
        Listen(listenfd, LISTENQ); 
    
        for (; ;) { 
         connfd = Accept(listenfd, (SA *) NULL, NULL); 
    
         ticks = time(NULL); 
         snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); 
    
         Write(connfd, buff, strlen(buff)); 
         Close(connfd); 
        } 
    } 
    
  3. 客戶端:收到服務器發送的字符

    int 
    main(int argc, char **argv) 
    { 
        int     sockfd, n; 
        char    recvline[MAXLINE + 1]; 
        struct sockaddr_in servaddr; 
         int count = 0; 
    
        if (argc != 2) 
         err_quit("usage: a.out <IPaddress>"); 
    
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
         err_sys("socket error"); 
    
        bzero(&servaddr, sizeof(servaddr)); 
        servaddr.sin_family = AF_INET; 
        servaddr.sin_port = htons(9999); /* daytime server */ 
        if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) 
         err_quit("inet_pton error for %s", argv[1]); 
    
        if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) 
         err_sys("connect error"); 
    
        while ((n = read(sockfd, recvline, MAXLINE)) > 0) { 
         recvline[n] = 0; /* null terminate */ 
           count++; 
         if (fputs(recvline, stdout) == EOF) 
          err_sys("fputs error"); 
        } 
        if (n < 0) 
         err_sys("read error"); 
         printf("read time:%d\n", count); 
    
        exit(0); 
    } 
    

的結果是既變盤點的輸出爲1。我的問題是,爲什麼第一臺服務器的輸出是1,我想結果應該strlen的(BUFF)爲第1服務器?

PS:我在同一臺機器上運行服務器和客戶端。

+1

第一個服務器有一個緩衝區溢出:'char temp [1];'必須是'char temp [2]; temp [1] = 0;''或者你必須將'strlen(temp)'替換爲1. –

回答

2

TCP是一個流協議。因爲一方的寫入次數不會導致另一方的讀取次數相同,因爲協議並不保存寫入套接字的信息。

通常情況下,在發送方發送數據包之前會有一個延遲,以防將更多數據寫入套接字,以便可以將更多數據填充到同一個數據包中。其中一個原因是寫入錯誤的服務器可能會使用單字節數據包氾濫網絡。

在接收端,協議並不知道爲什麼你的數據可能作爲單獨的數據包到達,它可能是由於MTU而被分離的,它可能已被某些數據包檢測軟件或設備重新組裝方式,所以每當你從你的套接字讀取它會給你儘可能多的數據,無論它如何發送給你。

在本地機器上,就像在您的設置中一樣,客戶端甚至可能在服務器正在寫入時甚至沒有運行,所以即使沒有在發送端進行緩衝,它也不會開始讀取,直到服務器寫入所有內容爲止,會一口氣讀完所有東西。或者不行,你可能會不太走運,你的服務器被搶先足夠長的時間,以至於你的內核中的TCP實現認爲你將不會有更多的數據要發送,發送一個字節給客戶端,客戶端被調度在服務器再次運行之前運行,客戶端將在第一次讀取時只接收一個字節。

+0

更重要的原因是緩衝難以正確進行,大多數應用程序都從中獲益,所以緩衝是默認設置。爲了得到無緩衝的輸出,你可以flush()套接字,但是根據數據量和物理傳輸的大小,你將通過線傳輸很多字節的頭,只有幾個字節的有效載荷加上數據包之間的延遲其他開銷。 –

+2

緩衝是一個實現細節。重點是它是一個流協議,並且沒有數據包邊界,所以讀取和寫入的數量可能不相同,並且與流的實現方式無關(有或沒有緩衝)。它甚至可能在發送端根本就沒有緩衝功能,單次讀取是接收端在一次系統調用中處理所有數據包的副作用。 – Art

+0

我的經驗是,緩衝是關於整個事情的最重要的「細節」,因爲它是大多數人偶然發現的一件事,因爲他們不希望它發生(或以不同的方式發生)。所以,是的,它是流媒體,使用下面的數據包,但使用它,緩衝是你首先需要考慮的。 –