[英]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: %i\nError Code: %i\n",r,WSAGetLastError);
現在,我在線程后調用了相同的代碼,如下所示: pthread_create(&listener, NULL, listenloop, &Socket);
(代碼基本上會忽略&socket
。)
從被調用線程執行的第一個recvfrom()
返回-1,但是來自“原始”線程(已建立網絡recvfrom()
的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: %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;
}
為什么使用全局Socket
? 為什么要在main中聲明另一個Socket
? 您最好使用在pthread_create
傳遞的套接字(只需在listenloop中將args
強制轉換為SOCKET *
)。 多線程中的全局變量是一個非常糟糕的主意(您需要同步機制)。 並struct sockaddr_in from
初始化您的struct sockaddr_in from
(例如,使用memset
或按照alk所說的來做: struct sockaddr_in from = {0}
)。
而且,您正在從兩個不同線程中的一個套接字讀取數據,而沒有任何形式的同步。 這勢必會導致許多錯誤。
另外,我在其他線程中也看到了WSACleanup
和recvfrom
的問題。 你不知道什么樣的順序將在這兩個運行(所以你也可以得到WSACleanup
才能recvfrom
其他線程)。你可以使用pthread_join
等待其他線程完成,然后做WSACleanup
。
這個評論太長了。
由於聲明了以下內容,因此發布的代碼根本無法使用:
struct sockaddr_in* from;
然后像這樣使用from
:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
您正在暫存struct sockaddr_in
的地址,而不僅僅是它的地址。
應為:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
但是,如果這樣做,您將無法將內存分配給from
。
好吧
struct sockaddr_in* from;
是一個錯字,應該閱讀:
struct sockaddr_in from = {0};
?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.