грабли о SCTP
Sep. 18th, 2010 05:52 pmИсследовал SCTP.
После наступания на практически все заботливо разложенные грабли решил описать траекторию и цвета искр в глазах, начиная с самого чайниковского.
1. Есть сокеты one-to-one и one-to-many. Их не следует путать с тем, сколько адресов на конце у каждой ассоциации: может быть one-to-one на много адресов и one-to-many на один адрес.
One-to-one - значит, может быть только одна ассоциация. При передаче не обязательно указывать, по какой передаёшь и почему, а при приёме - с какой получено. One-to-many - напоминает старый добрый UDP - общаешься с кем хочешь, но не забывай про цену - тут на каждого другого есть состояние в памяти.
2. SOCK_STREAM - это не поток, как в TCP, несмотря на название. Это всего лишь one-to-one сокет. Почему STREAM - видимо, констант не хватило. Сообщения, приходящие в него, всё равно не склеиваются. (Я вначале подумал, что назначил бы иначе - SEQPACKET для one-to-one и DGRAM для one-to-many. Было бы немного логичнее.)
3. sctp_send(), sctp_sendx() работают только при уже готовой ассоциации. Если такой ещё нет, функция обломится с совершенно невнятной диагностикой. Это значит, что первая посылка на one-to-many через них недопустима и надо использовать sctp_sendmsg[x](). А лучше - использовать её всегда для таких сокетов.
4. На one-to-many сокете передавать надо, как сказано выше, через sctp_sendmsg(). Это создаёт ассоциацию, если её ещё не было - но у этой функции нет возврата номера созданной ассоциации. Зовите sctp_getassocid(), если он нужен. Сравнивайте адреса, как в старом добром UDP.
5. У one-to-many сокета, если не сделать listen(), он не будет принимать новые ассоциации по входящим запросам. Однако логично.
6. Номер потока не может быть произвольным, они считаются от 0 до максимума. По умолчанию дают только 10 потоков - с 0 до 9. (FreeBSD: sysctl net.inet.sctp.outgoing_streams) Можно увеличивать желаемое (через sockopt SCTP_INITMSG), вопрос в том, насколько удобно получится с этим работать.
7. Поле ppid надо сохранять и извлекать с помощью htonl() и ntohl(). Ну или воспринимать его просто как char[4]. В мане написано специально, чтобы запутать: "Note that the stack passes this value without regard to byte order." Кроме того, есть рекомендации IANA по значениям для него - чтобы помогать расшифровке в случае чего. Не вижу глубокого смысла ставить его по этим рекомендациям, но можно использовать в качестве своего внешнего тега.
8. Поле assoc_id имеет выделенное значение 0 - "моя не знай", допустимо при передаче. Использовать одновременно адреса и assoc_id от разных ассоциаций я не пробовал - боюсь, порвётся.
9. Не забывать включать получение sctp_sndrcvinfo через SCTP_EVENTS (sctp_event_subscribe::sctp_data_io_event=1). FreeBSD по умолчанию его доставляет, а вот Linux - нет.
Возможно, to be continued.
После наступания на практически все заботливо разложенные грабли решил описать траекторию и цвета искр в глазах, начиная с самого чайниковского.
1. Есть сокеты one-to-one и one-to-many. Их не следует путать с тем, сколько адресов на конце у каждой ассоциации: может быть one-to-one на много адресов и one-to-many на один адрес.
One-to-one - значит, может быть только одна ассоциация. При передаче не обязательно указывать, по какой передаёшь и почему, а при приёме - с какой получено. One-to-many - напоминает старый добрый UDP - общаешься с кем хочешь, но не забывай про цену - тут на каждого другого есть состояние в памяти.
2. SOCK_STREAM - это не поток, как в TCP, несмотря на название. Это всего лишь one-to-one сокет. Почему STREAM - видимо, констант не хватило. Сообщения, приходящие в него, всё равно не склеиваются. (Я вначале подумал, что назначил бы иначе - SEQPACKET для one-to-one и DGRAM для one-to-many. Было бы немного логичнее.)
3. sctp_send(), sctp_sendx() работают только при уже готовой ассоциации. Если такой ещё нет, функция обломится с совершенно невнятной диагностикой. Это значит, что первая посылка на one-to-many через них недопустима и надо использовать sctp_sendmsg[x](). А лучше - использовать её всегда для таких сокетов.
4. На one-to-many сокете передавать надо, как сказано выше, через sctp_sendmsg(). Это создаёт ассоциацию, если её ещё не было - но у этой функции нет возврата номера созданной ассоциации. Зовите sctp_getassocid(), если он нужен. Сравнивайте адреса, как в старом добром UDP.
5. У one-to-many сокета, если не сделать listen(), он не будет принимать новые ассоциации по входящим запросам. Однако логично.
6. Номер потока не может быть произвольным, они считаются от 0 до максимума. По умолчанию дают только 10 потоков - с 0 до 9. (FreeBSD: sysctl net.inet.sctp.outgoing_streams) Можно увеличивать желаемое (через sockopt SCTP_INITMSG), вопрос в том, насколько удобно получится с этим работать.
7. Поле ppid надо сохранять и извлекать с помощью htonl() и ntohl(). Ну или воспринимать его просто как char[4]. В мане написано специально, чтобы запутать: "Note that the stack passes this value without regard to byte order." Кроме того, есть рекомендации IANA по значениям для него - чтобы помогать расшифровке в случае чего. Не вижу глубокого смысла ставить его по этим рекомендациям, но можно использовать в качестве своего внешнего тега.
8. Поле assoc_id имеет выделенное значение 0 - "моя не знай", допустимо при передаче. Использовать одновременно адреса и assoc_id от разных ассоциаций я не пробовал - боюсь, порвётся.
9. Не забывать включать получение sctp_sndrcvinfo через SCTP_EVENTS (sctp_event_subscribe::sctp_data_io_event=1). FreeBSD по умолчанию его доставляет, а вот Linux - нет.
Возможно, to be continued.
no subject
Date: 2011-12-26 09:37 am (UTC)Давно пора продвигать протокол SCTP повсеместно! Учитывая нынешнее активное продвижение в сторону IPv6 (http://ru.wikipedia.org/wiki/IPv6). + массу полезностей из этого извлекает ещё один хороший протокол SPDY (http://ru.wikipedia.org/wiki/SPDY). Нельзя тормозить развитие технологий и необходимо проталкивать современные протоколы в массы. Остаётся убедить Microsoft в полезности и необходимости данных протоколов и склонить к их интенсивному внедрению.