多线程时recvfrom()返回错误10022(C)
Error 10022 returned by recvfrom() when multithreading (C)
我是套接字编程和多线程的新手,我还在学习,但我有一个我无法解决的问题,在其他一些主题上我找到了一些答案,但他们看起来不遇到和我一样的问题。
我想创建一个 UDP 客户端。此客户端应该能够发送 (sendto()
) 和接收 (recvfrom()
)。
我正在对发送和接收函数进行多线程处理,但是 recvfrom()
return 在调用 WSAGetLastError()
.
时出现错误 10022
我将库 pthread.h
用于多线程,将 winsock2.h
用于套接字。
当我不是多线程时没有问题。
我的代码:
#include <sys/types.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER "127.0.0.1"
#define PORT 8888
#define MAXBUFFER 1024
void Sending(void *VarThread);
void Receiving(void *VarThread);
int main(int argc, char **argv)
{
int sock;
pthread_t Thread_ID_1;
pthread_t Thread_ID_2;
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
perror("\nsocket()");
printf("%d", WSAGetLastError());
exit(0);
}
pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);
pthread_join(Thread_ID_1, NULL);
pthread_join(Thread_ID_2, NULL);
close(sock);
WSACleanup();
return 0;
}
void Sending(void *VarThread)
{
int sock = *(int *)VarThread;
int i;
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr(SERVER);
si.sin_port = htons(PORT);
char buff[MAXBUFFER];
ssize_t message;
while(1)
{
fgets(buff, MAXBUFFER, stdin);
for(i = 1; i < MAXBUFFER; i++) // delete the last '\n'
{
if(buff[i] == '[=10=]')
{
buff[i - 1] = '[=10=]';
i = MAXBUFFER;
}
}
message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
if (message == -1)
{
perror("\nsendto()");
printf("%d", WSAGetLastError());
}
}
}
void Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
char buff[MAXBUFFER];
ssize_t recu;
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, NULL, 0);
if(recu == -1)
{
perror("\n\nError recvfrom ");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("message = %s\n", buff);
}
}
}
(我的机器上也有一个 pingpong 服务器 运行 来测试代码)
当我启动这个应用程序时,recvfrom()
没有阻塞并且 return 错误 10022
直到我使用 Sending()
函数。正是在我使用 fgets()
时 recvfrom()
停止到 return 错误。
我怎样才能阻止这个错误的发生?
P.S.: 我的机器在Windows10.
下
编辑:
我试过其他方法,我在函数 Receiving()
中使用 bind()
但它不起作用,这是我的代码:
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in SockRecv;
int slen = sizeof(SockRecv);
char buff[MAXBUFFER];
ssize_t recu;
memset((char *)&SockRecv, 0, sizeof(SockRecv));
SockRecv.sin_family = AF_INET;
SockRecv.sin_addr.s_addr = htonl(SERVER);
SockRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&SockRecv, sizeof(SockRecv)) == -1)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&SockRecv, &slen);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}
错误 10022 是 WSAEINVAL
。 The microsoft documentation of recvfrom 指定由该函数引起的含义(强调我的):
The socket has not been bound with bind, or an unknown flag was specified,
or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, or
(for byte stream-style sockets only) len was zero or negative.
您尝试在第二个代码片段中绑定它有一个不同的问题。您应该在启动任何一个线程之前绑定套接字,以避免接收线程中的绑定与作为发送一部分的隐式绑定之间的竞争条件。
虽然你没有明确说明你的绑定是如何失败的,但我的猜测是添加绑定代码延迟了接收者足够长的时间让发送者先绑定,然后接收者的绑定失败,因为你不能绑定一个插座两次。
接收函数
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in AddrRecv;
struct sockaddr_in AddrSend;
int LenAddrSend = sizeof(AddrSend);
char buff[MAXBUFFER];
ssize_t recu;
memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
AddrRecv.sin_family = AF_INET;
AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr(SERVER);
AddrRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}
这是最终代码,感谢@Griffon26 和@Gerhardh
#include <sys/types.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER "127.0.0.1"
#define PORT 8888
#define MAXBUFFER 1024
void *Sending(void *VarThread);
void *Receiving(void *VarThread);
int main(int argc, char ** argv){
int sock;
int i;
pthread_t Thread_ID_1;
pthread_t Thread_ID_2;
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
{
perror("\nsocket()");
printf("%d", WSAGetLastError());
exit(0);
}
struct sockaddr_in AddrRecv;
memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
AddrRecv.sin_family = AF_INET;
AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY);
AddrRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);
pthread_join(Thread_ID_1, NULL);
pthread_join(Thread_ID_2, NULL);
close(sock);
WSACleanup();
return 0;
}
void *Sending(void *VarThread)
{
int sock = *(int *)VarThread;
int i;
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr(SERVER);
si.sin_port = htons(PORT);
char buff[MAXBUFFER];
ssize_t message;
while(1)
{
fgets(buff, MAXBUFFER, stdin);
for(i = 1; i < MAXBUFFER; i++)
{
if(buff[i] == '[=10=]')
{
buff[i - 1] = '[=10=]';
i = MAXBUFFER;
}
}
message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
if (message == -1)
{
perror("\nsendto()");
printf("%d", WSAGetLastError());
}
}
}
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in AddrSend;
int LenAddrSend = sizeof(AddrSend);
char buff[MAXBUFFER];
ssize_t recu;
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}
我是套接字编程和多线程的新手,我还在学习,但我有一个我无法解决的问题,在其他一些主题上我找到了一些答案,但他们看起来不遇到和我一样的问题。
我想创建一个 UDP 客户端。此客户端应该能够发送 (sendto()
) 和接收 (recvfrom()
)。
我正在对发送和接收函数进行多线程处理,但是 recvfrom()
return 在调用 WSAGetLastError()
.
我将库 pthread.h
用于多线程,将 winsock2.h
用于套接字。
当我不是多线程时没有问题。
我的代码:
#include <sys/types.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER "127.0.0.1"
#define PORT 8888
#define MAXBUFFER 1024
void Sending(void *VarThread);
void Receiving(void *VarThread);
int main(int argc, char **argv)
{
int sock;
pthread_t Thread_ID_1;
pthread_t Thread_ID_2;
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
{
perror("\nsocket()");
printf("%d", WSAGetLastError());
exit(0);
}
pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);
pthread_join(Thread_ID_1, NULL);
pthread_join(Thread_ID_2, NULL);
close(sock);
WSACleanup();
return 0;
}
void Sending(void *VarThread)
{
int sock = *(int *)VarThread;
int i;
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr(SERVER);
si.sin_port = htons(PORT);
char buff[MAXBUFFER];
ssize_t message;
while(1)
{
fgets(buff, MAXBUFFER, stdin);
for(i = 1; i < MAXBUFFER; i++) // delete the last '\n'
{
if(buff[i] == '[=10=]')
{
buff[i - 1] = '[=10=]';
i = MAXBUFFER;
}
}
message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
if (message == -1)
{
perror("\nsendto()");
printf("%d", WSAGetLastError());
}
}
}
void Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
char buff[MAXBUFFER];
ssize_t recu;
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, NULL, 0);
if(recu == -1)
{
perror("\n\nError recvfrom ");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("message = %s\n", buff);
}
}
}
(我的机器上也有一个 pingpong 服务器 运行 来测试代码)
当我启动这个应用程序时,recvfrom()
没有阻塞并且 return 错误 10022
直到我使用 Sending()
函数。正是在我使用 fgets()
时 recvfrom()
停止到 return 错误。
我怎样才能阻止这个错误的发生?
P.S.: 我的机器在Windows10.
下编辑:
我试过其他方法,我在函数 Receiving()
中使用 bind()
但它不起作用,这是我的代码:
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in SockRecv;
int slen = sizeof(SockRecv);
char buff[MAXBUFFER];
ssize_t recu;
memset((char *)&SockRecv, 0, sizeof(SockRecv));
SockRecv.sin_family = AF_INET;
SockRecv.sin_addr.s_addr = htonl(SERVER);
SockRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&SockRecv, sizeof(SockRecv)) == -1)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&SockRecv, &slen);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}
错误 10022 是 WSAEINVAL
。 The microsoft documentation of recvfrom 指定由该函数引起的含义(强调我的):
The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, or (for byte stream-style sockets only) len was zero or negative.
您尝试在第二个代码片段中绑定它有一个不同的问题。您应该在启动任何一个线程之前绑定套接字,以避免接收线程中的绑定与作为发送一部分的隐式绑定之间的竞争条件。
虽然你没有明确说明你的绑定是如何失败的,但我的猜测是添加绑定代码延迟了接收者足够长的时间让发送者先绑定,然后接收者的绑定失败,因为你不能绑定一个插座两次。
接收函数
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in AddrRecv;
struct sockaddr_in AddrSend;
int LenAddrSend = sizeof(AddrSend);
char buff[MAXBUFFER];
ssize_t recu;
memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
AddrRecv.sin_family = AF_INET;
AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr(SERVER);
AddrRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}
这是最终代码,感谢@Griffon26 和@Gerhardh
#include <sys/types.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER "127.0.0.1"
#define PORT 8888
#define MAXBUFFER 1024
void *Sending(void *VarThread);
void *Receiving(void *VarThread);
int main(int argc, char ** argv){
int sock;
int i;
pthread_t Thread_ID_1;
pthread_t Thread_ID_2;
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
{
perror("\nsocket()");
printf("%d", WSAGetLastError());
exit(0);
}
struct sockaddr_in AddrRecv;
memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
AddrRecv.sin_family = AF_INET;
AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY);
AddrRecv.sin_port = htons(PORT);
if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
{
perror("\n\nbind()");
printf("Error Code : %d", WSAGetLastError());
exit(0);
}
pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);
pthread_join(Thread_ID_1, NULL);
pthread_join(Thread_ID_2, NULL);
close(sock);
WSACleanup();
return 0;
}
void *Sending(void *VarThread)
{
int sock = *(int *)VarThread;
int i;
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr(SERVER);
si.sin_port = htons(PORT);
char buff[MAXBUFFER];
ssize_t message;
while(1)
{
fgets(buff, MAXBUFFER, stdin);
for(i = 1; i < MAXBUFFER; i++)
{
if(buff[i] == '[=10=]')
{
buff[i - 1] = '[=10=]';
i = MAXBUFFER;
}
}
message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
if (message == -1)
{
perror("\nsendto()");
printf("%d", WSAGetLastError());
}
}
}
void *Receiving(void *VarThread)
{
int sock = *(int *)VarThread;
struct sockaddr_in AddrSend;
int LenAddrSend = sizeof(AddrSend);
char buff[MAXBUFFER];
ssize_t recu;
while(1)
{
recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
if(recu == -1)
{
perror("\n\nError recvfrom()");
printf("Error Code : %d", WSAGetLastError());
}
else
{
printf("Message = %s\n", buff);
}
}
}