Ты прелагаешь вызывать recv, пока соединение не оборвётся? Я так пробовал - когда данные передались, а я вызываю ещё один recv, то происходит ЗАВИСАНИЕ.
Локальный PROXY я создаю для перехвата (в целях просмотра) TCP-трафика приложения, которое умеет работать через PROXY-сервер. Вот мой алгоритм:
1. Создать прослушивающий сокет.
2. Ждать соединения клиента.
3. Прочитать пакет переданный клиентом.
4. Передать пакет серверу.
5. Ждать ответа от сервера.
6. Читать пакет сервера.
7. Передать пакет клиенту.
8. Повторять п.3-7 пока соединение открыто.
9. Закрыть сокеты.
10. Конец.
Я реализовал этот алгоритм, и он работает, но почему-то...26.01.09 08:24 Автор: Vedrus <Serokhvostov Anton> Статус: Member Отредактировано 26.01.09 08:27 Количество правок: 2
Я реализовал этот алгоритм, и он работает, но почему-то клиент не получает данных от сервера. Когда я устанавливал в качестве локального PROXY-сервера Paros всё работало.
Вот обрезанная версия моего кода (без проверки ошибок):
> Вот обрезанная версия моего кода (без проверки ошибок): >
> while (1)
> {
> // Получить пакет от клиента //
> dwBytesTransfered = recv(sockGameClient,
> szBuf, BUF_SIZE, 0);
> // Передать пакет серверу //
> dwBytesTransfered = send(sockGameServer,
> szBuf, dwBytesTransfered, 0);
> // Получить пакет от сервера //
> dwBytesTransfered = recv(sockGameServer,
> szBuf, BUF_SIZE, 0);
> // Передать пакет клиенту //
> dwBytesTransfered = send(sockGameClient,
> szBuf, dwBytesTransfered, 0);
> }
>
---
Без прокси: Игра передет пакет AAABBBCCC, сервер получает два пакета AAAB и BBCCC, разбирает сообщение, и отвечает BBB.
С твоей реализацией: Игра передает пакет AAABBBCCC, прокси ловит AAAB, и передает серверу; останавливается и ждет ответа. Сервер получает AAAB и ждет завершения сообщения.
Клиент ждет, прокси ждет, сервер ждет. Ляпота...
Фрагметнация пакета - это следующая задача. Но сейчас даже...26.01.09 19:11 Автор: Vedrus <Serokhvostov Anton> Статус: Member
Фрагметнация пакета - это следующая задача. Но сейчас даже на полностью переданных пакетах омй прокси не работает. Ты констатировал проблему, а альтернативный вариант для много обещающего заголовка "как вариант"?
> Фрагметнация пакета - это следующая задача. Но сейчас даже > на полностью переданных пакетах омй прокси не работает. Ты > констатировал проблему, а альтернативный вариант для много > обещающего заголовка "как вариант"?
Альтернативный вариант тебе подскажет серое вещество. Если блокирующие вызовы могут привести к проблеме, значит надо использовать не блокирующую архитектуру. Как именно - сам додумаешься.
Если на полностью полученных пакетах не работает, то 1. Врубай сниффер без прокси и смотри что идет.
2. В прокси логируй все что пришло, и что ушло. 3. Проснифь с прокси.
Проанализируй разницу и найди решение :)
Спасибо, попробую27.01.09 18:51 Автор: Vedrus <Serokhvostov Anton> Статус: Member
PS, я проделал описанную тобой процедуру. В результате убедился, что первый запрос от клиента к серверу одинаков и с прокси и без; ответ сервера на этот запрос также одинаков с прокси и без.
Далее, мой прокси перестаёт получать и передавать данные, вместо этого при обращении к функциям передачи возвращает нулевую длинну. GetLastError и WSAGetLastError при этом ошибок не возвращают.
Если перенести строку
"sockGameClient = accept(sockProxyServer, NULL, NULL);"
в начало цикла, то дело доходит до следующего запроса. Этот запрос успешно читается от клиента. При попытке передать этот запрос серверу (send) ошибки не выдаётся, но до снифера этот пакет не доходит. При последующем вызове recv выдаётся ошибка 10053 (Программа на вашем хость компьютере разорвала установленное подключение).
Я подозреваю, что эта проблема связана с необходимостью определённым образом использовать функции accept и connect, но как именно понять не могу.
А где спасибо ? :)28.01.09 15:41 Автор: PS <PS> Статус: Elderman
> PS, я проделал описанную тобой > процедуру. В результате убедился, что первый запрос от > клиента к серверу одинаков и с прокси и без; ответ сервера > на этот запрос также одинаков с прокси и без. > > Далее, мой прокси перестаёт получать и передавать данные, > вместо этого при обращении к функциям передачи возвращает > нулевую длинну. GetLastError и WSAGetLastError при этом > ошибок не возвращают. > > Если перенести строку > "sockGameClient = accept(sockProxyServer, NULL, NULL);" > в начало цикла, то дело доходит до следующего запроса. Этот > запрос успешно читается от клиента. При попытке передать > этот запрос серверу (send) ошибки не выдаётся, но до > снифера этот пакет не доходит. При последующем вызове recv > выдаётся ошибка 10053 (Программа на вашем хость компьютере > разорвала установленное подключение). > > Я подозреваю, что эта проблема связана с необходимостью > определённым образом использовать функции accept и connect, > но как именно понять не могу.
Для умного:
MSDN
If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.
Для не очень умного:
У тебя соединение разорвано
Для тупого:
Скорей всего твой клиент после получения ответа откоонективается от сервера, а для нового запроса - подрубается.
Совсем для тупого:
Обрабатывай дисконнект от клиента (да и от сервера тоже).
А есть ещё пункт после "Совсем для тупого"? Каким образом...28.01.09 16:06 Автор: Vedrus <Serokhvostov Anton> Статус: Member Отредактировано 28.01.09 16:15 Количество правок: 1
А есть ещё пункт после "Совсем для тупого"? Каким образом это обработать? В предыдущем посте я именно это и спросил. Плюс ко всему, я тоже предположил, что клиент отконнекчивается, поэтому воткнул accept в цикл, в конце цикла ставлю closesocket и shutdown.
Но проблема в том, что касяк наблюдается не на связке прокси-клиент, а на связки прокси-сервер. Вот собственно код:
while (1)
{
sockGameClient = accept(sockProxyServer, NULL, NULL);
// Получить пакет от клиента //
dwBytesTransfered = recv(sockGameClient, szBuf, BUF_SIZE, 0);
// Передать пакет серверу //
dwBytesTransfered = send(sockGameServer, szBuf, dwBytesTransfered, 0);
// Получить пакет от сервера //
dwBytesTransfered = recv(sockGameServer, szBuf, BUF_SIZE, 0);
// Передать пакет клиенту //
dwBytesTransfered = send(sockGameClient, szBuf, dwBytesTransfered, 0);
shutdown(sockGameClient, 2);
closesocket(sockGameClient);
}
---
Это все от лени у тебя28.01.09 16:31 Автор: PS <PS> Статус: Elderman
для категорично тупого:
Варианты использования клиент серверных приложений:
1. Перзистент коннект: клиент коннектиться к серверу и они держат соединение до второго пришествия - под этот вариант и была заточена реализация твоего прокси.
2. Типа Web коннект: один (любой!) из участников, после обмена сообщениями рвет соединение.
Сейчас ты обработал отвал клиента, но забыл, что и сервер может разорвать такое соединение.
Тупое решение для ленивого программера: Затачивать прокси под конкретных участников. В твоем случае в начало цикла ставить акцеп, после акцепта коннект к серверу. сенд-рецив-сенд, и закрытие обоих сокетов.
Нормальное решение: предложено в этой ветке чуть раньше. + твоя голова.
Если соединение разорвано - восстановить его с помощью connect для клиента или accept и ждать для сервера. А ещё можно для каждого сокета создавать отдельную нитку, в которой делать (connect; while not error do (recv;processdata)) - это решит все проблемы28.01.09 16:13 Автор: Ustin <Ustin> Статус: Elderman Отредактировано 28.01.09 16:22 Количество правок: 2
или (для слушающего сокета):
while not terminated do
(
bind; listen;
while not listenererror do forknewthread(accept)
)
- типа того, и работать с полученным в результате акцепта сокетом также как с клиентским
Ты имеешь в виду Fiber?29.01.09 12:42 Автор: Vedrus <Serokhvostov Anton> Статус: Member
Ты имеешь в виду Fiber?
А как тогда определить, что recv передала все данные? В случае с HTTP можно читать переменную content-length, а в общем случае как быть?
Тебе не нужно определять длинны :)29.01.09 15:13 Автор: PS <PS> Статус: Elderman
> Ты имеешь в виду Fiber? > А как тогда определить, что recv передала все данные? В > случае с HTTP можно читать переменную content-length, а в > общем случае как быть?
Тебе не нужно определять длинны :)
Тебе нужно получать данные и отсылать их на другое плечо до тех пор, пока соединение не разорвано.
Как только на одном из плечей коннекшен клозед - закрываешь другое плечо.
Ты прелагаешь вызывать recv, пока соединение не оборвётся? Я...29.01.09 15:40 Автор: Vedrus <Serokhvostov Anton> Статус: Member
Ты прелагаешь вызывать recv, пока соединение не оборвётся? Я так пробовал - когда данные передались, а я вызываю ещё один recv, то происходит ЗАВИСАНИЕ.
RTFM: If no incoming data is available at the socket, the recv call waits for data to arrive unless the socket is nonblocking29.01.09 16:55 Автор: Ustin <Ustin> Статус: Elderman
Прочитай хотя-бы главу MSDN "Windows Sockets 2 Application Program Interface" прежде чем классифицировать нормальную работу как ЗАВИСАНИЕ, да ещё и с большой буквы
И попробуй заюзать-таки indy port-mapper - он решает твою задачу в одно движение, + 2 движения - ты меняешь данные на лету
Ты имеешь в виду easy port mapper?29.01.09 18:05 Автор: Vedrus <Serokhvostov Anton> Статус: Member
> Ты имеешь в виду easy port mapper? subj
> PS. Я знаю, что это вполне штатная ситуация, предыдущий > пост был сделан с целью показать, что идея > PS'а в моём случае не сработает. бред, его идея работает. Единственное - её проблематично реализовать в контексте одного потока (как, собсно, и вообще работу с блокирующими сокетами, исключая вырожденные случаи).
Я не зря предлагаю использовать готовый компонент - там реализованы обходы кучи стандартных грабель типа междупоточной синхронизации, на которые есть все шансы наступить сообщений этак через 5, когда к многопоточности ты таки придёшь.
А ещё игруха может закончиться :)
Всё уже придумано до нас (цэ)
> бред, его идея работает. Единственное - её проблематично > реализовать в контексте одного потока (как, собсно, и > вообще работу с блокирующими сокетами, исключая вырожденные > случаи).
вообще-то select спасает отца русской демократии в одном потоке :) Никакой проблематичности не вызывает ни одно поточное, ни много поточная реализация. Хотя многопоточность, конечно, удобней. Особенно, если потоки создавать не win api, а с помощью boost. А еще можно использовать boost::asio - вообще конфетка. Но, самый шик - реализовать это дело на C#, используя вместо System.Threading.Thread ассинхронные делегаты. А вот самый большой изъеб, сделать то же самое с помощью WCF, причем на C++/CLI
Это я все над Вердусом издеваюсь :)
Издёвка удалась, ещё технологий добавил, и вообще меня в...01.02.09 19:12 Автор: Vedrus <Serokhvostov Anton> Статус: Member
Издёвка удалась, ещё технологий добавил, и вообще меня в этом деле закопал. Я нашёл ещё один пример прокси, сейчас разбираюсь с ним.
Попользовал я этот компонент. Всё работает на ура. Но...30.01.09 09:06 Автор: Vedrus <Serokhvostov Anton> Статус: Member Отредактировано 30.01.09 09:07 Количество правок: 1
Попользовал я этот компонент. Всё работает на ура. Но хотелось бы на боле низком уровне с этой задачей разобраться. Я нашёл 2 примера в сети - исходники socks4 proxy на дельфи и ещё нв асинхронных сокетах на C++ пример.
Первый пример не рабочий, а второй тормозит передачу данных. Может кто-нибудь поделится ссылкой на какой-нибудь другой простой прокси?