简体   繁体   English

多线程客户端未从服务器接收消息

[英]Multi-threaded client not receiving messages from server

I have a multiclient-server program. 我有一个多客户端服务器程序。 The client console will need to wait for user to input a message to send onto the server, and the client also needs to always be available for receiving messages from the server (this happens intermittently). 客户端控制台将需要等待用户输入要发送到服务器的消息,并且客户端还需要始终可用于接收来自服务器的消息(这是间歇性发生的)。 In order to do this, I have tried to set up two threads on the client-side, one for receiving, and one for sending. 为了做到这一点,我尝试在客户端设置两个线程,一个用于接收,另一个用于发送。

Initially, the client program (which I downloaded from here ) was designed to send a message to the server and receive a message back immediately. 最初,客户端程序(我从这里下载 )旨在将消息发送到服务器并立即收到消息。 This is the initial code (I have not included the functions here because I know they work, and the function names are self-explanatory): 这是初始代码(我在这里未包括这些功能,因为我知道它们可以工作,并且这些功能的名称不言而喻):

int main()
{
//initialize the winsock library
myTcpSocket::initialize();

//get client's information 
string clientName = clientInfo.getHostName();
string clientIPAddress = clientInfo.getHostIPAddress();

//get server's IP address and name
string serverIPAddress = "";
readServerConfig(serverIPAddress);

myHostInfo serverInfo(serverIPAddress,ADDRESS);
string serverName = serverInfo.getHostName();

//create the socket for client
myTcpSocket myClient(PORTNUM);

// connect to the server.
myClient.connectToServer(serverIPAddress, ADDRESS);

int recvBytes = 0;
while (1)
{
    // send message to server
    char messageToServer[MAX_MSG_LEN+1];
    memset(messageToServer, 0, sizeof(messageToServer));
    cout << "[SEND] ";
    cin.getline(messageToServer,MAX_MSG_LEN);

    winLog << "[SEND] " << messageToServer << endl;
    myClient.sendMessage(string(messageToServer));

    if ( !string(messageToServer).compare("Quit") || !string(messageToServer).compare("quit") ) 
        break;

    //receive message from server
    string messageFromServer = "";
    recvBytes = myClient.receiveMessage(messageFromServer);
    if ( recvBytes == -99 ) break;

    cout   << "[RECV:" << serverName << "]: " << messageFromServer << endl;
    winLog << "[RECV:" << serverName << "]: " << messageFromServer << endl;

}

return 1;
}

This code works, but since the server does not always have a message to send back to the client upon receiving a message, this holds up processes on the client side, which is why I am using a multi-threaded structure as below (functions not included for the above reason), separating the receiving and sending functions into different threads: 这段代码有效,但是由于服务器在接收到消息时并不总是有消息要发送回客户端,因此这会阻塞客户端的进程,这就是为什么我使用如下所示的多线程结构(功能包括在内),将接收和发送功能分为不同的线程:

DWORD WINAPI sendHandleThread(LPVOID threadInfo) //sending thread
{
//this structure contains all the data this callback will work on
myThreadArgument* sendArgument = (myThreadArgument*)threadInfo;

//create the socket for client
myTcpSocket myClient(PORTNUM); //PORTNUM = 1200

// connect to the server.
string serverIPAddress = "";
readServerConfig(serverIPAddress);
myClient.connectToServer(serverIPAddress, ADDRESS);

myHostInfo serverInfo(serverIPAddress,ADDRESS);
string serverName = serverInfo.getHostName();

int recvBytes = 0;

while (1)
{
    // send message to server
    char messageToServer[MAX_MSG_LEN+1];
    memset(messageToServer, 0, sizeof(messageToServer));
    cout << "[SEND] ";
    cin.getline(messageToServer,MAX_MSG_LEN);

    winLog << "[SEND] " << messageToServer << endl;
    myClient.sendMessage(string(messageToServer));

    if ( !string(messageToServer).compare("Quit") || !string(messageToServer).compare("quit") ) 
        break;
}
return 1;
}

DWORD WINAPI recHandleThread(LPVOID threadInfo) //receiving thread
{
//this structure contains all the data this callback will work on
myThreadArgument* recArgument = (myThreadArgument*)threadInfo;

//create the socket for client
myTcpSocket myClient(PORTNUM); //PORTNUM = 1200

// connect to the server.
string serverIPAddress = "";
readServerConfig(serverIPAddress);
myClient.connectToServer(serverIPAddress, ADDRESS);

myHostInfo serverInfo(serverIPAddress,ADDRESS);
string serverName = serverInfo.getHostName();

int recvBytes = 0;

while (1)
{
    //receive message from server
    string messageFromServer = "";
    recvBytes = myClient.receiveMessage(messageFromServer);
    if ( recvBytes == -99 ) break;

    cout   << "[RECV:" << serverName << "]: " << messageFromServer << endl;
    winLog << "[RECV:" << serverName << "]: " << messageFromServer << endl;
}
return 1;
}

