[英]winsock2: recvfrom() function ends with error 10022 (Invalid argument)
我正在C ++中的UDP套接字上工作,它既是客户端又是服务器。 我正在使用Visual Studio 2017并在Windows 7上运行它。recvfrom()函数有一些麻烦,以“ invalid arguments”错误结束。 我认为套接字可以,sockaddr_in结构也可以,线程也可以,甚至带有sendto()函数的while循环也可以。 但是线程在调用recvfrom()函数后结束,我真的不知道问题出在哪里...
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <thread>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
void printMessage(SOCKET s, SOCKADDR_IN destAddr) {
char message[100];
int result, error;
int addrSize = sizeof(destAddr);
do {
printf("som v threade\n");
result = recvfrom(s, message, 100, 0, (SOCKADDR*)&destAddr, &addrSize);
printf("%d\n", result);
if (result < 0) {
error = WSAGetLastError();
printf("%d\n", error);
}
if (result > 0)
printf("%s", message);
} while (result > 0);
}
int main(int argc, char *argv[]) {
WORD dllVersion = MAKEWORD(2, 1);
WSADATA wsaData;
if (WSAStartup(dllVersion, &wsaData) != 0) {
printf("Winsock startup failed");
exit(1);
}
const char *ip = "127.0.0.1";
int dstPort = 49999;
int srcPort = 49999;
SOCKADDR_IN destaddr, srcaddr;
SOCKET s;
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) {
printf("Error creating socket");
exit(1);
}
destaddr.sin_family = AF_INET;
destaddr.sin_addr.s_addr = inet_addr(ip);
destaddr.sin_port = htons(dstPort);
srcaddr.sin_family = AF_INET;
srcaddr.sin_addr.s_addr = htonl(INADDR_ANY);
srcaddr.sin_port = htons(srcPort);
bind(s, (SOCKADDR*)&srcaddr, sizeof(srcaddr));
thread receiving (printMessage, s, destaddr);
receiving.detach();
while (1) {
char message[100];
printf("Write a message:");
scanf("%s", message);
if (sendto(s, message, sizeof(message), 0, (SOCKADDR *) &destaddr, sizeof(destaddr)) < 0) {
printf("Message not sent");
exit(1);
}
}
return 0;
}
错误代码10022为WSAEINVAL
。 根据recvfrom()
文档:
WSAEINVAL
套接字尚未与
bind()
,或者未指定未知标志,或者已为启用SO_OOBINLINE
的套接字指定了MSG_OOB
,或者(对于字节流样式套接字,则为len
)为零或负数。
您没有做任何错误处理,以确保您的bind()
调用不会失败。 甚至您从一开始就调用正确的bind()
函数。 WinSock和STL都有自己的bind()
函数,但是using namespace std
的using namespace std
掩盖了事实 。
另外,每次调用recvfrom()
时,都需要重置addrSize
,因为它可能会修改值。 它希望您传入最大缓冲区大小,然后输出实际写入缓冲区的大小。
此外,您没有在正确的时间调用WSAGetLastError()
。 你需要一个失败的WinSock调用后立即调用它,在做任何事情之前。 换句话说,在调用WSAGetLastError()
之前不要调用printf()
WSAGetLastError()
,因为它可能会重置错误代码。
另外,如果recvfrom()
读取成功,则假定数据以null结尾,但这不能保证。 您需要将result
作为参数传递给printf()
。
而且,您实际上不应该将C风格的I / O与C ++混合使用。 请改用C ++风格的I / O。
尝试更多类似这样的方法:
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
void printMessage(SOCKET s)
{
char message[100];
int result, error, addrSize;
SOCKADDR_IN clientaddr;
do {
std::cout << "som v threade" << std::endl;
addrSize = sizeof(clientaddr);
result = recvfrom(s, message, 100, 0, (SOCKADDR*)&clientaddr, &addrSize);
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
std::cout << "Receive failed. Error: " << error << std::endl;
continue;
}
std::cout << "Received " << result << " byte(s) from " << inet_ntoa(clientaddr.sin_addr) << ":" << ntohs(clientaddr.sin_port) << std::endl;
if (result > 0) {
std::cout.write(message, result);
std::cout << std::endl;
}
}
while (result > 0);
}
int main(int argc, char *argv[]) {
WORD dllVersion = MAKEWORD(2, 1);
WSADATA wsaData;
int result, error;
result = WSAStartup(dllVersion, &wsaData);
if (result != 0) {
std::cout << "Winsock startup failed. Error: " << result << std::endl;
exit(1);
}
SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) {
error = WSAGetLastError();
std::cout << "Socket creation failed. Error: " << error << std::endl;
exit(1);
}
const char *ip = "127.0.0.1";
unsigned short dstPort = 49999;
unsigned short srcPort = 49999;
SOCKADDR_IN destaddr = {};
SOCKADDR_IN srcaddr = {};
destaddr.sin_family = AF_INET;
destaddr.sin_addr.s_addr = inet_addr(ip);
destaddr.sin_port = htons(dstPort);
srcaddr.sin_family = AF_INET;
srcaddr.sin_addr.s_addr = INADDR_ANY;
srcaddr.sin_port = htons(srcPort);
result = ::bind(s, (SOCKADDR*)&srcaddr, sizeof(srcaddr));
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
std::cout << "Socket bind failed. Error: " << error << std::endl;
exit(1);
}
std::thread receiving(printMessage, s);
receiving.detach();
std::string message;
do {
std::cout << "Write a message: ";
std::getline(std::cin, message);
result = sendto(s, message.c_str(), message.size(), 0, (SOCKADDR *) &destaddr, sizeof(destaddr));
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
std::cout << "Message not sent. Error: " << error << std::endl;
exit(1);
}
}
while (true);
return 0;
}
包含以下文件后,我也遇到了同样的问题
#include <thread> /*or*/ #include <future>
原来这是bind()
和std::bind()
之间的混淆。
using namespace std;
删除using namespace std;
或者只是使用::bind()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.