为什么套接字在多线程时不工作
Why is socket not working when multithreaded?
我有一个非常简单的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: %inError Code: %in",r,WSAGetLastError);
现在,我在线程后面调用了相同的代码,如下所示:pthread_create(&listener, NULL, listenloop, &Socket);
(代码基本忽略&socket
。)
来自被调用线程的第一个执行的recvfrom()
返回-1,但来自"原始"线程(其中设置了网络)的recvfrom()
成功地用来自服务器的消息填充了message
。
好心地告诉我我做错了什么?
编辑:我不喜欢对好心帮助我的陌生人说十几句话,但如果我不这样做,我想我不会得到答案。所以,这是经过轻微编辑的工具包和kaboodle:
#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: %inThread Error Code: %in", 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 << "nnPlease 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 << "nn 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 << "nnMiserable 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: %inError Code: %in", r, WSAGetLastError);
//SOCKET listener=(SOCKET)arg;
WSACleanup();
return 0;
}
为什么使用全局Socket
?为什么你主要声明另一个Socket
?您应该更好地使用pthread_create
中传递的套接字(只需将listenloop中的args
强制转换为SOCKET *
)。多线程中的全局变量是一个非常糟糕的主意(您需要同步机制)。并用零初始化struct sockaddr_in from
(例如用memset
,或者按照alk所说的操作:struct sockaddr_in from = {0}
)。
而且,您正在从两个不同线程中的一个套接字读取,而没有任何同步。这势必会导致许多错误。
另外,我在其他线程中看到了WSACleanup
和recvfrom
的问题。你不知道这两个会以什么顺序运行(所以你也可以在其他线程中使用recvfrom
之前获得WSACleanup
)。你可以使用pthread_join
等待其他线程完成,然后再执行WSACleanup
。
这对于注释来说太长了。
发布的代码根本不起作用,因为声明:
struct sockaddr_in* from;
然后像这样使用from
:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
您正在使用struct sockaddr_in
地址的地址,而不是仅使用其地址。
Is应为:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
但是,如果这样做,您将错过为from
分配内存的机会。
struct sockaddr_in* from;
是一个拼写错误,应该阅读:
struct sockaddr_in from = {0};
- Qt::D irectConnection在多线程环境中使用时如何工作?
- 在 C++ 中扩展作业/工作线程多线程系统
- Qt5 多线程:信号仅单向工作
- 工作器/控制器多线程和接口类
- 来自 boost 的 udp 服务器不适用于多线程,但仅在主线程上工作
- SDL 带变量的多线程处理 -- 无法按预期工作
- 在多线程工作负载上解释Gperftools的结果
- 如何使用pthreads使多线程正常工作,而不是使用C++在类中提升
- Winsock多客户端和多线程,计算机努力工作
- 在多线程中使用curl句柄的错误工作方法的替代方法
- 导入 DLL 的工作方式不同(VS2003 到 VS2010,多线程到多线程 DLL)
- 多线程服务器不工作
- C++多线程合并无法工作
- 为什么套接字在多线程时不工作
- 无法让 modf() 在多线程中工作
- 多线程 - 为什么在引用上工作不会改变它,而在指针上工作正常
- 我如何检查我的多线程程序是否在c++中正常工作
- Qt:多线程连接不工作
- 多线程:如何在wxthread中使显示图像的GUI线程和处理图像同步的工作线程无阻塞
- 分析多线程代码,采样是如何工作的