我对套接字编程和多线程还很陌生,我还在学习它,但是我有一个我无法解决的问题,在其他一些主题上,我找到了一些答案,但它们看起来与我没有相同的问题。
我想创建一个UDP客户端。此客户端应该能够发送(sendto()
)和接收(recvfrom()
)。
我正在多线程发送和接收函数,但是recvfrom()
在调用WSAGetLastError()
时返回错误10022。
我将librairy 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] == '\0')
{
buff[i - 1] = '\0';
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);
}
}
}
(在我的机器上也有一个乒乓服务器来测试代码)
当我启动这个应用程序时,recvfrom()
不会阻塞并返回错误10022
,直到我使用Sending()
函数。正是在我使用fgets()
时,recvfrom()
停止返回错误。
我怎样才能阻止这个错误的发生?
我的机器在Windows 10下。
编辑:
我尝试过其他方法,我在函数bind()
中使用了Receiving()
,但它不起作用,下面是我的代码:
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);
}
}
}
发布于 2018-12-22 07:10:07
错误10022是WSAEINVAL
。的microsoft文档指定了由该函数引起时的含义(强调“我的”):
没有用绑定绑定套接字,或者指定了未知标志,或者为启用SO_OOBINLINE的套接字指定了MSG_OOB,或者(仅用于字节流类型的套接字) len为零或负。
在第二个代码片段中绑定它的尝试有一个不同的问题。您应该在启动任何一个线程之前绑定套接字,以避免在接收线程中的绑定与作为发送的一部分的隐式绑定之间存在争用条件。
虽然您没有明确说明如何使用bind失败,但我的猜测是,添加bind代码会使接收方延迟足够长的时间,以便先让发送方绑定,然后接收方的bind失败,因为不能绑定两次套接字。
发布于 2018-12-22 07:22:15
接收功能
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);
}
}
}
发布于 2018-12-22 07:34:53
这是最后的代码,感谢@Griffon26 26和@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] == '\0')
{
buff[i - 1] = '\0';
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);
}
}
}
https://stackoverflow.com/questions/53895036
复制相似问题