Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2 3 4  Все   Вниз
  Печать  
Автор Тема: Сервер сокетов перестает работать  (Прочитано 78375 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Mikl
Постоялец

ru
Offline Offline

« : 03-07-2009 17:56 » 

Уважаемые, подскажите ЕСЛИ кто сталкивался.

Есть набор клиент-серверных приложений собственной разработки. Для связи используются сокеты в виде  классов в которых реализовна и клиентская и серверная части. Вся часть ПО ответственная за связь вынесена в отдельную DLL.

Сервер запускается, клиенты к нему подключаются, отключаются и т.д. и т.п.
Все нормально работало неделями - дольше не получалось тестировать непрерывно - приходилось перезапускать.
Клиентов было штук 20.

Сейчас клиентов увеличил до 150. Теперь все работает но 2,5 дня. Может и дольше - до недели, но не меньше точно.
Потом происходит следующая ситуация. Сервер видит подключения клиентов, новые подключаются, старые отключаются, но данные не пересылаются ни в одну сторону.

Была идея - сделать перезапуск класса сервера, отвечающего за связь. Обнаружил интересную штуку - если сделать этот перезапуск искусственно - скажем через 1 сутки - все нормально работает. Но если дождаться когда связь "отвалится" сама - увы, клиенты подключаются, а данные не ходят ни в одну сторону.

Перезапускаешь приложение - все опять работает.
Понятно, что где-то что-то переполняется, но вот что и где?Не понял

Идеи есть какие-нибудь?
Спасибо.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 03-07-2009 18:10 » 

А есть ли освобождение сокетов на серверной части, после окончание сессии с клиентом?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #2 : 03-07-2009 18:14 » 

Да, конечно.
Потом, даже если бы и не было - перезапуск класса связи - это delete, затем new со всеми вытекающими.
В конструкторе/деструкторе класса используются фукнции WSAStartup/WSACleanup.
Так что с МОЕЙ точки зрения - все начинается с нуля с перезапуском класса связи.
НО я где-то ошибаюсь.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 03-07-2009 18:17 » 

Mikl, не пробовал ли прогонять свое приложение через программы по отлову утечек и тому подобное?
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #4 : 03-07-2009 18:19 » 

Нет. Не силен я в этом. В Visual Stiduo есть механизм контроля утечек памяти и протоколирования всех исключений. Вот его я задействовал - там чисто.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 03-07-2009 18:31 » 

Хорошо. С другой стороны зайдем. Когда твое приложение зависло. В диспетчере задач. Сколько памяти выделено для твоего приложения. Также, сколько нитей?  Также эти цифри в рабочем состоянии.

Также программа netstat. Сколько открытых сокетов показано, которые принадлежат твоему приложению?

Кстати, у Виндовс есть лимит открытых сокетов. И по умолчанию он довольно маленький. Не превышаеш ли ты его?
« Последнее редактирование: 03-07-2009 18:34 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #6 : 03-07-2009 18:35 » 

Приложение НЕ зависло. Оно как работало - так и работает. Срабатывают функции перезапуска модуля связи.
Дальше я жду - ничего нет (в смысле данные не идут) и нажимаю в приложении кнопку выход - все КОРРЕКТНО завершается без каких-либо утечек чего-либо Жаль.

Памяти сколько выделено и нитей - столько же, сколько и при старте программы.

А вот насчет netstat - сказать ничего не могу - я только что про нее узнал - пока есть данные только ДО падения связи. Жду когда упадет - с учетом запланированного на завтра перезапуска - где-то в понедельник, не раньше.


Добавлено через 1 минуту и 15 секунд:
Да, еще забыл добавить интересное наблюдение - перезапуск класса связи искусственно срабатывает 101 раз. А потом надо один фиг перезагружать всю программу целиком.
« Последнее редактирование: 03-07-2009 18:36 от Mikl » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 03-07-2009 18:43 » 

Можно увидеть код создания нитки, после получения от клиента запроса на открытие сессии. Также саму нить. Логику самого приложение можеш убрать. Меня интересует, как именно ты работаеш с сокетом только.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #8 : 03-07-2009 18:44 » 

Да нет проблем. Так как классы связи вынесены в отдельную DLL - то....куда выслать проект?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #9 : 03-07-2009 18:50 » 

Меня проект не интересует. Да и я не смогу его запустить у себя. Код просто здесь выложи мест которые я указал.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #10 : 03-07-2009 18:53 » 

Хорошо. Выкладываю. Это поток, в котором сервер ждет запросы клиентов на присоединения.
Вы это имели в виду?
Код:
UINT Potok(LPVOID pParam)
{
SOCKADDR_IN saddr;
WSADATA data;

//
char hostname[20];
nomer_soketa=0; for(DWORD i=0;i<Max_Chislo_Klients;i++) {SocketUsed[i]=FALSE;}

if (WSAStartup(0x202,&data)) {Fl_Err=2;return 0;}
if (gethostname(hostname,sizeof(hostname))) {Fl_Err=2;return 0;}
start:
mainSocket=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if (mainSocket==INVALID_SOCKET) {Fl_Err=3;return 0;}
saddr.sin_family=AF_INET;
saddr.sin_addr.S_un.S_addr=INADDR_ANY;
saddr.sin_port=htons(PortServer);

int optval = 1;
int rc;
rc = setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR,
(char *)&optval, sizeof(optval));

if (bind(mainSocket,(PSOCKADDR) &saddr,sizeof(SOCKADDR_IN)))
{
DWORD mmm999=GetLastError();
Fl_Err=3;return 0;
}
Fl_Err=1;
if (listen(mainSocket,Max_Chislo_Klients)) {Fl_Err=3;return 0;}
if (PotokMastExit) return 0;
slaveSocket[nomer_soketa]=WSAAccept(mainSocket,NULL,NULL,NULL,0);
if (PotokMastExit) return 0;
if (slaveSocket[nomer_soketa]==INVALID_SOCKET) {Fl_Err=3;return 0;}
if (closesocket(mainSocket)) {Fl_Err=3;return 0;}
if (WSAAsyncSelect(slaveSocket[nomer_soketa],MainHandle,WM_TRANSACT,FD_READ || FD_CLOSE))
{Fl_Err=3;return 0;}
SocketUsed[nomer_soketa]=TRUE;
Massiv_Klients[nomer_soketa].Klient_To_Server=Massiv_Klients[nomer_soketa].Server_To_Klient=
Massiv_Klients[nomer_soketa].Byte_From_Klient_Soket_Service=
Massiv_Klients[nomer_soketa].Byte_From_Klient=0;
EventTotal[nomer_soketa]=0;
    EventArray[nomer_soketa][EventTotal[nomer_soketa]] = WSACreateEvent();
    ZeroMemory(&AcceptOverlapped[nomer_soketa], sizeof(WSAOVERLAPPED));
    AcceptOverlapped[nomer_soketa].hEvent = EventArray[nomer_soketa][EventTotal[nomer_soketa]];
    DataBuf[nomer_soketa].len = DATA_BUFSIZE;
    DataBuf[nomer_soketa].buf = buffer[nomer_soketa];
RecvBytes[nomer_soketa]=BytesTransferred[nomer_soketa]=CallBack[nomer_soketa]=
Flags[nomer_soketa]=0;
    EventTotal[nomer_soketa]++;
DataBuf[nomer_soketa].len = DATA_BUFSIZE;
DataBuf[nomer_soketa].buf = buffer[nomer_soketa];
Schitano[nomer_soketa]=true;
KolvoUsedSockets++;
if (nomer_soketa==Max_Chislo_Klients-1) nomer_soketa=0;
else nomer_soketa++;
m1:
if (SocketUsed[nomer_soketa]==TRUE)
{
if (nomer_soketa==Max_Chislo_Klients-1) nomer_soketa=0;
else nomer_soketa++;
goto m1;
}
//PostMessage(MainHandle,WM_PAINT,0,0);
m2:
if (KolvoUsedSockets==Max_Chislo_Klients)
{
Sleep(1000);
goto m2;
}
goto start;
return 0;
}
« Последнее редактирование: 03-07-2009 19:00 от Finch » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #11 : 03-07-2009 19:03 » 

