Linux C / C ++ socket отправляет в многопоточном коде - PullRequest
7 голосов
/ 30 октября 2011

Если в многопоточном коде несколько потоков пытаются одновременно отправить данные в tcp-сокет, что произойдет? будут ли их данные смешаны или разные потоки будут отправлять данные по очереди?

Ответы [ 2 ]

7 голосов
/ 30 октября 2011

Это зависит от того, какие примитивы вы используете для отправки данных в сокет.

Если вы используете write(2), send(2), sendto(2) или sendmsg(2) и размер вашего сообщения достаточно мал, чтобы полностью поместиться в буферах ядра для сокета, тогда вся эта запись будет отправлена ​​как блок без перемежения других данных.

Если вы используете fwrite(3) (или любой другой высокоуровневой буферизованной абстракции ввода-вывода), тогда существует вероятность того, что ваши данные будут отправлены без каких-либо других данных, но я бы не стал полагаться на это поведение.

Я не могу говорить о sendfile(2) поведении.Я хотел бы думать, что операция sendfile(2) «записывает» все содержимое файла в сокет перед любыми другими write(2) запросами к сокету, но прочитанная документация ничего не говорит об этом, так что вам лучше не предполагать, что это в каком-то смысле «атомарное».

Самый безопасный механизм - передача данных в сокет только одному потоку.

0 голосов
/ 17 мая 2017

Действительно, как сказано в предыдущем ответе: «Самый безопасный механизм - передача данных в сокет только одному потоку».

Но если вы хотите, чтобы несколько потоков вызывали чтение / запись, вы должны сами гарантировать безопасность потоков. Я написал обертку вокруг send и recv ниже, которая сделает это за вас.

Send () и Recv () являются потокобезопасными в том смысле, что они не вызывают сбой, но нет гарантии, что данные не будут «смешаны» с данными, отправленными из других потоков. Поскольку мы, скорее всего, этого не хотим, мы должны блокировать, пока все данные потока не будут подтверждены, отправлены или получены, или по ошибке. Такой длительный блокирующий вызов может быть проблематичным, поэтому убедитесь, что вы делаете это в потоках, которые могут обрабатывать длинные блокирующие операции.

Для Linux:

#include <sys/types.h>
#include <sys/socket.h>
#include <map>
#include <mutex>



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

    static std::map<int, std::mutex> mtx;

    std::lock_guard<std::mutex> lock(mtx[sock]);

    int bytes_received = 0;

    while (bytes_received != len){

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

        //error check
        if (bytes == -1){
            throw std::runtime_error("Network Exception");
        }

        bytes_received += bytes;

    } 
}



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

    static std::map<int, std::mutex> mtx;

    std::lock_guard<std::mutex> lock(mtx[sock]);

    int bytes_sent = 0; 

    while (bytes_sent != len){

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

        if (bytes_sent == -1) {
            throw std::runtime_error("Network Exception");
        }

        bytes_sent += bytes_s0;

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...