Рано или поздно у большинства кодеров появляется желание написать какую-нибудь сетевую программу. И у многих начинающих появляется куча вопросов – как, что и чем.… Вот так и я, решив написать что-то простенькое, задумался, а как? Выбор пал на изучение WinSock, так как он предоставляет все возможности и обеспечивает максимальное быстродействие для работы с сетью по сравнению с компонентами-обертками типа Indy, с которым даже ни разу не работа О_о.
Фиг с ними индейцами вернемся к нашим событиям. Events – вещь в какой-то степени удобная и простая. Как обуздать это детище – да в принципе не сложно, но обо всем по порядку. Для начала все как обычно – подготовим библиотеку winsock2:
WSAStartup(MakeWord(2, 2), wsaData);
Создадим сокет для TCP\IP:
hSocket:= WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, 0);
Заполним структуру
SockAddrIn.sin_family:= AF_INET; SockAddrIn.sin_port:= htons(Port); SockAddrIn.sin_addr.s_addr:= inet_addr(‘127.0.0.1’);
А далее перейдем к созданию события с помощью
hEvent:= WSACreateEvent;
После того, как событие создано, его необходимо связать с сокетом, события которого мы хотим обрабатывать. Это делается функцией
Небольшое замечание по поводу привязки обрабатываемых событий, вот так делать нельзя:
hEvent1:= WSACreateEvent; hEvent2:= WSACreateEvent; WSAEventSelect(hSocket, hEvent1, FD_READ); WSAEventSelect(hSocket, hEvent2, FD_WRITE);
Правильно сделать так:
WSAEventSelect(hSocket, hEvent, FD_READ or FD_WRITE);
Теперь, когда обрабатываемые события заданы для сокета, нам необходимо их как-то обрабатывать. Для ожидания событий используется функция
function WSAWaitForMultipleEvents(cEvents: DWORD; lphEvents: PWSAEVENT; fWaitAll: LongBool; dwTimeout: DWORD; fAlertable: LongBool): DWORD; stdcall;
cEvents – количество событий для ожидания;
lphEvents – указатель на массив событий для ожидания;
fWaitAll – определяет будет ли функция оставаться в спящем режиме до тех пор пока не сработают все события;
dwTimeout – определяет как долго ожидать наступления события.
fAlertable – значение, которое определяет, будет ли поток помещается в alertable.
Пример вызова этой функции только одного события:
WSAWaitForMultipleEvents(1, @hEvent, False, WSA_INFINITE, False);
Для того чтобы определить какое событие произошло необходимо вызвать функцию
function WSAEnumNetworkEvents(const s: TSocket; const hEventObject: WSAEVENT; lpNetworkEvent: LPWSANETWORKEVENTS): Integer; stdcall;
В нашем случае она будет выглядеть так:
WSAEnumNetworkEvents(hSocket, hEvent, @NetworkEvents);
Осталось только проверить что за событие и не произошла ли ошибка, в обобщенном виде код примерно такой:
if ((NetworkEvents.lNetworkEvents and FD_xxx)<>0) then begin if (NetworkEvents.iErrorCode[FD_xxx_BIT]<>0) then begin // FD_xxх failed with error: // NetworkEvents.iErrorCode[FD_xxx_BIT] Break; end else begin // FD_xxx is Ok end; end;
Где «xxx» одно из ожидаемых событий READ, WRITE, CONNECT и так далее.
Вот в общем-то и все, ко всему вышесказанному прилагаю небольшой, и не очень красиво сделанный, но работающий пример “программулины”.
Files:
Links:
- Windows Sockets 2
- Tutorials on ‘Advanced’ Winsock 2 Network Programming
- WSAEnumNetworkEvents
- WSAWaitForMultipleEvents
- LPWSANETWORKEVENTS
- WSAEventSelect
- WSACreateEvent
- SockAddr_In
- WSASocket
- WSAStartup
— =Zeus= · 2 Май 2011, 14:21 · #
Спасибо за пример, очень пригодился.