簡體   English   中英

為什么多線程時套接字不起作用?

[英]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} )。

而且,您正在從兩個不同線程中的一個套接字讀取數據,而沒有任何形式的同步。 這勢必會導致許多錯誤。

另外,我在其他線程中也看到了WSACleanuprecvfrom的問題。 你不知道什么樣的順序將在這兩個運行(所以你也可以得到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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM