2010-03-05 3 views
0

В C++, когда я бегу (красное предупреждение! Псевдо-код)Двойной UDP сокет связывание в Linux

bind(s1, <local address:port1234>) 
bind(s2, <local address:port1234>) 

на двух разных UDP сокетов (s1 и s2 каждый созданный с помощью вызова socket()) Я получаю проблемы , В Linux (Ubuntu) двойное связывание кажется прекрасным. Однако в Windows двойное связывание завершается сбоем, а вызов bind() второй раз для того же адреса возвращает != 0.

Я хочу получить поведение, которое у меня есть в Windows на моей машине Linux. Есть ли какие-то настройки, которые я могу работать, чтобы «заняться портом» в Linux?

+1

Можете ли вы разместить реальный код? Пока вы не спросили меня, я был уверен, что вы * сделаете * получите ошибку во второй раз, когда вы привяжетесь. –

+3

Я тоже так думал, поэтому я его протестировал. После вызова socket() второй bind() в тот же порт возвращает EADDRINUSE. – msw

ответ

4

Пожалуйста, смотрите bind и setsockopt. Если вы не вызвали setockopt с SO_REUSEADDR, то ваш вызов привязки с тем же адресом должен привести к ошибке с EADDRINUSE.

+0

Вы правы на деньги! SO_REUSEADDR не работает одинаково в Windows и Linux (BSD-сокеты?). –

+0

SO_REUSEADDR не позволяет вам привязываться к конечной точке дважды. Его цель - переопределить состояние TIME_WAIT после закрытия сокета TCP. Обычно ОС хранит TCP-соединение в TIME_WAIT в течение нескольких минут, чтобы забрать все «поздние» пакеты, которые еще не были получены. Если вы попытаетесь открыть новый сокет, вы получите EADDRINUSE, если вы не укажете SO_REUSEADDR, который убивает гнездо TIME_WAIT. –

+0

@ JohnKugelman - на самом деле неправда; на Linux и для UDP SO_REUSEADDR на самом деле позволяет одновременно иметь несколько сокетов, связанных с одной и той же конечной точкой. Это отличается от семантики для Linux + TCP, а также отличается от семантики BSD. –

0

Уверены ли вы в этом? По man 7 ip на моем Linux коробки (Fedora 9):

Когда процесс хочет принимать новые входящие пакеты или соединения, то он должен связать сокет с адресом локального интерфейса, используя привязку (2). Только один IP-разъем может быть привязан к любой локальной (адрес, порт).

Там нет упоминания исключения для UDP связывания в любом man 7 ip или man 7 udp. (Это ничего не доказывает, но не документированное поведение в чем-то столь же основное, как это ... удивительно.)

2

Это не то поведение, которое я получаю в Linux. Когда я запускаю следующую тестовую программу, то второй bind вызов не выполняется EADDRINUSE:

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

int main() 
{ 
    int s1, s2; 
    struct sockaddr_in sa = { 
     .sin_family = AF_INET, 
     .sin_port = 0x5555, 
     .sin_addr.s_addr = INADDR_ANY }; 

    s1 = socket(PF_INET, SOCK_DGRAM, 0); 
    s2 = socket(PF_INET, SOCK_DGRAM, 0); 
    if (bind(s1, (struct sockaddr *)&sa, sizeof sa) < 0) 
     perror("bind 1"); 
    if (bind(s2, (struct sockaddr *)&sa, sizeof sa) < 0) 
     perror("bind 2"); 

    return 0; 
} 
+0

+1 для примера кода (я собирался опубликовать его, но теперь не буду: -P), но для семейства адресов (т. Е. В поле 'sin_family') следует использовать небольшую нить:' AF_INET'. –

+0

Лично я использую 'AF_INET' в вызове' socket' тоже: в базовой спецификации базы Open Group фактически нет констант 'PF_ *', но я могу видеть больше случаев для «lenient» для ' socket "и других неадресных использованиях. –

+0

Правильно, вы сэр, обновлено (страницы руководства Linux говорят использовать константы 'PF_' для аргумента' socket() ', но я уверен, что практической разницы нет). – caf

Смежные вопросы