У тебя не правильная логика серверного приложения. Попробую сейчас поправить. Предупреждаю сразу. Что могут быть ошибки в моем коде.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #12 : 03-07-2009 19:04 » 

Лучше на словах. Т.к. здесь почти все взято с примеров MSDN
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #13 : 03-07-2009 19:42 » 

Код:
DWORD WINAPI SessionThread( LPVOID lpParam )
{
   //lpParam у нас будет номер сокета  
   SOCKET socket = (SOCKET) lpParam;
   // Тут логика работы твоего приложения с клиентом
   closesocket(socket);
   return 0;
}


UINT Potok(LPVOID pParam)
{
   SOCKADDR_IN saddr;
   WSADATA data;
   SOCKET mainSocket=INVALID_SOCKET;
   SOCKET slaveSocket=INVALID_SOCKET;
   HANDLE dwThread;

   if (WSAStartup(0x202,&data))
   {
      Fl_Err=2;
      return 0;
   }
   mainSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
   if (mainSocket==INVALID_SOCKET) Fl_Err=3;
   else
   {
   saddr.sin_family=AF_INET;
saddr.sin_addr.S_un.S_addr=INADDR_ANY;
saddr.sin_port=htons(PortServer);

int optval = 1;
int rc;
rc = setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));

if (bind(mainSocket,(PSOCKADDR) &saddr,sizeof(SOCKADDR_IN)))
{
DWORD mmm999=GetLastError();
Fl_Err=3;
PotokMastExit = true;
}
        Fl_Err=1;
