Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Дуплексная передача по сокету


Автор: Finalist 1.8.2013, 14:31
Приветствую всех!
Сейчас использую такую схему приемо-передачи данных клиент-сервер:
каждый клиент подключается к серверу дважды.. после рукопожатия отмечает сокеты как приемный и передающий.. в один сокет пишет он серверу, по второму сервер пишет клиенту. таким образом есть возможность серверу быть инициатором команд..
все работает прекрасно, нет никаких проблем.
Вчера появился в голове вопрос.. возможно ли сделать такую схему на одном сокете? 
Не будет ли коллизии при отсылке пакетов от клиента к серверу и наоборот? 
Накидал два проектика со схемой одного сокета. снифером пытался пронюхать.. есть ошибки приема.. хочу получить подтверждение того что эта схема не работает!

В снифере вот такой результат:
Код

Отправка: Код возврата:0x00000000
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Получение: Код возврата:0x00000000
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Получение: Код возврата:0x00002733


Отправка: Код возврата:0x00000000
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Автор: Finalist 1.8.2013, 18:35
Переписал немного тестовые программки...
отсылаю не просто ААА в одну сторону и  ВВВ в другую, а теперь шлю в обе стороны по очереди 111, 222, 333, 444, 555 и так далее...

снифаю порт: 
получаю нормальную очередность, но иногда приходят пустые пакеты.. а иногда два пакета склеены в один.
так что, вопрос снят. 
Если у кого-то есть соображения по этому поводу, прошу говорить! мне эта тема очень интересна и важна.

