Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux socket and multi threaded program

I have to write simple client-server application that uses Unix datagram socket. Client may send information to server on the request from the server or he may receive information from server on the request from himself.

I have an idea that one thread will be waiting for user input that determines what request we want to send to the server, and the other thread will just wait for message on the socket from the server, if it is the message we requested it will write it to standard output, if it is the server request thread would write what server requested. I would use mutex so the two threads won't write at the same time to the same socket.

My question is, how the sockets will behave if one thread will read from some socket and at the same time other thread will be sending data using the same socket, is it safe? Or should I use mutex for this situation also?

like image 581
Andna Avatar asked Dec 21 '22 21:12

Andna


2 Answers

Kernel structures are normally built in a thread-safe way; and sockets are no exception. If you should be worried about anything, it isn't the safety of using sockets and threads but the logic of your program.

Also, I'd like to mention that stream sockets are full-duplex, meaning read/write are guaranteed happen simultaneously safely, how can this be happen? Kernel locks for you or makes sure you can do both send and receive at the same time.

For the full-duplex argument:
http://www.kernel.org/doc/man-pages/online/pages/man2/socket.2.html For the kernel structures are thread safe:
I couldn't find you a link to support this, but I am 99% sure about it.

P.S When in doubt, testing the thing might help
EDIT:
Please, if something of what I said is wrong, comment about it before down voting.


EDIT.2 :
Here you can find that ths POSIX standard specifies that all of its functions have to be thread-safe except a list defined in section 2.9.1
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

like image 126
Fingolfin Avatar answered Jan 08 '23 01:01

Fingolfin


In linux and windows, the send() and recv() calls (typically used for TCP but I think may be used with UDP as well) may return early without having sent the full amount of data you wanted to send. This will lead to threading issues as your messages will get split up.

I find it's easiest to just wrap the recv() and send() functions with the following properties:

  • only return after all the data we requested is written to the socket
  • thread safety

and then just use the wrappers in all the places I would have used send/recv.

Here's the code for the wrappers ( feel free to change the error handling):

//linux (must change SOCKET types to int)
//#include <sys/socket.h>

//windows 
//#include <Winsock2.h>
//#include <ws2tcpip.h>

//blocks until the full amount of bytes requested are read
//thread safe
//throws exception on error
void recv_bytes(SOCKET socket, char* buf, int len, int flags){

    static std::mutex mtx;

    mtx.lock();

    int bytes_received = 0;

    while (bytes_received != len){

        int bytes = recv(socket, buf + bytes_received, len - bytes_received, flags);

        //error check
        if (bytes == 0){
            throw std::exception("Network Exception");
        }

        bytes_received += bytes;

    }

    mtx.unlock();

}



//blocks until the full amount of bytes requested are sent
//thread safe
//throws exception on error
void send_bytes(SOCKET socket, char* buf, int len, int flags){

    static std::mutex mtx;

    mtx.lock();

    int bytes_sent = 0; 

    while (bytes_sent != len){

        int bytes_s0 = send(socket, buf, len, flags);

        if (bytes_sent == SOCKET_ERROR) {
            mtx.unlock();
            throw std::exception("Network Exception");
        }

        bytes_sent += bytes_s0;

    }

    mtx.unlock();
}
like image 36
randyrand Avatar answered Jan 08 '23 02:01

randyrand