Оригинальный источник: «Технология программирования сети Windows». Глава 8 Заполненная модель порта
Поскольку оригинальная книга сопровождается C -кодом, я перевел ее в код Delphi.
Среди них winsock2.pas не включен в Delphi.
Программа завершение;
{$ Apptype Console}
Использование
Sysutils,
Winsock2 в 'winsock2.pas',
Сеть в «mains.pas»;
Начинать
основной();
конец.
// Имя модуля: iocmmplt.cpp
//
// Описание:
//
// Этот образец иллюстрирует, как разработать простой Winsock Sever Server Echo Winsock
// Применение с использованием модели ввода/вывода полного порта
// образец реализован в качестве приложения в стиле консоли и просто печатать
// Сообщения, когда соединения установлены и удаляются с сервера.
// Приложение прослушивает подключения TCP на порту 5150 и принимает их
// как они прибывают.
// просто эхо (вот почему мы называем его сервером Echo), данные обратно
// Это исходная форма, пока клиент не закроет соединение.
//
// 2005-2-5
// CPP конвертируется в Delphi Pas от Johnson
//
подразделение сети;
интерфейс
использует Windows, Winsock2, Winsock, Sysutils;
констант
Порт = 5150;
Data_bufsize = 8192;
тип
Lpvoid = pointer;
Lpper_io_operation_data = ^ per_io_operation_data;
Per_io_operation_data = упакованная запись
Перекрывается: перекрыт;
Databuf: twsabuf;
Буфер: массив [0..data_bufsize] char;
Bytessend: DWORD;
BytesRecv: DWORD;
конец;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = упакованная запись
Сокет: Tsocket;
конец;
процедура основной;
Выполнение
Function ServerWorkerThread (oppetionPortId: LPVoid): DWORD;
Процедура printf (fmt: string; num: integer);
Начинать
Writeln (формат (fmt, [num]));
конец;
процедура основной;
вар
InternetAddr: sockaddr_in;
Слушайте: Tsocket;
Принять: Tsocket;
Завершение порта: Тандл;
SystemInfo: System_Info;
Perhandledata: lpper_handle_data;
PEORIONATA: LPPER_IO_OPERATION_DATA;
я: целое число;
Recvbytes: dword;
Флаги: DWORD;
ThreadId: DWORD;
Wsadata: Twsadata;
RET: DWORD;
Threathandle: Thandle;
Начинать
Ret: = wsaStartup ($ 0202, wsadata);
if (ret <> 0), тогда
Начинать
printf ('wsaStartup не удалось с ошибкой %d', ret);
Выход;
конец;
// Настройка порта завершения ввода/вывода.
OpplionPort: = createioCOMPLUICEPORT (Invalid_Handle_Value, 0, 0, 0);
if (oppetionPort = 0), тогда
Начинать
printf ('createioCOmplaceOrt с ошибкой с ошибкой: %d', getLasterRor ());
Выход;
конец;
// Определите, сколько процессоров в системе.
GetSysteminfo (SystemInfo);
// Создать рабочие потоки на основе количества процессоров, доступных на
// Система.
для i: = 0 to SystemInfo.dwnumberofProcessors * 2 - 1 DO
Начинать
// Создание потока работника сервера и передать порт завершения в поток.
ThreatHandle: = CreateThread (Nil, 0, @ServerWorkerThread, pointer (opplionPort),
0, ThreadId);
if (threadhandle = 0) тогда
Начинать
printf ('createThread () не удастся с ошибкой %d', getLasterRor ());
Выход;
конец;
// закройте ручку резьбы
Крупный руск (Threadhandle);
конец;
// Создать сокет прослушивания
Слушайте: = wsaSocket (af_inet, sock_stream, 0, nil, 0, wsa_flag_overlapped);
if (слушать = valud_socket), тогда
Начинать
printf ('wsaSocket () сбой с ошибкой %d', wsagetlasterror ());
Выход;
конец;
InternetAddr.sin_family: = af_inet;
InternetAddr.sin_addr.s_addr: = htonl (inaddr_any);
InternetAddr.sin_port: = htons (порт);
if (bind (слушание, интернет -промышленность, sizeof (InternetAddr)) = socket_error) тогда
Начинать
printf ('bind () сбой с ошибкой %d', wsagetlasterror ());
Выход;
конец;
// подготовить сокет для прослушивания
if (winsock.listen (слушать, 5) = socket_error) тогда
Начинать
printf ('Listen () не удастся с ошибкой %d', wsagetlasterror ());
Выход;
конец
еще
Начинать
printf ('сервер прослушивает порт = %d ...', порт);
конец;
// Принять соединения и присваивать порту завершения.
пока (правда) делай
Начинать
Принять: = wsaAccept (слушать, ноль, ноль, ноль, 0);
if (Accept = socket_error) тогда
Начинать
printf ('wsaAccept () не удалось с ошибкой %d', wsagetlasterror ());
Выход;
конец;
// Создать информационную структуру сокета, чтобы связать с сокетом
Perhandledata: = lpper_handle_data (globalalloc (gptr, sizeof (per_handle_data)));
if (perhandledata = nil), тогда
Начинать
printf ('globalalloc () не удался с ошибкой %d', wsagetlasterror ());
Выход;
конец;
// Свяжитесь с принятым сокетом с исходным портом завершения.
printf ('номер сокета %d подключен', принять);
Perhandledata.socket: = принять;
if (createiocomplaceOrt (Accept, opplionPort, dword (perhandledata), 0) = 0) тогда
Начинать
printf ('createiocomplaceorport () не удастся с ошибкой %d', wsagetlasterror ());
Выход;
конец;
// Создание информационной структуры в виде ввода/вывода для связи с
// Вызов WSARECV ниже.
Periodata: = lpper_io_operation_data (globalalloc (gptr, sizeof (per_io_operation_data)));
if (periodata = nil), тогда
Начинать
printf ('globalalloc () не удался с ошибкой %d', wsagetlasterror ());
Выход;
конец;
Zeromemory ( @periodata.overlapped, sizeof (перекрывать));
Periodata.bytessend: = 0;
Periodata.bytesrecv: = 0;
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @teverata.buffer;
Флаги: = 0;
if (wsarecv (Accept, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = socket_error) тогда
Начинать
if (wsagetlasterror () <> error_io_pending) тогда
Начинать
printf ('wsarecv () сбой с ошибкой %d', wsagetlasterror ());
Выход;
конец
конец;
конец;
конец;
Function ServerWorkerThread (opplionPortId: LPVoid): DWORD;
вар
Завершение порта: Тандл;
Bytestransed: DWORD;
// перекрывать: бедный;
Perhandledata: lpper_handle_data;
PEORIONATA: LPPER_IO_OPERATION_DATA;
Sendbytes, Recvbytes: dword;
Флаги: DWORD;
Начинать
OpplionPort: = thandle (oppertionPortId);
Результаты: = 0;
пока (правда) делай
Начинать
if (getQuedCompletionStatus (opplionPort, Bytestransered,
Dword (perhandledata), бедра (периодата), бесконечно) = false) тогда
Начинать
printf ('getQueuedCompletionStatus не удалось с ошибкой %d', getLasterRor ());
Выход;
конец;
// сначала проверьте, произошла ли ошибка в розетке и если да
// затем закройте гнездо и очистите структуру сокета_информации
// связано с гнездом.
if (bytestransferred = 0) тогда
Начинать
printf ('закрытие сокета %d/', perhandledata.socket);
if (clossocket (perhandledata.socket) = socket_error) тогда
Начинать
printf ('clossocket () сбой с ошибкой %d', wsagetlasterror ());
Выход;
конец;
GlobalFree (dword (perhandledata));
GlobalFree (DWORD (PEORIONATA));
продолжать;
конец;
// Проверьте, будет ли поле BAYTESRECV равна нулю.
// это означает, что вызов WSARECV только что завершился, поэтому обновите поле BytesRecv
// с BytestrendsFered значением из завершенного вызова wsarecv ().
if (periodata.bytesrecv = 0) тогда
Начинать
Periodata.bytesrecv: = bytestransferred;
Periodata.bytessend: = 0;
конец
еще
Начинать
Periodata.bytessend: = teverata.bytessend + bytestransferred;
конец;
if (periodata.bytesrecv> tevenata.bytessend) тогда
Начинать
// опубликовать другой запрос wsasend ().
// Поскольку wsasend () не является приглашенным для отправки всех запрашиваемых байтов,
// Продолжить публикацию вызовов wsasend () до тех пор, пока все полученные байты не будут отправлены.
Zeromemory (@(periodata.overlapped), sizeof (перекрывать));
Periodata.databuf.buf: = periodata.buffer + periodata.bytessend;
Periodata.databuf.len: = periodata.bytesrecv - periodata.bytessend;
if (wsasend (perhandledata.socket, @(tevenata.databuf), 1, @sendbytes, 0,
@(Periodata.overlapped), nil) = socket_error) тогда
Начинать
if (wsagetlasterror () <> error_io_pending) тогда
Начинать
printf ('wsasend () не удалось с ошибкой %d', wsagetlasterror ());
Выход;
конец;
конец;
конец
еще
Начинать
Periodata.bytesrecv: = 0;
// теперь, когда больше нет байтов для отправки сообщения о другом запросе wsarecv ().
Флаги: = 0;
Zeromemory (@(periodata.overlapped), sizeof (перекрывать));
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @teverata.buffer;
if (wsarecv (perhandledata.socket, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = socket_error) тогда
Начинать
if (wsagetlasterror () <> error_io_pending) тогда
Начинать
printf ('wsarecv () сбой с ошибкой %d', wsagetlasterror ());
Выход;
конец;
конец;
конец;
конец;
конец;
конец.