if (listen(mainSocket,Max_Chislo_Klients))
{
  Fl_Err=3;
  PotokMastExit = true;
}
while (!PotokMastExit)
{
   slaveSocket = WSAAccept(mainSocket,NULL,NULL,NULL,0);
   if (slaveSocket != INVALID_SOCKET)
   {
        dwThread = CreateThread(NULL, 0, SessionThread, (void *)slaveSocket, 0, &dwThread);  
        CloseHandle(dwThread);  // Закрываем хендл нити, так как с серверной части он нас больше не интересует
   }
}
closesocket(mainSocket);
   }
   WSACleanup();
   return 0;
}
Вот так примерно должно выглядеть серверная часть приложения. Могут быть ошибки. Не компилировал и не проверял.
« Последнее редактирование: 03-07-2009 19:51 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #14 : 03-07-2009 19:44 » 

спасибо, попробую завтра разобраться на свежую голову.

Добавлено через 7 часов, 18 минут и 52 секунды:
Попробовал.
Согласен с тем, что Вы более изящно оформили код в плане обработки ошибок.
Но в том то и дело, что их нет - даже когда связь валится - соединения с клиентом происходят нормально, т.е. в ветви обработки ошибок программа не попадает.

Принципиальное отличие только в том, что Вы создаете отдельный поток на каждого подключенного клиента. Для меня это не нужно да и нежелательно. Т.к. ожидание соединений вынесено в поток, то обработчик событий в сокетах я оставил в самом классе. И он один.

Так что где у меня неправильная логика - не понимаю. И потом, все это не объясняет почему возможен только 101 перезапуск (удаление и создание вновь) класса связи.
« Последнее редактирование: 04-07-2009 03:03 от Mikl » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #15 : 04-07-2009 05:49 » 