Код

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 3c c3 49 40 00 40 06  79 70 7f 00 00 01 7f 00   .<.I@.@. yp......
0020  00 01 dd 26 de db 4b 0b  6d c5 00 00 00 00 a0 02   ...&..K. m.......
0030  80 18 6b d4 00 00 02 04  40 0c 04 02 08 0a 00 59   ..k..... @......Y
0040  ae 8c 00 00 00 00 01 03  03 07                     ........ ..      

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 34 c3 4a 40 00 40 06  79 77 7f 00 00 01 7f 00   .4.J@.@. yw......
0020  00 01 dd 26 de db 4b 0b  6d c6 66 05 7b 94 80 10   ...&..K. m.f.{...
0030  01 01 c3 80 00 00 01 01  08 0a 00 59 ae 8c 00 59   ........ ...Y...Y
0040  ae 8c                                              ..               

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 34 c3 4b 40 00 40 06  79 76 7f 00 00 01 7f 00   .4.K@.@. yv......
0020  00 01 dd 26 de db 4b 0b  6d c6 66 05 7b f8 80 10   ...&..K. m.f.{...
0030  01 01 c3 1c 00 00 01 01  08 0a 00 59 ae 8c 00 59   ........ ...Y...Y
0040  ae 8c                                              ..               

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 98 c3 4c 40 00 40 06  79 11 7f 00 00 01 7f 00   ...L@.@. y.......
0020  00 01 dd 26 de db 4b 0b  6d c6 66 05 7b f8 80 18   ...&..K. m.f.{...
0030  01 01 fe 8c 00 00 01 01  08 0a 00 59 ae 8c 00 59   ........ ...Y...Y
0040  ae 8c 31 31 31 31 31 31  31 31 31 31 31 31 31 31   ..111111 11111111
0050  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31   11111111 11111111
0060  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31   11111111 11111111
0070  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31   11111111 11111111
0080  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31   11111111 11111111
0090  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31   11111111 11111111
00a0  31 31 31 31 31 31                                  111111           

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 98 c3 4d 40 00 40 06  79 10 7f 00 00 01 7f 00   ...M@.@. y.......
0020  00 01 dd 26 de db 4b 0b  6e 2a 66 05 7c 5c 80 18   ...&..K. n*f.|\..
0030  01 01 fe 8c 00 00 01 01  08 0a 00 59 ae 8d 00 59   ........ ...Y...Y
0040  ae 8d 32 32 32 32 32 32  32 32 32 32 32 32 32 32   ..222222 22222222
0050  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32   22222222 22222222
0060  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32   22222222 22222222
0070  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32   22222222 22222222
0080  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32   22222222 22222222
0090  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32   22222222 22222222
00a0  32 32 32 32 32 32                                  222222           

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 98 c3 4e 40 00 40 06  79 0f 7f 00 00 01 7f 00   ...N@.@. y.......
0020  00 01 dd 26 de db 4b 0b  6e 8e 66 05 7c c0 80 18   ...&..K. n.f.|...
0030  01 01 fe 8c 00 00 01 01  08 0a 00 59 ae 8e 00 59   ........ ...Y...Y
0040  ae 8d 33 33 33 33 33 33  33 33 33 33 33 33 33 33   ..333333 33333333
0050  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33   33333333 33333333
0060  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33   33333333 33333333
0070  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33   33333333 33333333
0080  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33   33333333 33333333
0090  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33   33333333 33333333
00a0  33 33 33 33 33 33                                  333333           

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 98 c3 4f 40 00 40 06  79 0e 7f 00 00 01 7f 00   ...O@.@. y.......
0020  00 01 dd 26 de db 4b 0b  6e f2 66 05 7d 24 80 18   ...&..K. n.f.}$..
0030  01 01 fe 8c 00 00 01 01  08 0a 00 59 ae 8f 00 59   ........ ...Y...Y
0040  ae 8e 34 34 34 34 34 34  34 34 34 34 34 34 34 34   ..444444 44444444
0050  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34   44444444 44444444
0060  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34   44444444 44444444
0070  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34   44444444 44444444
0080  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34   44444444 44444444
0090  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34   44444444 44444444
00a0  34 34 34 34 34 34                                  444444           

0000  00 00 00 00 00 00 00 00  00 00 00 00 08 00 45 00   ........ ......E.
0010  00 98 c3 50 40 00 40 06  79 0d 7f 00 00 01 7f 00   ...P@.@. y.......
0020  00 01 dd 26 de db 4b 0b  6f 56 66 05 7d 88 80 18   ...&..K. oVf.}...
0030  01 01 fe 8c 00 00 01 01  08 0a 00 59 ae 8f 00 59   ........ ...Y...Y
0040  ae 8f 35 35 35 35 35 35  35 35 35 35 35 35 35 35   ..555555 55555555
0050  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35   55555555 55555555
0060  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35   55555555 55555555
0070  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35   55555555 55555555
0080  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35   55555555 55555555
0090  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35   55555555 55555555
00a0  35 35 35 35 35 35                                  555555           


Автор: 1Nikita 1.8.2013, 22:09
Я вот думаю, можно ли перекачивать воду по одной трубе в обе стороны одновременно(полный дуплекс)?

Автор: feodorv 2.8.2013, 00:34
Цитата(1Nikita @  1.8.2013,  23:09 Найти цитируемый пост)
Я вот думаю, можно ли перекачивать воду по одной трубе в обе стороны одновременно(полный дуплекс)? 

Да ладно Вам, сокет изначально дуплексный.

Цитата(Finalist @  1.8.2013,  19:35 Найти цитируемый пост)
получаю нормальную очередность, но иногда приходят пустые пакеты.. а иногда два пакета склеены в один.

Сокет же потоковый (SOCK_STREAM), так и должно быть. 

Цитата(Finalist @  1.8.2013,  15:31 Найти цитируемый пост)
возможно ли сделать такую схему на одном сокете? 

Все так делают, без особых проблем...

Автор: Finalist 2.8.2013, 10:26
Цитата(feodorv @  2.8.2013,  00:34 Найти цитируемый пост)
Все так делают, без особых проблем...

Благодарю! теперь буду делать только так.

Автор: 1Nikita 2.8.2013, 11:37
Цитата(feodorv)
Да ладно Вам, сокет изначально дуплексный.


Полудуплекс или полный дуплекс? Если полный, то каким образом отделить в памяти принятые пакеты от отправляемых? порт то один.

Автор: Finalist 2.8.2013, 13:10
Цитата(1Nikita @  2.8.2013,  11:37 Найти цитируемый пост)
Полудуплекс или полный дуплекс? Если полный, то каким образом отделить в памяти принятые пакеты от отправляемых? порт то один.

Можешь что нибудь конкретно сказать? камни подводные может знаешь?

Автор: feodorv 2.8.2013, 17:35
Цитата(1Nikita @  2.8.2013,  12:37 Найти цитируемый пост)
Если полный, то каким образом отделить в памяти принятые пакеты от отправляемых? порт то один. 

Гм. Есть большое желание отправить книжки читать))) На самом деле так сокеты и планировались - полнодуплексными. Порт один, да, но и сокет один, полнодуплексности это никак не мешает. Просто где-то на транспортном уровне формируются отдельные очереди на приём и передачу. Очередь на приём считывается вызовами recv/recvfrom/read, очередь на передачу формируется вызовами send/sendto/write. И всё это на одном и том же сокете. На канальном уровне уже полнодуплесность может отсутствовать (а может и нет), например, в один и тот же момент времени по кабелям может передаваться только один пакет и только в одну сторону. Но и тогда пакеты передаются с бешеной скоростью, то в одну сторону, то в другую, чем, собственно, и обеспечивается одновременная (с точки зрения приложения) передача данных в обе стороны. Никакого водопровода.

