2016-04-30 42 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个字节?这对我来说没有任何意义。 –