Действительно ли необходима сериализация сокета через Lock при отправке и получении? - PullRequest
0 голосов
/ 10 декабря 2018

Мне было интересно, есть ли необходимость использовать, например, threading.Lock при работе с сокетами Pythons, где каждый поток только отправляет и получает из этого сокета.Открытие и закрытие всегда выполняется родителем.

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

Другие говорят, что send и recv являются поточно-ориентированными на уровне операционной системы и поэтому могут использоваться параллельно без сериализации ( здесь ).Я не знаю, правильно ли я здесь, но я подумал, что Python использует C-реализацию POSIX-сокетов, верно?(А как насчет реализации сокетов в Windows?)

Если неправильно, что send и recv вызываются без блокировок, то почему это именно так?Возможно ли, что в потоке получаются данные, запрошенные другим?

1 Ответ

0 голосов
/ 10 декабря 2018

Нет причин, по которым вы должны синхронизировать вызовы с send или recv , если только один отправитель или получатель.Подумайте, не было ли двух потоков, пытающихся получить сообщение.Скажем, ради обсуждения, что сообщение client => server имеет длину 8 байтов, причем первые 4 байта являются командой, а вторые 4 байта являются идентификатором объекта некоторого вида:

Thread A: sock.recv(8) obtains first 4 bytes
Thread B: sock.recv(8) obtains second 4 bytes

Здесь ни одна ветка не заканчивается полным сообщением.Теперь, много раз, что не произойдет , вы получите целое 8-байтовое сообщение как единое целое.Но это не гарантируется, и когда сервер / сеть загружаются, а сетевые буферы ОС заполняются, и у вас несколько потоков, пытающихся получить доступ к ЦП, более вероятно, что это произойдет.(И это не только Python BTW; то же самое было бы верно для программы на C).

Так что, да, сокеты «поточнобезопасны» в том смысле, что ровно один recv одного потока получит заданный байтданные и ничто не мешает двум потокам одновременно вызывать recv.ОС не запутается в этом.Но в сокете TCP (SOCK_STREAM) нет ничего, что могло бы гарантировать, что один «поток» получит все «сообщение» (любой длины больше одного байта).

Если у вас есть два потока, с одним только получением и одним только отправкой, то конкуренции не будет, и для поддержания согласованного потока данных не потребуется блокировка.

UDP-сокеты OTOH «ориентированы на сообщения», поэтому для них не существует такой же проблемы.Каждый send или recv доставляет неделимую дейтаграмму.Получающий поток не получит часть дейтаграммы.Он получает всю дейтаграмму или ничего (хотя дейтаграмма может быть усечена из-за недостатка места в буфере; но в этом случае остаток просто отбрасывается , а не доставляется следующему получающему потоку).

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