Originalquelle: "Windows Network -Programmierungstechnologie" Kapitel 8 Fertiger Portmodell
Da das Originalbuch von C -Code begleitet wird, habe ich es in den Delphi -Code übersetzt.
Unter ihnen ist Winsock2.pas nicht in Delphi enthalten.
Programmabschluss;
{$ AppType Console}
Verwendung
SYSUTILS,
Winsock2 in 'Winsock2.pas',
Netz in 'mains.pas';
Beginnen
hauptsächlich();
Ende.
// Modulname: iocmmplt.cpp
//
// Beschreibung:
//
// Dieses Beispiel zeigt, wie ein einfacher Echo -Server Winsock entwickelt wird
// Anwendung mit dem vollständigen Port -I/A -Modell
// Beispiel wird als Konsolenanwendung implementiert und druckt einfach aus
// Nachrichten Wenn Verbindungen hergestellt und vom Server entfernt werden.
// Die Anwendung hört auf TCP -Verbindungen auf Port 5150 zu und akzeptiert sie
// Wenn sie ankommen.
// Echos einfach (deshalb nennen wir es einen Echo -Server) die Daten zurück in
// Es ist Originalform, bis der Kunde die Verbindung schließt.
//
// 2005-2-5
// CPP konvertieren von Johnson zu Delphi Pas
//
Einheitsstreiter;
Schnittstelle
Verwendet Windows, Winsock2, Winsock, Sysutils;
Const
Port = 5150;
Data_bufsize = 8192;
Typ
Lpvoid = pointer;
Lpper_io_operation_data = ^ per_io_operation_data;
Per_io_operation_data = verpackter Datensatz
Überlappend: überlappend;
Datenbank: Twsabuf;
Puffer: Array [0..data_bufsize] von char;
Bytessend: DWORD;
ByteRecv: DWORD;
Ende;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = verpackter Datensatz
Sockel: Tsocket;
Ende;
Verfahren Haupt;
Durchführung
FunktionsfertigerThread (CompletionPortID: LPVOID): DWORD;
Prozedur printf (FMT: String; num: Integer);
Beginnen
WriteLN (Format (fmt, [num]));
Ende;
Verfahren Haupt;
var
InternetAddr: Sockaddr_in;
Hören Sie: Tsocket;
Akzeptieren: Tsocket;
Fertigstellungsport: Thandle;
SystemInfo: System_info;
Perhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
I: Ganzzahl;
RecvBytes: DWORD;
Flaggen: DWORD;
ThreadID: DWORD;
Wsadata: Twsadata;
Ret: DWORD;
Fadenhand: Thandle;
Beginnen
Ret: = wsastartup ($ 0202, wsadata);
if (ret <> 0) dann
Beginnen
printf ('wsastartup fehlgeschlagen mit Fehler %d', ret);
Ausfahrt;
Ende;
// Einen I/A -Fertigstellungsport einrichten.
CompletionPort: = CreateICompletionPort (Invalid_handle_Value, 0, 0, 0);
if (completionport = 0) dann
Beginnen
printf ('createICompletionport fehlgeschlagen mit Fehler: %d', getLasterror ());
Ausfahrt;
Ende;
// Bestimmen Sie, wie viele Prozessoren sich auf dem System befinden.
GetSystemInfo (SystemInfo);
// Erstellen Sie Worker -Threads basierend auf der Anzahl der auf dem verfügbaren Prozessoren
// System.
für i: = 0 bis systemInfo.dwnumberofprocessors * 2 - 1 tun
Beginnen
// Erstellen Sie einen Server -Worker -Thread und übergeben Sie den Fertigstellungsport an den Thread.
Threadle: = CreateThead (nil, 0, @ServerworkerThread, Zeiger (Fertigstellungsport),
0, ThreadID);
if (fadenhandle = 0) dann
Beginnen
printf ('createThead () fehlgeschlagen mit Fehler %d', getLasterror ());
Ausfahrt;
Ende;
// den Fadengriff schließen
Nahe Handle (Fadenhand);
Ende;
// Erstellen Sie eine Hörstecke
Hören Sie: = wsasocket (AF_INET, SOCK_STREAM, 0, NIL, 0, WSA_FLAG_OVERLADD);
if (listen = invaly_socket) dann
Beginnen
printf ('wsasocket () fehlgeschlagen mit Fehler %d', wsagetlasterror ());
Ausfahrt;
Ende;
InternetAddr.sin_Family: = af_inet;
InternetAddr.sin_Addr.s_addr: = htonl (INADDR_ANY);
InternetAddr.sin_port: = htons (Port);
if (bind (hören, InternetAddr, sizeof (InternetAddr)) = socket_error) dann
Beginnen
printf ('bind () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende;
// Bereiten Sie Socket zum Zuhören vor
if (winsock.listen (listen, 5) = socket_error) dann
Beginnen
printf ('listen () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende
anders
Beginnen
printf ('Server anhören auf Port = %d ...', Port);
Ende;
// Verbindungen akzeptieren und dem Fertigstellungsport zuweisen.
während (wahr) tun
Beginnen
Akzeptieren: = WSAaccept (Hören, Nil, Nil, Nil, 0);
if (Accept = socket_error) dann
Beginnen
printf ('wSaaccept () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende;
// Erstellen Sie eine Socket -Informationsstruktur, die mit dem Socket assoziiert ist
Perhandledata: = lpper_handle_data (globalalloc (gptr, sizeof (per_handle_data)));
if (perhandledata = nil) dann
Beginnen
printf ('globalalloc () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende;
// Die akzeptierte Socket mit dem ursprünglichen Fertigstellungsport verknüpfen.
printf ('Socket -Nummer %d angeschlossen, akzeptieren);
Perhandledata.Socket: = Akzeptieren;
if (createIocompletionPort (Akzeptieren, Fertigstellungsport, DWORD (perhandledata), 0) = 0) Dann
Beginnen
printf ('createICompletionPort () fehlgeschlagen mit Fehler %d', wsagetlasterror ());
Ausfahrt;
Ende;
// Erstellen Sie die I/A -Socket -Informationsstruktur, um sie mit dem zu verbinden
// wsarecv rufen Sie unten an.
Periodata: = lpper_io_operation_data (globalalloc (gptr, sizeof (per_io_operation_data)));
if (periodata = nil) dann
Beginnen
printf ('globalalloc () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende;
Zeromemory ( @periodata.overlapped, sizeof (überlappt));
Periodata.Bytessend: = 0;
Periodata.BytesRecv: = 0;
Periialata.databuf.len: = data_bufsize;
Periiendata.databuf.buf: = @probioTata.Buffer;
Flaggen: = 0;
if (wSarecv (Akzeptieren, @(periodata.databuf), 1, @recvBytes, @flags,
@(Periodata.overlapped), nil) = socket_error) dann
Beginnen
if (wsagetlasterror () <> ERROR_IO_PENDEN) dann dann
Beginnen
printf ('wSarecv () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende
Ende;
Ende;
Ende;
Function ServerworkerThread (CompletionPortID: LPVoid): DWORD;
var
Fertigstellungsport: Thandle;
Bytestransferred: dword;
// überlappend: poverlappt;
Perhandledata: lpper_handle_data;
Periodata: lpper_io_operation_data;
SendBytes, recvBytes: dWord;
Flaggen: DWORD;
Beginnen
CompletionPort: = Thandle (CompletionPortId);
Ergebnisse: = 0;
während (wahr) tun
Beginnen
if (getQuEedCompletionStatus (Completionport, Bytestransferred,
Dword (perhandledata), pus
Beginnen
printf ('getQuEedCompletionStatus fehlgeschlagen mit Fehler %d', getLasterror ());
Ausfahrt;
Ende;
// Überprüfen Sie zuerst, ob in der Sockel ein Fehler aufgetreten ist und ob ja
// Schließen Sie dann die Socket und räumen Sie die Socket_informationsstruktur auf
// mit der Steckdose verbunden.
if (byTestransferred = 0) dann
Beginnen
printf ('Schließen von Socket %d/', perhandledata.socket);
if (closocket (perhandledata.socket) = socket_error) dann
Beginnen
printf ('closocket () fehlgeschlagen mit Fehler %d', wsagetlasterror ());
Ausfahrt;
Ende;
GlobalFree (DWORD (PERHANDLEDATA));
GlobalFree (DWORD (periodata));
weitermachen;
Ende;
// prüfen Sie, ob das Feld ByteRecv null ist.
// Dies bedeutet, dass ein WsARECV -Anruf gerade abgeschlossen wurde. Aktualisieren Sie also das Feld ByteRecv
// mit dem Bytestransferred -Wert aus dem abgeschlossenen WSARECV () -Aufruf.
if (periodata.bytesRecv = 0) dann
Beginnen
Periodata.ByteSRecv: = bytestransferred;
Periodata.Bytessend: = 0;
Ende
anders
Beginnen
Periiendata.ByTessend: = periodata.ByTessend + bytestransferred;
Ende;
if (periodata.bytesRecv> periodata.Bytessend) dann
Beginnen
// Poste eine andere wsasend () Anfrage.
// Da wsasend () nicht alle angeforderten Bytes gesendet wird, senden
// Veröffentlichung weiterhin wsasend () Anrufe, bis alle empfangenen Bytes gesendet werden.
Zeromemory (@(periodata.overlapped), sizeof (überlappt));
Periiendata.databuf.buf: = periodata.Buffer + periodata.Bytessend;
Periiendata.databuf.len: = periodata.bytesRecv - periodata.Bytessend;
if (wsasend (perhandledata.socket, @(periodata.databuf), 1, @SendBytes, 0,,
@(Periodata.overlapped), nil) = socket_error) dann
Beginnen
if (wsagetlasterror () <> ERROR_IO_PENDEN) dann dann
Beginnen
printf ('wsaSend () fehlgeschlagen mit Fehler %d', wsagetlasterror ());
Ausfahrt;
Ende;
Ende;
Ende
anders
Beginnen
Periodata.BytesRecv: = 0;
// Jetzt, da es keine Bytes mehr gibt, um eine andere wSarecv () -Anforderung zu senden.
Flaggen: = 0;
Zeromemory (@(periodata.overlapped), sizeof (überlappt));
Periialata.databuf.len: = data_bufsize;
Periiendata.databuf.buf: = @probioTata.Buffer;
if (wsarecv (perhandledata.socket, @(periodata.databuf), 1, @RecvBytes, @flags,
@(Periodata.overlapped), nil) = socket_error) dann
Beginnen
if (wsagetlasterror () <> ERROR_IO_PENDEN) dann dann
Beginnen
printf ('wSarecv () fehlgeschlagen mit Fehler %d', Wsagetlasterror ());
Ausfahrt;
Ende;
Ende;
Ende;
Ende;
Ende;
Ende.