Посмотрите на описание функции select (или если дело происходит в рамках WinAPI, то WSAWaitForMultipleEvents). Убедитесь, что функция способна обеспечить (даже асинхронную) обработку данных в обе стороны - на приём и на передачу на одном единственном сокете. Никакого мошенничества smile 


Цитата(Finalist @  2.8.2013,  14:10 Найти цитируемый пост)
камни подводные может знаешь? 

Подводные камни встречаются повсюду, но нужно знать реку/залив/гавань, в которой Вы плаваете. Всё сильно зависит от задачи и используемого API.

Автор: 1Nikita 2.8.2013, 20:00
Цитата(feodorv)
Гм. Есть большое желание отправить книжки читать))) На самом деле так сокеты и планировались - полнодуплексными. Порт один, да, но и сокет один, полнодуплексности это никак не мешает. 


Ну вот ты скажи тогда, раз порт один то и приёмник и буфер для отправки находятся по одному адресу в памяти. Нам нужно отправить 10 байт в сеть , мы записываем их в порт (send), и тут же из сети приходят пакет 10 байт и тоже попадает в этот порт и нам нужно их считать (recv). И как отделить мух от котлет?

С полудуплексом всё понятно,ибо он переключается с приёма на передачу и обратно (типа радиостанции).

Автор: feodorv 2.8.2013, 20:47
Цитата(1Nikita @  2.8.2013,  21:00 Найти цитируемый пост)
И как отделить мух от котлет?

Цитата(feodorv @  2.8.2013,  18:35 Найти цитируемый пост)
где-то на транспортном уровне формируются отдельные очереди на приём и передачу. 

Буферы разные. Один - на приём, другой - на передачу. Что здесь непонятного?

Автор: 1Nikita 3.8.2013, 12:05
Цитата(feodorv @  2.8.2013,  18:35 Найти цитируемый пост)
где-то на транспортном уровне формируются отдельные очереди на приём и передачу. 


Цитата(feodorv)
Буферы разные. Один - на приём, другой - на передачу. Что здесь непонятного?


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

Мы сейчас говорим о сокетах, а не о том как реализуется передача данных на других более низких уровнях. И вопрос, кстати, был о дуплексности сокетов. 

Каким образом ты запишешь в порт (send) и считаешь (recv) оттуда данные одновременно??? ведь полнодуплексный режим именно так работать должен. Даже если делать через события, то всё равно получается полудуплекс, но не полный.

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

Автор: feodorv 3.8.2013, 14:06
Цитата(1Nikita @  3.8.2013,  13:05 Найти цитируемый пост)
Если порт один, то и буфер тоже один

Ну вот что за упёртость)))) Почему буфер один??? Что мешает завести два (а то и более) буфера?

