大家好。
我正在尝试使用Windows sockets(C++)发送和接收UDP数据包。
一切都很正常,直到三天前,程序突然停止了正常运行。
总结如下:
- 当调用WSAPoll()时,始终返回更新了每个revents的套接字(对应于我给出的每个事件),即使没有启动服务器。
- 当调用recvfrom()且未启动服务器时,它将返回SOCKET_ERROR,错误代码为10054(*)。
- 当调用recvfrom()且已启动服务器时,它可以正常工作-阻塞直到接收到数据。
- 无论是尝试连接到本地主机还是远程主机,行为都是相同的。
(*) 我调查了这个错误。在UDP中,它意味着存在一个ICMP问题。(“在UDP数据报套接字上,此错误表示先前的发送操作导致了一个ICMP端口不可达消息。”)。
我确实在recvfrom()之前调用了sendto(),所以问题不在这里。
我试图关闭我的防火墙,看看是否有任何变化,但没有。我还试图关闭通过我的PC流动的所有网络。在这种状态下,我设法让程序运行了几分钟,但当我启用网络时,它又停止工作了。我试图重复这个过程,但它再也不能工作了。
我尝试使用Visual Studio(2015)和MinGW编译。
我也在另一台计算机上尝试过(在Windows 7下,我的是Windows 8.1),但没有成功。
这里是一个简单的测试文件,在我的电脑上无法运行。
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <vector>
#include <iostream>
int main() {
int clientSock;
char buf[100];
int serverPort;
/* Initializing WSA */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
/* I create my socket */
struct addrinfo specs;
struct addrinfo *addr = new addrinfo;
ZeroMemory(&specs, sizeof(specs));
specs.ai_family = AF_INET;
specs.ai_socktype = SOCK_DGRAM;
specs.ai_flags = 0;
getaddrinfo("127.0.0.1", "2324", &specs, &addr);
clientSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
/* I get the server's address */
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddr.sin_port = htons(2324);
int len = sizeof(struct sockaddr);
/* I'll poll & recvfrom on my socket */
std::vector<pollfd> fds;
pollfd fd;
fd.fd = clientSock;
fd.events = POLLRDNORM;
fd.revents = -1;
fds.push_back(fd);
while(1) {
memset(buf,0,sizeof(buf));
printf("\nClient--->: ");
gets(buf);
/* It's UDP, so it doesn't matter if there is someone to receive the packet */
sendto(clientSock, buf, strlen(buf), 0, (sockaddr*)&serverAddr ,len);
memset(buf,0,sizeof(buf));
int ret;
/* Always returns "1" */
if ((ret = WSAPoll(fds.data(), 1, 0)) > 0) {
std::cout << ret;
/* Always returns "-1" */
std::cout << recvfrom(clientSock,buf,sizeof(buf),0, (sockaddr*)&serverAddr,&len) << std::endl;
printf("\n--->From the server: ");
printf("%s",buf);
}
}
closesocket(clientSock);
WSACleanup();
return 0;
}
两个问题:
- 即使没有与其进行任何交互,为什么WSAPoll()总是返回更新的套接字?
- recvfrom()为什么会返回这个错误,我该如何修复它?我想这可能是来自我的计算机。我尝试允许ICMP通过我的防火墙,但没有改变任何东西,也许我做错了什么?
编辑:我通过忽略我收到的任何“错误10054”来修复了我的主要程序(此处未显示,因为它太大了)。现在它的工作方式与Unix相同。
不过,这并不是真正的解决方案(忽略错误代码...嗯),如果有人知道我在调用sendto()
时为什么会收到“ICMP端口不可达”错误,我将很高兴听取建议。
recvfrom()
之前调用了sendto()
,所以问题不在这里”是没有意义的。你调用了sendto()
,返回了一个ICMP UNREACH,并在接下来的recvfrom()
中检测到了它。 - user207421sendto()
。你自己说的。即使你没有调用,调用recvfrom()
也会隐式绑定。不清楚你在这里到底在说什么。 - user207421recvfrom()
之前调用sendto()
,否则它将无法工作。 我不知道recvfrom()
也会隐式绑定。 是我的错。 - Heowyn