Код:
slaveSocket[nomer_soketa]=WSAAccept(mainSocket,NULL,NULL,NULL,0);
if (PotokMastExit) return 0;
if (slaveSocket[nomer_soketa]==INVALID_SOCKET) {Fl_Err=3;return 0;}
if (closesocket(mainSocket)) {Fl_Err=3;return 0;}
Зачем например закрывать главный сокет? А потом его заново пересоздавать? В моем коде он создается один раз. И до тех пор пока приложение не будет закрыто. Кстати, та логика, что я привел. Это стандартная логика серверных приложений.  В твоей логике. Если например клиент начнет тупить, и не отсылать запрос сразу. Сервер повиснит и не будет принимать последуюшие запросы. Т.е убить твое приложение можно просто, открыть соединение и держать его открытым.

И кстати эти return 0 везде по коду, явная утечка. Текут у тебя зомби-сокеты.
« Последнее редактирование: 04-07-2009 05:51 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #16 : 04-07-2009 05:59 » 

Зачем например закрывать главный сокет? - Честно? А фиг его знает. Даже не задумывался.
Совет дельный - сейчас переделаю, но не совсем как ты предлагаешь - просто в своем коде перенесу метку
start:
  к коду
   slaveSocket[nomer_soketa]=WSAAccept(mainSocket,NULL,NULL,NULL,0);

Насчет "клиент начнет тупить" - проверено неоднократно - ничего не виснет. Серверу пофиг на этого клиента. Все работает с остальными дальше.

Выяснил еще один интересный факт. Сейчас  усиленно гоняю приложение  в режиме постоянных перезапусков класса связи и обнаружил, что ИНОГДА:
1. Перезапускаю класс связи. Ни одна из функций класса сервера НЕ возвращает ошибку.
2. netstat -n НЕ показывает что на таком-то порту что-то кем-то слушается.
3. клиент естественно говорит - сервер не найден.
4. после нескоьких(1-n) перезапусков все работает опять.

По этому поводу наткнулся на

http://forum.vingrad.ru/forum/topic-99522/unread-1.html

там описаны параметры

TcpTimedWaitDelay,TcpNumConnections,MaxUserPort.

У меня их в реестре нет. Может создать?

Добавлено через 3 минуты и 16 секунд:
Да, а насчет потоков и дескрипторов - пытаюсь понаблюдать, но толку мало - в приложении десятка 2 потоков, все постоянно "шевелится" и уловить что-то трудновато. Но устойчивого роста какого-либо показателя нет.
А виртуальная память вообще подупала Улыбаюсь.
« Последнее редактирование: 04-07-2009 06:02 от Mikl » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #17 : 04-07-2009 06:06 » 

Я не разбирался как именно ты работаеш с клиектом при открытии сессии. Поэтому не могу ничего сказать. Но можно проверить кстати. Просто на клиенте открой соединение. И ничего не посылай серверу.
А вот то, что netstat тебе показывает, что сервер ничего не слушает. Вот это есть очень плохо. Сервер должен постоянно прослушивать порт, когда приложение запушено в рабочее состояние.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #18 : 04-07-2009 06:11 » 

поотключал все что смог - счетчик дескрипторов подрастает.
Сейчас переделаю по твоему совету, а заодно добавлю параметров в реестр, а затем снова погоняю.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #19 : 04-07-2009 06:13 » 

То что описано на винграде, это если ты привышаеш лимит открытых сокетов. Я не вижу в коде, сколько точно ты собираешся открывать соединений. Но явно меньше чем лимит.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #20 : 04-07-2009 06:15 » 

да немного штук 40 мне пока хватит, просто некоторые клиенты очень специфичны и считать их в нагрузке один к одному нельзя.

Я думал про другое - там указан максимальный порт в системе 5000. У меня в реестре таких параметров нет, а порт как раз 5001.
Ну и время когда сокет в TIME_WAIT я бы сократил ниже плинтуса. Кстати вопрос до скольки? Сеть локальная, клиентов с инета нет.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #21 : 04-07-2009 06:23 » 

Ты не правильно понял. Это не максимальный порт. А количество открытых портов одновременно. Т.е. это количество открытых соединений одновременно. Например порт у аськи 5190. А на твоей стороне порт обязательно будет выше 32536. Кстати настоятельно не рекомендуется открывать порты на прослушивание выше чем 32536. Порты от 32536 и до 65535 предназначены для автоматической биндовки.

