2014-12-04 2 views
6

У меня есть реализация сервера, где мне нужно 2 отдельных сокета - 1 сокет сокета IPv4, прослушивающий определенный адрес IPv4 и порт сервера X, и сокет IPv6, прослушивающий определенный IPv6-адрес и тот же серверный порт X. Адреса IPv4 и IPv6 находятся на одном интерфейсе.IPv6 Bind failures

memset(&sin, 0, sizeof(sin)); 
    sin.sin_family  = AF_INET; 
    sin.sin_addr.s_addr = htonl(v4addr); 
    sin.sin_port  = htons(tcp_port); 

Я использую evconnlistener_new_bind создать ipv4 сокет и привязать к нему. Для прослушивателя IPv6 код выглядит следующим образом.

memset(&sin6, 0, sizeof(sin6)); 
    sin6.sin6_family  = AF_INET6; 
    memcpy(sin6.sin6_addr.s6_addr, v6addr_bytes, IPV6_ADDR_LEN); 
    sin6.sin6_port  = htons(tcp_port); 

    fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 
    evutil_make_socket_nonblocking(fd) 
    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on)) 
    setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof(on)) 
    evutil_make_listen_socket_reuseable(fd) /* Libevent call to set SO_REUSEADDR */ 
    evutil_make_socket_nonblocking(fd)  /* Libevent call to set fd non-blocking */ 
    bind(fd, (const struct sockaddr *)&sin6, sizeof(sin6)) 

Поскольку я привязываю свой fd к конкретному адресу ipv6, я вижу прерывание связи с перерывами.

связывают v6 не удалось sin6 3FFE :: A00: 513 - ERRNO 99 - Невозможно назначить запрашиваемый адрес

Я пытался GdB в, но каждый раз, когда я GdB в, привязка успешно.

Я не уверен, почему я вижу эту проблему. Кто-то может помочь?

+0

в '-адресами 3ffe ::/16' не действительны. Вместо этого используйте действительный адрес IPv6. –

+0

Мой интерфейс имеет адрес 3ffe :: 10.1.14.14/120. При создании сокета маска префикса не имеет никаких последствий? И почему вы говорите его недействительный адрес? – shrejal

+0

Потому что это неверно. Этот netblock был устаревшим несколько лет назад. И тот факт, что он вообще используется, указывает на то, что что-то ужасно неправильно с вашей настройкой IPv6. Исправьте это в первую очередь. –

ответ

0

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

Это делается путем установки опции SO_REUSEADDR сокета:

int one = 1; 
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) 
+1

Чтобы очистить, сокет входит в состояние «TIME_WAIT», когда приложение-владелец активно закрывает сокет, когда у него установлено соединение (если удаленный одноранговый узел инициирует закрытие, сокет не будет вводить 'TIME_WAIT'). Затем вы можете включить 'SO_REUSEADDR' в сокете NEXT, который вы хотите привязать к ранее связанному ip + порту. –

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