簡體   English   中英

來自客戶端的udp接收

[英]C udp recvfrom client side

我正在編寫udp服務器/客戶端應用程序,其中服務器正在發送數據而客戶端正在接收。 當數據包丟失時,客戶端應向服務器發送小費。 我將套接字設置為O_NONBLOCK,以便可以通知客戶端是否未收到數據包

if (( bytes = recvfrom (....)) != -1 ) {
  do something
}else{
  send nack
}

我的問題是,如果服務器未開始發送數據包,則客戶端會像數據包丟失一樣開始向服務器發送小費。 (當沒有可用數據時,recvfrom失敗)我想要一些建議,如何在服務器沒有開始發送數據包以及是否發送數據包但數據包確實丟失的情況下如何區分這兩種情況

您正在使用UDP。 對於此協議,如果需要的話,完全可以丟棄數據包。 因此,“發送的內容將到達”是不可靠的。 在客戶端中,您需要檢查是否需要的所有數據包都到達了,如果沒有,請與您的服務器進行禮貌的交談,以重新發送那些您未收到的數據包。 要實現這些目標並非易事,

如果必須使用UDP傳輸較大的數據塊,請設計一個小型應用程序級協議,該協議可處理可能的數據包丟失和重新排序(這是TCP為您服務的一部分)。 我會選擇這樣的東西:

數據報的大小(例如1024字節)小於MTU(加上IP和UDP報頭),以避免IP分段。 每個數據報的固定長度報頭,包括數據長度和序列號,因此您可以將數據縫合在一起,並檢測丟失,重復和重新排序的部分。 接收方對已成功接收並匯總的內容的確認。 如果這些ack沒有在適當的時間內到達,則發送方將超時並重新發送。

您有一個循環調用select()poll()以確定數據是否已到達-如果是,則調用recvfrom()讀取數據。

您可以如下設置接收數據的超時時間

ssize_t recv_timeout(int fd,void * buf,size_t len,int flags){

ssize_t ret;

struct timeval tv;
fd_set rset;

// init set
FD_ZERO(&rset);
// add to set
FD_SET(fd, &rset);

 // this is set to 60 seconds
tv.tv_sec =
    config.idletimeout;
tv.tv_usec = 0; 

    // NEVER returns before the timeout value.
ret = select(fd, &rset, NULL, NULL, &tv);

if (ret == 0) {
    log_message(LOG_INFO,
                "Idle Timeout (after select)");
    return 0;
} else if (ret < 0) {
    log_message(LOG_ERR,
            "recv_timeout: select() error \"&#37;s\". Closing connection (fd:%d)",
            strerror(errno), fd);
    return;
} 

ret = recvfrom(fd, buf, len, flags);
return ret;

}

它告訴您,如果有數據准備就緒,通常,read()應該返回您指定的最大字節數,其中可能包括零字節(這實際上是一件有效的事情!),但是永遠不要在先前已報告准備就緒后阻止。

在Linux下,select()可能會將套接字文件描述符報告為“准備讀取”,但是隨后的讀取會阻塞。 例如,這可能在數據到達但檢查時校驗和錯誤並被丟棄時發生。 在其他情況下,文件描述符可能會虛假地報告為就緒。 因此,在不應阻塞的套接字上使用O_NONBLOCK可能更安全。

在此處查找滑動窗口協議。

想法是將有效負載分為適合物理udp數據包的數據包,然后對其編號。 您可以將緩沖區可視化為一圈插槽,以某種方式(例如順時針)順序編號。

然后,您從12點開始發送,移至1,2,3...。在此過程中,您可能會(可能不會)收到來自服務器的ACK數據包,其中包含您發送的數據包的插槽號。

如果收到ACK,則可以從環中刪除該數據包,然后將還沒有在環中的下一個未發送數據包放在該數據包中。

如果收到發送的數據包的NAK,則表示服務器已接收到數據損壞的數據包,然后從NAK中報告的環形插槽重新發送該數據包。

該協議類別允許通過具有數據或包丟失(例如RS232,UDP等)的通道進行傳輸。 如果您的基礎數據傳輸協議不提供校驗和,那么您需要為發送的每個環形數據包添加一個校驗和,以便服務器可以檢查其完整性並向您報告。

來自服務器的ACK和NAK數據包也可能丟失。 要解決此問題,您需要將計時器與每個環形插槽相關聯,並且如果在計時器達到您設置的超時限制時沒有收到針對該插槽的ACK或NAK,則您將重新發送數據包並重置計時器。

最后,要檢測致命的連接丟失(即服務器關閉),可以為環中的所有數據包建立最大超時值。 要對此進行評估,您只需計算單個插槽有多少個連續超時。 如果此值超過您設置的最大值,則可以認為連接丟失。

顯然,此協​​議類要求根據數據包編號在兩側進行數據集組裝,因為數據包可能無法按順序發送或接收。 “環”對此有所幫助,因為僅在成功傳輸之后才在接收方刪除數據包,僅在先前的數據包編號已被刪除並附加到增長的數據集時才在接收方刪除。 但是,這只是一種策略,還有其他策略。

希望這個幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM