Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多线程时套接字为什么不工作?_C++_Multithreading_Sockets_Winsock - Fatal编程技术网

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