TCP Sockets. Помогите с реализацией простого приложения.

Тема в разделе "WASM.BEGINNERS", создана пользователем Span, 15 май 2008.

  1. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    Решил написать приложение для отладки TCP взаимодействия других приложений и для некой "маршрутизации" трафика.
    Все просто: мой софт встает между 2х приложений (клиент и сервер) и прозрачно передает данные между ними.

    Клиент соединяется с моим ПО, а мое ПО соединяется с сервером.
    Для клиента мое ПО - то же что и сервер, только адрес другой.
    Для сервера мое ПО - то же что и клиент, только адрес другой.
    Ну а дальше мое ПО логирует то, что через него проходит.

    ПО многопоточное. Слушает несколько портов разными потоками + при подключении клиента создает еще один поток, и продолжает слушать дальше.

    Думал все будет совсем просто. Но столкнулся с трудностями.
    Вот есть несколько вопросов, подскажите п-та:

    1) Как грамотно организовать подключение? Я делаю просто:
    жду клиента (listen/accept),
    после подключения создаю еще один поток,
    ему передаю клиентский сокет,
    поток открывает сокет с сервером (connect).

    В этом методе есть один большой минус: если сервер не слушает соответственный порт, мое ПО не может установить TCP соединение, и отключает клиента. Для клиента это выглядит так: он подключается к серверу, который его затем отключает. Если бы моего ПО не было - клиент бы просто не смог подключиться к серверу. Значит мое ПО добавляет какую-то логику, и работа с ним уже не прозрачна.
    Как это исправить? В идеале, ПО должно понять, что у клиент запросил подключение, затем попытаться соединится с сервером, и по результатам отшить клиента или продолжить работу, установив с ним соединение.

    2) Дисконнект клиента/сервера при дисконнекте сервера/клиента. Здесь вообще не ясно. Предположим, ПО соединено и с клиентом и с сервером. В один прекрасный момент сервер отвалился (закрыл сокет). ПО должно сразу же закрыть сокет с клиентом. Но как отследить этот момент??? Я что-то слышал про keepalive, но имхо, это не очень удачный вариант. В моем случае можно отключать и клиента и сервер при отсутствии активности более чем t секунд.

    3) Написал кусок кода, который в конечном варианте будет пробрасывать траффик от сервера клиенту и наоборот.
    Когда у меня один поток - работает на отлично. Но когда потоков много - работает плохо. Теряются пакеты, рвется соединение. А отлаживать несколько потоков весьма сложно. Гляньте, п-та, может я где-то допустил ошибку?
    Еще раз: этот кусок кода должен пробрасывать траффик между 2мя открытыми сокетами и рвать соединение по таймауту:
    Код (Text):
    1.     fd_set remoteServerSocketReadSet;
    2.     fd_set connectSocketReadSet;
    3.     timeval readTimeout;
    4.     readTimeout.tv_sec = 0;
    5.     readTimeout.tv_usec = 25; // 25 msecks
    6.     FD_ZERO(&remoteServerSocketReadSet);
    7.     FD_ZERO(&connectSocketReadSet);
    8.     FD_SET(params->remoteServerSocket, &remoteServerSocketReadSet);
    9.     FD_SET(ConnectSocket, &connectSocketReadSet);
    10.     BOOL optVal;
    11.     int optLen = sizeof(BOOL);
    12.     int inactiveCount = INATIVE_COUNT; // initial value
    13.     while (true){
    14.         FD_ZERO(&remoteServerSocketReadSet);
    15.         FD_ZERO(&connectSocketReadSet);
    16.         FD_SET(params->remoteServerSocket, &remoteServerSocketReadSet);
    17.         FD_SET(ConnectSocket, &connectSocketReadSet);
    18.         // read from client socket
    19.         if(select(0, &remoteServerSocketReadSet, NULL, NULL, &readTimeout) == 1){
    20.             recvLen = recv(params->remoteServerSocket, recvBuffer, BUFF_LEN - 1, 0);
    21.             if (recvLen != 0){
    22.                 if((recvLen == SOCKET_ERROR) || (send(ConnectSocket, recvBuffer, recvLen, 0) == SOCKET_ERROR))
    23.                     break;
    24.                 inactiveCount = INATIVE_COUNT;
    25.             }      
    26.         }
    27.         if(select(0, &connectSocketReadSet, NULL, NULL, &readTimeout) == 1){
    28.             recvLen = recv(ConnectSocket, recvBuffer, BUFF_LEN - 1, 0);
    29.             if (recvLen != 0){
    30.                 if((recvLen == SOCKET_ERROR) || (send(params->remoteServerSocket, recvBuffer, recvLen, 0) == SOCKET_ERROR))
    31.                     break;
    32.                 inactiveCount = INATIVE_COUNT;
    33.             }
    34.         }
    35.         inactiveCount--;
    36.         if(inactiveCount <= 0) // if no traffic during timeout
    37.             break;
    38.         Sleep(10);
    39.  
    40.     }
    41.     closesocket(params->remoteServerSocket);
    42.     closesocket(ConnectSocket);
    Вот такие вот проблемы.
    Может нужно работать на уровне ниже, чем транспортный???

    П.С. Есть приложение TCP Viewer от Westbrook. Вот мне нужно то же самое по функционалу + кое-что от себя. Это приложение работает просто отлично.

    Спасибо.
     
  2. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Span
    способ не самый оптимальный, но если хочеш, посмотри сорцы проксей :)
     
  3. Span

    Span New Member

    Публикаций:
    0
    Регистрация:
    5 ноя 2006
    Сообщения:
    134
    Дык а какой тогда оптимальный?? Желательно чтобы код работал быстро.

    Кстати, глянул TCW Viewer, он не использует select() вообще.