int main()
{
//semaphore
mySemaphore coutSemaphore(string(""), 1);

//initialize the winsock library
myTcpSocket::initialize();

//get client's information (assume neither the name nor the address is given)
string clientName = clientInfo.getHostName();
string clientIPAddress = clientInfo.getHostIPAddress();

//get server's IP address and name
string serverIPAddress = "";
readServerConfig(serverIPAddress);

myHostInfo serverInfo(serverIPAddress,ADDRESS);
string serverName = serverInfo.getHostName();

//create sending thread
myTcpSocket send;
string sendName = "sendName";
myThreadArgument* sendArgument = new myThreadArgument(&send, &coutSemaphore, sendName);
myThread* sendThread = new myThread(sendHandleThread, (void*)sendArgument);
sendThread->execute();

//create receiving thread
myTcpSocket rec;
string recName = "recName";
myThreadArgument* recArgument = new myThreadArgument(&rec, &coutSemaphore, recName);
myThread* recThread = new myThread(recHandleThread, (void*)recArgument);
recThread->execute();

while (1)
{

    //dummy process
    Sleep(30000);
    cout << "--" << endl;

}

return 1;
}

I have tested that I have set up the threads properly - but only my send thread works ie when the user inputs a message, it will be sent to and received by the server. 我测试过我已经正确设置了线程-但是只有我的发送线程有效,即当用户输入消息时,它将被发送到服务器并由服务器接收。 However, I cannot seem to receive the message from my server. 但是,我似乎无法从服务器收到消息。

I'm new to this - is there anything that I am doing wrongly? 我是新手-我做错了什么吗? Sorry if the question isn't clear enough - I don't know what else is needed. 很抱歉,这个问题还不够清楚-我不知道还需要什么。

The relevant snippet of my server code is here for reference (I don't know if more is required, since the server portion seems to work the way I need it to) - at the moment I have set it up for testing so that when it receives a message from a client, it will 'reply' immediately (so that I can test the receiving thread on my client). 我的服务器代码的相关代码段在这里供参考(我不知道是否需要更多代码,因为服务器部分似乎可以按我需要的方式工作)-目前,我已将其设置为进行测试,以便它从客户端收到一条消息,它将立即“回复”(以便我可以在客户端上测试接收线程)。 Subsequently it will not reply immediately, but only when it has messages to pass on to the client. 随后,它不会立即答复,而只会在有消息传递给客户端时答复。

DWORD WINAPI clientHandleThread(LPVOID threadInfo)
{
     // this structure will contain all the data this callback will work on
     myThreadArgument* clientArgument = (myThreadArgument*)threadInfo;

   // get the client connection: receiving messages from client and
   // sending messages to the client will all be done by using
   // this client connection
   myTcpSocket* clientConnection = clientArgument->getClientConnect();
   string clientName = clientArgument->getHostName();

   // the server is communicating with this client here
   while(1)
   {
       string messageFromClient = "";

       // receive from the client

       int numBytes = clientConnection->recieveMessage(messageFromClient);
       if ( numBytes == -99 ) break;

       cout   << "[RECV fr " << clientName << "]: " << messageFromClient << endl;

       // if the client wants to disconnect
       if ( messageFromClient.compare("quit") == 0 || messageFromClient.compare("Quit") == 0 )
       {
           break;
       }
       else // send to the client
      {
           clientConnection->sendMessage(string("testing")); //test reply
       }
   }

   // if we reach here, this session with the client is done,
   // so we set the event on this thread to inform the main
  // control that this session is finished
   clientArgument->getExitEvent()->setEvent();
   return 1;
}

In your multi-threaded program, you are creating two clients, one in sendHandleThread and the other in recHandleThread , and therewith two connections. 在多线程程序中,您将创建两个客户端,一个在sendHandleThread ,另一个在recHandleThread ,并recHandleThread两个连接。 Of course, the server sends its reply message over the connection where the client's message came in, ie to the sendHandleThread , which is not prepared to receive it, while the recHandleThread receives nothing over its connection, because nothing was sent there. 当然,服务器通过客户端消息进入的连接发送答复消息,即发送到不准备接收消息的sendHandleThread ,而recHandleThread接收任何消息,因为那里没有发送任何消息。 To rectify that, you must create only one client connection and let both threads use the same. 要解决此问题,您必须仅创建一个客户端连接,并让两个线程使用相同的连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM