假設我們有一個用 accept() 接受的客戶端檔案描述符
client_socket = accept(_socket, (sockaddr *)&client_addr, &len)
我們現在在讀寫 fd_set 中設定這個檔案描述符:
fd_set readfds;
fd_set writefds;
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
FD_SET(client_socket, &writefds);
現在我們使用 select 來檢查套接字是否可讀或可寫:
select(FD_SETSIZE, &readfs, &writefds, NULL, NULL)
我們現在檢查是否可以先讀取并從中讀取所有位元組。
if (FD_ISSET(client_socket, &readfds) {
read(client_socket, &buf, 4096);
}
//assume that buf is big enough and that read returns less than 4096
在下一個回圈中,我們像以前一樣重置 fd_sets。現在 select 將允許我們將回應寫入客戶端:
if (FD_ISSET(client_socket, &readfds) {
write(client_socket, &buf, len(buf));
}
直到這里一切正常,但現在發生了奇怪的行為。假設我們的客戶端告訴我們保持連接處于活動狀態,在這種情況下,我們將像以前一樣設定 fd_set,如下所示:
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
FD_SET(client_socket, &writefds);
// reading not allowed
現在使用 select 時,它將允許我們再次寫入,但不允許從 client_socket 讀取。但是,如果我們將 writefds 的設定更改為零,它將允許我們讀取,盡管我們沒有更改 readfds 中的任何內容。
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
//FD_SET(client_socket, &writefds); -> don't set the file-descriptors for write
// now reading is allowed
有人可以解釋一下這是 select 的正確行為,還是我的錯可能是我沒有顯示的代碼的其他部分(太復雜了)。對我來說,在設定兩個集合(寫入和讀取)時,select 的行為似乎是隨機的。我知道有一種方法可以解決這個問題,通過保持一種狀態來決定我們是要設定讀取檔案描述符還是寫入檔案描述符,但我希望有一個更清晰的解決方案。
uj5u.com熱心網友回復:
的目的select()是在您的程式有事情要做之前不回傳。這樣你的程式就可以在內部休眠select()直到 I/O 準備好,立即醒來執行 I/O,然后盡快回到休眠狀態。
所以問題是,如何select()知道何時回傳?FD_SET()答案是,您必須通過以適當的方式呼叫來告訴它應該導致它回傳的原因。
通常select(),當您的任何套接字上的資料準備好讀取時,您會想要回傳(這樣您就可以讀取新到達的資料),因此您通常應該呼叫FD_SET(mySock, &readFD)所有套接字。
FD_SET(mySock, &writeFD)有點微妙。它告訴select()當套接字有緩沖區空間可用于寫入輸出位元組時回傳。但是,在許多情況下,您不想select()在套接字有可用緩沖區空間時回傳,這僅僅是因為您目前沒有任何要寫入套接字的資料。在這種情況下,如果您總是呼叫FD_SET(mySocket, &writeFD)thenselect()將立即回傳,即使您沒有要執行的任何任務,這將導致您的程式無用地占用大量 CPU 周期。
因此,您唯一應該呼叫FD_SET(mySocket, &writeFD)的是如果您知道要盡快將一些資料寫入該套接字。
在您的程式中,可能發生的FD_SET(mySocket, &writeFD)是導致select()立即回傳(因為mySocket當前有可用于寫入的緩沖區空間),然后您的程式(錯誤地)假設因為select()已回傳,因此套接字已準備好讀取,才發現不是。在您注釋掉 的情況下FD_SET(mySocket, &writeFD),OTOHselect()在套接字準備好讀取之前不會回傳,因此您在呼叫FD_ISSET(mySocket, &readFD).
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/447348.html
上一篇:HttpURLConnection:為什么指定Expect:100-ContinueHeader時每個塊有5秒延遲?
