2016-04-30 43 views
1

我目前使用D來爲遊戲寫一個小的UDP服務器。問題是收到的一些數據包與實際數據包的長度不匹配(通過wireshark查看)。D receiveFrom沒有收到完整的數據包

例如,客戶端通過網絡發送一個110字節的數據包,該數據包顯示在wireshark下。但是D碼只接收7個字節!沒有其他7字節的數據包通過網絡從客戶端發送。

來自D的7個字節與來自110字節分組的前7個字節匹配。我相信這是套接字庫的問題,因爲我想不出任何其他可能導致此問題的東西。

問題總是發生在同一點和完全相同的數據包。如果被忽略,問題會繼續存在某些數據包。

請注意,在這個項目中的多個文件,所以我包括下面的代碼的剪:

this(in Logger logger, string bindInterface = "0.0.0.0", ushort bindPort = 19132) { 
    this.logger = logger; 
    socket = new UdpSocket(AddressFamily.INET); 
    bindAddress = new InternetAddress(bindInterface, bindPort); 
} 

void bind(uint sendBufferSize = 1024 * 1024, uint recvBufferSize = 1024 * 1024) { 
    socket.bind(bindAddress); 

    socket.setOption(SocketOptionLevel.SOCKET, SocketOption.BROADCAST, true); 
    socket.setOption(SocketOptionLevel.SOCKET, SocketOption.SNDBUF, sendBufferSize); 
    socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVBUF, recvBufferSize); 
    socket.blocking = false; 
} 

bool recv(ref Address address, ref byte[] buffer) { 
    auto length = socket.receiveFrom(buffer, SocketFlags.NONE, address); 
    if(length > 0) { 
     buffer.length = length; 
     debug logger.logDebug(to!string(length) ~ " Packet IN: " ~ to!string(cast(ubyte[]) buffer)); 
     return true; 
    } 
    buffer = null; 
    return false; 
} 

...

Address a; 
    byte[] data = new byte[1024 * 1024]; 
    while(max-- > 0 && socket.recv(a, data)) { 
     handlePacket(a, data); 
    } 

完整的源可以發現here.

任何幫助將不勝感激。

客戶是

+0

你能看到正在發送的整個消息的確切內容嗎?不是你相信它是什麼,而是實際發送了什麼內容? – zipzit

+0

這不太可能。 UDP傳遞完整的消息或沒有任何東西。這是UDP做出的唯一保證。所以如果你說的是真的,你的網絡基礎設施,你的操作系統或者代碼編譯器中的某些東西是非常糟糕的。 – jgauffin

+0

@zipzit如果你的意思是通過wireshark,是的,整個內容出現。有問題的數據是RakNet協議的二進制握手數據包的一部分。 – jython234

回答

3

問題是這一行:

bool recv(ref Address address, ref byte[] buffer) 

隨着ref你不會使片,但你真的修改原來的緩衝區,所以如果前一個數據包是7個字節長的比你不能得到更多的超過700個字節了

所以,你可以改變你的代碼刪除ref和回報,而不是簡單的布爾長度

size_t recv(ref Address address, byte[] buffer); 

然後:

Address a; 
byte[] data = new byte[1024 * 1024]; 
size_t len; 
while(max-- > 0 && (len = socket.recv(a, data))) { 
    handlePacket(a, data[0 .. len]); 
} 

但是,這可能會不同意你的handlePacket功能工作,因爲另一個ref所以另一種變體是不改變你的recv但只有部分代碼arount handlePacket

Address a; 
byte[] data = new byte[1024 * 1024]; 
size_t arr = data[]; 
while(max-- > 0 && socket.recv(a, arr)) { 
    handlePacket(a, arr); 
    arr = data[]; 
} 
+0

他不能簡單地刪除ref,因爲他需要爲'handlePacket'更新'.length'。但是一個問題的確是,在第一次recv調用之後,傳遞給'receiveFrom'的'data'緩衝區太小了。可能的解決方案:刪除'ref',但從'recv'中返回更新後的slice並將其用於'handlePacket'。或者在'handlePacket'之後保持'recv'未修改並將'data'重置爲完整的緩衝區大小。 – jpf

+0

@jpf是的,我修改了我的答案,使其更加準確 – Kozzi11

+0

你可以深入瞭解爲什麼'ref byte [] buffer'只接受7個字節?這對我來說沒有任何意義。 –