Fuente original: "Tecnología de programación de red de Windows" Capítulo 8 Modelo de puerto completado
Dado que el libro original está acompañado por el código C, lo traducí al código Delphi.
Entre ellos, Winsock2.pas no está incluido en Delphi.
Finalización del programa;
{$ AppType Console}
usos
Sysutils,
Winsock2 en 'winsock2.pas',
Mains en 'Mains.pas';
Comenzar
principal();
fin.
// Nombre del módulo: iocmmplt.cpp
//
// Descripción:
//
// Esta muestra ilustra cómo desarrollar un servidor de eco simple Winsock
// Solicitud utilizando el modelo de E/S de Puerto Complete.
// La muestra se implementa como una aplicación estilo consola y simplemente imprime
// Mensajes cuando se establecen y se eliminan las conexiones del servidor.
// La aplicación escucha las conexiones TCP en el puerto 5150 y las acepta
// A medida que llegan.
// Simply Echos (es por eso que lo llamamos un servidor ECHO) los datos vuelven a
// Es la forma original hasta que el cliente cierra la conexión.
//
// 2005-2-5
// CPP Convertir a Delphi Pas de Johnson
//
Unidad plena;
interfaz
usa ventanas, winsock2, winsock, sysutils;
estúpido
Puerto = 5150;
Data_bufsize = 8192;
tipo
Lpvoid = puntero;
Lpper_io_operation_data = ^ per_io_operation_data;
Per_io_operation_data = registro empacado
Superpuesto: superpuesto;
Databuf: twsabuf;
Búfer: array [0..data_bufsize] de char;
Bytessend: dword;
BytesRecv: dword;
fin;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = registro empacado
Socket: tsocket;
fin;
procedimiento principal;
Implementación
function ServerWorkerThread (FinalationPortID: LPVoid): DWORD;
procedimiento printf (fmt: string; num: entero);
Comenzar
WriteLn (formato (fmt, [num]));
fin;
procedimiento principal;
varilla
Internetaddr: Sockaddr_in;
Escuchar: tsocket;
Aceptar: tsocket;
FinalationPort: Thandle;
SystemInfo: system_info;
Porhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
I: entero;
Recvbytes: dword;
Banderas: dword;
Threadid: dword;
wsadata: twsadata;
Ret: DWORD;
ThreadHandle: Thandle;
Comenzar
Ret: = wsastartup ($ 0202, wsadata);
if (ret <> 0) entonces
Comenzar
printf ('WSASTARTUP falló con error %d', ret);
Salida;
fin;
// Configurar un puerto de finalización de E/S.
FinalationPort: = createIOCompletionPort (invalid_handle_value, 0, 0, 0);
if (finalationPort = 0) entonces
Comenzar
printf ('createIOCompletionPort falló con error: %d', getLasterRor ());
Salida;
fin;
// Determinar cuántos procesadores hay en el sistema.
GetSystemInfo (SystemInfo);
// crear hilos de trabajadores según la cantidad de procesadores disponibles en el
// Sistema.
para i: = 0 a systeminfo.dwnumberofprocessors * 2 - 1 do
Comenzar
// Cree un hilo de trabajador del servidor y pase el puerto de finalización al hilo.
ThreadHandle: = CreateThread (nil, 0, @ServerworkerThread, Pointer (FinalationPort),
0, threadid);
if (threadhandle = 0) entonces
Comenzar
printf ('createthread () falló con error %d', getLasterRor ());
Salida;
fin;
// Cierre el mango de hilo
CloseHandle (ThreadHandle);
fin;
// Crea un enchufe de escucha
Escuchar: = wsasocket (AF_INET, SOCK_STREAM, 0, NIL, 0, WSA_FLAG_OVERLAPPADO);
if (escuchar = invalid_socket) entonces
Comenzar
printf ('wsasocket () falló con error %d', wsagetLasterRor ());
salida;
fin;
Internetaddr.sin_family: = AF_INET;
Internetaddr.sin_addr.s_addr: = htonl (inAddr_any);
Internetaddr.sin_port: = htons (puerto);
if (bind (escuchar, internetaddr, sizeof (internetaddr)) = socket_error) entonces
Comenzar
printf ('bind () falló con error %d', wsagetLasterRor ());
salida;
fin;
// Prepara el enchufe para escuchar
if (winsock.listen (escuchar, 5) = Socket_error) entonces
Comenzar
printf ('escuchar () falló con error %d', wsagetLasterRor ());
salida;
fin
demás
Comenzar
printf ('Servidor Escuchar en Port = %D ...', puerto);
fin;
// Acepta conexiones y asigna al puerto de finalización.
Mientras (verdadero) haz
Comenzar
Aceptar: = wsaaccept (escuchar, nulo, nulo, nulo, 0);
if (aceptar = Socket_error) entonces
Comenzar
printf ('wsaaccept () falló con error %d', wsagetLasterRor ());
salida;
fin;
// Crear una estructura de información de socket para asociar con el socket
Perhandledata: = lpper_handle_data (globalAlloc (GPTR, sizeOf (per_handle_data)));
if (porhandledata = nil) entonces
Comenzar
printf ('globalAlloc () falló con error %d', wsagetLasterRor ());
salida;
fin;
// Asociar el socket aceptado con el puerto de finalización original.
printf ('número de socket %d conectado', aceptar);
Perhandledata.socket: = Aceptar;
if (createioCompletionPort (Acept, FinalationPort, DWord (Porhandledata), 0) = 0) Entonces
Comenzar
printf ('createIOCompletionPort () falló con un error %d', wsagetLasterRor ());
salida;
fin;
// Crear una estructura de información del socket de E/S para asociarse con el
// Llamada de WSARECV a continuación.
Periodata: = lpper_io_operation_data (globalAlloc (GPTR, sizeOf (per_io_operation_data)));
if (periodata = nil) entonces
Comenzar
printf ('globalAlloc () falló con error %d', wsagetLasterRor ());
salida;
fin;
Zeromemory ( @periodata.Overlapped, sizeof (superpuesto));
Periodata.ByTessend: = 0;
Periodata.bytesRecv: = 0;
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
Banderas: = 0;
if (wsarecv (aceptar, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = Socket_error) entonces
Comenzar
if (wsagetLasterRor () <> error_io_pending) entonces
Comenzar
printf ('wsarecv () falló con error %d', wsagetLasterRor ());
salida;
fin
fin;
fin;
fin;
Function ServerWorkerThread (FinalationPortID: LPVoid): DWord;
varilla
FinalationPort: Thandle;
ByTestransfered: DWord;
// superpuesto: pobreza;
Porhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
SendBytes, Recvbytes: dword;
Banderas: dword;
Comenzar
FinalationPort: = Thandle (FinalationPortID);
Resultados: = 0;
Mientras (verdadero) haz
Comenzar
if (getQueueDCompletionStatus (FinalationPort, ByTestransferred,
DWord (porhandledata), pobreza (periodata), infinito) = falso) entonces
Comenzar
printf ('getqueedCompletionStatus falló con error %d', getLasterRor ());
salida;
fin;
// Primero verifique si se ha producido un error en el enchufe y si es así
// luego cierre el enchufe y limpie la estructura Socket_information
// Asociado con el enchufe.
if (bytestransferred = 0) entonces
Comenzar
printf ('Socket de cierre %d/', Perhandledata.socket);
if (Clossocket (porhandledata.socket) = Socket_error) entonces
Comenzar
printf ('Clossocket () falló con error %d', wsagetLasterRor ());
salida;
fin;
GlobalFree (DWORD (Porhandledata));
GlobalFree (dWord (periodata));
continuar;
fin;
// Verifique si el campo BytesRecv es igual a cero.
// Esto significa que una llamada WSARECV acaba de completar, así que actualice el campo BytesRecv
// con el valor de ByTestransfered de la llamada WSARECV () completa.
if (periodata.bytesRecv = 0) entonces
Comenzar
Periodata.bytesRecv: = byTestransferred;
Periodata.ByTessend: = 0;
fin
demás
Comenzar
Periodata.bytessend: = periodata.bytessend + bytestransferred;
fin;
if (periodata.bytesRecv> periodata.bytessend) entonces
Comenzar
// Publicar otra solicitud wsasend ().
// Dado que wsasend () no está Gauranted para enviar todos los bytes solicitados,
// Continuar publicando llamadas wsasend () hasta que se envíen todos los bytes recibidos.
Zeromemory (@(periodata.Overlapped), sizeOf (superpuesto));
Periodata.databuf.buf: = periodata.buffer + periodata.bytessend;
Periodata.databuf.len: = periodata.bytesRecv - periodata.bytessend;
if (wsasend (porhandledata.socket, @(periodata.databuf), 1, @sendbytes, 0,
@(Periodata.overlapped), nil) = Socket_error) entonces
Comenzar
if (wsagetLasterRor () <> error_io_pending) entonces
Comenzar
printf ('wsasend () falló con error %d', wsagetLasterRor ());
Salida;
fin;
fin;
fin
demás
Comenzar
Periodata.bytesRecv: = 0;
// Ahora que no hay más bytes para enviar otra solicitud wsarecv ().
Banderas: = 0;
Zeromemory (@(periodata.Overlapped), sizeOf (superpuesto));
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
if (wsarecv (porhandledata.socket, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = Socket_error) entonces
Comenzar
if (wsagetLasterRor () <> error_io_pending) entonces
Comenzar
printf ('wsarecv () falló con error %d', wsagetLasterRor ());
salida;
fin;
fin;
fin;
fin;
fin;
fin.