реклама на сайте
подробности

 
 
> проблема с SO_REUSEADDR в Linux, (работа с сокетами)
romez777
сообщение Oct 11 2005, 12:35
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 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);
}
...

что еще нужно подкрутить?
Спасибо!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 5)
Olej
сообщение Oct 12 2005, 10:26
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 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, но нет файлов под рукой).

Если совсем уж плохо smile.gif - посмотрите вот здесь, может что подскажет:
http://qnxclub.net/files/articles/EchSrv/echsrv-107.html
http://qnxclub.net/files/articles/tcpip-qnx/tcpip-qnx.pdf

А "ругается", да ещё "периодически" smile.gif ... А вы случаем 2 экземпляра приложения не пытаетесь пустить, или 2-й (поток, например) запускать - пока 1-й ещё окончательно не завершился?
Go to the top of the page
 
+Quote Post
romez777
сообщение Oct 12 2005, 12:02
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 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);
}


"Ругается периодически" в том смысле, что я не заметил пока какой-то закономерности smile.gif Всегда запускается только одна копия, сервер построен на основе fork()'ов, треды не применяются. Мне также рекомендовали посмотреть на опцию SO_REUSEPORT, но в моем линуксе ее не нашел, наверное платформенно-зависимый параметр.
Go to the top of the page
 
+Quote Post
Olej
сообщение Oct 12 2005, 12:44
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 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 (или по У.Стивенсу smile.gif ) - она должна быть заполнена:
Код
/* fill in structure */
serv_addr.sin_len = sizeof( serv_addr );


2. И порт какой-то странненький (маленький, из well-known) - вы уверены, что на нём не сидит какая-то из служб, работающих в вашей конфигурации OS?

Цитата(romez777 @ Oct 12 2005, 15:02)
"Ругается периодически" в том смысле, что я не заметил пока какой-то закономерности smile.gif Всегда запускается только одна копия, сервер построен на основе fork()'ов, треды не применяются. Мне также рекомендовали посмотреть на опцию SO_REUSEPORT, но в моем линуксе ее не нашел, наверное платформенно-зависимый параметр.
*


3. То, что fork() или pthread_create() - это значения не имеет, "что в лоб, что по-лбу" - одно и тоже... но если вы в разных ветках fork() хотите открыть сокеты с одинаковыми параметрами (внешними) - этот номер не проходит, здесь и SO_REUSEADDR вам не поможет... да и зачем: я, как понял по INADDR_ANY - это у вас сервер? сервер по bind() создаёт единый экземпляр прослушивающего сокета, а каждая ветка fork() получает по accept() свою копию связанного сокета, имеющие те-же внешние параметны (адрес, порт) - с ними и работаете...
Или я чего-то не так понял blink.gif

4. Посмотрте те URL, что я назвал ... там рядом есть готовые проекты 7-ми серверов, принципиально разной структуры, со сравнением результатов:
http://qnxclub.net/files/articles/EchSrv/echsrv.tgz
Go to the top of the page
 
+Quote Post
romez777
сообщение Oct 13 2005, 05:23
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 292
Регистрация: 9-11-04
Пользователь №: 1 077



Приветствую.
Цитата(Olej @ Oct 12 2005, 15:44)
1. Я вам не зря показывал заполнение - заполните поле длины: в некоторых реализациях без неё проходило (в Linux, но это зависит от верс. стека-ядра - оно вам надо?) ... но строго по POSIX (или по У.Стивенсу smile.gif ) - она должна быть заполнена:
Код
/* 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() свою копию связанного сокета, имеющие те-же внешние параметны (адрес, порт) - с ними и работаете...
Или я чего-то не так понял  blink.gif

Да, именно так и работает мой сервер: каждый новый форк получает после accept'a свой socket handler и работает с ним.

Еще поизучаю примеры с вашей ссылки, спасибо.
Go to the top of the page
 
+Quote Post
Dizel
сообщение Oct 19 2005, 08:31
Сообщение #6


Участник
*

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



Цитата
В системе ни одна из служб не занимает порт 5000, проверено. Стивенс пишет, что диапозон портов 1024-5000 используются системой для авто-назначения, то есть все >5000 вполне легально импользовать для своих нужд, правильно я понимаю?


Иксы к примеру висят на 6000 порте. А вообще cat /etc/services - там довольно много портов > 5000.
Состояние портов можно глянуть с помощью netstat -a
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th July 2025 - 13:50
Рейтинг@Mail.ru


Страница сгенерированна за 0.01394 секунд с 7
ELECTRONIX ©2004-2016