Fonte original: "Tecnologia de programação de rede Windows" Capítulo 8 Modelo de porta concluído
Como o livro original é acompanhado pelo código C, eu o traduzi para o código Delphi.
Entre eles, Winsock2.Pas não está incluído em Delphi.
Conclusão do programa;
{$ Apptype Console}
usos
Sysutils,
Winsock2 em 'Winsock2.Pas',
Mains em 'Mains.pas';
Começar
principal();
fim.
// Nome do módulo: iocmmplt.cpp
//
// Descrição:
//
// Esta amostra ilustra como desenvolver um servidor de eco simples
// Aplicativo usando o modelo de E/S da porta completa
// A amostra é implementada como um aplicativo em estilo de console e simplesmente imprime
// mensagens quando as conexões são estabelecidas e removidas do servidor.
// O aplicativo ouve as conexões TCP na porta 5150 e as aceita
// quando eles chegam.
// simplesmente ecos (é por isso que chamamos de servidor de eco) os dados de volta
// é o formulário original até que o cliente feche a conexão.
//
// 2005-2-5
// cpp converte em delphi pas por Johnson
//
rede de unidades;
interface
usa Windows, Winsock2, Winsock, Sysutils;
const
Porta = 5150;
Data_bufsize = 8192;
tipo
Lpvoid = ponteiro;
Lpper_io_operation_data = ^ per_io_operation_data;
Per_io_operation_data = registro embalado
Sobreposto: sobreposto;
Banco de dados: TWSABUF;
Buffer: Array [0..data_bufsize] de char;
BYTESSEND: DWORD;
BytesRecv: dword;
fim;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = registro embalado
Soquete: tsocket;
fim;
procedimento principal;
Implementação
Função ServerworkerThread (conclusão do LPVOid): DWORD;
procedimento printf (fmt: string; num: inteiro);
Começar
WriteLN (formato (fmt, [num]));
fim;
procedimento principal;
var
InternetAddr: Sockaddr_in;
Ouça: tsocket;
Aceitar: tsocket;
CONCLUSÃO: THANDLE;
SystemInfo: System_info;
Perhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
I: Inteiro;
Recvbytes: dword;
Sinalizadores: dword;
ThreadID: DWORD;
Wsadata: Twsadata;
Ret: dword;
ThreadHandle: Thandle;
Começar
RET: = WSASTARTUP (US $ 0202, WSADATA);
se (ret <> 0) então
Começar
printf ('WSASTARTUP falhou com o erro %d', ret);
Saída;
fim;
// Configure uma porta de conclusão de E/S.
CONCLUSIONGORT: = CREATIONOCIMNCIONCTIONST (Invalid_Handle_Value, 0, 0, 0);
if (conclitoPort = 0) então
Começar
printf ('createIociclortionptionport falhou com o erro: %d', getLasterRor ());
Saída;
fim;
// Determine quantos processadores estão no sistema.
GetSystemInfo (SystemInfo);
// Crie tópicos de trabalhador com base no número de processadores disponíveis no
// Sistema.
para i: = 0 a SystemInfo.dwnumberofProcessors * 2 - 1 do
Começar
// Crie um encadeamento de um trabalhador do servidor e passe a porta de conclusão para o thread.
ThreadHandle: = CreateThread (nil, 0, @ServerworkerThread, Pointer (conclusão),
0, ThreadID);
if (threadHandle = 0) então
Começar
printf ('createThread () falhou com o erro %d', getLasterRror ());
Saída;
fim;
// Feche a alça do fio
CloseHandle (ThreadHandle);
fim;
// Crie um soquete de escuta
Ouça: = wsasocket (AF_INET, SOCK_STREAM, 0, NIL, 0, WSA_FLAG_OVERLAPADO);
se (ouça = inválido_socket) então
Começar
printf ('wsasocket () falhou com erro %d', wsagetLasterror ());
saída;
fim;
Internetaddr.sin_family: = af_inet;
Internetaddr.sin_addr.s_addr: = htonl (inaddr_any);
Internetaddr.sin_port: = htons (porta);
if (bind (ouça, internetAddr, sizeof (internetAddr)) = Socket_error) Então
Começar
printf ('bind () falhou com o erro %d', wsagetLasterRor ());
saída;
fim;
// Prepare o soquete para ouvir
if (winsock.listen (ouça, 5) = soket_error) Então
Começar
printf ('Listen () falhou com o erro %d', wsagetLasterRor ());
saída;
fim
outro
Começar
printf ('servidor ouça na porta = %d ...', porta);
fim;
// Aceite conexões e atribua à porta de conclusão.
enquanto (verdadeiro) faça
Começar
Aceitar: = wSAaccept (ouça, nil, nil, nil, 0);
se (aceitar = soket_error) então
Começar
printf ('wsaaccept () falhou com o erro %d', wsagetLasterror ());
saída;
fim;
// Crie uma estrutura de informações de soquete para se associar ao soquete
Perhandledata: = lpper_handle_data (globalAlloc (gptr, sizeof (per_handle_data)));
se (perhandledata = nil) então
Começar
printf ('globalAlloc () falhou com o erro %d', wsagetLasterror ());
saída;
fim;
// Associar o soquete aceito à porta de conclusão original.
printf ('Número do soquete %d conectado', aceite);
Perhandledata.socket: = aceitou;
if (createioCelictionOport (AceptionPlort, dWord (Perhandledata), 0) = 0) Então
Começar
printf ('createiocicliondingport () falhou com o erro %d', wsagetLasterRor ());
saída;
fim;
// Crie por estrutura de informações do soquete de E/S para se associar ao
// chamada WSARECV abaixo.
Periodata: = lpper_io_operation_data (globalAlloc (gptr, sizeof (per_io_operation_data)));
if (periodata = nil) então
Começar
printf ('globalAlloc () falhou com o erro %d', wsagetLasterror ());
saída;
fim;
Zeromemory ( @periodata.overlapped, sizeof (sobreposto));
Periodata.byTessend: = 0;
Periodata.bytesRecv: = 0;
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
Sinalizadores: = 0;
if (wsarecv (aceite, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = soket_error) então
Começar
if (wsagetLasterror () <> error_io_pending) então
Começar
printf ('wsarecv () falhou com o erro %d', wsagetLasterror ());
saída;
fim
fim;
fim;
fim;
função serverworkerThread (conclusão outportID: lpvoid): dword;
var
CONCLUSÃO: THANDLE;
ByteSTransferred: dword;
// sobreposto: Poverlapped;
Perhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
SendBytes, Recvbytes: DWORD;
Sinalizadores: dword;
Começar
CONCLIPIONPORT: = THANDLE (CONCLUSÃOPORTID);
Resultados: = 0;
enquanto (verdadeiro) faça
Começar
if (getQueedCompletionStatus (concepionport, bytestransferred,
DWORD (Perhandledata), Poverlapped (periodata), infinito) = false) então
Começar
printf ('getQueuedCompletionStatus falhou com o erro %d', getLasterRor ());
saída;
fim;
// primeiro verifique se ocorreu se ocorreu um erro no soquete e, em caso afirmativo
// então feche o soquete e limpe a estrutura Socket_information
// associado ao soquete.
if (bytestransferred = 0) então
Começar
printf ('encerramento do soquete %d/', perhandledata.socket);
if (clossocket (perhandledata.socket) = soket_error) então
Começar
printf ('clossocket () falhou com erro %d', wsagetLasterror ());
saída;
fim;
GlobalFree (DWORD (Perhandledata));
GlobalFree (DWORD (Periodata));
continuar;
fim;
// Verifique se o campo BytesRecv é igual a zero.
// Isso significa que uma chamada WSARECV acabou de ser concluída, então atualize o campo BytesRecv
// com o valor bytestransferred da chamada WSARECV () preenchida.
if (periodata.bytesrecv = 0) então
Começar
Periodata.bytesRecv: = bytestransferred;
Periodata.byTessend: = 0;
fim
outro
Começar
Periodata.byTessend: = periodata.bytessend + bytestransferred;
fim;
if (periodata.bytesrecv> periodata.bytessend) então
Começar
// Publique outra solicitação WSASEND ().
// Como o WSASEND () não é gaurante para enviar todos os bytes solicitados,
// Continue postando as chamadas wsasend () até que todos os bytes recebidos sejam enviados.
Zeromemory (@(periodata.overlapped), sizeof (sobreposto));
Periodata.databuf.buf: = periodata.buffer + periodata.bytessend;
Periodata.databuf.len: = periodata.bytesrecv - periodata.bytessend;
if (wsasend (Perhandledata.socket, @(periodata.databuf), 1, @sendbytes, 0,
@(Periodata.overlapped), nil) = soket_error) então
Começar
if (wsagetLasterror () <> error_io_pending) então
Começar
printf ('wsasend () falhou com erro %d', wsagetLasterror ());
Saída;
fim;
fim;
fim
outro
Começar
Periodata.bytesRecv: = 0;
// Agora que não há mais bytes para enviar postar outra solicitação wsarecv ().
Sinalizadores: = 0;
Zeromemory (@(periodata.overlapped), sizeof (sobreposto));
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
if (wsarecv (perhandledata.socket, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = soket_error) então
Começar
if (wsagetLasterror () <> error_io_pending) então
Começar
printf ('wsarecv () falhou com o erro %d', wsagetLasterror ());
saída;
fim;
fim;
fim;
fim;
fim;
fim.