2013-03-01 144 views
0

我有一个多客户端服务器程序。客户端控制台需要等待用户输入消息才能发送到服务器上,并且客户端也需要始终可用于从服务器接收消息(这是间歇性发生的)。为了做到这一点,我试图在客户端建立两个线程,一个用于接收,另一个用于发送。多线程客户端未收到来自服务器的消息

最初,客户端程序(我从here下载)旨在向服务器发送消息并立即收到消息。这是最初的代码(我没有包括的功能在这里,因为我知道他们的工作,和函数名是不言自明):

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

此代码的工作,但因为服务器并不总是有一个消息在接收到消息时发送给客户端,这在客户端保留了进程,这就是为什么我使用如下的多线程结构(功能未包括在上述原因中),将接收和发送功能分离为不同的线程:

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

,我已经设置了正确的线程我已经测试 - 但只有我发送线程,我的作品也就是说,当用户输入消息时,它将被发送到服务器并由服务器接收。但是,我似乎无法从我的服务器收到消息。

我是新来的 - 有什么我错了吗?对不起,如果问题不够清楚 - 我不知道还需要什么。

我的服务器代码的相关片段在这里供参考(我不知道是否需要更多,因为服务器部分似乎以我需要的方式工作) - 此刻我已将它设置为测试,以便当它从客户端收到消息时,它会立即“回复”(以便我可以在客户端上测试接收线程)。随后它不会立即回复,但只有当它有消息传递给客户端时。

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

我的猜测是服务器可能没有向您的客户端发送任何东西,或者它没有发送recieveMessage()所期望的数据格式。 recieveMessage()在返回之前期望接收多少个字节?它实际接收了多少字节?您可能希望在recieveMessage()实现中放置一些printf以查看那里正在发生的事情......或运行WireShark以查看实际从服务器进入计算机的字节,或者两者都有... – 2013-03-01 02:37:38

+0

服务器_is_发送消息给客户端(如果接收和发送功能都在同一个线程中,我可以收到它),只有当它们被分离到不同的线程中时,程序看起来不会收到任何东西 – sccs 2013-03-01 02:43:45

+0

服务器正在发送当两个函数在同一个线程中时,消息传递给客户端。当函数处于不同的线程中时,你是如何演示它向客户端发送消息的? – 2013-03-01 16:30:39

回答

0

在你的多线程程序时,需要创建两个客户,一个在sendHandleThread和其他在recHandleThread,以及与其两个连接。当然,服务器通过客户端消息进入的连接发送它的回复消息,即到sendHandleThread,这是不准备接收它,而recHandleThread没有收到任何关于它的连接,因为没有发送到那里。 要纠正这种情况,您必须只创建一个客户端连接,并让两个线程使用相同的连接。