С пользовательской точки зрения
У открываемого сокета создаются два буфера - на приём и передачу. В буфер на приём складываются данные, которые пользовательское приложение отправляет в сеть, эти данные могут быть тотчас отправлены, а могут и с задержкой, а то и не отправлены совсем (сеть перегружена или вообще вышла из строя). В буфер на приём складываются данные, которые приходят из сети, и которые должны быть считаны пользовательским приложением, иначе буфер приёма забьётся, и более туда ничего поместить не получится - пришедшие данные будут потеряны. С помощью вызова setsockopt сокету раздельно можно задать размеры этих двух буферов: SO_RCVBUF - для буфера приёма, SO_SNDBUF - для буфера передачи.

Можно изловчиться и на одном и том же порту открыть несколько сокетов, у каждого из которых будут свои буферы приёма-передачи, и они не будут друг другу мешать ни коим образом.

С точки зрения ОС
Каждый приходящий из сети пакет http://paramax.susu.ru/study/tcpips/-Obzor_TCP-IP-Demulmztipleksirovanie_prinimaemyh_dannyh.htm до пользовательского сокета и кладётся в его буфер приёма. Каждая порция пользовательских данных из буфера передачи аккуратно завёртывается в пакет, который затем уходит в сеть. 

Я больше скажу. Реально нет никаких статических буферов, есть очереди буферов (которые позволяют избежать лишнего копирования данных). Почитайте хотя бы про mbuf.

И срочно читать http://yandex.ru/yandsearch?text=%D1%81%D1%82%D0%B8%D0%B2%D0%B5%D0%BD%D1%81%20%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0%20%D1%81%D0%B5%D1%82%D0%B5%D0%B2%D1%8B%D1%85%20%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9&clid=48648&lr=213. Пока не прочтёте, лучше не делайте поспешных выводов.

Автор: feodorv 3.8.2013, 14:25
Цитата(1Nikita @  3.8.2013,  13:05 Найти цитируемый пост)
Либо нужна вторая труба, а это уже другой сокет

У одного единственного сокета две трубы, вот так  smile 

Автор: 1Nikita 4.8.2013, 20:25
Цитата(feodorv)
У одного единственного сокета две трубы, вот так  smile


Если две трубы то это уже симплект по каждой из них smile

Автор: feodorv 4.8.2013, 21:35
Цитата(1Nikita @  4.8.2013,  21:25 Найти цитируемый пост)
Если две трубы то это уже симплект по каждой из них smile

Честно, не математик, и юмора не понял  smile 

Ну подумайте сами, какая может быть причина для того, чтобы пользоваться одним единственным буфером со всеми вытекающими отсюда неудобствами? 
Вон у FILE один единственный буфер, по, вполне, кстати, понятным причинам, так каким же нужно быть осторожным, когда переходишь от чтения к записи или от записи к чтению.
А у сокета? Да без проблем:
Код

struct socket_data
{
  ...
  struct buffer in;
  struct buffer out;
  ...
};

и все проблемы с полнодуплексностью ложатся на сеть. Удобно же. 

А сколько бы крику было по разным форумам, если бы буфер был один. Так и вижу темы: "Потеряны пакеты при отправке в сокет???" с однотипными ответами "Так нужно было дождаться полного приёма присылаемых данных, а уж потом туда записывать!" и т.д. Два буфера реализуются легко, поддержки по синхронизации не требуют, схема работы с сокетом сразу упрощается, автоматом получается полнодуплексность. Красота  smile 

Автор: 1Nikita 5.8.2013, 14:27
В предыдущем посте сделал описку, следует читать "СИМПЛЕКС". Это не из математики (хотя и там есть), симплекс (телевизионный сигнал), полудуплекс (радиостанция), полныйдулекс (двусторонее движение автомобилей по одному полотну одновременно в обе стороны). 

А с сокетами трубы то две получается. Меня этот момент интерисовал. 

PS ты вот модератор, а по этому вопросу http://forum.vingrad.ru/forum/c-c++network.html есть у тебя какие нибудь мысли?

