C++ 多线程时套接字为什么不工作?
我有一个非常简单的C++ 多线程时套接字为什么不工作?,c++,multithreading,sockets,winsock,C++,Multithreading,Sockets,Winsock,我有一个非常简单的recvfrom()命令,只要它不是在“另一个”线程中调用的,它就可以正常工作 我会发布更多的代码,但其中有相当多的代码,所以希望我能过滤掉相关的代码: 首先我们有一个全局变量:SOCKET-SOCKET=SOCKET(AF_INET,SOCK_DGRAM,IPPROTO_UDP) 只要不涉及线程,这就可以正常工作: char message[_max_message_]; struct sockaddr_in* from; int r; int SenderAddrS
recvfrom()
命令,只要它不是在“另一个”线程中调用的,它就可以正常工作
我会发布更多的代码,但其中有相当多的代码,所以希望我能过滤掉相关的代码:
首先我们有一个全局变量:SOCKET-SOCKET=SOCKET(AF_INET,SOCK_DGRAM,IPPROTO_UDP)代码>
只要不涉及线程,这就可以正常工作:
char message[_max_message_];
struct sockaddr_in* from;
int r;
int SenderAddrSize = sizeof (struct sockaddr);
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n",r,WSAGetLastError);
现在我在线程后面调用了相同的代码,如下所示:
pthread_创建(&listener、NULL、listenloop和Socket)代码>
(代码基本上忽略了&socket
)
从被调用线程执行的第一个recvfrom()
返回-1,但是从“原始”线程(网络设置的地方)执行的recvfrom()
成功地用来自服务器的消息填充message
能告诉我我做错了什么吗
编辑:我讨厌对陌生人说十几句好话来帮助我,但如果我不这么做,我想我不会得到答案。这是经过轻微编辑的工具包和卡布多:
#include <iostream>
//#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <conio.h>
using namespace std;
#include <string>
//One thread shall listen continually for responses from the server.
/*The other thread shall listen continually for user input, and fire off user input at the local
client to the server...*/
//#ifdef _WINDOWS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
inline int randport()
{
return (50000 % rand() + 1000);
}
#define _serverip_ "***.***.***.***"
#define _welcome_ "Welcome,Wagon!"
#define _randomport_ 64000%rand()+100
#define _max_message_ 100
void *listenloop(void *arg)
{
//SOCKET* listener = (SOCKET)arg;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
int r;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
//while (1){
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Thread Bytes recieved: %i\nThread Error Code: %i\n", r,
WSAGetLastError);
return NULL ;
//}
return NULL ;
}
int main()
{
string user, pass, login;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
int port;
cout << "Welcome!"
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
fflush(stdin); //As long as we compile with GCC Behavoir should be consistant
//TRY NOT TO SEND PLAINTEXT PASSWORDS LIKE THIS! IT MAY MAKE YOUR USERS VULNERABLE! DONE FOR SAKE OF SIMPLICITY HERE!
cout << "\n\nPlease enter the username you registered with:";
getline(cin, user);
cout << "\nPlease enter your password, my good sir: ";
getline(cin, pass);
struct hostent *host;
host = gethostbyaddr(_serverip_, strlen(_serverip_), AF_INET);
if (host == NULL )
{
cout << "\n\n UNABLE TO CONNECT TO SERVER. QUITTING. ";
return -1;
}
short errorcount = 3;
int socketfeedback;
///Put the address for the server on the "evelope"
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(_serverip_);
///Sign the letter...
int myport = _randomport_;
int code;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("localhost");
service.sin_port = htons(myport);
//bind(Socket, (SOCKADDR *) &service, sizeof(service));
//Start a thread, listening for that server
while ((errorcount))
{
code = bind(Socket, (SOCKADDR *) &service, sizeof(service));
if (code)
break;
else
return -5;
errorcount--;
myport = _randomport_;
service.sin_port = htons(myport);
}
login = user + ',' + pass;
if (!errorcount)
{
cout << "\n\nMiserable failure. Last Known Error Code: " << code;
return -1;
}
///Begin the listen loop!!
pthread_t listener;
pthread_create(&listener, NULL, listenloop, &Socket);
struct sockaddr result;
sendto(Socket, login.c_str(), strlen(login.c_str()), 0,
(struct sockaddr *) &SockAddr, sizeof(SockAddr));
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
int r;
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n", r, WSAGetLastError);
//SOCKET listener=(SOCKET)arg;
WSACleanup();
return 0;
}
#包括
//#包括
#包括
#包括
#包括
#包括
使用名称空间std;
#包括
//一个线程应持续监听服务器的响应。
/*另一个线程应持续监听用户输入,并在本地启动用户输入
客户端到服务器*/
//#ifdef_窗口
#包括
#包括
#包括
SOCKET SOCKET=SOCKET(主机、SOCK DGRAM、IPPROTO_UDP);
内联int randport()
{
回报率(50000%兰特()+1000);
}
#定义_serverip u“***.**.**”
#定义“欢迎”——“欢迎,马车!”
#定义随机端口64000%rand()+100
#定义最大消息100
void*listenloop(void*arg)
{
//套接字*侦听器=(套接字)参数;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2,0)和WsaDat);
字符消息[_max_message];
//套接字侦听器=(套接字)参数;
INTR;
//SenderAddr中的sockaddr_;
来自中的结构sockaddr_;
//而(1){
int SenderAddrSize=sizeof(结构sockaddr);
r=recvfrom(套接字、消息、最大消息、0、(结构sockaddr*)和from,
&SenderAddressSize);
printf(“接收到的线程字节数:%i\n读取错误代码:%i\n”,r,
WSAGetLastError);
返回NULL;
//}
返回NULL;
}
int main()
{
字符串用户、pass、login;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2,0)和WsaDat);
国际港口;
cout这篇评论太长了
发布的代码根本不起作用,因为声明:
struct sockaddr_in* from;
然后像这样使用来自
的:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
您正在使用
中的struct sockaddr\u的地址,而不仅仅是它的地址
Is应为:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
但是,如果这样做,您将无法从
向分配内存
很可能
struct sockaddr_in* from;
是一个打字错误,应该阅读:
struct sockaddr_in from = {0};
这篇评论太长了
发布的代码根本不起作用,因为声明:
struct sockaddr_in* from;
然后像这样使用来自
的:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
您正在使用
中的struct sockaddr\u的地址,而不仅仅是它的地址
Is应为:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
但是,如果这样做,您将无法从
向分配内存
很可能
struct sockaddr_in* from;
是一个打字错误,应该阅读:
struct sockaddr_in from = {0};
?为什么要使用全局Socket
?为什么要在main中声明另一个Socket
?最好使用在pthread\u create
中传递的套接字(只需在listenloop中将args
转换为Socket*
)。多线程中的全局变量是一个非常糟糕的主意(需要同步机制)。并用零初始化from中的结构sockaddr_(例如,使用memset
,或者按照alk所说的操作:struct sockaddr_in from={0}
)
而且,您正在两个不同线程中从一个套接字读取数据,而没有任何类型的同步。这必然会导致许多错误
我还发现另一个线程中的WSACleanup
和recvfrom
存在问题。您不知道这两个线程的运行顺序(因此,您也可以在另一个线程中的recvfrom
之前获得WSACleanup
)。您可以使用pthread\u join
等待其他线程完成,然后执行WSACleanup
为什么要使用全局Socket
?为什么要在main中声明另一个Socket
?您最好使用传入的套接字pthread\u create
(只需将列表中的args
转换为SOCKET*
)。多线程中的全局变量是一个非常糟糕的主意(您需要同步机制)。并将struct sockaddr\u从中初始化为零(例如,使用memset
,或者按照alk所说的那样:struct sockaddr\u in from={0}
)
而且,您正在两个不同线程中从一个套接字读取数据,而没有任何类型的同步。这必然会导致许多错误
我还发现另一个线程中的WSACleanup
和recvfrom
存在问题。您不知道这两个线程的运行顺序(因此,您也可以在另一个线程中的recvfrom
之前获得WSACleanup
)。您可以使用pthread\u join
等待其他线程完成,然后执行WSACleanup
与-1的返回值关联的errno
是什么?发生这种情况时,调用perror
。根据WSAgetlast error…这是一个非常大的数字,但对于工作和非工作线程来说都是相同的数字recvfrom
,所以我认为它只是某种人工制品……谢谢,我会试试perror,根据这一点,它不适用于WINSock调用“…非常大的数字……”这个数字会很有趣。你介意给我们看一下吗?4200684。这似乎可以在节目重播时重复,我不确定明天会是一样的。什么是errno