|
проблема с SO_REUSEADDR в Linux, (работа с сокетами) |
|
|
|
Oct 11 2005, 12:35
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Приветствую. Установил бит SO_REUSEADDR на сокет, но что-то не всегда работает должным образом, периодически ругается (при запуске приложения), что мол сокет порт занят:
... int sd; int yes = 1;
if ( (sd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { perror("socket() error!"); exit(1); }
if ( setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 ) { { perror("setsockopt() error"); exit(1); } ...
if ( bind(sd, (struct sockaddr *)&serv_addr, sizeof serv_addr) == -1 ) { perror("bind() error"); exit(1); } ...
что еще нужно подкрутить? Спасибо!
|
|
|
|
|
 |
Ответов
(1 - 5)
|
Oct 12 2005, 10:26
|
Местный
  
Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458

|
Цитата(romez777 @ Oct 11 2005, 15:35) Приветствую. Установил бит SO_REUSEADDR на сокет, но что-то не всегда работает должным образом, периодически ругается (при запуске приложения), что мол сокет порт занят: ... if ( bind(sd, (struct sockaddr *)&serv_addr, sizeof serv_addr) == -1 ) { perror("bind() error"); exit(1); } ... что еще нужно подкрутить? Спасибо! Всё, похоже, - так, только непонятно что там в &serv_addr ? все ли поля заполнены? Вот под рукой оказался фрагмент: это для серверного сокета (SO_REUSEADDR, как правило, применяют для серверных-прослушивающих сокетов, ... я другого не видел), это работало давно и безукоризненно: Код struct sockaddr_in addr; int rc = 1, ls; if( ( ls = socket( AF_INET, SOCK_STREAM, 0 ) ) = -1 ) errx( "create stream socket failed" ); if( setsockopt( ls, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof( rc ) ) != 0 ) errx( "set socket option failed" ); memset( &addr, 0, sizeof( addr ) ); addr.sin_len = sizeof( addr ); addr.sin_family = AF_INET; addr.sin_port = htons( p ); addr.sin_addr.s_addr = htonl( INADDR_ANY ); if( bind( ls, (struct sockaddr*)&addr, sizeof( sockaddr ) ) != 0 ) errx( "bind socket address failed" ); if( listen( ls, 25 ) != 0 ) errx( "put socket in listen state failed" ); - посмотрите заполнение addr полей (это код QNX, но значения не имеет - стек TCP у них ... одинаково работает, я это использовал и в Linux, но нет файлов под рукой). Если совсем уж плохо  - посмотрите вот здесь, может что подскажет: http://qnxclub.net/files/articles/EchSrv/echsrv-107.htmlhttp://qnxclub.net/files/articles/tcpip-qnx/tcpip-qnx.pdfА "ругается", да ещё "периодически"  ... А вы случаем 2 экземпляра приложения не пытаетесь пустить, или 2-й (поток, например) запускать - пока 1-й ещё окончательно не завершился?
|
|
|
|
|
Oct 12 2005, 12:02
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Цитата(Olej @ Oct 12 2005, 13:26) Всё, похоже, - так, только непонятно что там в &serv_addr ? все ли поля заполнены? Вот под рукой оказался фрагмент: это для серверного сокета (SO_REUSEADDR, как правило, применяют для серверных-прослушивающих сокетов, ... я другого не видел), это работало давно и безукоризненно: Код struct sockaddr_in addr; int rc = 1, ls; if( ( ls = socket( AF_INET, SOCK_STREAM, 0 ) ) = -1 ) errx( "create stream socket failed" ); if( setsockopt( ls, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof( rc ) ) != 0 ) errx( "set socket option failed" ); memset( &addr, 0, sizeof( addr ) ); addr.sin_len = sizeof( addr ); addr.sin_family = AF_INET; addr.sin_port = htons( p ); addr.sin_addr.s_addr = htonl( INADDR_ANY ); if( bind( ls, (struct sockaddr*)&addr, sizeof( sockaddr ) ) != 0 ) errx( "bind socket address failed" ); if( listen( ls, 25 ) != 0 ) errx( "put socket in listen state failed" ); - посмотрите заполнение addr полей (это код QNX, но значения не имеет - стек TCP у них ... одинаково работает, я это использовал и в Linux, но нет файлов под рукой). Приветствую. Вот как выглядит заполнение структуры: Код const int port = 5000; ... /* zero out structure */ memset(&serv_addr, 0, sizeof serv_addr);
/* fill in structure */ serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port);
if ( bind(sd, (struct sockaddr *)&serv_addr, sizeof serv_addr) == -1 ) { perror("bind() error"); exit(1); } "Ругается периодически" в том смысле, что я не заметил пока какой-то закономерности  Всегда запускается только одна копия, сервер построен на основе fork()'ов, треды не применяются. Мне также рекомендовали посмотреть на опцию SO_REUSEPORT, но в моем линуксе ее не нашел, наверное платформенно-зависимый параметр.
|
|
|
|
|
Oct 12 2005, 12:44
|
Местный
  
Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458

|
Цитата(romez777 @ Oct 12 2005, 15:02) Код const int port = 5000; ... /* fill in structure */ serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); 1. Я вам не зря показывал заполнение - заполните поле длины: в некоторых реализациях без неё проходило (в Linux, но это зависит от верс. стека-ядра - оно вам надо?) ... но строго по POSIX (или по У.Стивенсу  ) - она должна быть заполнена: Код /* fill in structure */ serv_addr.sin_len = sizeof( serv_addr ); 2. И порт какой-то странненький (маленький, из well-known) - вы уверены, что на нём не сидит какая-то из служб, работающих в вашей конфигурации OS? Цитата(romez777 @ Oct 12 2005, 15:02) "Ругается периодически" в том смысле, что я не заметил пока какой-то закономерности  Всегда запускается только одна копия, сервер построен на основе fork()'ов, треды не применяются. Мне также рекомендовали посмотреть на опцию SO_REUSEPORT, но в моем линуксе ее не нашел, наверное платформенно-зависимый параметр. 3. То, что fork() или pthread_create() - это значения не имеет, "что в лоб, что по-лбу" - одно и тоже... но если вы в разных ветках fork() хотите открыть сокеты с одинаковыми параметрами (внешними) - этот номер не проходит, здесь и SO_REUSEADDR вам не поможет... да и зачем: я, как понял по INADDR_ANY - это у вас сервер? сервер по bind() создаёт единый экземпляр прослушивающего сокета, а каждая ветка fork() получает по accept() свою копию связанного сокета, имеющие те-же внешние параметны (адрес, порт) - с ними и работаете... Или я чего-то не так понял 4. Посмотрте те URL, что я назвал ... там рядом есть готовые проекты 7-ми серверов, принципиально разной структуры, со сравнением результатов: http://qnxclub.net/files/articles/EchSrv/echsrv.tgz
|
|
|
|
|
Oct 13 2005, 05:23
|
Местный
  
Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077

|
Приветствую. Цитата(Olej @ Oct 12 2005, 15:44) 1. Я вам не зря показывал заполнение - заполните поле длины: в некоторых реализациях без неё проходило (в Linux, но это зависит от верс. стека-ядра - оно вам надо?) ... но строго по POSIX (или по У.Стивенсу  ) - она должна быть заполнена: Код /* fill in structure */ serv_addr.sin_len = sizeof( serv_addr ); Поле длины отсутствует (и соответственно компиляция обламывается: structure has no member named `sin_len'). Цитата 2. И порт какой-то странненький (маленький, из well-known) - вы уверены, что на нём не сидит какая-то из служб, работающих в вашей конфигурации OS? В системе ни одна из служб не занимает порт 5000, проверено. Стивенс пишет, что диапозон портов 1024-5000 используются системой для авто-назначения, то есть все >5000 вполне легально импользовать для своих нужд, правильно я понимаю? Цитата 3. То, что fork() или pthread_create() - это значения не имеет, "что в лоб, что по-лбу" - одно и тоже... но если вы в разных ветках fork() хотите открыть сокеты с одинаковыми параметрами (внешними) - этот номер не проходит, здесь и SO_REUSEADDR вам не поможет... да и зачем: я, как понял по INADDR_ANY - это у вас сервер? сервер по bind() создаёт единый экземпляр прослушивающего сокета, а каждая ветка fork() получает по accept() свою копию связанного сокета, имеющие те-же внешние параметны (адрес, порт) - с ними и работаете... Или я чего-то не так понял  Да, именно так и работает мой сервер: каждый новый форк получает после accept'a свой socket handler и работает с ним. Еще поизучаю примеры с вашей ссылки, спасибо.
|
|
|
|
|
Oct 19 2005, 08:31
|
Участник

Группа: Свой
Сообщений: 30
Регистрация: 25-01-05
Пользователь №: 2 169

|
Цитата В системе ни одна из служб не занимает порт 5000, проверено. Стивенс пишет, что диапозон портов 1024-5000 используются системой для авто-назначения, то есть все >5000 вполне легально импользовать для своих нужд, правильно я понимаю? Иксы к примеру висят на 6000 порте. А вообще cat /etc/services - там довольно много портов > 5000. Состояние портов можно глянуть с помощью netstat -a
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|