2015-12-30 41 views
7

讓我們考慮下面的代碼段行爲投票()系統調用和接收或發送數據之後

pollfd file_descriptors[1]; 
file_descriptors[0].fd = sock_fd; 
file_descriptors[0].events = POLLIN; 

int return_value = poll(file_descriptors, 1, 0); 

if (return_value == -1) { cerr << strerror(errno); } 
else if (return_value == 0) { cerr << "No data available to be read"; } 
else { 
    if (file_descriptors[0].revents & POLLIN) { 
     recv(sock_fd, buff, 1024, 0); 
    } 
} 

現在我有一個關於上面的代碼中的兩個問題。

  1. 如果調用輪詢()返回既不-1也不0並設置POLLIN標誌位圖中的reventsfile_descriptors陣列中的第一個條目,然後將調用recv()塊?如果不是,那麼數據會被即時讀取?
  2. 假設對poll()的呼叫採用與上述相同的方式。將讀入多少數據?它是否會像定期致電recv()一樣?即在上述情況下小於或等於1024的任意(對程序員)的數量。然後,如果我想在再次閱讀之前想要poll(),那麼我是否只需從第一次調用poll()開始重複,直到完全讀取所有數據(即在客戶端服務器場景中,這將對應於請求正在完成爲止)?

謝謝!

+1

3,請參閱http://stackoverflow.com/questions/589928/socket-programming-how-do-i-handle-out-of-band-data。實際上,如果一個套接字端發送正常數據和*然後* OOB數據,則客戶端儘可能快地獲得OOB數據,可能*在其他數據之前。 [好吧,這取決於客戶如何調用recv,以及其他一些事情,這不是全部內容......查看鏈接] – deviantfan

+0

非常感謝!我會研究一下:) – Curious

+0

@deviantfan從我在這個問題的答案中讀到的。我將忽略當前用例中的所有OOB數據。但我有一個後續問題。如果確實發送了一些OOB數據,並且我忽略它,也就是隻調用recv()。數據會被忽略嗎?或者將它注入到我正在閱讀的字節流(或recv() - ing)中? – Curious

回答

2

如果對poll()的調用既不返回-1,也不返回0,並且在file_descriptors數組中的第一個條目的位圖revents中設置POLLIN標誌,那麼將調用recv()塊嗎?如果不是,那麼數據會被即時讀取?

poll的呼叫對recv的呼叫沒有影響。 recv塊是否取決於您在撥打recv時可用的數據以及套接字是處於阻塞模式還是非阻塞模式。

假設調用poll()的方式與上面提到的相同。將讀入多少數據?這是否會像對recv()的常規調用一樣?即在上述情況下任意(對程序員)小於或等於1024的數量。那麼如果我想在再次讀取之前進行poll(),那麼我是否只需要重複第一次poll()調用,直到完全讀取所有數據爲止(即在客戶端服務器場景中,這將對應於請求正在完成)?

假設你不想阻塞,你應該設置套接字非阻塞。你有兩個基本選擇。您可以再次調用接收功能,然後poll。或者,您可以繼續撥打接聽電話,直到您收到「可能會阻止」的提示。如果套接字是TCP連接,則可以繼續調用receive函數,直到獲得「will block」指示或接收到的字節數少於請求的數量。

有三種常見的非阻塞I/O策略,您可以基於pollselect。所有要求的套接字被設置爲非阻塞。

1)在執行I/O操作之前,您始終可以撥打pollselect。只有當您獲得pollselect的讀取或寫入命中時,纔會嘗試進行單個讀取或寫入操作。

2)您可以先嚐試readwrite操作。如果它立即成功,那很好。如果沒有,請在重試操作之前等待pollselect

3)在執行I/O操作之前,您可以撥打pollselect。然後您嘗試多次read s或write s,直到您完成您需要執行的所有操作或獲得「will block」指示。當您收到「將阻止」指示時,您需要等到selectpoll告訴您在該套接字上嘗試其他方向的操作。

