Задать вопрос
@Vermut756

TCP: правда ли, что send/write нельзя вызывать из разных потоков, иначе перепутается содержимое буферов?

Я строю довольно сложную клиент-серверную систему, поэтому хотелось бы применить многопоточность, скажем на клиенте в одном потоке отправлять heartbeat, а в другом - команду серверу, и при этом использовать только один сокет.
Но нормальное ли это решение?

Для начала поясню, о какой именно путанице я говорю.

Итак, псевдокод то что я отправляю:
send("123456"); // Поток 1
send("ABCDEF");  // Поток 2


Я знаю, что в итоге на принимающую сторону может прийти вот такое:
ABCDEF
123456


То есть я понимаю, что может перепутаться порядок самих сообщений, которые я отправляю.
Когда я попробовал создать много потоков, я наблюдал такое, значит это действительно так.
И я этого не боюсь.

Но один человек на форуме, если я его правильно понял, утверждает, что все еще хуже.
Говорит, что якобы могут перепутаться сами байты в сообщениях, то есть может прийти и такое:
ABC45F
123DE6


Правда ли это?
Когда я пробовал создать много потоков, то этого я НЕ наблюдал, сообщений было много, но ни в одном из них байты не смешивались с байтами из других сообщений.
Но не буду надеяться на авось, вот на всякий случай спрашиваю.

Операционная система:
Windows, разных версий и разрядностей, но только Windows, и на сервере и на клиентах.
  • Вопрос задан
  • 801 просмотр
Подписаться 1 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 4
@sitev_ru
sitev.ru - мой блог ...
Добавь мютексы:

mutex my_mutex;
void my_send() {
	my_mutex.lock();
	// тут отправляем в сокет
	my_mutex.unlock();
}
void my_recv() {
	my_mutex.lock();
	// тут читаем из сокета
	my_mutex.unlock();
}


Эти команды пропиши и на сервере и на клиенте
Ответ написан
@lega
Если используется кеш на уровне ОС, а не на уровне приложения, то все будет ок.
Для надежности и сокращения ошибок, можете сделать 3-й поток под отправку, и уже в него складывать все данные для отправки.
Ответ написан
15432
@15432
Системный программист ^_^
На коротких сообщениях (меньше MTU) такого не будет. Вот если будете в одном из потоков слать несколько килобайт, может возникнуть ситуация, когда части сообщений перемешаются.
Пример:
- поток 1 посылает 10000 байт, send вернул 2048
- поток 2 в это время записывает короткую команду в этот же сокет
- поток 1 досылает оставшиеся байты, но перед ними уже влезла команда из потока 2

Почему бы не добавить мьютексы? Или несколько сокетов?
Ответ написан
Перепутаться содержимое именно в send()/write() не должно, т.к. вывод не буферизирован, функция выполняется за один системный вызов. Но send()/write() в любом случае могут отправить не полный буфер данных, обязательно надо контролировать возвращаемое значение. И доотправлять неотправленное. Поскольку одну команду может быть придется отправлять за несколько операций send()/write() - содержимое в разных потоках может перемешаться. Правда на практике такое (отправка неполного буфера) в Windows мне не встречалось (а вот в POSIX системах это достаточно обычное явление). Но пологаться на это, разумеется, не стоит и лучше, как уже говорилось, использовать критические секции или мутексы для синхронизации отправки данных.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы