我撰寫了一個服務器/客戶端程式,我可以在其中將檔案從客戶端復制到服務器。問題是當寫入檔案完成時,我無法跳出服務器中的 while 回圈。我只能在關閉服務器程式時打開新復制的檔案,因為該檔案不會以fclose(copyFile). 該檔案每次都成功復制。但是,當我在同一臺機器上運行服務器/客戶端時,它確實可以正常作業,但是當我將客戶端移動到另一臺電腦時,服務器會一直阻塞recv()在我的服務器中。
服務器:
while (1)
{
int res = recv(s, buf, BUFSIZ, 0);
if (res == SOCKET_ERROR)
{
printf("3 error %d\n", WSAGetLastError);
break;
}
fwrite(buf, 1, res, copyFile);
if (strncmp(buf, "exit", 4) == 0)
{
break;
}
}
fclose(copyFile);
客戶:
while (size == BUFSIZ)
{
size = fread(buf, 1, BUFSIZ, originalFile);
int r = send(ClientSocket, buf, size, 0);
if (r == SOCKET_ERROR)
{
printf("1 error: %d\n", WSAGetLastError);
}
}
int r = send(ClientSocket, "exit", 4, 0);
if (r == SOCKET_ERROR)
{
printf("2 error: %d\n", WSAGetLastError);
}
fclose(originalFile);
如何正確退出while()服務器中的回圈?
uj5u.com熱心網友回復:
你試圖用“exit”這個詞來表示檔案的結尾,但至少有兩個問題:
如果正在傳輸的檔案包含單詞“exit”,那么這可能會被誤解為檔案結束標記,并且
您似乎假設您
send()在客戶端的呼叫將與服務器上的呼叫一對一地配對recv(),因此當服務器接收到它時,可以依賴“退出”出現在緩沖區的開頭。這不是一個安全的假設。
(還要注意,即使服務器確實在緩沖區的開頭收到了“退出”,您仍然會在將其識別為檔案結束標記之前將其寫入檔案。如果這是唯一的問題,那么這很容易解決。)
您需要一個可行的應用程式級協議來幫助客戶端和服務器進行通信——在套接字連接提供的平面位元組流之上分層所需的附加結構。“退出”終結器是一種嘗試,但它不是一個可行的解決方案,至少本身不是。
相比之下,請考慮 HTTP:訊息由一系列標頭組成,這些標頭可以通過它們的詞法形式單獨和作為一個組來識別,然后是訊息正文。標頭可以傳達的內容之一是訊息正文的長度,這就是接收者如何在發送者關閉連接的情況下識別訊息正文的結尾。
你不需要實作 HTTP,但你可以從中得到啟發。如果你想傳輸任意長度和內容的訊息,而不是通過關閉連接來表示訊息結束,那么最好的辦法是提前告訴接收者在訊息中期望多少位元組。這可能就像在前面加上一個固定長度的訊息長度欄位一樣簡單。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/452311.html
