1

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()、「元の」スレッド (ネットワークがセットアップされた場所)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;

}
4

2 に答える 2

1

なぜグローバルを使用するのSocketですか? そして、なぜあなたSocketはメインで別のものを宣言しているのですか? 渡されたソケットを使用することをお勧めします ( listenloop を にpthread_createキャストするだけです)。マルチスレッドでのグローバル変数は本当に悪い考えです (同期メカニズムが必要です)。そして、あなたをゼロで初期化します(たとえば with 、または単に alk が言ったようにします : )。argsSOCKET *struct sockaddr_in frommemsetstruct sockaddr_in from = {0}

また、同期を行わずに、2 つの異なるスレッドで 1 つのソケットから読み取っています。これにより、多くのエラーが発生します。

また、他のスレッドに問題がWSACleanupあります。recvfromこれら2つがどの順序で実行されるかはわかりません(したがって、他のスレッドでWSACleanup実行する前に取得することもできrecvfromます). を使用pthread_joinして、他のスレッドが終了するのを待ってから実行できますWSACleanup.

于 2013-08-19T11:45:14.397 に答える
0

これはコメントするには長すぎます。

宣言されているため、投稿されたコードはまったく機能しません。

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};

?

于 2013-07-04T09:03:17.390 に答える