I have studied Java for 8 months but decided to learn some c++ to on my spare time.
I'm currently making a multithreaded server in QT with minGW. My problem is that when a client connects, I create an instance of Client( which is a class) and pass the socket in the client class contructor.
And then I start a thread in the client object (startClient()) which is going to wait for messages, but it doesn't. Btw, startClient is a method that I create a thread from. See code below.
What happens then? Yes, when I try to send messages to the server, only errors, the server won't print out that a new client connects, and for some reason my computer starts working really hard. And qtcreator gets super slow until I close the server-program.
What I actually is trying to achieve is an object which derives the thread, but I have heard that it isn't a very good idea to do so in C++.
The listener loop in the server:
for (;;)
{
if ((sock_CONNECTION = accept(sock_LISTEN, (SOCKADDR*)&ADDRESS, &AddressSize)))
{
cout << "\nClient connected" << endl;
Client client(sock_CONNECTION); // new object and pass the socket
std::thread t1(&Client::startClient, client); //create thread of the method
t1.detach();
}
}
the Client class:
Client::Client(SOCKET socket)
{
this->socket = socket;
cout << "hello from clientconstructor ! " << endl;
}
void Client::startClient()
{
cout << "hello from clientmethod ! " << endl;
// WHEN I ADD THE CODE BELOW I DON'T GET ANY OUTPUT ON THE CONSOLE!
// No messages gets received either.
char RecvdData[100] = "";
int ret;
for(;;)
{
try
{
ret = recv(socket,RecvdData,sizeof(RecvdData),0);
cout << RecvdData << endl;
}
catch (int e)
{
cout << "Error sending message to client" << endl;
}
}
}
It looks like your Client object is going out of scope after you detach it.
if (/* ... */)
{
Client client(sock_CONNECTION);
std::thread t1(&Client::startClient, client);
t1.detach();
} // GOING OUT OF SCOPE HERE
You'll need to create a pointer of your client object and manage it, or define it at a higher level where it won't go out of scope.
The fact that you never see any output from the Server likely means that your client is unable to connect to your Server in the first place. Check that you are doing your IP addressing correctly in your connect calls. If that looks good, then maybe there is a firewall blocking the connection. Turn that off or open the necessary ports.
Your connecting client is likely getting an error from connect that it is interpreting as success and then trying to send lots of traffic on an invalid socket as fast as it can, which is why your machine seems to be working hard.
You definitely need to check the return values from accept, connect, read and write more carefully. Also, make sure that you aren't running your Server's accept socket in non-blocking mode. I don't think that you are because you aren't seeing any output, but if you did it would infinitely loop on error spawning tons of threads that would also infinitely loop on errors and likely bring your machine to its knees.
If I misunderstood what is happening and you do actually get a client connection and have "Client connected" and "hello from client method ! " output, then it is highly likely that your calls to recv() are failing and you are ignoring the failure. So, you are in a tight infinite loop that is repeatedly outputting "" as fast as possible.
You also probably want to change your catch block to catch (...) rather than int. I doubt either recv() or cout throw an int. Even so, that catch block won't be invoked when recv fails because recv doesn't throw any exceptions AFAIK. It returns its failure indicator through its return value.
Related
[TL;DR version: the code below hangs indefinitely on the second recv() call both in Release and Debug mode. In Debug, if I place or remove a breakpoint anywhere in the code, it makes the execution continue and everything behaves normally]
I'm coding a simple client-server communication using UNIX sockets. The server is in C++ while the client is in python. The connection (TCP socket on localhost) gets established no problem, but when it comes to receiving data on the server side, it hangs on the recv function. Here is the code where the problem happens:
bool server::readBody(int csock) // csock is the socket filedescriptor
{
int bytecount;
// protobuf-related variables
google::protobuf::uint32 siz;
kinMsg::request message;
// if the code is working, client will send false
// I initialize at true to be sure that the message is actually read
message.set_endconnection(true);
// First, read 4-characters header for extracting data size
char buffer_hdr[5];
if((bytecount = recv(csock, buffer_hdr, 4, MSG_WAITALL))== -1)
::std::cerr << "Error receiving data "<< ::std::endl;
buffer_hdr[4] = '\0';
siz = atoi(buffer_hdr);
// Second, read the data. The code hangs here !!
char buffer [siz];
if((bytecount = recv(csock, (void *)buffer, siz, MSG_WAITALL))== -1)
::std::cerr << "Error receiving data " << errno << ::std::endl;
//Finally, process the protobuf message
google::protobuf::io::ArrayInputStream ais(buffer,siz);
google::protobuf::io::CodedInputStream coded_input(&ais);
google::protobuf::io::CodedInputStream::Limit msgLimit = coded_input.PushLimit(siz);
message.ParseFromCodedStream(&coded_input);
coded_input.PopLimit(msgLimit);
if (message.has_endconnection())
return !message.endconnection();
return false;
}
As can be seen in the code, the protocol is such that the client will first send the number of bytes in the message in a 4-character array, followed by the protobuf message itself. The first recv call works well and does not hang. Then, the code hangs on the second recv call, which should be recovering the body of the message.
Now, for the interesting part. When run in Release mode, the code hangs indefinitely and I have to kill either the client or the server. It does not matter whether I run it from my IDE (qtcreator), or from the CLI after a clean build (using cmake/g++).
When I run the code in Debug mode, it also hangs at the same recv() call. Then, if I place or remove a breakpoint ANYWHERE in the code (before or after that line of code), it starts again and works perfectly : the server receives the data, and reads the correct message.endconnection() value before returning out of the readBody function. The breakpoint that I have to place to trigger this behavior is not necessarily trigerred. Since the readBody() function is in a loop (my C++ server waits for requests from the python client), at the next iteration, the same behavior happens again, and I have to place or remove a breakpoint anywhere in the code, which is not necessarily triggered, in order to go past that recv() call. The loop looks like this:
bool connection = true;
// server waiting for client connection
if (!waitForConnection(connectionID)) std::cerr << "Error accepting connection" << ::std::endl;
// main loop
while(connection)
{
if((bytecount = recv(connectionID, buffer, 4, MSG_PEEK))== -1)
{
::std::cerr << "Error receiving data "<< ::std::endl;
}
else if (bytecount == 0)
break;
try
{
if(readBody(connectionID))
{
sendResponse(connectionID);
}
// if client is requesting disconnection, break the while(true)
else
{
std::cout << "Disconnection requested by client. Exiting ..." << std::endl;
connection = false;
}
}
catch(...)
{
std::cerr << "Erro receiving message from client" << std::endl;
}
}
Finally, as you can see, when the program returns from readBody(), it sends back another message to the client, which processes it and prints in the standard output (python code working, not shown because the question is already long enough). From this last behavior, I can conclude that the protocol and client code are OK. I tried to put sleep instructions at many points to see whether it was a timing problem, but it did not change anything.
I searched all over Google and SO for a similar problem, but did not find anything. Help would be much appreciated !
The solution is to not use any flags. Call recv with 0 for the flags or just use read instead of recv.
You are requesting the socket for data that is not there. The recv expects 10 bytes, but the client only sent 6. The MSG_WAITALL states clearly that the call should block until 10 bytes are available in the stream.
If you dont use any flags, the call will succeed with a bytecount at 6, which is the exact same effect than with MSG_DONTWAIT, without the potential side effects of non-blocking calls.
I did the test on the github project, it works.
The solution is to replace MSG_WAITALL by MSG_DONTWAIT in the recv() calls. It now works fine. To summarize, it makes the recv() calls non blocking, which makes the whole code work fine.
However, this still raises many questions, the first of which being: why was it working with this weird breakpoint changing thing ?
If the socket was blocking in the first place, one could assume that it is because there is no data on the socket. Let's assume both situations here :
There is no data on the socket, which is the reason why the blocking recv() call was not working. Changing it to a non blocking recv() call would then, in the same situation, trigger an error. If not, the protobuf deserialization would afterwards fail trying to deserialize from an empty buffer. But it does not ...
There is data on the socket. Then, why on earth would it block in the first place ?
Obviously there is something that I don't get about sockets in C, and I'd be very happy if somebody has an explanation for this behavior !
I wrote a chess client/server mobile application and have a remote server that has been tested on the West Coast, the East Coast, in between, etc. The program is this in a nutshell:
1. Log in to remote server with correct username/password via iOS/Android or Windows desktop.
2. Enter queue for a 1-minute, 5-minute or 30-minute game of chess.
3. Wait for another opponent to join queue.
4. Get matched and play game of chess.
5. When game is over, log out or play more chess.
I am getting the weirdest freaking error when I log in to the server via my school's internet, however. This is so weird because it the ONLY ISP that has problems out of the many ISP's I have connected from.
When I log into the server through my school's internet, I will get the following error and errorString from my socket.
QAbstractSocket::UnknownSocketError "Unknown error"
The steps to produce this in my application are:
1. Enter username and password, log into server. (Successfully completes this).
2. Click to join a queue for a game of chess. (Successfully writes to socket, but fails to wait for bytes written then emits the above error and error string.
I checked the server and readyRead() is not even called, so I know the client is not sending anything to the server.
The funny thing is, I found a workaround for getting past this error.
1. Click on Settings page.
2. Click Save. (Does the exact same thing as I try to do above. Write to socket, flush and wait for bytes written).
3. Join queue (Successfully joins queue).
The workaround MAKES NO SENSE since it does not do anything differently than what I tried to do above (write to socket, flush and wait for bytes written).
Does anyone have a clue on what might be going on?
Why is this error specific to ONE internet location? My school internet is slow as hell, but doesn't explain why the socket is disconnected immediately in the function below.
Why does my workaround work?
What can I do to learn more about my problem (i.e. stupid error message..."unknown error").
Not only this, but when I right-click on the function below, then click 'Find usages', the build folder appears. This is the only function in the program that does this. WTF???
Socket disconnects in this function.
void CG_serverConnection::sendQueueType(int timeControl)
{
//Create local JSON object
QJsonObject userInfo;
//Create object
userInfo["PacketHeader"] = QUEUE_REQUEST;
userInfo["TimeControl"] = timeControl;
//Create JSON document
QJsonDocument doc;
doc.setObject(userInfo);
qDebug() << "Send queue type called! ";
qDebug() << doc.toJson();
QByteArray byteArray = doc.toBinaryData();
//Send over socket
if(m_socket->write(byteArray))
{
qDebug() << "Wrote to socket";
}
else
m_socket->errorString();
if(m_socket->flush())
{
qDebug() << "Flushed";
}
else
qDebug() << m_socket->errorString();
if(m_socket->waitForBytesWritten(50000))
{
qDebug() << "Bytes were written.";
}
else
{
qDebug() << m_socket->error();
qDebug() << m_socket->errorString();
}
}
Where I call the function
Button
{
id: btn_oneMinuteGame
text: "One Minute"
style: cgButtonStyle
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: Lobby.getControlWidth()
Layout.preferredHeight: Lobby.getControlHeight()
onClicked:
{
ServerConnection.sendQueueType(1) // TODO : Magic numbers
root.startOneMinuteGame()
}
}
For some reason if I call this at the top of my function, everything works...
Makes no sense. If someone can explain why this works or you have another solution, please post it.
//Temporary bug fix
this->sendUpdatedUserInfo();
Function I call that somehow makes everything work
void CG_serverConnection::sendUpdatedUserInfo()
{
QJsonObject request;
request["PacketHeader"] = UPDATE_INFO;
request["loggedIn"] = m_player.loggedIn;
request["banned"] = m_player.banned;
request["username"] = m_player.username;
request["elo"] = m_player.elo;
request["countryFlag"] = m_player.countryFlag;
request["pieceSet"] = m_player.pieceSet;
request["language"] = m_player.language;
request["sound"] = m_player.sound;
request["coordinates"] = m_player.coordinates;
request["arrows"] = m_player.arrows;
request["autoPromote"] = m_player.autoPromote;
request["boardTheme"] = m_player.boardTheme;
QJsonDocument doc;
doc.setObject(request);
qDebug() << "Updated userInfo being sent: ";
qDebug() << doc.toJson();
m_socket->write(doc.toBinaryData());
m_socket->flush();
m_socket->waitForBytesWritten();
}
I am trying to connect to a computer through a socket in c++. Basically what this code should do is try to connect, and if it cant connect, it should wait 3 seconds and try again.
while (true) {
if (connect(sock, (struct sockaddr *) &echoserver, sizeof(echoserver)) >= 0)
{
break;
}
cout << "Connection failed!";
sleep(3);
}
What the code does when its running is it will connect if it can, but if it can't, the cout never gets called and sleep never gets called either. When sleep is not there, the program works and continually tries to connect to the socket but there is no delay so it wouldn't connect anyway. I really need the delay to work.
Could anyone please help?
Once the connect fails, the socket refers to the failed connection. You can no longer use it to connect to anything. You need to close the existing socket and allocate a new one. This would have been much easier to diagnose if you had reported the error in the cout statement. (See docs for strerror and errno.)
I'm currently stress testing my server.
sometimes I get "A non-recoverable error occurred during database lookup" Error
coming from error.message()
error is sent to my handling function by boost::asio::placeholders::error called on the async_read method.
I have no idea what this error means, and I am not able to reproduce purposely this error, it only happen sometimes and seems to be random (of course it is not, but it seems)
Does anyone have ever got this error message, and if so, know where it came from ?
EDIT 1
Here's what I found on the boost library, the error is :
no_recovery = BOOST_ASIO_NETDB_ERROR(NO_RECOVERY)
But can't figure out what this is...
EDIT 2
Just so you know everything about my problem, here the design :
I have only one io_service.
Everytime a user is connecting, an async_read is starting, waiting for something to read.
When it reads something, most of the time, it is doing some work on a thread (coming from a pool), and write something synchronously back to the user. (using boost write).
Even since boost 1.37 claims that synchronous write is thread safe, I'm really worried about the fact that it is coming from this.
If the user sends different message really quick, it can happen that async_read and write are called simultaneously, can it does any harm ?
EDIT 3
Here's some portion of my code asked by Dave S :
void TCPConnection::listenForCMD() {
boost::asio::async_read(m_socket,
boost::asio::buffer(m_inbound_data, 3),
boost::asio::transfer_at_least(3),
boost::bind(&TCPConnection::handle_cmd,
shared_from_this(),
boost::asio::placeholders::error)
);
}
void TCPConnection::handle_cmd(const boost::system::error_code& error) {
if (error) {
std::cout << "ERROR READING : " << error.message() << std::endl;
return;
}
std::string str1(m_inbound_data);
std::string str = str1.substr(0,3);
std::cout << "COMMAND FUNCTION: " << str << std::endl;
a_fact func = CommandFactory::getInstance()->getFunction(str);
if (func == NULL) {
std::cout << "command doesn't exist: " << str << std::endl;
return;
}
protocol::in::Command::pointer cmd = func(m_socket, client);
cmd->setCallback(boost::bind(&TCPConnection::command_is_done,
shared_from_this()));
cmd->parse();
}
m_inbound_data is a char[3]
Once cmd->parse() is done, it will call a callback command_is_done
void TCPConnection::command_is_done() {
m_inbound_data[0] = '0';
m_inbound_data[1] = '0';
m_inbound_data[2] = '0';
listenForCMD();
}
The error occurs in the handle_cmd when checking for error at the first line.
As I said before, the cmd->parse() will parse the command it just got, sometime lauching blocking code in a thread coming from a pool. On this thread it sends back data to the client with a synchronous write.
IMPORTANT THING : The callback command_is_done will always be called before the said thread is launched. this means that listenForCMD is already called when the thread may send something back to the client in synchronous write. Therefore my first worries.
When it reads something, most of the time, it is doing some work on a
thread (coming from a pool), and write something synchronously back to
the user. (using boost write). Even since boost 1.37 claims that
synchronous write is thread safe, I'm really worried about the fact
that it is coming from this.
Emphasis added by me, this is incorrect. A single boost::asio::tcp::socket is not thread safe, the documentation is very clear
Thread Safety
Distinct objects: Safe.
Shared objects: Unsafe.
It is also very odd to mix async_read() with a blocking write().
I am using the C++ boost asio library, where I listen to new connections on the socket. On getting a connection I process the request and then listen for a new connection on another socket in a loop.
while (true)
{
tcp::socket soc(this->blitzIOService);
this->blitzAcceptor.listen();
boost::system::error_code ec;
this->blitzAcceptor.accept(soc,ec);
if (ec)
{
// Some error occured
cerr << "Error Value: " << ec.value() << endl;
cerr << "Error Message: " << ec.message() << endl;
soc.close();
break;
}
else
{
this->HandleRequest(soc);
soc.shutdown(tcp::socket::shutdown_both);
soc.close();
}
}
According to my understanding it should always block at this->blitzAcceptor.accept(soc,ec); and everytime a new connection is made it should handle it in this->HandleRequest(soc); and again block at this->blitzAcceptor.accept(soc,ec);
But what I see is this that for the first time it will block at this->blitzAcceptor.accept(soc,ec) and when a new connection is made it will handle the request, but instead of blocking again at this->blitzAcceptor.accept(soc,ec) it will go ahead into this->HandleRequest(soc); and block at soc.receive(); inside.
This doesn't happen always, but happens most of the time. What could be the reason to this behavior, and how can I ensure that it always block at this->blitzAcceptor.accept(soc,ec) until a new request is made?
What could be the reason to this
behavior?
This behavior is entirely dependent on the client code. If it connects, but does not send a request, the server with block when receiving data.
how can I ensure that it always block
at this->blitzAcceptor.accept(soc,ec)
until a new request is made?
You can't. But your server can initiate a timeout that starts immediately after accepting the connection. If the client does not send a request within that duration, close the socket. To do that, you should switch to using asynchronous methods rather than synchronous methods.
Be sure you're not blocking on a read(2) call for the file descriptor that you are listen(2)'ing on vs the file descriptor that you accept(2)'ed. I think if you print out the file descriptor numbers you'll very quickly find your problem.