2012-10-27 143 views
3

我正嘗試在C中編寫一個簡單的網絡服務器。截至目前,我可以接收連接並接收完整的消息。但是,根據HTTP/1.0協議,我希望能夠在遇到「\ r \ n \ r \ n」序列時將信息發送回客戶端。但是,當使用Telnet來測試我的服務器時,當我輸入「\ r \ n \ r \ n」時,服務器不會執行任何操作,直到我在客戶端上點擊「^」「。我對Apache進行了測試,Apache沒有這個問題。所以我希望能夠提供一些關於如何模仿Apache行爲的信息。我的代碼在下面添加,但請記住我沒有接近完成的地方,也沒有執行過很多錯誤檢查。 謝謝!在C中編寫網絡服務器

所有的
main(){ 
     int sock_fd = 0; 
     int client_fd = 0; 
     struct sockaddr_in socket_struct; 
     /*Creates the socket*/ 
     if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
     { 
       fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); 
       exit(EXIT_FAILURE); 
     }/*Ends the socket creation*/ 

     /*Populates the socket address structure*/ 
     socket_struct.sin_family = AF_INET; 
     socket_struct.sin_addr.s_addr=INADDR_ANY; 
     socket_struct.sin_port =htons(port); 

     if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0) 
     { 
       fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the binding. 

     if (listen(sock_fd, 5) <0) 
     { 
       fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the listening function 

     if ((client_fd = accept(sock_fd, NULL, NULL)) <0) 
     { 
       fprintf(stderr, "%s: %s\n", getprogname(), strerror(errno)); 
       exit(EXIT_FAILURE); 
     }//Ends the accepting. 
     while ((size = read(client_fd, msg, 1024)) > 0) 
     { 
       //size = recv(client_fd, msg, 1024, MSG_PEEK|MSG_WAITALL); 
       if ((msg[size-4] == 13) && (msg[size-3] == 10)&&(msg[size-2] == 13) && (msg[size-1] == 10)) 
       { 
         char* buffer = (char *)malloc(sizeof("The msg was: ")+ sizeof(msg)); 
         sprintf(buffer, "The msg was: %s", msg); 
         send(client_fd, buffer, sizeof("The msg was: ")+ sizeof(msg), MSG_OOB); 
       } 

     }//ends the while loop for receiving data 
     close(client_fd); 
} 
+0

試着做一個'printf()'看看它是否進入while循環中的if()條件。似乎有一個問題@'send()' –

+0

它不是一個發送問題,因爲我已經做了printf()的事情發佈之前......謝謝 – tpar44

回答

2

首先,這條線將無法正常工作:

while ((size = read(client_fd, msg, 1024)) > 0) 

這將收到的消息的塊,每一次你收到塊將覆蓋最後一個大塊。做這樣的事情:

char msg[1024]; 
size_t pos = 0; 
while (1) { 
    assert(pos < sizeof(msg)); 
    ssize_t amt = read(client_fd, msg + pos, sizeof(msg) - pos); 
    if (amt < 0) 
     err(1, "read failed"); 
    if (amt == 0) 
     break; // EOF 
    pos += amt; 
    char *e = strstr(msg, "\r\n\r\n"); 
    if (e) { 
     size_t msglen = e - msg; 
     /* Handle a complete message here */ 
    } 
} 

這樣,當您收到消息塊時,它們會被寫入緩衝區。一旦你有了"\r\n\r\n"的順序,那麼你可以處理整個消息,即使你可能會把它分成幾塊。

重點課程:在TCP中,數據包邊界和消息邊界可能完全不同,並且從read獲得的大小可能仍然不同。您必須通過查看數據本身來查找消息的結尾,而不是查看從read()返回多少數據(EOF除外,EOF在read()返回0時發出信號)。

腳註:我不認爲帶外數據能做到您認爲的那樣。

send(client_fd, buffer, sizeof("The msg was: ")+ sizeof(msg), MSG_OOB); 

帶外數據是TCP的一個古怪特性,應該在現代協議中幾乎可以避免。它的實現方式因平臺而異,因此發送帶外數據的一個字節只是安全的。

它通過Telnet協議(以及擴展名爲基於Telnet的FTP)用於某些事情,但在HTTP中沒有用處。

+0

謝謝你的幫助!我改變了它與recv而不是閱讀工作,但你肯定把我放在正確的軌道上,所以非常感謝你 – tpar44

+0

@ tpar44:對於套接字,'recv'和'read'是相同的(flags參數除外)所以隨時可以使用任何一個。 –