方法3可能是最常見的讀取。方法2可能是最常用的寫入方式。

請務必記住poll是一個狀態報告功能,可以告訴您當前的信息。它沒有任何未來的保證。來自poll的讀取指示意味着未來的讀取操作不會阻止的這一假設是錯誤的,並且它在過去造成了嚴重的錯誤,並帶來重大的安全隱患。確保套接字操作不會阻塞的唯一方法是設置套接字非阻塞。

+0

非常感謝!但你認爲我的邏輯看起來正確嗎?然後是'poll()',然後是'recv()',然後是'poll()',然後是'recv()'等等......這是爲了從網絡中獲得一個非阻塞讀取。基本上我的意思是要問,如果POLLIN標誌設置在'revents'結構中,那麼緊跟在後面的'recv()'不會阻止正確的? – Curious

+0

@Curious如果你想要非阻塞讀取,你必須設置套接字非阻塞。然後你可以使用'poll'來知道什麼時候執行讀寫操作。您可以每次在操作前使用'poll',或者您可以調用'poll'作爲等待您收到「would block」指示的等待方式。兩種方法都有效。在讀取之前首先進行輪詢是很常見的,但是隻有在寫入操作獲得「將阻止」指示時,才能首先寫入並回退到「輪詢」。但是,你可以做到這一點,但你想要的。 –

+0

好吧,以下步驟是正確的? 1.將套接字設置爲非阻塞,2.調用poll(),3.如果poll()指示有數據要讀取,則調用recv(),4.如果所有需要的數據都有(2) – Curious

0

如果調用poll()返回既不-1也不0並設置POLLIN標誌位圖中的revents中爲file_descriptors陣列中的第一個條目,然後將調用recv()塊?

它不應該,除非另一個線程已經讀取了從套接字當前可用的所有數據。

如果不是,那麼數據會在瞬間被讀取嗎?

是的。

假設對poll()的呼叫採用與上述相同的方式。將讀入多少數據?

儘可能多的數據已經到達。

這是否就像定期致電recv()一樣?即在上述情況下任意(對程序員)小於或等於1024的數量。

是的。

然後,如果我想poll()再次閱讀之前,我剛剛從poll()第一次調用重複,直到所有數據已完全被讀(即在客戶端服務器方案,這將對應於正在完成的請求) ?

是的。

+0

謝謝你的回答!你能分享一些參考嗎?當我有類似的問題時,我知道去哪裏看 – Curious

+0

「輪詢」功能是一種狀態報告功能。它沒有任何未來的保證。假設來自'poll'或'select'的指示將保證將來的讀取或recv不會在任何情況下阻止*是錯誤的,並且它是過去導致安全隱患的錯誤。 –

1

如果poll()返回嚴格正值,則表示至少有一個描述符有一些要返回的數據。

recv()應該不被阻塞:因爲有數據它應該返回一些東西。在任何情況下,不能保證所有的1024字節都會被調用返回。

因此您必須檢查由recv()返回的字節數。最後,你必須循環你的投票/接收,直到你得到所有的預期數據。

您可以通過調用標記參數MSG_DONTWAIT或通過fcntl()以更持久的方式來控制阻塞/非阻塞行爲。

編輯:需要注意的是,如果出現錯誤的插座(for example a loss of connection)對投票承諾的可用數據可能會丟失,並阻止recv()出乎所有人的預料。因此明確地使用非阻塞標誌是更安全的(並且認爲recv()可能會返回錯誤代碼而不是讀取的字節數)。

+0

謝謝!你能分享一些你的答案參考嗎? – Curious

+0

當你在調用'recv()'之前進行輪詢時,有什麼'MSG_DONTWAIT'? – Curious

+0

@這最後一句話是一個普遍的信息,因爲OP似乎擔心封鎖與否。如上所述,在一次成功的poll()之後,將不會有任何阻止。 – Christophe