원본 출처 : "Windows Network 프로그래밍 기술"8 장 완성 된 포트 모델
원래 책에는 C 코드가 수반되므로 델파이 코드로 변환했습니다.
그중 Winsock2.Pas는 델파이에 포함되어 있지 않습니다
프로그램 완료;
{$ apptype console}
용도
sysutils,
'winsock2.pas'의 winsock2
'mains.pas'의 메인;
시작하다
기본();
끝.
// 모듈 이름 : iocmmplt.cpp
//
// 설명:
//
//이 샘플은 간단한 Echo 서버 Winsock을 개발하는 방법을 보여줍니다.
// 완료 포트 I/O 모델을 사용한 응용 프로그램
// 샘플은 콘솔 스타일 애플리케이션으로 구현되며 간단히 인쇄
// 연결이 설정되어 서버에서 제거 될 때 메시지.
// 응용 프로그램은 포트 5150에서 TCP 연결에 대해 듣고 수락합니다.
// 도착하면이 응용 프로그램이 클라이언트로부터 데이터를 수신 할 때
// 간단히 에코 (이것이 우리가 에코 서버라고 부르는 이유) 데이터를 다시
// 클라이언트가 연결을 닫을 때까지 원래 양식입니다.
//
// 2005-2-5
// CPP Johnson의 Delphi Pas로 변환
//
단위 메인;
인터페이스
Windows, Winsock2, Winsock, Sysutils를 사용합니다.
Const
포트 = 5150;
data_bufsize = 8192;
유형
lpvoid = 포인터;
lpper_io_operation_data = ^ per_io_operation_data;
per_io_operation_data = 포장 레코드
중첩 : 중첩;
Databuf : twsabuf;
버퍼 : char의 배열 [0..data_bufsize];
바이트 엔드 : dword;
BYTESRECV : dword;
끝;
lpper_handle_data = ^ per_handle_data;
PER_HANDLE_DATA = 포장 된 레코드
소켓 : tsocket;
끝;
절차 메인;
구현
기능 ServerWorkerThread (wemperionportid : lpvoid) : dword;
프로 시저 printf (fmt : 문자열; num : 정수);
시작하다
Writeln (형식 (fmt, [num]));
끝;
절차 메인;
var
InternetAddr : sockaddr_in;
듣기 : tsocket;
수락 : tsocket;
완료 : Thandle;
SystemInfo : System_Info;
PerhAndledata : lpper_handle_data;
periodata : lpper_io_operation_data;
I : 정수;
recvbytes : dword;
깃발 : dword;
Threadid : dword;
wsadata : twsadata;
ret : dword;
Threadhandle : Thandle;
시작하다
ret : = wsastartup ($ 0202, wsadata);
if (ret <> 0) 그러면
시작하다
printf ( 'wsastartup은 오류 %d', ret로 실패);
출구;
끝;
// I/O 완료 포트를 설정합니다.
완료 : = createiocompletionport (invalid_handle_value, 0, 0, 0);
if (완료 = 0) 그러면
시작하다
printf ( 'createiocompletionport가 오류로 실패 : %d', getLasterror ());
출구;
끝;
// 시스템에 얼마나 많은 프로세서가 있는지 결정합니다.
getsysteminfo (SystemInfo);
//에서 사용 가능한 프로세서 수를 기반으로 작업자 스레드 생성
// 시스템을 작성합니다. 각 프로세서에 대한 작업자 스레드를 작성합니다.
i : = 0 to systemInfo.dwnumberofprocessors * 2-1 do
시작하다
// 서버 작업자 스레드를 생성하고 완료 포트를 스레드로 전달합니다.
ThreadHandle : = CreateTheRdead (NIL, 0, @ServerWorkerThread, 포인터 (완료),
0, threadid);
if (threadhandle = 0) 그러면
시작하다
printf ( 'createThread ()는 error %d', getLasterror ())로 실패했습니다.
출구;
끝;
// 스레드 핸들을 닫습니다
CloseHandle (ThreadHandle);
끝;
// 청취 소켓을 만듭니다
듣기 : = wsasocket (af_inet, sock_stream, 0, nil, 0, wsa_flag_overlapp);
if (listen = invalid_socket) 그러면
시작하다
printf ( 'wsasocket ()은 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝;
InternetAddr.sin_family : = af_inet;
InternetAddr.sin_addr.s_addr : = htonl (inaddr_any);
InternetAddr.sin_port : = htons (포트);
if (bind (listen, internetAddr, sizeof (internetAddr)) = socket_error)
시작하다
printf ( 'bind ()는 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝;
// 청취를 위해 소켓을 준비합니다
if (winsock.listen (듣기, 5) = socket_error)
시작하다
printf ( 'listen ()는 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝
또 다른
시작하다
printf ( 'server listen on port = %d ...', 포트);
끝;
// 연결을 수락하고 완료 포트에 할당합니다.
(진실)하는 동안
시작하다
수락 : = wsaaccept (듣기, nil, nil, nil, 0);
if (accept = socket_error) 그러면
시작하다
printf ( 'wsaaccept ()는 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝;
// 소켓과 연결하기 위해 소켓 정보 구조 생성
PerhAndledata : = lpper_handle_data (GlobalAlloc (gptr, sizeof (per_handle_data)));
if (perhAndledata = nil) 그러면
시작하다
printf ( 'globalAlloc ()는 error %d', wsagetlasterror ())로 실패했습니다.
출구;
끝;
// 허용 된 소켓을 원래 완성 포트와 연결합니다.
printf ( '소켓 번호 %d Connected', accept);
PerhAndledata.socket : = 수락;
if (createiocompletionport (수락, 완료, dword (perhandledata), 0) = 0)
시작하다
printf ( 'createiocompletionport ()는 error %d', wsagetlasterror ())로 실패했습니다.
출구;
끝;
// I/O 소켓 정보 구조 생성
// wsarecv 아래 호출.
periodata : = lpper_io_operation_data (GlobalAlloc (gptr, sizeof (per_io_operation_data)));
if (periodata = nil) 그러면
시작하다
printf ( 'globalAlloc ()는 error %d', wsagetlasterror ())로 실패했습니다.
출구;
끝;
Zeromemory ( @periodata.overlapped, sizeof (Ovterpaped));
Periodata.cdessend : = 0;
periodata.bytesRecv : = 0;
periodata.databuf.len : = data_bufsize;
periodata.databuf.buf : = @ageerata.buffer;
깃발 : = 0;
if (wsarecv (accept, @(ageerata.databuf), 1, @recvbytes, @flags,
@(periodata.overlapp), nil) = socket_error)
시작하다
if (wsagetlasterror () <> error_io_pending)
시작하다
printf ( 'wsarecv ()는 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝
끝;
끝;
끝;
기능 ServerWorkerThread (wemberionportid : lpvoid) : dword;
var
완료 : Thandle;
bytestransferred : dword;
// 중첩 : 포버 랩핑;
PerhAndledata : lpper_handle_data;
periodata : lpper_io_operation_data;
Sendbytes, Recvbytes : dword;
깃발 : dword;
시작하다
완료 : = Thandle (wempletionportid);
결과 : = 0;
(진실)하는 동안
시작하다
if (getqueuedCompletionStatus (완료, bytestransferred,
그런 다음 dword (perhandledata), poverlapped (periodata), infinite) = false)
시작하다
printf ( 'getqueuedCompletionStatus는 error %d', getLasterror ())에서 실패했습니다.
출구;
끝;
// 소켓에서 오류가 발생했는지 확인하십시오.
// 그런 다음 소켓을 닫고 socket_information 구조를 정리하십시오.
// 소켓과 관련이 있습니다.
if (bytestransferred = 0) 그러면
시작하다
printf ( 'Closing Socket %d/', perhAndledata.socket);
if (clossocket (perhandledata.socket) = socket_error)
시작하다
printf ( 'clossocket ()은 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝;
GlobalFree (dword (perhAndledata));
GlobalFree (dword (dword));
계속하다;
끝;
// BYTESRECV 필드가 0과 같은지 확인하십시오
// 이것은 방금 완료된 WSARECV 호출을 의미하므로 BYTESRECV 필드를 업데이트합니다.
// 완성 된 WSARECV () 호출에서 BYTESTRANSFERRED 값으로.
if (periodata.bytesrecv = 0) 그러면
시작하다
periodata.bytesrecv : = bytestransferred;
Periodata.cdessend : = 0;
끝
또 다른
시작하다
periodata.
끝;
if (periodata.bytesRecv> ageartesnata.ByTessend)
시작하다
// 다른 wsasend () 요청을 게시합니다.
// WSASEND ()가 요청 된 모든 바이트를 보내도록 가해지지 않으므로
// 수신 된 모든 바이트가 전송 될 때까지 WSASEND () 호출을 계속 게시합니다.
Zeromemory (@(periodata.overlapp), sizeof (중첩));
periodata.databuf.buf : = periodata.buffer + periodata.bytessend;
periodata.databuf.len : = periodata.BytesRecv -ageerata.Bytessend;
if (wsasend (perhAndledata.socket, @(ageerata.databuf), 1, @sendbytes, 0,
@(periodata.overlapp), nil) = socket_error)
시작하다
if (wsagetlasterror () <> error_io_pending)
시작하다
printf ( 'wsasend ()는 오류 %d', wsagetlasterror ())로 실패했습니다.
출구;
끝;
끝;
끝
또 다른
시작하다
periodata.bytesRecv : = 0;
// 이제 다른 wsarecv () 요청을 게시 할 바이트가 더 이상 없으므로.
깃발 : = 0;
Zeromemory (@(periodata.overlapp), sizeof (중첩));
periodata.databuf.len : = data_bufsize;
periodata.databuf.buf : = @ageerata.buffer;
if (wsarecv (perhandledata.socket, @(ageerata.databuf), 1, @recvbytes, @flags,
@(periodata.overlapp), nil) = socket_error)
시작하다
if (wsagetlasterror () <> error_io_pending)
시작하다
printf ( 'wsarecv ()는 오류 %d', wsagetlasterror ())로 실패했다.
출구;
끝;
끝;
끝;
끝;
끝;
끝.