Thomas Thomas - 2 months ago 13
C++ Question

socket: multithreading doesn't work when client reads messages

I have a server, which can accept two socket connections. It creates a thread for each socket so that messages can be sent parallel.


Now I'm trying to code my client.


I create a class named

SocketThread
as a thread of socket. Here is the main code:


void SocketThread::ReadData()
{
int n = 0;
while (!finished)
{
while ((n = read(sockfd, recvBuff, sizeof(Data))) > 0)
{
std::cout<<std::this_thread::get_id()<<std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
}
}

std::thread SocketThread::run()
{
return std::thread([=] { ReadData(); });
}


in the function
main
:


SocketThread s0("127.0.0.1", 10000);
SocketThread s1("127.0.0.1", 10000);
std::thread td0{sts[0].run()};
std::thread td1{sts[1].run()};
td0.join(); // stop here
td1.join();
// something else


When I execute the program, it will block at
td0.join();
, meaning that I can get the id of the thread
td0
on the console and I can NEVER get the other thread.


However, when I remove
(n = read(sockfd, recvBuff, sizeof(Data))) > 0
, which means that now the client is just a simple thread, that it won't receive anything, things gonna be fine ---- I can get two ids of the two threads.

Why?

EDIT
It seems that I used
join
incorrectly.

What I need is that
main
doesn't execute
//something else
until the two threads get 1000 characters together.

What should I do?

Answer

You did not use join() incorrectly. If you want main() to block until both threads end, your code is correct : td0.join() will block until thread td0 ends, and the same for td1.

Now, if you want your threads to end after receiving sizeof(Data) bytes, your function void SocketThread::ReadData() should rather look like this :

void SocketThread::ReadData()
{
    int n, total = 0;
    while (!finished)
    {
        while ((n = read(sockfd, &recvBuff[total], sizeof(Data) - total)) > 0)
        {
            total += n;
        }
        if (n == -1)
        {
            // manage error here
        }
        if (n == 0)
        {
            std::cout << "client shut the socket down; got " << total << " bytes over " << sizeof(Data) << std::endl;
            finished = true;
        }
    }
}

For a short explanation : there is no guarantee that you can get all data sent by client in a single read() operation, so you need to call read() and cumulate data into the buffer until you get a return value of 0 (meaning the client shut down the socket). read(sockfd, &recvBuff[total], sizeof(Data) - total) ensures that the incomming data is properly appended at the right position in the buffer.