Sumber Asli: "Teknologi Pemrograman Jaringan Windows" Bab 8 Model Port Selesai
Karena buku asli disertai dengan kode C, saya menerjemahkannya ke dalam kode Delphi.
Di antara mereka, winsock2.pas tidak termasuk dalam Delphi.
Penyelesaian Program;
{$ AppType konsol}
penggunaan
Sysutils,
Winsock2 di 'winsock2.pas',
Induk di 'induk.pas';
Mulai
utama();
akhir.
// Nama Modul: iocmmplt.cpp
//
// Keterangan:
//
// Sampel ini menggambarkan cara mengembangkan server gema sederhana Winsock
// Aplikasi Menggunakan Model I/O Port Lengkapi
// Sampel diimplementasikan sebagai aplikasi gaya konsol dan cukup mencetak
// Pesan Saat koneksi dibuat dan dihapus dari server.
// Aplikasi mendengarkan koneksi TCP di port 5150 dan menerimanya
// Saat mereka tiba.
// Cukup echos (inilah sebabnya kami menyebutnya server gema) data kembali
// Ini formulir asli sampai klien menutup koneksi.
//
// 2005-2-5
// CPP Konversi ke Delphi Pas oleh Johnson
//
unit induk;
antarmuka
menggunakan Windows, Winsock2, Winsock, Sysutils;
const
Port = 5150;
Data_bufsize = 8192;
jenis
Lpvoid = pointer;
Lpper_io_operation_data = ^ per_io_operation_data;
Per_IO_Operation_Data = Rekor yang dikemas
Tumpang tindih: tumpang tindih;
Databuf: twsabuf;
Buffer: array [0..data_bufsize] dari char;
Bytessend: DWORD;
BYTESRECV: DWORD;
akhir;
Lpper_handle_data = ^ per_handle_data;
Per_handle_data = catatan yang dikemas
Soket: tsocket;
akhir;
prosedur utama;
Pelaksanaan
Function ServererThread (CompletionportId: LPVoid): DWORD;
Prosedur printf (fmt: string; num: integer);
Mulai
Writeln (format (fmt, [num]));
akhir;
prosedur utama;
var
InternetAddr: sockaddr_in;
Dengarkan: Tsocket;
Terima: Tsocket;
Penyelesaian: Thandle;
SystemInfo: System_info;
Perhandedata: lpper_handle_data;
Periodata: lpper_io_operation_data;
I: Integer;
Recvbytes: DWORD;
Bendera: DWORD;
ThreadID: DWORD;
wsadata: twsadata;
Ret: dword;
ThreadHandle: Thandle;
Mulai
Ret: = wsastartup ($ 0202, wsadata);
if (ret <> 0) lalu
Mulai
printf ('wsastartup gagal dengan kesalahan %d', ret);
KELUAR;
akhir;
// Siapkan port penyelesaian I/O.
Penyelesaian: = createiocompletionport (invalid_handle_value, 0, 0, 0);
if (completionport = 0) lalu
Mulai
printf ('createiocompetionport gagal dengan kesalahan: %d', getlasterror ());
KELUAR;
akhir;
// Tentukan berapa banyak prosesor yang ada di sistem.
GetSystemInfo (SystemInfo);
// Buat utas pekerja berdasarkan jumlah prosesor yang tersedia di
// Sistem. Buat dua utas pekerja untuk setiap prosesor.
untuk i: = 0 ke SystemInfo.dwnumberofprocessors * 2 - 1 lakukan
Mulai
// Buat utas Pekerja Server dan berikan port penyelesaian ke utas.
ThreadHandle: = CreateThread (nil, 0, @serverworkerthread, pointer (penyelesaian),
0, threadid);
if (threadHandle = 0) lalu
Mulai
printf ('createThread () gagal dengan kesalahan %d', getlasterror ());
KELUAR;
akhir;
// tutup pegangan utas
CloseHandle (ThreadHandle);
akhir;
// Buat soket mendengarkan
Dengarkan: = wsasocket (af_inet, sock_stream, 0, nil, 0, wsa_flag_overlapped);
if (listen = invalid_socket) lalu
Mulai
printf ('wsasocket () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
InternetAddr.sin_family: = af_inet;
InternetAddr.sin_addr.s_addr: = htonl (inaddr_any);
InternetAddr.sin_port: = hTons (port);
if (bind (dengarkan, internetAddr, sizeof (internetAddr)) = socket_error)
Mulai
printf ('bind () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
// Siapkan soket untuk mendengarkan
if (winsock.listen (dengarkan, 5) = socket_error)
Mulai
printf ('listen () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir
kalau tidak
Mulai
printf ('server dengarkan di port = %d ...', port);
akhir;
// Terima koneksi dan tetapkan ke port penyelesaian.
sementara (benar) lakukan
Mulai
Terima: = wsaaccept (dengarkan, nil, nil, nil, 0);
if (accept = socket_error) lalu
Mulai
printf ('wsaaccept () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
// Buat struktur informasi soket untuk dikaitkan dengan soket
Perhandledata: = lpper_handle_data (globalAlloc (gptr, sizeof (per_handle_data))));
if (perhandedata = nil) lalu
Mulai
printf ('GlobalAlloc () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
// Hubungkan soket yang diterima dengan port penyelesaian asli.
printf ('nomor soket %d terhubung', terima);
Perhandedata.socket: = terima;
if (createOcompetionport (terima, penyelesaian, dword (perhandledata), 0) = 0) lalu
Mulai
printf ('createiocompletionport () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
// buat struktur informasi soket per I/O untuk bergaul dengan
// WSARECV Hubungi di bawah ini.
Periodata: = lpper_io_operation_data (globalAlloc (gptr, sizeof (per_io_operation_data)));
if (periodata = nil) lalu
Mulai
printf ('GlobalAlloc () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
Zeromemory ( @periodata.overlapped, sizeof (tumpang tindih));
Periodata.bytessend: = 0;
Periodata.bytesRecv: = 0;
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
Bendera: = 0;
if (wsarecv (terima, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = socket_error)
Mulai
if (wsagetlasterror () <> error_io_pending)
Mulai
printf ('wsarecv () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir
akhir;
akhir;
akhir;
Function ServererThread (CompletionPortID: LPVoid): DWORD;
var
Penyelesaian: Thandle;
Bytestransfer: DWORD;
// tumpang tindih: poverlapped;
Perhandedata: lpper_handle_data;
Periodata: lpper_io_operation_data;
Sendbytes, Recvbytes: DWORD;
Bendera: DWORD;
Mulai
Penyelesaian: = Thandle (CompletionportId);
Hasil: = 0;
sementara (benar) lakukan
Mulai
if (getqueuedCompetiontatus (penyelesaian, bytestransferred,
Dword (perhandedata), poverlapped (periodata), tak terbatas) = false) kemudian
Mulai
printf ('getQueuedCompetiontatus gagal dengan kesalahan %d', getlasterror ());
KELUAR;
akhir;
// Periksa terlebih dahulu untuk melihat apakah terjadi kesalahan pada soket dan jika demikian
// Kemudian tutup soket dan bersihkan struktur socket_information
// terkait dengan soket.
if (bytestransferred = 0) lalu
Mulai
printf ('soket penutupan %d/', perhandedata.socket);
if (clossocket (perhandleData.socket) = socket_error)
Mulai
printf ('clossocket () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
GlobalFree (DWORD (Perhandedata));
GlobalFree (DWORD (periodata));
melanjutkan;
akhir;
// Periksa untuk melihat apakah bidang BytesRecv sama dengan nol.
// Ini berarti panggilan WSARECV yang baru saja selesai jadi perbarui bidang BYTESRECV
// dengan nilai Bytestransferred dari panggilan WSARECV () yang sudah selesai.
if (periodata.bytesRecv = 0) lalu
Mulai
Periodata.bytesrecv: = bytestransferred;
Periodata.bytessend: = 0;
akhir
kalau tidak
Mulai
Periodata.bytessend: = periodata.bytessend + bytestransferred;
akhir;
if (periodata.bytesrecv> periodata.bytessend)
Mulai
// Posting permintaan wsasend lain ().
// Karena wsasend () tidak bersemangat untuk mengirim semua byte yang diminta,
// Lanjutkan memposting panggilan wsasend () sampai semua byte yang diterima dikirim.
Zeromemory (@(periodata.overlapped), sizeof (tumpang tindih));
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) = socket_error)
Mulai
if (wsagetlasterror () <> error_io_pending)
Mulai
printf ('wsasend () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
akhir;
akhir
kalau tidak
Mulai
Periodata.bytesRecv: = 0;
// Sekarang tidak ada lagi byte untuk mengirim posting permintaan wsarecv () lain.
Bendera: = 0;
Zeromemory (@(periodata.overlapped), sizeof (tumpang tindih));
Periodata.databuf.len: = data_bufsize;
Periodata.databuf.buf: = @periodata.buffer;
if (wsarecv (perhandedata.socket, @(periodata.databuf), 1, @recvbytes, @flags,
@(Periodata.overlapped), nil) = socket_error)
Mulai
if (wsagetlasterror () <> error_io_pending)
Mulai
printf ('wsarecv () gagal dengan kesalahan %d', wsagetlasterror ());
KELUAR;
akhir;
akhir;
akhir;
akhir;
akhir;
akhir.