Multi-threaded client not receiving messages from server - c++

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 i.e. 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. Of course, the server sends its reply message over the connection where the client's message came in, i. e. to the sendHandleThread, which is not prepared to receive it, while the recHandleThread receives nothing over its connection, because nothing was sent there.
To rectify that, you must create only one client connection and let both threads use the same.

Related

ZMQ messages not being received

Please forgive me if I'm missing something simple, this is my first time doing anything with messaging and I inherited this codebase from someone else.
I am trying to send a message from a windows machine with an IP of 10.10.10.200 to an Ubuntu machine with an IP of 10.10.10.15.
I got the following result when running TCPView from the Windows machine, which makes me suspect that the problem lies in the Ubuntu machine. If I'm reading that right, then my app on the windows machine has created a connection on port 5556 which is what it is supposed to do. In case I'm wrong, I'll include the windows code too.
my_app.exe 5436 TCP MY_COMPUTER 5556 MY_COMPUTER 0 LISTENING
Windows app code:
void
NetworkManager::initializePublisher()
{
globalContext = zmq_ctx_new();
globalPublisher = zmq_socket(globalContext, ZMQ_PUB);
string protocol = "tcp://*:";
string portNumber = PUBLISHING_PORT; //5556
string address = protocol + portNumber;
char *address_ptr = new char[address.size() + 1];
strncpy_s(address_ptr, address.size() + 1, address.c_str(), address.size());
int bind_res = zmq_bind(globalPublisher, address_ptr);
if (bind_res != 0)
{
cerr << "FATAL: couldn't bind to port[" << portNumber << "] and protocol [" << protocol << "]" << endl;
}
cout << " Connection: " << address << endl;
}
void
NetworkManager::publishMessage(MESSAGE msgToSend)
{
// Get the size of the message to be sent
int sizeOfMessageToSend = MSG_MAX_SIZE;//sizeof(msgToSend);
// Copy IDVS message to buffer
char buffToSend[MSG_MAX_SIZE] = "";
// Pack the message id
size_t indexOfId = MSG_ID_SIZE + 1;
size_t indexOfName = MSG_NAME_SIZE + 1;
size_t indexOfdata = MSG_DATABUFFER_SIZE + 1;
memcpy(buffToSend, msgToSend.get_msg_id(), indexOfId - 1);
// Pack the message name
memcpy(buffToSend + indexOfId, msgToSend.get_msg_name(), indexOfName - 1);
// Pack the data buffer
memcpy(buffToSend + indexOfId + indexOfName, msgToSend.get_msg_data(), indexOfdata - 1);
// Send message
int sizeOfSentMessage = zmq_send(globalPublisher, buffToSend, MSG_MAX_SIZE, ZMQ_DONTWAIT);
getSubscriptionConnectionError();
// If message size doesn't match, we have an issue, otherwise, we are good
if (sizeOfSentMessage != sizeOfMessageToSend)
{
int errorCode = zmq_errno();
cerr << "FATAL: couldn't not send message." << endl;
cerr << "ERROR: " << errorCode << endl;
}
}
I can include more of this side's code if you think it's needed, but the error is popping up on the Ubuntu side, so I'm going to focus there.
The problem is when I call zmq_recv it returns -1 and when I check zmq_errno I get EAGAIN (Non-blocking mode was requested and no messages are available at the moment.) I also checked with netstat and I didn't see anything on port 5556
First is the function to connect to the publisher, then the function to get data, followed by main.
Ubuntu side code:
void
*connectoToPublisher()
{
void *context = zmq_ctx_new();
void *subscriber = zmq_socket(context, ZMQ_SUB);
string protocol = "tcp://";
string ipAddress = PUB_IP; //10.10.10.15
string portNumber = PUB_PORT; // 5556
string address = protocol + ipAddress + ":" + portNumber;
cout << "Address: " << address << endl;
char *address_ptr = new char[address.size() + 1];
strcpy(address_ptr, address.c_str());
// ------ Connect to Publisher ------
bool isConnectionEstablished = false;
int connectionStatus;
while (isConnectionEstablished == false)
{
connectionStatus = zmq_connect(subscriber, address_ptr);
switch (connectionStatus)
{
case 0: //we are good.
cout << "Connection Established!" << endl;
isConnectionEstablished = true;
break;
case -1:
isConnectionEstablished = false;
cout << "Connection Failed!" << endl;
getSubscriptionConnectionError();
cout << "Trying again in 5 seconds..." << endl;
break;
default:
cout << "Hit default connecting to publisher!" << endl;
break;
}
if (isConnectionEstablished == true)
{
break;
}
sleep(5); // Try again
}
// by the time we get here we should have connected to the pub
return subscriber;
}
static void *
getData(void *subscriber)
{
const char *filter = ""; // Get all messages
int subFilterResult = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, filter, strlen(filter));
// ------ Get in main loop ------
while (1)
{
//get messages from publisher
char bufferReceived[MSG_MAX_SIZE] = "";
size_t expected_messageSize = sizeof(bufferReceived);
int actual_messageSize = zmq_recv(subscriber, bufferReceived, MSG_MAX_SIZE, ZMQ_DONTWAIT);
if (expected_messageSize == actual_messageSize)
{
MESSAGE msg = getMessage(bufferReceived); //Uses memcpy to copy id, name, and data strutct data from buffer into struct of MESSAGE
if (strcmp(msg.get_msg_id(), "IDXY_00000") == 0)
{
DATA = getData(msg); //Uses memcpy to copy data from buffer into struct of DATA
}
} else
{
// Something went wrong
getReceivedError(); //This just calls zmq_errno and cout the error
}
usleep(1);
}
}
int main (int argc, char*argv[])
{
//Doing some stuff...
void *subscriber_socket = connectoToHeadTrackerPublisher();
// Initialize Mux Lock
pthread_mutex_init(&receiverMutex, NULL);
// Initializing some variables...
// Launch Thread to get updates from windows machine
pthread_t publisherThread;
pthread_create(&publisherThread,
NULL, getData, subscriber_socket);
// UI stuff
zmq_close(subscriber_socket);
return 0;
}
If you cannot provide a solution, then I will accept identifying the problem as a solution. My main issue is that I don't have the knowledge or experience with messaging or networking to correctly identify the issue. Typically if I know what is wrong, I can fix it.
Ok, this has nothing to do with signalling / messaging framework
Your Ubuntu code instructs the ZeroMQ Context()-instance engine to create a new SUB-socket instance and next the code insist this socket to try to _connect() ( to setup a tcp:// transport-class connection towards the peering counterparty ) to "opposite" access-point, sitting on an address of the Ubuntu localhost:port# that was setup as 10.10.10.15:5556, while the intended PUB-side archetype access-point actually lives not on this Ubuntu machine, but on another, Windows host, IP:port# of which is 10.10.10.200:5556
This seems to be the root-cause of the problem, so change it accordingly to match the physical layout and you may get the toys work.

Timeout for dropped packets (UDP)

I'm trying to create a timeout using select() for UDP socket transfer. I want to send an int from client to server, wait 300ms, and if I don't get an ACK, resend the packet. I'm not sure how to set this up properly with the timeout. From what I've gathered online and on the notes I have from class, select should be used on the receiving end.
the client at the server send back and forth the numbers 1-100. I have a separate router simulated code that randomly drops packets
Here is the code i have for the client side
int sent = 1;
int received = 1;
for (int i = 0; i < 100; i++)
{
string sent1 = to_string(sent);
char const *pchar = sent1.c_str();
if(!sendto(s, pchar, sizeof(pchar), 0, (struct sockaddr*) &sa_in, sizeof(sa_in)))
cout << "send NOT successful\n";
else
{
cout << "Client sent " << sent << endl;
sent++;
}
// receive
fd_set readfds; //fd_set is a type
FD_ZERO(&readfds); //initialize
FD_SET(s, &readfds); //put the socket in the set
if(!(outfds = select (1 , &readfds, NULL, NULL, & timeouts)))
break;
if (outfds == 1) //receive frame
{
if (!recvfrom(s, buffer2, sizeof(buffer2), 0, (struct sockaddr*) &client, &client_length))
cout << "receive NOT successful\n";
else
{
received = atoi(buffer2);
cout << "Client received " << received << endl;
received++;
}
}
}
The code is identical for the receiving side except it is in reverse: receive first, then send
My code doesn't utilize the timeout at all. This is basically what I want to do:
send packet(N)
if (timeout)
resend packet(N)
else
send packet(N+1)
If the receiver gets a timeout it needs to tell the sender, or else not tell the sender. In other words you have to implement either a NACK-based protocol or an ACK-based protocol.

"Connection was broken" error with UDT (UDP-based data transfer protocol)

I am programming a real-time game in which I need reliable UDP, so I've chosen to work with UDT (UDP-based data transfer protocol - http://sourceforge.net/projects/udt/).
The clients (on browsers) send real-time messages to my server via CGI scripts. The problem is that there are some messages that are being lost, and I don't know why because the server says that it sent all the messages successfully to the corresponding clients, but sometimes the client doesn't receive the message.
In my debug file, I've found that when a message is not received by the client, its script says:
error in recv();
recv: Connection was broken.
I would like to get some help on how the server shall know if the client got its message; should I send a NACK or something from the client side? I thought that UDT should do that for me. Can someone clarify this situation?
The relevant sections of the communication parts of my code are bellow, with some comments:
server's relevant code:
//...
void send_msg_in(player cur, char* xml){
/*this function stores the current message, xml, in a queue if xml!=NULL, and sends the 1st message of the queue to the client*/
/*this function is called when the player connects with the entering xml=NULL to get the 1st message of the queue,
or with xml!=NULL when a new message arrives: in this case the message is stored in the queue, and then the message will be sent in the appropriate time, i.e. the messages are ordered.*/
char* msg_ptr=NULL;
if (xml!=NULL){ //add the message to a queue (FIFO), the cur.xml_msgs
msg_ptr=(char*) calloc(strlen(xml)+1, sizeof(char));
strcpy(msg_ptr, xml);
(*(cur.xml_msgs)).push(msg_ptr);
} //get the 1st message of the queue
if (!(*(cur.xml_msgs)).empty()){
xml=(*(cur.xml_msgs)).front();
}
if (cur.get_udt_socket_in()!=NULL){
UDTSOCKET cur_udt = *(cur.get_udt_socket_in());
// cout << "send_msg_in(), cur_udt: " << cur_udt << endl;
//send the "xml", i.e. the 1st message of the queue...
if (UDT::ERROR == UDT::send(cur_udt, xml, strlen(xml)+1, 0)){
UDT::close(cur_udt);
cur.set_udt_socket_in(NULL);
}
else{ //if no error this else is reached
cout << "TO client:\n" << xml << "\n"; /*if there is no error,
i.e. on success, the server prints the message that was sent.*/
// / \
// /_!_\
/*the problem is that
the messages that are lost don't appear on the client side,
but they appear here on the server! */
if (((string) xml).find("<ack.>")==string::npos){
UDT::close(cur_udt);
cur.set_udt_socket_in(NULL); //close the socket
}
(*(cur.xml_msgs)).pop();
}
}
}
//...
client's relevant code:
//...
#define MSGBUFSIZE 1024
char msgbuf[MSGBUFSIZE];
UDTSOCKET client;
ofstream myfile;
//...
main(int argc, char *argv[]){
//...
// connect to the server, implict bind
if (UDT::ERROR == UDT::connect(client, (sockaddr*)&serv_addr, sizeof(serv_addr))){
cout << "error in connect();" << endl;
return 0;
}
myfile.open("./log.txt", ios::app);
send(xml);
char* cur_xml;
do{
cur_xml = receive(); //wait for an ACK or a new message...
myfile << cur_xml << endl << endl; // / \
/* /_!_\ the lost messages don't appear on the website
neither on this log file.*/
} while (((string) cur_xml).find("<ack.>")!=string::npos);
cout << cur_xml << endl;
myfile.close();
UDT::close(client);
return 0;
}
char* receive(){
if (UDT::ERROR == UDT::recv(client, msgbuf, MSGBUFSIZE, 0)){
// / \
/* /_!_\ when a message is not well received
this code is usually reached, and an error is printed.*/
cout << "error in recv();" << endl;
myfile << "error in recv();" << endl;
myfile << "recv: " << UDT::getlasterror().getErrorMessage() << endl << endl;
return 0;
}
return msgbuf;
}
void* send(string xml){
if (UDT::ERROR == UDT::send(client, xml.c_str(), strlen(xml.c_str())+1, 0)){
cout << "error in send();" << endl;
myfile << "error in send();" << endl;
myfile << "send: " << UDT::getlasterror().getErrorMessage() << endl << endl;
return 0;
}
}
Thank you for any help!
PS. I tried to increase the linger time on close(), after finding the link http://udt.sourceforge.net/udt4/doc/opt.htm, adding the following to the server's code:
struct linger l;
l.l_onoff = 1;
l.l_linger = ...; //a huge value in seconds...
UDT::setsockopt(*udt_socket_ptr, 0, UDT_LINGER, &l, sizeof(l));
but the problem is still the same...
PPS. the other parts of the communication in the server side are: (note: it seams for me that they are not so relevant)
main(int argc, char *argv[]){
char msgbuf[MSGBUFSIZE];
UDTSOCKET serv = UDT::socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', sizeof(my_addr.sin_zero));
if (UDT::ERROR == UDT::bind(serv, (sockaddr*)&my_addr, sizeof(my_addr))){
cout << "error in bind();";
return 0;
}
UDT::listen(serv, 1);
int namelen;
sockaddr_in their_addr;
while (true){
UDTSOCKET recver = UDT::accept(serv, (sockaddr*)&their_addr, &namelen);
if (UDT::ERROR == UDT::recv(recver, msgbuf, MSGBUFSIZE, 0)){
//this recv() function is called only once for each aqccept(), because the clients call CGI scripts via a browser, they need to call a new CGI script with a new UDT socket for each request (this in in agreement to the clients' code presented before).
cout << "error in recv();" << endl;
}
char* player_xml = (char*) &msgbuf;
cur_result = process_request((char*) &msgbuf, &recver, verbose); //ACK
}
}
struct result process_request(char* xml, UDTSOCKET* udt_socket_ptr, bool verbose){
//parse the XML...
//...
player* cur_ptr = get_player(me); //searches in a vector of player, according to the string "me" of the XML parsing.
UDTSOCKET* udt_ptr = (UDTSOCKET*) calloc(1, sizeof(UDTSOCKET));
memcpy(udt_ptr, udt_socket_ptr, sizeof(UDTSOCKET));
if (cur_ptr==NULL){
//register the player:
player* this_player = (player*) calloc(1, sizeof(player));
//...
}
}
else if (strcmp(request_type.c_str(), "info_waitformsg")==0){
if (udt_ptr!=NULL){
cur_ptr->set_udt_socket_in(udt_ptr);
if (!(*(cur_ptr->xml_msgs)).empty()){
send_msg_in(*cur_ptr, NULL, true);
}
}
}
else{ //messages that get instant response from the server.
if (udt_ptr!=NULL){
cur_ptr->set_udt_socket_out(udt_ptr);
}
if (strcmp(request_type.c_str(), "info_chat")==0){
info_chat cur_info;
to_object(&cur_info, me, request_type, msg_ptr); //convert the XML string values to a struct
process_chat_msg(cur_info, xml);
}
/* else if (...){ //other types of messages...
}*/
}
}
void process_chat_msg(info_chat cur_info, char* xml_in){
player* player_ptr=get_player(cur_info.me);
if (player_ptr){
int i=search_in_matches(matches, cur_info.match_ID);
if (i>=0){
match* cur_match=matches[i];
vector<player*> players_in = cur_match->followers;
int n=players_in.size();
for (int i=0; i<n; i++){
if (players_in[i]!=msg_owner){
send_msg_in(*(players_in[i]), xml, flag);
}
}
}
}
}
Looking at the UDT source code at http://sourceforge.net/p/udt/git/ci/master/tree/udt4/src/core.cpp, the error message "Connection was broken" is produced when either of the Boolean flags m_bBroken or m_bClosing is true and there is no data in the receive buffer.
Those flags are set in just a few cases:
In sections of code marked "should not happen; attack or bug" (unlikely)
In deliberate close or shutdown actions (don't see this happening in your code)
In expiration of a timer that checks for peer activity (the likely culprit)
In that source file at line 2593 it says:
// Connection is broken.
// UDT does not signal any information about this instead of to stop quietly.
// Application will detect this when it calls any UDT methods next time.
//
m_bClosing = true;
m_bBroken = true;
// ...[code omitted]...
// app can call any UDT API to learn the connection_broken error
Looking at the send() call, I don't see anywhere that it waits for an ACK or NAK from the peer before returning, so I don't think a successful return from send() on the server side is indicative of successful receipt of the message by the client.
You didn't show the code on the server side that binds to the socket and listens for responses from the client; if the problem is there then the server might be happily sending messages and never listening to the client that is trying to respond.
UDP is not a guaranteed-transmission protocol. A host will send a message, but if the recipient does not receive it, or if it is not received properly, no error will be raised. Therefore, it is commonly used in applications that require speed over perfect delivery, such as games. TCP does guarantee delivery, because it requires that a connection be set up first, and each message is acknowledged by the client.
I would encourage you to think about whether you actually need guaranteed receipt of that data, and, if you do, consider using TCP.

SFML TCP packet receive

I send a packet as client to server and I want to the server sends that packet forward to all client, here is the code:
#include <iostream>
#include <SFML/Network.hpp>
using namespace std;
int main()
{
int fromID; // receive data from 'fromID'
int Message; // fromID's message
sf::SocketTCP Listener;
if (!Listener.Listen(4567))
return 1;
// Create a selector for handling several sockets (the listener + the socket associated to each client)
sf::SelectorTCP Selector;
Selector.Add(Listener);
while (true)
{
unsigned int NbSockets = Selector.Wait();
for (unsigned int i = 0; i < NbSockets; ++i)
{
// Get the current socket
sf::SocketTCP Socket = Selector.GetSocketReady(i);
if (Socket == Listener)
{
// If the listening socket is ready, it means that we can accept a new connection
sf::IPAddress Address;
sf::SocketTCP Client;
Listener.Accept(Client, &Address);
cout << "Client connected ! (" << Address << ")" << endl;
// Add it to the selector
Selector.Add(Client);
}
else
{
// Else, it is a client socket so we can read the data he sent
sf::Packet Packet;
if (Socket.Receive(Packet) == sf::Socket::Done)
{
// Extract the message and display it
Packet >> Message;
Packet >> fromID;
cout << Message << " From: " << fromID << endl;
//send the message to all clients
for(unsigned int j = 0; j < NbSockets; ++j)
{
sf::SocketTCP Socket2 = Selector.GetSocketReady(j);
sf::Packet SendPacket;
SendPacket << Message;
if(Socket2.Send(SendPacket) != sf::Socket::Done)
cout << "Error sending message to all clients" << endl;
}
}
else
{
// Error : we'd better remove the socket from the selector
Selector.Remove(Socket);
}
}
}
}
return 0;
}
Client code:
in Player class I have this function :
void Player::ReceiveData()
{
int mess;
sf::Packet Packet;
if(Client.Receive(Packet) == sf::Socket::Done)
{
Client.Receive(Packet);
Packet >> mess;
cout << mess << endl;
}
}
main.cpp:
Player player;
player.Initialize();
player.LoadContent();
player.Connect();
..
..
//GAME LOOP
while(running==true)
{
sf::Event Event;
while(..) // EVENT LOOP
{
...
}
player.Update(Window);
player.ReceiveData();
player.Draw(Window);
}
When I run this client code, the program not responding, freezes.
The problem is with that ReceiveDate() function.
All sockets, even the one created by SFML, are by default blocking. This means that when you try to receive when there is nothing to receive, the call will block, making your application seem "freezed".
You can toggle the blocking status of a SFML socket with the sf::SocketTCP::SetBlocking function.
The problem with sending to all clients failing is because you use GetSocketReady to get the clients to send to. That function only returns a socket for clients that are ready (i.e. the previous call to Wait marked the socket as having input).
You need to refactor the server to keep track of the connected clients in another way. The common way is to reset and recreate the selector every time in the outer loop, and have a separate collection of the connected clients (e.g. a std::vector).

How to access same socket on multiple threads for multi-threaded client

I have a multi-threaded client that's set up in order to receive messages on one thread from the server, while the other thread waits for user input in order to send a message to the server.
I am new to this, and what my code currently does is: both threads would individually connect to server, which made the server recognise the single client as two clients (since both threads connected to server individually). How do I fix this so that the receive and send connections would utilise the same connection?
I have included the relevant portion of my client code (connecting to server is through the function connectToServer)
/*thread for sending messages to server*/
DWORD WINAPI send_handle_thread(LPVOID threadInfo)
{
/*structure contains all the data this callback works on*/
myThreadArgument* send_argument = (myThreadArgument*)threadInfo;
/*get client connection*/
myTcpSocket my_client(PORTNUM);
string server_ip_address = "";
readServerConfig(server_ip_address);
my_client.connectToServer(server_ip_address, ADDRESS); //this is where the thread connects to server
while (1)
{
/*send messages*/
}
return 1;
}
/*thread for receiving messages from server*/
DWORD WINAPI rec_handle_thread(LPVOID threadInfo)
{
/*structure contains all the data this callback works on*/
myThreadArgument* send_argument = (myThreadArgument*)threadInfo;
/*get client connection*/
myTcpSocket my_client(PORTNUM);
string server_ip_address = "";
readServerConfig(server_ip_address);
my_client.connectToServer(server_ip_address, ADDRESS); //this is where thread connects to server
int rec_bytes = 0;
while (1)
{
/*receive messages*/
}
return 1;
}
int main()
{
/*build a semaphore to synchronise access to std::cout*/
mySemaphore cout_semaphore(string(""),1);
/*initialize the winsock library*/
myTcpSocket::initialize();
/*get local (client) information (assume neither the name nor the address is given)*/
myHostInfo client_info;
string client_name = client_info.getHostName();
string client_ip_address = client_info.getHostIPAddress();
cout << "local host (client) information: " << endl;
cout << " name: " << client_name << endl;
cout << " address: " << client_ip_address << endl << endl;
/*retrieve server's IP name and address*/
string server_ip_address = "";
readServerConfig(server_ip_address);
myHostInfo server_info(server_ip_address, ADDRESS);
string server_name = server_info.getHostName();
cout << "remote host (server) information: " << endl;
cout << " name: " << server_name << endl;
cout << " address: " << server_ip_address << endl;
/*retrieve client's IP name and address*/
myTcpSocket my_client(PORTNUM);
cout << my_client;
/*create thread to send messages to server*/
myThreadArgument* send_argument = new myThreadArgument(&my_client, &cout_semaphore, client_name);
myThread* send_thread = new myThread(send_handle_thread, (void*)send_argument);
send_thread->execute();
/*create thread to receive message from server*/
myThreadArgument* rec_argument = new myThreadArgument(&my_client, &cout_semaphore, client_name);
myThread* rec_thread = new myThread(rec_handle_thread, (void*)rec_argument);
rec_thread->execute();
while (1)
{
Sleep(300);
cout << "main thread";
}
return 1;
}
connectToServer code:
void myTcpSocket::connectToServer(string& serverNameOrAddr,hostType hType)
{
/*
when this method is called, a client socket has been built already,
so we have the socketId and portNumber ready.
a myHostInfo instance is created, no matter how the server's name is
given (such as www.yuchen.net) or the server's address is given (such
as 169.56.32.35), we can use this myHostInfo instance to get the
IP address of the server
*/
myHostInfo serverInfo(serverNameOrAddr,hType);
// Store the IP address and socket port number
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(serverInfo.getHostIPAddress());
serverAddress.sin_port = htons(portNumber);
// Connect to the given address
try
{
if (connect(socketId,(struct sockaddr *)&serverAddress,sizeof(serverAddress)) == -1)
{
#ifdef WINDOWS_7 //XP
int errorCode = 0;
string errorMsg = "error calling connect():\n";
detectErrorConnect(&errorCode,errorMsg);
myException socketConnectException(errorCode,errorMsg);
throw socketConnectException;
#endif
#ifdef UNIX
myException unixSocketConnectException(0,"unix: error calling connect()");
throw unixSocketConnectException;
#endif
}
}
catch(myException& excp)
{
excp.response();
exit(1);
}
}
Just use the same socket FD in both places. You don't even have to synchronize when using it.