Форум: "Сети";
Текущий архив: 2003.01.13;
Скачать: [xml.tar.bz2];
ВнизМожно ли перевести сокет из блокирующего в неблокирующий режим? Найти похожие ветки
← →
Repeater (2002-11-01 12:46) [0]Привет!
Такая трабла. Надо бы перевести сокет из блокирующего режима в неблокирующий. Если конкретнее то мне надо сделать такое. Допустим ко мне обращается клиент на серверный сокет. Я в свою очередь создаю блокирующий клиентский сокет и соединяюсь с удаленным сервером. После этого происходит небольшой диалог с удаленным сервером. Диалог состоит в том что я посылаю команды и жду пока сервер ответит. Потом снова посылаю команды и мнова жду ответа. Все это время серверный сокет должен ждать окончания этого диалога, а как только он закончится надо перевести клиентский сокет в неблокирующий режим. Можно такое сделать? Если можно то как?
← →
Digitman (2002-11-01 12:49) [1]см. WSAAsyncSelect(), WSAEventSelect()
← →
Repeater (2002-11-01 13:42) [2]А что можно уже законекченый сокет перевести из одного состояния в другое не разрывая соединения?
← →
Digitman (2002-11-01 13:50) [3]можно. на то и ф-ции эти существуют
← →
Repeater (2002-11-01 16:03) [4]Интересно, а почему тогда в Делфе в ее стандартной компоненте TClientSocket нельзя этого сделать? Они ее до конца не доделали или как?
← →
Digitman (2002-11-01 16:17) [5]Почему нельзя ? Можно.
Хэндл созданного гнезда всегда доступен чтением соотв.св-ва TCustomWinSocket.SocketHandle. А это как раз то, что требуется одним из обязательных параметров указанных ф-ций.
← →
Repeater (2002-11-01 16:43) [6]Ну напрямую нельзя указать TClientSocket.ClientType:=ctNonBlockin. Это вызывает ошибку. А если сделать так как ты сказал, то компонент не будет знать, что тип его сокета поменялся и не назначит соответствующие обработчики сообщений. Тогда уж лучше вообще компоненты не использовать а писать все на АПИ.
← →
Digitman (2002-11-01 16:55) [7]А нахрена тебе все это надо, скажи на милость ? Все, что ты задумал, даже самое изощренное, делается элементарно без всяких переключений, в любом режиме.
К тому же я, в первую очередь, упомянул эти ф-ции вовсе не для того, стобы "скакать козлом" между блок. и неблок. режимами.
В неблок.режиме гнездо в TCustomWinSocket инициализируется Борландом для асинхронной статус-нотификации с использованием оконных сообщений. Не нравится ? Да на здоровье ! Создал гнездо, реинициализировал его с использованием WSAEventSelect() - и получай нотификации иным образом - через сист.объект синхронизации типа Event !
Ну а уж если тебя прижала проблема, что TCustomWinSocket не "знает" о смене режима с блок. на неблок. (или наоборот), возьми да пользуй транспортные гнездовые ф-ции непосредственно - send(), recv() и т.п. Хэндл-то у тебя есть)..
← →
Repeater (2002-11-01 20:07) [8]>А нахрена тебе все это надо, скажи на милость ? Все, что ты
>задумал, даже самое изощренное, делается элементарно без всяких
>переключений, в любом режиме.
Ок. Как тогда лучше всего сделать такое. Есть что то типа прокси. К нему конектятся клиенты, а он отсылает запросы на удаленный сервер. Алгоритм работы такой. Клиент конектится к прокси. Прокси в ответ на это конектится к удаленному серверу, совершает авторизацию и потом служит в качестве гейта для клиентов. То есть все что посылают клиенты отсылает удаленному серверу, а все, что посылает удаленный сервер отсылает клиентам. Я сделал так. При конекте клиента создается блокирующий сокет. Он коннектится к удаленному серверу. Потом происходит некий диалог авторизации между сервером и этим сокетом. Диалог происходит так. прокси отсылает запрос серверу и ждет пока сервер ответит. После считки ответа прокси снова отсылает запрос и ждет ответа. Ну а уже после авторизации сокет переводится в неблок. режим и дальше все идет по такому алгоритму. Когда прокси получает данные от клиента (окну приходит месага) он считывает данные и отсылает серверу. Когда сервер присылает данные для клиента (окну снова приходит месага) прокси считывает эти данные и отсылает их клиенту. Вроде все нормально, но есть одна проблемма. Когда клиент коннектится, то идет коннект от блок. сокета к серверу и пока не пройдет авторизация все замирает потому что все сообщения от сокетов стоят в очереди. Ведь работа идет в процедуре окна. Но я не могу позволить им (другим сокетам) работать пока удаленный сервер отвечает на авторизацию. Ведь среди них будет и тот, в ответ на коннект которого пошла авторизация к серверу и он должен ждать пока сервер ответит. Что можно сдесь сделать? Можно ли как то для каждого клиента открывать отдельную нить и получать все относящиеся к этому клиенту сообщения в нее?
← →
Digitman (2002-11-02 14:44) [9]Используй единый режим и не занимайся ерундой с переключениями.
Все это решаемо в любом из режимов.
Для клиентской стороны прокси останови выбор либо на ctBlocking (с созданием доп.кодового потока для чтения/записи) либо на ctNonBlocking (никакие доп.потоки не нужны)
Для серверной стороны прокси останови выбор либо на stThreadBlocking (доп.кодовые потоки для чтения/записи создаются и диспетчеризуются автоматически компонентом TServerSocket) либо на stNonBlocking (никакие доп.потоки не нужны)
← →
Repeater (2002-11-07 17:10) [10]Спасибо, попробую.
← →
Repeater (2002-11-08 14:37) [11]В чем может быть проблема? Создаю сокет
Var rmaddr:TSockAddrIn;
CliSock:=TSocket;
Begin
rmaddr.sin_family := AF_INET;
rmaddr.sin_addr.s_addr := inet_addr(PChar("10.0.0.1));
rmaddr.sin_port := htons(1080);
CliSock := socket(AF_INET,SOCK_STREAM,0);
..............
Но все время почему то получаю CliSock = INVALID_SOCKET.
Хотя точно известно, что на машине 10.0.0.1 есть открытый порт 1080. По крайней мере TClientSocket без проблем коннектится.
← →
Digitman (2002-11-08 14:53) [12]
> Создаю сокет
Прежде чем обращаться к любым ф-циям из состава WinsockAPI, необходимо инициализировать сессию вызовом WSAStartup(). завершение сессии - соответственно WSACleanup()
> Хотя точно известно, что на машине 10.0.0.1 есть открытый
> порт 1080
Вызов ф-ции socket() предназначен ТОЛЬКО для создания гнезда.
Для осуществления попытки коннекта к целевому хосту/сервису необходимо вывзвать ф-цию connect()
← →
Repeater (2002-11-08 14:54) [13]Последний вопрос отменяется. Уже нашел ошибку.
← →
Repeater (2002-11-08 14:58) [14]Такой еще вопрос. Когда вызываю функцию
WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
почему то сразу же происходит переход на последнюю строчку функции, которая вызвала WSAEventSelect. То же самое происходит если вызвать функцию WSACreateEvent.
← →
Digitman (2002-11-08 15:12) [15]
> переход на последнюю строчку функции
Как это понимать ?
← →
Repeater (2002-11-08 15:34) [16]А вот так. Если смотреть Делфовым дебагером, то сразу же после вызова этой функции, внутри моей функции, весь последующий код пропускается и происходит скачок на последнюю строчку.
← →
Digitman (2002-11-08 15:42) [17]
> весь последующий код пропускается
Какой код-то ?? "Догадайся , мол, сама" ?)
← →
Repeater (2002-11-08 15:47) [18]Хорошо. Привожу полный код.
Function ConnectToProxy:Boolean;
Var rmaddr:SOCKADDR_IN;
sd:String;
p:pointer;
Begin
Result:=False;
rmaddr.sin_family := AF_INET;
rmaddr.sin_addr.s_addr := inet_addr(PChar(OUT_IP));
rmaddr.sin_port := htons (OUT_PORT);
CliSock := socket(AF_INET,SOCK_STREAM,0);
if CliSock = INVALID_SOCKET Then MessageBox(MainWnd,"INVALID_SOCKET","Socker Error!!!",0);
MainEvent:=CreateEvent(0,True,False,"1234567");
connect(CliSock, rmaddr,sizeof(rmaddr));
WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
WSAWaitForMultipleEvents(1,@MainEvent,False,INFINITE,False);
sd:=#10#26#134#87;
p:=@sd[1];
Send(CliSock,p^,Length(sd),0);
WSAWaitForMultipleEvents(1,@MainEvent,False,INFINITE,False);
Recv(CliSock,buf,MAX_DATA,0);
sd:=#5#1#0#1#149#16#9#22#31#144;
p:=@sd[1];
Send(CliSock,p^,Length(sd),0);
WSAWaitForMultipleEvents(1,@MainEvent,False,INFINITE,False);
Recv(CliSock,buf,10,0);
If buf[1]<>#0 Then Begin
MessageBox(MainWnd,PChar("Cant connect"+#13#10+"Error # "+Int2Str(Ord(buf[1]))),"Error",0);
Exit;
End;
WSAAsyncSelect(CliSock,MainWnd,WM_ASYNC_PROXYEVENT, FD_ACCEPT or FD_READ or FD_CLOSE);
Result:=True;
End;
Ну так вот после вызова
WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
Сразу же осуществляется переход на последнюю строчку
Result:=True;
← →
Repeater (2002-11-08 15:49) [19]Причем WSAGetLastError возвращает 0.
← →
Digitman (2002-11-08 15:56) [20]Быть того не может)
Это - раз.
Второе. Ты в курсе, что практически ВСЕ вызовы WinsockAPI являют собой вызовы ф-ций, а у ф-ции возвращают результат ?
Где у тебя анализ результатов этих ф-ций ? За исключением socket() ? Где (опять же !) вызов WSAStartup(), WSACleanup() ?
Прокомментируй КАЖДУЮ строчку в своем коде - где, что, для чего делаешь и какой результат от вызова очер.ф-ции из состава WinsockAPI в своем коде ты ожидаешь...
← →
Repeater (2002-11-08 16:11) [21]>Быть того не может)
Я знаю, но факт налицо.
>Второе. Ты в курсе, что практически ВСЕ вызовы WinsockAPI
>являют собой вызовы ф-ций, а у ф-ции возвращают результат ?
Да, знаю. Но этот результат может быть опущен, компилятор позволяет это делать. Это во первых. А во вторых результат, возвращаемый этой функцией, я уже проверял. Он равен 0. И в третьих если бы была какая то ошибка то WSAGetLastError должен бы вернуть код ошибки, а он возвращает 0.
>Где (опять же !) вызов WSAStartup(), WSACleanup().
Они вызываются при инициализации приложения за пределами этой функции. Поэтому этих вызовов нет в самой функции, но эти вызовы точно производятся.
>Прокомментируй КАЖДУЮ строчку в своем коде - где, что, для чего
>делаешь и какой результат от вызова очер.ф-ции из состава
Да причем здесь коментарии. Весь остальной код не имеет значения ни для кого кроме меня. Это простой диалог моей проги с сервером. Тем болле, что он почему-то пропускается. Но могу привести коментарии первой части функции, если надо.
Function ConnectToProxy:Boolean;
Var rmaddr:SOCKADDR_IN;
sd:String;
p:pointer;
Begin
//Если возникнет какя то ошибка автоматически возвращаем False
Result:=False;
//Заполняем структуру для соединения с сервером
rmaddr.sin_family := AF_INET;
rmaddr.sin_addr.s_addr := inet_addr(PChar(OUT_IP));//адрес
rmaddr.sin_port := htons (OUT_PORT);//порт
//создаем сокет
CliSock := socket(AF_INET,SOCK_STREAM,0);
//если ошибка показываем сообщение
if CliSock = INVALID_SOCKET Then MessageBox(MainWnd,"INVALID_SOCKET","Socker Error!!!",0);
//создаем event для ожидания ответта от сервера
MainEvent:=CreateEvent(0,True,False,"1234567");
//коннектимся к серверу
connect(CliSock, rmaddr,sizeof(rmaddr));
//выбираем блокируемый режим (устанавливаем event, который будет срабатывать в случае) если сервер вернул результат
WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
//ждем соединения с сервером
WSAWaitForMultipleEvents(1,@MainEvent,False,INFINITE,False);
//когда соединились отсылаем запрос
sd:=#10#26#134#87;
p:=@sd[1];
Send(CliSock,p^,Length(sd),0);
//ждем ответа
WSAWaitForMultipleEvents(1,@MainEvent,False,INFINITE,False);
//как только сервер ответил считываем его ответ
Recv(CliSock,buf,MAX_DATA,0);
...................
← →
Polevi (2002-11-09 14:56) [22]//коннектимся к серверу
connect(CliSock, rmaddr,sizeof(rmaddr));
//выбираем блокируемый режим (устанавливаем event, который будет срабатывать в случае) если сервер вернул результат
WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
местами поменяй
← →
Digitman (2002-11-10 08:25) [23]
> результат, возвращаемый этой функцией, я уже проверял. Он
> равен 0
Какой функции ?
ты потрудись-таки взглянуть в исх.код TCustomWinSocket и обрати внимание, что при вызове практически ЛЮБОЙ Winsock-ф-ции Борланд либо явно проверяет результат ее выполнения либо это делается в ф-ции CheckWSAResult(). Считаешь , что это бред сивой кобылы ? Борланд с дури это делает, по-твоему, и ты умней его, когда игнорируешь результаты, считая их ВСЕГДА только такими, какими тебе хочется из видеть ?
Какой вообще смысл в установке неблок.режима, если в конеч. итоге весь этот твой код будет работать синхронно из-за блокировки выполнения в момент вызова ф-ций ожидания трансп.событий ?
Вникни в то, что говорит <Polevi>. Сначала гнездо переводится в некий режим, а уж затем вызываются прочие ф-ции, результат работы которых ЗАВИСИТ от режима
← →
Repeater (2002-11-11 14:16) [24]2 Polevi
Поменял, результат тот же.
2 Digitman
>Какой функции ?
WSAEventSelect. Я проверяю ее результат. Но я не могу проверять ее результат непосредственно, так как весь код, какой бы он ни был, после этой функции пропускается и осуществляется переход на последнюю строчку. Пока я проверяю ее так
err:=WSAEventSelect(...);
А потом после выполнения и перехода на последнюю строчку жму Ctrl-F7 и в окне пишу err. Значение этой переменной равно 0 Значит ошибки нету. Также вызываю там же WSAGetLastError и тоже получаю 0.
>ты потрудись-таки взглянуть в исх.код TCustomWinSocket и обрати
>внимание, что при вызове практически ЛЮБОЙ Winsock-ф-ции
>Борланд либо явно проверяет результат ее выполнения либо это
>делается в ф-ции CheckWSAResult(). Считаешь , что это бред>
>сивой кобылы ?
Нет я так не считаю, но сколько я не искал я не нашел вызова этой функции ни в одном исходнике от Борланда. Может ты имел ввиду CheckSocketResult. Но она делает проверку результата на 0, а я и сам это делаю, но как я уже выше говорил, получаю 0, то есть - нет ошибки.
>Какой вообще смысл в установке неблок.режима, если в конеч.
>итоге весь этот твой код будет работать синхронно из-за
>блокировки выполнения в момент вызова ф-ций ожидания
>трансп.событий ?
Хорошо, объясню еще раз. Клиент коннектится. Я в свою очередь коннекчусь к серверу и провожу с ним небольшой диалог. Во время диалога я задаю серверу команды, а он отвечает. И я должен дождаться ответа сервера. А это возможно только в блок. режиме. Все это время клиент должен ждать когда же ему ответят. А как только я договорюсь с сервером я перехожу в прозрачный режим. Тоесть перехожу в неблок режим и действую так. Пришла инфа от клиента - передаю ее серверу. Пришла инфа от сервера - передаю ее клиенту.
Причем у меня не один а допустим 10 клиентов одновременно подконнекчиваются.
← →
Digitman (2002-11-11 14:23) [25]Я, похоже, догадываюсь, почему у тебя че-то куда-то там "скачет"
Ты самостоятельно импортируешь ф-ции, отсутствующие в составе деклараций в Winsock.pas ? Ведь декларации WSAEventSelect, WSACreateEvent там отсутствуют. Или ты пользуешь Winsock2.pas ?
Если "вручную" импортируешь, покажи, как ты это делаешь.
← →
Repeater (2002-11-11 14:34) [26]Использую такие юниты
winsock, sconnect, ScktComp;
Вручную импортирую только такую функцию
Function WSAWaitForMultipleEvents(cEvents:DWord;const lpEvents:PDWORD;fWaitAll:Boolean;dwTimeOut:DWORD;fAlertable:Boolean):DWORD; external "ws2_32.dll" name "WSAWaitForMultipleEvents";
← →
Repeater (2002-11-11 14:38) [27]Ага, я кажись тоже понял. Сначала наверное надо было выполнить LoadWinSock2 из модуля sconnect.
← →
Digitman (2002-11-11 14:46) [28]Вот она-то (WSAWaitForMultipleEvents) как раз тебе на хрен не нужна) ... Довольно бестолковая ф-ция, и ее с гораздо большей эффективностью и успехом заменяют MsgWaitForMultipleObjects() + WSAEnumNetworkEvents()
та-а-ак ... ну и ? Откуда у тебя взялись ни с того ни с сего декларации и актуальные точки входа для ф-ций WSAEventSelect, WSACreateEvent, если НИ явно НИ неявно они у тебя нигде не присутствуют ? Раз ты не используешь Winsock21.pas ?
Куда, по какому адресу, спрашивается, будет передано управление при вызове той же WSAEventSelect, если нигде НИ статически НИ динамически не вызывалась GetProcAddr() для этой (и иных нестандартных для Winsock.pas) ф-ции ?
← →
Repeater (2002-11-11 14:59) [29]Ладно, по поводу WSAWaitForMultipleEvents я еще подумаю. Попробую твой вариант.
По поводу точек входа смотри в sconnect.pas.
var
WSACreateEvent: function: THandle stdcall;
WSAResetEvent: function(hEvent: THandle): Boolean stdcall;
WSACloseEvent: function(hEvent: THandle): Boolean stdcall;
WSAEventSelect: function(s: TSocket; hEventObject: THandle; lNetworkEvents: Integer): Integer stdcall;
................
function LoadWinSock2: Boolean;
const
DLLName = "ws2_32.dll";
begin
Result := hWinSock2 > HINSTANCE_ERROR;
if Result then Exit;
hWinSock2 := LoadLibrary(PChar(DLLName));
Result := hWinSock2 > HINSTANCE_ERROR;
if Result then
begin
WSACreateEvent := GetProcAddress(hWinSock2, "WSACreateEvent");
WSAResetEvent := GetProcAddress(hWinSock2, "WSAResetEvent");
WSACloseEvent := GetProcAddress(hWinSock2, "WSACloseEvent");
WSAEventSelect := GetProcAddress(hWinSock2, "WSAEventSelect");
end;
end;
Это ответ на твой вопрос?
← →
Digitman (2002-11-11 15:02) [30]Да, это ответ, если ты используешь sconnect.pas .
А вот нахрена он тебе нужен, я пока не пойму. Прокомментируй.
← →
Repeater (2002-11-11 15:42) [31]Мне вообще то не sconnect.pas нужен. Мне просто нужны были некоторые функции и я воспользовался тем что было.
Если у тебя есть какие либо другие модули (pas) с декларациями WinSocks2-функций, то, пожалуйста, пришли их мне на адрес aos@inbox.ru
← →
Digitman (2002-11-11 15:50) [32]набери в www.filesearch.com модель поиска "winsock2.pas" и качай себе на здоровье !
← →
Repeater (2002-11-11 16:37) [33]Я скачал его, но мне кажется, что он какой то кривой. Например там не так описана функция connect и другие функции. В результате теперь ф-ция connect не хочет коннектиться и всегда возвращает ошибку. А старая функция connect работала без проблем
← →
Digitman (2002-11-11 17:03) [34]
> он какой то кривой
> там не так описана функция connect
Чушь.
Winsock.pas :
function connect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer; stdcall;
Winsock2.pas :
function connect( const s: TSocket; const name: PSockAddr; namelen: Integer): Integer; stdcall;
Где ПРИНЦИПИАЛЬНАЯ разница ?
← →
Repeater (2002-11-11 17:23) [35]Я наткнулся на такое.
Если делать так
err:=WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
gle:=WSAGetLastError;
If err<>0 Then MessageBox(MainWnd,"WSAEvent Failed","Socker Error!!!",0);
err:=connect(CliSock, @rmaddr,sizeof(rmaddr));
gle:=WSAGetLastError;
То connect вызывает ошибку (err=4294967295; gle=10035)
А если не вызывать WSAEventSelect, то connect проходит без ошибок.
← →
Digitman (2002-11-11 17:41) [36]Ну и долго ты эксперементировать будешь еще ?
WSAEWOULDBLOCK = 10035
Не выдумывай.
WSAEventSelect() не может вернуть такой ошибки
Вот черным по белому описание ошибок, возвращаемых ф-цией :
Error Codes
WSANOTINITIALISED A successful WSAStartup must occur before using this function.
WSAENETDOWN The network subsystem has failed.
WSAEINVAL Indicates that one of the specified parameters was invalid, or the specified socket is in an invalid state.
WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAENOTSOCK The descriptor is not a socket.
У тебя полная путаница с логикой последовательности вызова ф-ций
err:=WSAEventSelect(..); // вызвали ф-цию , сохранили результат
If err<>0 Then ; если результат = SOCKET_ERROR, то выясняем причину отказа
begin
gle:=WSAGetLastError; // вот она - причина ! Код отказа !
... здесь что-то предпринимаем, в зависимости от кода отказа
end
else
.. все ОК, движемся дальше
← →
Repeater (2002-11-11 17:56) [37]Разве я сказал, что WSAEventSelect() возвращает эту ошибку? Я же сказал, что connect возвращает эту ошибку. А WSAEventSelect() возвращает 0, как и WSAGetLastError.
Ладно, более подробно. После выполнения такого кода
err:=WSAEventSelect(CliSock,MainEvent, FD_CONNECT or FD_READ or FD_CLOSE);
gle:=WSAGetLastError;
If err<>0 Then MessageBox(MainWnd,"WSAEvent Failed","Socker Error!!!",0);
err:=connect(CliSock, @rmaddr,sizeof(rmaddr));
gle:=WSAGetLastError;
err=4294967295; gle=10035
(После вызова WSAEventSelect err=0;gle=0;)
После такого кода
//не вызываем WSAEventSelect
err:=connect(CliSock, @rmaddr,sizeof(rmaddr));
gle:=WSAGetLastError;
err=0; gle=0.
Так более понятно?
← →
Digitman (2002-11-11 18:04) [38]последовательность д.б. такова :
- инициировать сессию (WSAStartup)
- создать гнездо (socket)
- создать событие (WSACreateEvent)
- ассоциировать гнездо с событием (WSASelectEvent)
- попытка коннекта (connect), результат практически всегда равен -1 и WSAGetLastError() = 10035, и это нормально для неблок.режима
- циклическое ожидание сигнала события с возможным параллельным ожиданием оконных сообщений (MsgWaitForMultipleObjects)
- анализ и обработка сетевых событий (WSAEnumNetworkEvents) + анализ и диспетчеризация/обработка оконных сообщений (если нужно)
...
БЕЗУСЛОВНЫЕ ШАГИ :
- закрытие гнезда (closesocket)
- закрытие события (closehandle)
- завершение сессии (WSACleanup)
любой из шагов должен сопровождаться анализом результата и следом, если необходимо, кодом отказа
← →
Digitman (2002-11-11 18:06) [39]То, что connect() возвращает WSAEWOULDBLOCK в данной ситуации - это АБСОЛЮТНО НОРМАЛЬНО для неблок.режима !
Бросай слепые эксперименты и читай внимательно документацию по Winsock.
← →
Repeater (2002-11-11 18:12) [40]>То, что connect() возвращает WSAEWOULDBLOCK в данной ситуации -
>это АБСОЛЮТНО НОРМАЛЬНО для неблок.режима !
Да, я это тоже в MSDN читал. Но тогда у меня все остальное не работает. WSAWaitForMultipleEvents, Send и recv возвращают ошибки.
>- циклическое ожидание сигнала события с возможным параллельным
>ожиданием оконных сообщений (MsgWaitForMultipleObjects)
Вот как это сделать? Это меня больше всего интересует.
Страницы: 1 2 вся ветка
Форум: "Сети";
Текущий архив: 2003.01.13;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.009 c