Кстати обрати внимание на return 0 в своем коде. Почти всегда это чревато не закрытием сокетов у тебя. 
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #22 : 04-07-2009 06:27 » 

MaxUserPort - максимально доступный открываемый № порта, по умолчанию 5000.

как раз написано порт пользователя, а не используемые (USED). Ну да это не важно и без них все работает до определенного момента.

Сокеты закрываются в деструкторе класса.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #23 : 04-07-2009 06:32 » 

Вот здесь тоже не правильная логика. При программировании надо почти всегда придерживаться принципа. "Где открыл, там и закрыл."
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #24 : 04-07-2009 06:34 » 

согласен. Туговато у меня с логикой ООП. И всякие "goto" тоже не есть гуд. Но т.к. первый язык был ассемблер - никак не могу переучиться.

Добавлено через 9 минут и 28 секунд:
>Просто на клиенте открой соединение. И ничего не посылай серверу.

Попробовал. Все отлично работает - следующий спокойно цепляется и работает, а тестовый так и висит, пока сервер его сам не прибьет по другим факторам.

Добавлено через 4 часа, 30 минут и 51 секунду:
to Finch

> поотключал все что смог - счетчик дескрипторов подрастает.
>С ейчас переделаю по твоему совету, а заодно добавлю параметров в реестр, а затем снова погоняю.

Реестр пока решил для чистоты эксперимента не трогать.
Погонял. Решились (кажется) 2 проблемы сразу - счетчик дескрипторов расти перестал.
И перестала уменьшаться выделенная приложению память - раньше сползала с 600 до 300 мб.

Сейчас попробую повключать нагрузки сколько смогу, а на рабочей системе запущу в понедельник.

Спасиобо огромное.

Добавлено через 19 дней, 5 часов, 58 минут и 44 секунды:
Еще раз  спасибо!

Проблема решена. Сервер проработал 2 недели вывалившись по совершенно иной причине.

Вот только сомнения остались - в чем была причина?!?! Что "крамольного" в закрытии и открытии главного сокета вновь, что приводило к таким последствиям?

Но в принципе тема закрыта.
« Последнее редактирование: 23-07-2009 17:13 от Mikl » Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #25 : 23-07-2009 18:58 » 

Ну скорее всего в подвисании ресурсов. 
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Mikl
Постоялец

ru
Offline Offline

« Ответ #26 : 27-04-2011 12:04 » 

Как теперь выяснилось (спустя почти 2 года) проблема не решена. Опять все повторилось. Поэтому вопрос снова открыт - какие могут быть варианты? библиотеку которая содержит классы по работе с потоками я это время не трогал. Менял только код основного приложения. Все работало. Сейчас переехал на другое железо - вылезла старая проблема. Дистрибутивы ОС и VS один и тот же.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #27 : 27-04-2011 16:35 » 

Делай проверки, лови исключения. Отладить по фотографии нельзя.


Серверный сокет вполне можно закрыть. Открывая его вновь не забудь REUSE.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Mikl
Постоялец

ru
Offline Offline

« Ответ #28 : 27-04-2011 16:40 » 

Про фотографии я в курсе Улыбаюсь. Пока рою землю.
Дело в том что сервер работает под отладчиком - и никаких проблем не возникает - студия не ругается ни на что.
REUSE - поподробнее можно?
У меня при детекте потери связи класс отвечающий за связь уничтожается и создается заново. Единственное что до меня дошло - надо попробовать делать WSACleanup и затем WSAStartup. Но этот вариант означает - есть грабли в библиотеке WSA. В подтверждение этого

http://muforum.info/forums/index.php?showtopic=1586

Не кто не сталкивался с заплатками от MS для WinSocket?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #29 : 27-04-2011 17:44 » 

Опция сокета - port reuse. Чтобы система не отвергала попытку bind на сокет, пока еще существуют соединения на этот порт (активные или в финишных стадиях).
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1] 2 3 4  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines