Форум: "Сети";
Текущий архив: 2003.01.20;
Скачать: [xml.tar.bz2];
ВнизСообщения сокетов Найти похожие ветки
← →
Repeater (2002-11-19 11:11) [0]Вобщем такой вопрос. У меня организуется прозрачная передача данных от сервера к клиенту и обратно через мою прогу. Для каждого оединения создается нить в которой работает такой цикл.
While not cmd_stop Do Begin //Цикл работает до тех пор пока не получим команду завершить
//Ждем пока придет сообщение
res:=WSAWaitForMultipleEvents(2,@Events,False,1000,False);
Case res Of
WSA_WAIT_EVENT_0:Begin //Client
//Смотрим какие сообщения произошли
res:=WSAEnumNetworkEvents(threadsocket, Events[0], @NetEvnt);
//Если ошибка то глушим нить
If res=SOCKET_ERROR Then CloseThread;
//Если надо читать - читаем
If (NetEvnt.lNetworkEvents and FD_READ)>0 Then Begin
ZeroMemory(@buf,SizeOf(Buf));
//берем данные от клиента
rcv:=recv(threadsocket,Buf,Length(Buf),0);
gle:=WSAGetLastError;
if (rcv=0) or (gle=WSAECONNRESET) then CloseThread;
//отправляем серверу
snd:=send(ProxySock,Buf,rcv,0);
gle:=WSAGetLastError;
If snd=SOCKET_ERROR Then If WSAGetLastError<>WSAEINPROGRESS Then CloseThread;
End;
//Если разорвался коннект, то глушим нить
If (NetEvnt.lNetworkEvents and FD_CLOSE)>0 Then CloseThread;
End;
WSA_WAIT_EVENT_0+1:Begin //Server
//Смотрим какие сообщения произошли
res:=WSAEnumNetworkEvents(ProxySock, Events[1], @NetEvnt);
//Если ошибка то глушим нить
If res=SOCKET_ERROR Then CloseThread;
If NetEvnt.lNetworkEvents=0 Then CloseThread;
//Если надо читать - читаем
If (NetEvnt.lNetworkEvents and FD_READ)>0 Then Begin
ZeroMemory(@buf,SizeOf(Buf));
//берем данные от сервера
rcv:=recv(ProxySock,Buf,Length(Buf),0);
gle:=WSAGetLastError;
if (rcv=0) or (gle=WSAECONNRESET) then CloseThread;
//Отправляем клиенту
snd:=send(threadsocket,Buf,rcv,0);
gle:=WSAGetLastError;
If snd=SOCKET_ERROR Then If WSAGetLastError<>WSAEINPROGRESS Then CloseThread;
End;
//Если разорвался коннект, то глушим нить
If (NetEvnt.lNetworkEvents and FD_CLOSE)>0 Then CloseThread;
End;
End;
end; //end while
В принципе все работает. Только иногда нить зависает. То есть не приходят никакие сообщения, хотя один из сокетов уже закрыт. Может я че не так делаю? Почему не приходят эти сообщения?
← →
Repeater (2002-11-19 11:15) [1]Да, забыл сказать. Ивенты установлены на все события
CliEvent:=WSACreateEvent;
ServEvent:=WSACreateEvent;
res:=WSAEventSelect(ServSock,ServEvent, FD_ALL_EVENTS);
res:=WSAEventSelect(threadsocket,CliEvent, FD_ALL_EVENTS);
Events[0]:=CliEvent;
Events[1]:=ServEvent;
← →
Digitman (2002-11-19 11:32) [2]Где у тебя обработка события FD_WRITE ? У тебя же неблок.режим !
← →
Polevi (2002-11-19 11:44) [3]в дополнение к Digitman © (19.11.02 11:32)
//отправляем серверу
snd:=send(ProxySock,Buf,rcv,0);
gle:=WSAGetLastError;
If snd=SOCKET_ERROR Then If WSAGetLastError<>WSAEINPROGRESS Then CloseThread;
где обработка WASEWOULDBLOCK ??
в этом коде при первом-же переполнении буфера winsock поток завершится, а надо сохранять буфер и пытаться отправить его при первом FD_WRITE
← →
Digitman (2002-11-19 12:07) [4]в дополнение к Polevi © (19.11.02 11:44)
Структура NetworkEvents содержит коды ошибок для каждого из трансп.событий, перечисленных в массиве. Нет смысла запрашивать WSAGetLastError(), ибо, если трансп.метод вызвал ошибку (в т.ч. WASEWOULDBLOCK), возникнет соотв.событие с ненулевым кодом ошибки.
← →
Repeater (2002-11-19 12:18) [5]Спасибо, буду разбираться.
← →
Repeater (2002-11-19 12:21) [6]To Digitman
>>Где у тебя обработка события FD_WRITE ? У тебя же неблок.режим !
А мне это сообщение не нужно. Мне нужно только когда данные придут передать их из одного сокета в другой.
Не, ну может я чего то не понимаю. Обясни, пожалуйста.
← →
Digitman (2002-11-19 12:48) [7]send() не является ф-цией, непосредственно осуществляющей передачу. Этот вызов лишь ставит указанные тобой данные в хвост внутренней передающей очереди гнезда, из головы которой по мере готовности трансп.ресурсов ядром Winsock выбираются данные для факт.попытки отправки. При успешной отправке фрагмента данных из головы очереди в хвосте этой же очереди освобождается ровно столько места, сколько успешно отправлено.
Очередь передачи являет собой внутр.буфер в памяти, контролируемой ядром Winsock. Буфер не "резиновый" и имеет определ.размер. Если ты пытаешься вызовом send() поставить в очередь на передачу данные размером большим, чем позволяет "свободное" в дан.момент "место" в хвосте буфера-очереди, Winsock имеет право отвергнуть полностью или частично запрошенные к постановке в очередь данные.
При полном отвержении (*), если код ошибки = WSAEWOULDBLOCK, это означает, что попытку повтора передачи тех же данных тем же send-вызовом можно будет повторить не ранее, чем возникнет событие FD_WRITE, извещающее об освобождении очереди передачи.
При частичном отвержении допустимо повторно вызвать send() для попытки постановки в очередь оставшегося фрагмента отвергнутых в предыдущем send-вызове данных; можно повторять send-вызов в цикле, пока либо все оставшиеся данные не будут поставлены в очередь, либо см. (*)
← →
Repeater (2002-11-21 17:08) [8]Спасибо за подробное объяснения.
Такой вопрос. Почему у меня сразу на один сокет приходят 2 сообщенеия FD_WRITE и FD_READ. Как их обрабатывать?
← →
Digitman (2002-11-21 17:13) [9]1-й FD_WRITE просто извещает тебя о готовности буфера передачи гнезда. Можешь его проигногировать, если на этот момент нечего передавать.
FD_READ извещает тебя о том, что буфер приема не пуст и ты можешь попытаться прочитать из него (recv) ожидаемый по логике блок данных (но - оч желательно - не более чем rcvbuf_size)
← →
Repeater (2002-11-21 17:21) [10]А откуда взять rcvbuf_size?
← →
Digitman (2002-11-21 17:24) [11]см. WinsockAPI : GetSockOpt()
Страницы: 1 вся ветка
Форум: "Сети";
Текущий архив: 2003.01.20;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.011 c