2016-12-28 135 views
-1

我想用C其中工程樣的這種方式使用TCP套接字來實現協議:TCP套接字凍結服務器

  1. 客戶端連接到服務器併發送文件名,它要 下載
  2. 服務器讀取值,並檢查它是否是有效的文件名(它存在於服務器上)+發送ACCEPTFAILURE狀態,客戶端
  3. 客戶端讀取狀態,並準備自己下載+發送READY狀態服務器
  4. 服務器發送文件並關閉連接

Server代碼

char response[128]; 
int bytes_read; 
while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

if (valid_request(files, files_count, response)) { 
    write(info.socket, MC_ACCEPT, 4); 
} else { 
    write(info.socket, MC_FAILURE, 4); 
} 

客戶端代碼

int w_status = write(sck, requested_file, strlen(requested_file)); 
if (w_status < 0) { 
    fprintf(stderr, "Error writing to socket. Status: %d", w_status); 
    exit(1); 
} 

char status[4]; 
while ((resp = read(sck, status, 4)) > 0) {} 

if (strcmp(status, MC_ACCEPT) == 0) { 
    printf("ACCEPTED!\n"); 
} else if (strcmp(status, MC_ACCEPT) == 0) { 
    printf("FAILURE\n"); 
} else { 
    printf("DONT KNOW\n"); 
} 

close(sck); 

的問題是,服務器凍結本身的read()一部分。它看起來像客戶端發送文件名並等待服務器響應(狀態),但服務器被凍結在read()

我以某種方式阻止TCP套接字?我的推理出了什麼問題?

+0

@Barmar我的錯,我沒有在我的實際代碼 –

+0

您是否嘗試過做一個數據包捕獲,看看消息是否是發送到服務器? – Barmar

+0

@Barmar當我第一次運行一個服務器,然後客戶端和它掛起時,什麼是有趣的,但之後,我用CTRL + C終止客戶端進程,服務器似乎得到的消息恰到好處,但直到客戶端進程還活着 –

回答

1

在服務器端:

char response[128]; 
int bytes_read; 
while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

您嘗試在幾個read調用讀那些128個字符。但是它會永遠阻塞直到客戶端關閉套接字(它是TCP連接的,除非對等關閉連接,總會有東西要讀取)。

如果數據到達超過1個塊,則代碼不正確,因爲第一個塊將被下一個塊覆蓋,依此類推。您必須更改緩衝區的偏移量,並且不要每次都嘗試讀取128個字節,否則會卡住。

int bytes_read = 0; 
while (bytes_read < 128) 
{ 
    int currently_read = read(info.socket, response + currently_read, 128-bytes_read); 
    bytes_read += currently_read; 
} 

在客戶端,相同類型的問題太多:

你似乎等待4個字符。

您嘗試閱讀第一個read中的那4個字符。但是你不檢查是否有4個字符被實際讀取(返回代碼丟棄)。

之後,您使用循環讀取,直到您獲得0個字節。但是因爲連接並沒有結束,所以你被困在那裏。

你想要的是在做別的事情之前正好讀取4個字節。

並增加緩衝區大小& null-terminate你的字符串或strcmp將會失敗。

char status[5]; 
status[4] = '\0'; 
int nb_read = 0; 
while (nb_read < 4) 
{ 
    int currently_read = read(sck, status + nb_read, 4-nb_read); 
    nb_read += currently_read; 
} 
+0

你的解釋是理解我的問題的關鍵。謝謝。 –

0

的問題是,你不處理while循環內的請求:

while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

這樣可以使循環,直到read()回報0,這發生在客戶端關閉連接,或者收到錯誤並返回-1。在從客戶端讀取請求後,它將返回並再次呼叫read()。由於客戶端沒有發送任何其他內容,因此會阻止。

這就是爲什麼殺死客戶端將其取消的原因。關閉連接,所以它獲得EOF並且read()返回0

您需要處理循環內的輸入:

while ((bytes_read = read(info.socket, response, sizeof response -1)) > 0) { 
    response[bytes_read] = '\0'; // add string null terminator 
    if (valid_request(files, files_count, response)) { 
     write(info.socket, MC_ACCEPT, 4); 
    } else { 
     write(info.socket, MC_FAILURE, 4); 
    } 
} 
+0

但無法讀取(info.socket,response,sizeof response -1)'返回小於'sizeof response -1'? –

+0

是的,它可以。他實際上需要設計協議,以便服務器可以通過某種方式來確定請求的結束位置,或者使用長度前綴或分隔符,然後繼續閱讀,直到獲取完整消息。如果沒有這個,他所能做的最好的就是希望'read()'將返回整個消息,這是相當可能的。 – Barmar