Source d'origine: "technologie de programmation du réseau Windows" Chapitre 8 Modèle de port terminé
Étant donné que le livre original est accompagné de Code C, je l'ai traduit en code Delphi.
Parmi eux, Winsock2.pas n'est pas inclus dans Delphi.
Complétion du programme;
{$ Apptype Console}
usages
Sysutils,
Winsock2 dans 'winsock2.pas',
Secteur dans «Mains.pas»;
Commencer
principal();
fin.
// Nom du module: iocmmplt.cpp
//
// Description:
//
// Cet échantillon illustre comment développer un simple serveur d'écho winsock
// Application utilisant le modèle d'E / S du port complet.
// L'échantillon est implémenté comme une application de style console et simplement imprime
// Messages lorsque les connexions sont établies et supprimées du serveur.
// l'application écoute les connexions TCP sur le port 5150 et les accepte
// à leur arrivée.
// fait simplement écho (c'est pourquoi nous appelons cela un serveur d'écho) les données
// C'est un formulaire d'origine jusqu'à ce que le client ferme la connexion.
//
// 2005-2-5
// CPP Converti à Delphi PAS par Johnson
//
secteur unitaire;
interface
Utilise Windows, Winsock2, Winsock, Sysutils;
const
Port = 5150;
Data_bufSize = 8192;
taper
LpVoid = pointeur;
LPPER_IO_OPERATION_DATA = ^ PER_IO_OPERATION_DATA;
Per_io_operation_data = enregistrement emballé
Chevauché: chevauché;
Databuf: Twsabuf;
Buffer: Array [0..DATA_BUFSIZE] de Char;
Bytessend: dword;
BytesRecv: dword;
fin;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = enregistrement emballé
Socket: Tsocket;
fin;
procédure principale;
Mise en œuvre
fonction ServerworkerThread (CompletionportId: lpvoid): dword;
Procédure printf (fmt: string; num: entier);
Commencer
WriteLn (format (fmt, [num]));
fin;
procédure principale;
var
InternetAddr: sockaddr_in;
Écoutez: Tsocket;
Accepter: Tsocket;
Completionport: Thandle;
SysteMInfo: System_info;
Perhandledata: lpper_handle_data;
Periodata: LPPER_IO_OPERATION_DATA;
I: entier;
Recvbytes: dword;
Flags: dword;
ThreadID: dword;
Wsadata: Twsadata;
Ret: DWORD;
Threadhandle: Thandle;
Commencer
Ret: = wsastartup (0202 $, wsadata);
si (ret <> 0) alors
Commencer
printf ('wsastartup a échoué avec l'erreur% d', ret);
Sortie;
fin;
// Configuration d'un port d'achèvement d'E / S.
Completionport: = CreateIoCleTetionport (invalid_handle_value, 0, 0, 0);
if (completionport = 0) alors
Commencer
printf ('CreateIoCletionport a échoué avec erreur:% d', getLasterRor ());
Sortie;
fin;
// déterminer le nombre de processeurs sur le système.
GetSystemInfo (SysteMInfo);
// Créer des threads de travail en fonction du nombre de processeurs disponibles sur le
// Système.
pour i: = 0 à Systeminfo.dwnumberofProcessors * 2 - 1 do
Commencer
// Créez un thread de travailleur de serveur et transmettez le port d'achèvement au thread.
ThreadHandle: = CreateTheRad (nil, 0, @ServerWorkerThread, Pointer (Completionport),
0, threadid);
si (threadhandle = 0) alors
Commencer
printf ('CreateTheread () a échoué avec l'erreur% d', getLasterRor ());
Sortie;
fin;
// Fermez la poignée du fil
CloseHandle (ThreadHandle);
fin;
// Créer une prise d'écoute
Écouter: = wsasocket (af_inet, sock_stream, 0, nil, 0, wsa_flag_overlapt);
if (écouter = invalid_socket) alors
Commencer
printf ('wsasocket () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
Internetaddr.sin_family: = af_inet;
Internetaddr.sin_addr.s_addr: = htonl (inaddr_any);
InternetAddr.sin_port: = htons (port);
if (lier (écouter, InternetAddr, sizeof (InternetAdDdr))) = socket_error) alors
Commencer
printf ('bind () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
// Préparez la prise à l'écoute
if (winsock.Listen (écouter, 5) = socket_error) alors
Commencer
printf ('écouter () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin
autre
Commencer
printf ('Server écouter sur port =% d ...', port);
fin;
// Accepter les connexions et attribuer au port d'achèvement.
tandis que (vrai) faire
Commencer
Accepter: = wsaaccept (écouter, nil, nil, nil, 0);
if (accepte = socket_error) alors
Commencer
printf ('wsaaccept () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
// Créer une structure d'information à douille pour associer à la prise
Perhandledata: = lpper_handle_data (globalalloc (gptr, sizeof (per_handle_data)));
si (parhandledata = nil) alors
Commencer
printf ('globalalloc () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
// Associer la prise acceptée au port d'achèvement d'origine.
printf ('socket numéro% d connecté', accepter);
Perhandledata.socket: = accepter;
if (CreateIOCletionport (accepter, completionport, dword (parhandledata), 0) = 0) puis
Commencer
printf ('CreateIoCletionport () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
// Créer par structure d'informations sur socket d'E / S pour associer au
// Appel wsarecv ci-dessous.
Periodata: = LPPER_IO_OPERATION_DATA (GlobalAlloc (gptr, sizeof (per_io_operation_data)));
si (periodata = nil) alors
Commencer
printf ('globalalloc () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
Zeromemory (@ periodata.Overlapp, sizeof (chevauché));
Periodata.bytessend: = 0;
Periodata.BytesRecv: = 0;
PilaTa.databuf.len: = data_bufSize;
Earodata.databuf.buf: = @ periodata.buffer;
Flags: = 0;
if (wsarecv (accepter, @ (periodata.databuf), 1, @recvbytes, @flags,
@ (Periodata.overlaps), nil) = socket_error) puis
Commencer
if (wsagetlasterror () <> error_io_pending) alors
Commencer
printf ('wsarecv () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin
fin;
fin;
fin;
fonction ServerworkerThread (CompletionportId: lpVoid): dword;
var
Completionport: Thandle;
BytestransFerred: DWORD;
// chevauché: pauvrent;
Perhandledata: lpper_handle_data;
Periodata: LPPER_IO_OPERATION_DATA;
SendBytes, recvbytes: dword;
Flags: dword;
Commencer
Completionport: = Thandle (complétionportId);
Résultats: = 0;
tandis que (vrai) faire
Commencer
if (getQueuedCompletionStatus (Completionport, bytestransfert,
Dword (parhandledata), poverlapp (periodata), infinite) = false) puis
Commencer
printf ('getQueuedCompletionStatus a échoué avec l'erreur% d', getlasterror ());
sortie;
fin;
// Vérifiez d'abord si une erreur s'est produite sur la prise et si oui
// Fermez ensuite la prise et nettoyez la structure Socket_Information
// associé à la prise.
if (bytestransferred = 0) alors
Commencer
printf ('fermeture socket% d /', perhandledata.socket);
if (clossocket (perhandledata.socket) = socket_error) alors
Commencer
printf ('clossocket () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
GlobalFree (DWORD (PerHandleData));
GlobalFree (DWORD (periodata));
continuer;
fin;
// Vérifiez si le champ BytesRecv est égal à zéro.
// Cela signifie qu'un appel wsarecv vient de terminer, alors mettez à jour le champ BytesRecv
// avec la valeur bytestransserred de l'appel wsarecv () terminé.
if (periodata.BytesRecv = 0) alors
Commencer
Periodata.BytesRecv: = bytestransferred;
Periodata.bytessend: = 0;
fin
autre
Commencer
Periodata.bytessend: = periodata.bytessend + bytestransferred;
fin;
if (periodata.BytesRecv> peloadata.bytessend) alors
Commencer
// publier une autre demande wsasend ().
// puisque wsasend () n'est pas accéléré pour envoyer tous les octets demandés,
// Continuez à publier des appels wsasend () jusqu'à ce que tous les octets reçus soient envoyés.
Zeromemory (@ (periodata.Overlaplap), sizeof (chevauché));
Periodata.databuf.buf: = periodata.buffer + periodata.bytessend;
Periodata.databuf.len: = periodata.bytesrecv - peloadata.bytessend;
if (wsasend (perhandledata.socket, @ (periodata.databuf), 1, @SendBytes, 0,
@ (Periodata.overlaps), nil) = socket_error) puis
Commencer
if (wsagetlasterror () <> error_io_pending) alors
Commencer
printf ('wsasend () a échoué avec l'erreur% d', wsagetlasterror ());
Sortie;
fin;
fin;
fin
autre
Commencer
Periodata.BytesRecv: = 0;
// Maintenant, il n'y a plus d'octets pour envoyer un poste de demande une autre demande wsarecv ().
Flags: = 0;
Zeromemory (@ (periodata.Overlaplap), sizeof (chevauché));
PilaTa.databuf.len: = data_bufSize;
Earodata.databuf.buf: = @ periodata.buffer;
if (wsarecv (perhandledata.socket, @ (periodata.databuf), 1, @recvbytes, @flags,
@ (Periodata.overlaps), nil) = socket_error) puis
Commencer
if (wsagetlasterror () <> error_io_pending) alors
Commencer
printf ('wsarecv () a échoué avec l'erreur% d', wsagetlasterror ());
sortie;
fin;
fin;
fin;
fin;
fin;
fin.