
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.75] |
![]() |
|
Сообщ.
#1
,
|
|
|
Привет. Пытаюсь сделать простого клиента, который подсоединяется к серверу. Клиент должен быть запущен на определенном порту, т.е. вызываю bind.
Сервер привязывается к 127.0.0.1:7777 а клиент к 127.0.0.1:7778. Система WinXP SP3. И вот какая странная штука получается: клиент работает без ошибок через раз! Т.е. бывает нормально идут соединения а бывает следующая ошибка: когда я подсоединяюсь к серверу, то первый раз все работает отлично (и bind, и connect), клиент и сервер обмениваются сообщениями. После этого клиент завершается и обязательно вызывается WSACleanup и даже не нужный для Windows Sockets 2 WSACancelBlockingCall(на всякий случай)! И когда я снова пытаюсь подсоединится к серверу вылетает следующая ошибка WSAEADDRINUSE(10048)(Обычно разрешается одно использование адреса сокета). ![]() Причем странно, что это ошибка вылезает после вызова connect, хотя перед этим вызов bind происходит без ошибки!? Даже когда полностью закрываешь приложение клиента все равно вылезает ошибка. Я решил посмотреть какие коннекты есть в системе и выяснилось, что после того как сервер и клиент обменяются информацией и оба закроют сокеты в системе остается соединение с именем процесса [System Process] и остальными данными точно такими же как и у акцептованного сервером сокета (входящее с 127.0.0.01:7778 на 127.0.0.01:7777). ![]() Это соединение через пару минут пропадает и странно, что OutpostFirewall его не видит вообще. Я поначалу думал, что это из-за фаерволла, но отключив его да и антивирус вдобавок, убедился, что ошибка все равно возникает. Дальше я пробую установить в 1 для клиента с помощью setsockopt параметр SO_REUSEADDR, который разрешает - "Allow the socket to be bound to an address which is already in use". Все равно та же ошибка вылетает! Далее я пробую разные версии библиотеки Windows Sockets DLL от 1 до 2.2. Все равно та же ошибка! Странно также, что сервер запускается и останавливается без проблем без оставления каких-либо соединений с именем [System Process]. Это соединение остается в системе на некоторое время только когда происходит операция accept сервера для клиента, т.е. когда сервер создает параллельное соединение(входящее с 127.0.0.1:7778 на 127.0.0.0.1:7777). Т.е. получается как бы именно этот сокет "превращается" в [System Process] после того как и клиент, и сервер закрывают свои сокеты. Причем даже при закрытии приложения сервера все равно остается в системе на некоторое время(3-4 мин.). Может кто сталкивался с проблемой? Понимаю, что если клиент и сервер будут на разных компьютерах, то проблеиы в принципе не будет. Также если не использовать bind для клиента, то все вроде бы работает, но эти [System Process] остаются для каждого коннекта клиента акцептованного сервером, просто порты назначаются каждый раз новые и ошибки WSAEADDRINUSE не происходит. PS: Т.е. получается система как бы блокирует порт, который использовался для соединений на какое-то время! Но Брандмауэр Windows отключен... |
Сообщ.
#2
,
|
|
|
Код в студию.
|
Сообщ.
#3
,
|
|
|
Все совершенно справедливо.
Так как вы намертво привязали программу клиента к порту (ведь обычно клиент получает динамический порт от системы), после его выключения запись об адресе локального сокета сохраняется в таблице соединений TCP около 4-х минут - состояние TIME_WAIT (в никсах, в винде может меньше ![]() Значит надо работать с опцией SO_REUSEADDR - или ждать 4 минуты.... ![]() |
Сообщ.
#4
,
|
|
|
Цитата Oleg2004 @ Значит надо работать с опцией SO_REUSEADDR - или ждать 4 минуты.... Я же пишу, что устанавливаю эту опцию: Цитата Grad @ Дальше я пробую установить в 1 для клиента с помощью setsockopt параметр SO_REUSEADDR, который разрешает - "Allow the socket to be bound to an address which is already in use". Все равно та же ошибка иногда вылетает! Цитата Oleg2004 @ после его выключения запись об адресе локального сокета сохраняется в таблице соединений TCP около 4-х минут - состояние TIME_WAIT (в никсах, в винде может меньше А вот об этом можно поподробнее. Где хотя бы почитать. Жутко интересно стало! Может быть это можно отключить? Еще странно то, что, например, сервер может закрывать свой сокет а потом открывать и привязываться к тому же порту без проблем! При этом не создается ни одного соединения с именем процесса [System Process]. То есть как бы для сервера не действует эта политика безопасности. Почему? |
Сообщ.
#5
,
|
|
|
Цитата Grad @ Я же пишу, что устанавливаю эту опцию: Извините, пропустил видно по невнимательности. Цитата Grad @ Клиент должен быть запущен на определенном порту, т.е. вызываю bind. Наверно все-таки нужен код. биндите вы локальный адрес сокета - и для него же должен быть SO_REUSE Наверно все таки код нужен. Потому как SO_REUSE работает 100%. И клизм не должно быть. Единственный вариант - какая-то служба или приложение вдруг тоже захотело сесть на этот порт, пока он в отключке. Можно поставить где-то 60000 ? Насчет таймвейта - куча инфы в сети например |
Сообщ.
#6
,
|
|
|
Цитата Oleg2004 @ Наверно все-таки нужен код. ![]() ![]() int sopt,sopt_size; ... //проверяю текущее значение SO_REUSEADDR------------------------------- sopt_size=sizeof(int); if (getsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&sopt,&sopt_size)!=0) { ErrorSocketMessage("Ошибка getsockopt"); return; } //после этого sopt=0 //---------------------------------------------------------------------- //устанавливаю значение SO_REUSEADDR в 1------------------------------- sopt=1; if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&sopt,sizeof(int))!=0) { ErrorSocketMessage("Ошибка setsockopt"); return; } //---------------------------------------------------------------------- //проверяю текущее значение SO_REUSEADDR------------------------------- sopt_size=sizeof(int); if (getsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&sopt,&sopt_size)!=0) { ErrorSocketMessage("Ошибка getsockopt"); return; } //после этого sopt=1 //---------------------------------------------------------------------- |
Сообщ.
#7
,
|
|
|
Первое
У Микрософта многие флаги - BOOL ![]() ![]() BOOL bOptVal = TRUE;// MSDN int bOptLen = sizeof(BOOL); int iOptVal; int iOptLen = sizeof(int); if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen) != SOCKET_ERROR) { printf("Set SO_REUSEADDR: ON\n"); } There are two types of socket options: Boolean options that enable or disable a feature or behavior, and options that require an integer value or structure. To enable a Boolean option, the optval parameter points to a nonzero integer. To disable the option optval points to an integer equal to zero. The optlen parameter should be equal to sizeof(int) for Boolean options. For other options, optval points to an integer or structure that contains the desired value for the option, and optlen is the length of the integer or structure. Но это так, для корректности..... Второе. Установку опции надо делать между soсket() и bind() И еще. Проверить привязку локального адреса можно с помощью getsockname() |
Сообщ.
#8
,
|
|
|
Цитата Oleg2004 @ Первое У Микрософта многие флаги - BOOL Но это так, для корректности..... BOOL Boolean variable (should be TRUE or FALSE). This type is declared in WinDef.h as follows: typedef int BOOL; или The optlen parameter should be equal to sizeof(int) Но это так, для корректности... Цитата Oleg2004 @ Второе. Установку опции надо делать между soсket() и bind() Ну естественно, а где же ей еще быть то? Цитата Oleg2004 @ Проверить привязку локального адреса можно с помощью getsockname() Я использую только конкретный всегда локальный IP-адрес 127.0.0.1(loopback), безо всяких имен. |
Сообщ.
#9
,
|
|
|
Цитата Grad @ Я использую только конкретный всегда локальный IP-адрес 127.0.0.1(loopback), безо всяких имен. Эта функция к имени не имеет никакого отношения - она возвращает адрес локального сокета, так как он прописан в системе - т.е. должно быть 127.0.0.1 + порт. И еще - посмотрел вашу картинку...... Может быть, именно то обстоятельство, что работает все через System - т.е. все замыкается через один и тот же модуль IP - это же лупбэк - и для System-процесса реюз не работает? В общем проблемку вы надыбали непростую...... ![]() |
Сообщ.
#10
,
|
|
|
Еще раз хочу повторить, чтобы меня правильно поняли сказать:
Клиент работает без ошибок через раз! Т.е. бывает нормально идут соединения а бывает ошибка. |
Сообщ.
#11
,
|
|
|
Хуже нет случайных несистематических ошибок!!!!!!!!!!
Как их диагностировать то? попробуйте для интереса разнести порты клиента и сервера - скажем 30000 и 50000 |