Автор: feodorv 5.8.2013, 15:03
Цитата(1Nikita @  5.8.2013,  15:27 Найти цитируемый пост)
симплекс (телевизионный сигнал)

А, это из связи, понял  smile 


Цитата(1Nikita @  5.8.2013,  15:27 Найти цитируемый пост)
ты вот модератор, а по этому вопросу

Модератор - тоже человек, всего знать не может. Очень сложный http://book.itep.ru/6/tls.htm, если честно, должны http://en.wikipedia.org/wiki/Transport_Layer_Security какие-нибудь библиотеки для упрощения реализации, я так думаю.

Автор: 1Nikita 5.8.2013, 20:29
Цитата(feodorv @ 5.8.2013,  15:03)


Цитата(1Nikita @  5.8.2013,  15:27 Найти цитируемый пост)
Модератор - тоже человек, всего знать не может. Очень сложный http://book.itep.ru/6/tls.htm, если честно, должны http://en.wikipedia.org/wiki/Transport_Layer_Security какие-нибудь библиотеки для упрощения реализации, я так думаю.



Сложностей там нет. Библиотеки есть в составе винды, реализовывать эти алгоритмы не надо. А если и надо было, то реализация всех алгоритмов есть в интернете на С. Только как их (TLS) юзать непонятно.

Автор: SVN74 6.8.2013, 22:40
Ничего не надо изобретать...
Заведите два потока один на приемку, другой на отправку и увидите на что способен сокет...

Автор: feodorv 7.8.2013, 00:42
Цитата(SVN74 @  6.8.2013,  23:40 Найти цитируемый пост)
Заведите два потока один на приемку, другой на отправку и увидите на что способен сокет... 

А чем один-единственный поток плох в демонстрационных целях?

Автор: SVN74 7.8.2013, 11:32
Цитата(feodorv @  7.8.2013,  00:42 Найти цитируемый пост)
А чем один-единственный поток плох в демонстрационных целях? 

Про экспериментируйте, что быстрей работает?
Один поток:
    send(Любой текст);
    recv(Любой текст);
    send(Любой текст);
    recv(Любой текст);
    send(Любой текст);
    recv(Любой текст);
и т.д. ( в цикле)
Или
Два потока:
    Thread1 -> send(Любой текст)
    Thread2-> recv(Любой текст)
(в циклах)

В потоках скорость в несколько раз выше.   smile  

Автор: feodorv 7.8.2013, 12:56
Цитата(SVN74 @  7.8.2013,  12:32 Найти цитируемый пост)
В потоках скорость в несколько раз выше.

Ну так надо пользоваться асинхронной моделью. В синхроне-то понятно, что медленнее. smile 

Автор: Finalist 4.9.2013, 17:39
http://habrahabr.ru/post/192284/
с завтрашнего дня начинаю тесты Boost::Asio

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

Автор: feodorv 4.9.2013, 19:13
Цитата(Finalist @  4.9.2013,  18:39 Найти цитируемый пост)
хотелось бы услышать интересную историю по поводу выбора порта для своей игры)) 

Ну, эээ...
Цитата

Порт — это просто любое условное число от 1 до 65535. Теоретически номер порта ни на что не влияет.

Важно только, чтобы этот порт был свободен. Впрочем, если ваша программа при запуске обнаружит, что указанный вами порт занят (то есть его уже слушает какая-то другая программа на вашем компьютере), то она вам сразу пожалуется сама.

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

Если вам не важен с эстетической точки зрения номер порта, то рекомендуется выбрать какой-нибудь порт выше 5000. Некоторые пользователи рекомендуют выбирать порт выше 42000.

Для системных и некоторых популярных программ выделены общепринятые порты с номерами от 0 до 1023, называемые привилегированными или зарезервированными.

(взято http://ru.wikibooks.org/wiki/%D0%9F%D0%BE%D1%80%D1%82)

Но я бы всё же проверил, не используется ли понравившийся порт http://ru.wikipedia.org/wiki/%D1%EF%E8%F1%EE%EA_%EF%EE%F0%F2%EE%E2_TCP_%E8_UDP...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)