php udp 非阻塞,使用非阻塞udp读取时丢失消息

当在两个主机之间使用非阻塞的udp读取时,我有丢失消息的问题。发送者在linux上,读取器在winxp上。python中的这个例子显示了这个问题。

这里有三个脚本用于显示问题。

发送.py:import socket, sys

s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

host = sys.argv[1]

s.sendto('A'*10, (host,8888))

s.sendto('B'*9000, (host,8888))

s.sendto('C'*9000, (host,8888))

s.sendto('D'*10, (host,8888))

s.sendto('E'*9000, (host,8888))

s.sendto('F'*9000, (host,8888))

s.sendto('G'*10, (host,8888))

读取.pyimport socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind(('',8888))

while True:

data,address = s.recvfrom(10000)

print "recv:", data[0],"times",len(data)

读取nb.pyimport socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.bind(('',8888))

s.setblocking(0)

data =''

address = ''

while True:

try:

data,address = s.recvfrom(10000)

except socket.error:

pass

else:

print "recv:", data[0],"times",len(data)

示例1(工作正常):

ubuntu>python send.py

winxp>读取.py

从read.py中给出这个ok结果:

记录:A乘以10

记录:B乘以9000

接收:C乘以9000

接收:D乘以10

接收:E乘以9000

接收:F乘以9000

记录:G乘以10

示例2(缺少消息):

在这种情况下,read_nb.py通常不会捕获短消息

我举了两个例子来说明它的样子。

ubuntu>python send.py

winxp>读取nb.py

从read_nb.py给出此结果:

记录:A乘以10

记录:B乘以9000

接收:C乘以9000

接收:D乘以10

接收:E乘以9000

记录:F乘以9000

上面是最后一条丢失的10字节消息

下面是中间缺少的10字节消息

记录:A乘以10

记录:B乘以9000

接收:C乘以9000

接收:E乘以9000

接收:F乘以9000

记录:G乘以10

我已经在windows上与wireshark进行了检查,每次捕获所有消息时,它们都会到达主机界面,但不是由read_nb.py捕获的。怎么解释?

我还尝试过在linux上使用read_nb.py,在windows上使用send.py,然后它就工作了。

所以我想这个问题和winsock2有关

或者我使用非阻塞udp的方式不对?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一份简单的 C++ Windows 下 UDP 非阻塞发送和接收示例代码: ```c++ #include <iostream> #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib, "Ws2_32.lib") int main() { // 初始化 Winsock 库 WSADATA wsaData; int result = WSAStartup(MAKEWORD(2, 2), &wsaData); if (result != 0) { std::cerr << "WSAStartup failed: " << result << std::endl; return 1; } // 创建 UDP 套接字 SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == INVALID_SOCKET) { std::cerr << "Failed to create socket: " << WSAGetLastError() << std::endl; WSACleanup(); return 1; } // 设置套接字为非阻塞模式 u_long nonBlocking = 1; if (ioctlsocket(sock, FIONBIO, &nonBlocking) != 0) { std::cerr << "Failed to set non-blocking mode: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 绑定套接字到本地端口 sockaddr_in localAddr; localAddr.sin_family = AF_INET; localAddr.sin_port = htons(12345); // 绑定到端口 12345 localAddr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, reinterpret_cast<sockaddr*>(&localAddr), sizeof(localAddr)) == SOCKET_ERROR) { std::cerr << "Failed to bind socket: " << WSAGetLastError() << std::endl; closesocket(sock); WSACleanup(); return 1; } // 发送数据 sockaddr_in destAddr; destAddr.sin_family = AF_INET; destAddr.sin_port = htons(12345); inet_pton(AF_INET, "127.0.0.1", &destAddr.sin_addr); // 发送到本地回环地址 const char* message = "Hello, UDP!"; int messageLen = strlen(message); int bytesSent = sendto(sock, message, messageLen, 0, reinterpret_cast<sockaddr*>(&destAddr), sizeof(destAddr)); if (bytesSent == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != WSAEWOULDBLOCK) { std::cerr << "Failed to send data: " << error << std::endl; closesocket(sock); WSACleanup(); return 1; } } else { std::cout << "Sent " << bytesSent << " bytes of data." << std::endl; } // 接收数据 char buffer[1024]; sockaddr_in srcAddr; int srcAddrLen = sizeof(srcAddr); int bytesReceived = recvfrom(sock, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr*>(&srcAddr), &srcAddrLen); if (bytesReceived == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != WSAEWOULDBLOCK) { std::cerr << "Failed to receive data: " << error << std::endl; closesocket(sock); WSACleanup(); return 1; } } else { buffer[bytesReceived] = '\0'; std::cout << "Received " << bytesReceived << " bytes of data: " << buffer << std::endl; } // 关闭套接字并清理 Winsock 库 closesocket(sock); WSACleanup(); return 0; } ``` 在本示例代码中,我们首先初始化了 Winsock 库,然后创建了一个 UDP 套接字,并将其设置为非阻塞模式。接着,我们将套接字绑定到本地端口,然后发送了一条 UDP 数据报到本地回环地址。最后,我们接收了一条 UDP 数据报,并将其输出到控制台。 需要注意的是,由于套接字被设置为非阻塞模式,所以在发送和接收数据,我们需要检查返回值并根据返回值判断操作是否成功。如果返回值为 SOCKET_ERROR,则说明操作失败,此我们需要通过 WSAGetLastError() 函数获取错误码,并根据错误码判断错误类型。如果错误类型为 WSAEWOULDBLOCK,则说明套接字处于非阻塞模式,暂无法进行发送或接收操作,可以继续等待后续操作。 希望这份示例代码能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值