Чи дійсні паралельні дзвінки для відправлення / повторної передачі в одному сокеті?


127
  1. Чи можемо ми зателефонувати надсилати з одного потоку та рев. З іншого на той же сокет?
  2. Чи можемо ми викликати кілька відправлень паралельно з різних потоків одного і того ж сокета?

Я знаю, що хороший дизайн повинен уникати цього, але мені не ясно, як будуть поводитися ці системні API. Я не можу знайти гарну документацію і для того ж.

Будь-які покажчики у напрямку будуть корисними.


3
чому ви стверджуєте, що робити це - погана практика ?. Мені це добре виглядає, тому що ти слухаєш і отримуєш з різних ниток.
TheMathNoob

Відповіді:


92

POSIX визначає send / recv як атомні операції, тому припускаючи, що ви говорите про POSIX send / recv, то так, ви можете викликати їх одночасно з декількох потоків і все буде працювати.

Це не обов'язково означає, що вони будуть виконуватися паралельно - у випадку декількох надсилань, другий, ймовірно, блокується, поки перший не завершиться. Ви, мабуть, цього не помітите, оскільки відправка завершиться після того, як він поставить свої дані в буфер сокета.

Якщо ви використовуєте розетки SOCK_STREAM, намагання робити паралельні речі менш ймовірно буде корисним, оскільки send / recv може надіслати або отримати лише частину повідомлення, а це означає, що речі можуть розпастися.

Блокування send / recv у розетках SOCK_STREAM блокується лише до тих пір, поки вони не надсилають або реквізують принаймні 1 байт, тому різниця між блокуванням і неблокуванням не корисна.


1
@Joao: Сокет SOCK_DGRAM задокументований як "збереження меж повідомлення", що не дуже зрозуміло. Подивившись на джерела ядра Linux, ви можете принаймні побачити, що кожне відправлення та recv має справу з одним пакетом атомно (принаймні, для udp).
Кріс Додд

2
@Kedar: не впевнений, що ти маєш на увазі. А sendповертається , як тільки дані містяться в буфер передачі, і дані передаються на через стек netowrk і вихід на мережі асинхронно. Отже, якщо у вас є один потік потоку і один потік отримання, цілком можливо (навіть ймовірно), що потік, що надсилає, надсилає багато пакетів, перш ніж приймаючий потік отримає перший пакет. Це повністю асинхронно і не одночасно.
Кріс Додд

6
@ChrisDodd, чи можете ви надати посилання для "POSIX визначає send / recv як атомні операції"?
suitianshi

2
@suitianshi: Стандартний документ POSIX 1003.1c перераховує всі функції в 1003.1, які є повторними (безпечні для дзвінка з потоків) і які не є. На жаль, мені невідома безкоштовна онлайн-копія, доступна де завгодно.
Кріс Додд

2
@ChrisDodd Я знайшов копію на unix-systems.org/version4, і я можу побачити список таблиці системного інтерфейсу в главі 7.1, але не бачу, де він перераховує функції як атомні операції. Не сумніваюся у вас, але чи можете ви поділитися / відредагувати свою відповідь, щоб обґрунтувати свою точку в документі?
користувач153882

17

Дескриптор сокета належить до процесу, а не до певного потоку. Отже, можна надсилати / приймати в / з одного і того ж сокета в різних потоках, ОС буде обробляти синхронізацію.

Однак, якщо порядок надсилання / отримання є семантично значущим, ви самі (відповідно ваш код) повинні забезпечити належне послідовність операцій у різних потоках - як це завжди буває з потоками.


4

Я не бачу, як паралельний прийом може щось досягти. Якщо у вас є 3-байтне повідомлення, 1-й потік може отримати 1-й 2-й байт, а інший останній байт, але ви не зможете сказати, що це було. Якщо ваші повідомлення не мають байту, ви не можете надійно змусити щось працювати при отриманні декількох потоків.

Якщо ви надіслали все повідомлення за один дзвінок, може бути багаторазове надсилання , але я не впевнений. Цілком можливо, що один міг би переписати інший. Звичайно, не було б жодної користі від цього.

Якщо потрібно надіслати кілька потоків, вам слід реалізувати синхронізовану чергу повідомлень. Майте один потік, який виконує фактичне надсилання, що читає повідомлення з черги, а інші потоки охоплюють цілі повідомлення. Те ж саме буде працювати для отримання, але потік прийому повинен знати формат повідомлень, щоб він міг їх дезаріалізувати належним чином.


9
Якщо ви використовуєте розетки SOCK_DGRAM, кожен recv отримає одну дейтаграму; вона ніколи не буде розбита між реквізитами
Кріс Додд

2
@noah, я погоджуюсь, що паралельні рекорди нічого не можуть досягти. Тому я цього не запитував. Моє запитання - паралельно відправити / повторити, а потім паралельно надсилати кілька разів. Ваша відповідь дає зрозуміти паралельне надсилання. Дякую за те саме.
Джей

1
@Chris хороший момент. Я припускав TCP. @Jay Ви можете уточнити, що питання "Чи можемо ми викликати паралельно надсилати / рев." Звучить так, як ви хочете отримувати паралельно.
ноя
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.