第二个问题我决定用设置超时,刚才试了一下,5000000条记录检索一遍几乎不费时间。
代码如下:
unit CompletePort;
interface
uses
Windows, WinSock2, Dialogs;
Const
DATA_BUFSIZE = 10;
RECV_POSTED = 0;
SEND_POSTED = 1;
Type
LPPER_HANDLE_DATA = ^PER_HANDLE_DATA;
PER_HANDLE_DATA = record //用于存放套接字句柄
Socket: TSocket;
end;
LPPER_IO_OPERATION_DATA = ^PER_IO_OPERATION_DATA;
PER_IO_OPERATION_DATA = record //用于存放跟套接字句柄有关的信息
Overlapped: OVERLAPPED;
DataBuf: WSABUF;
Buffer: array[0..DATA_BUFSIZE] of CHAR;
OperationType: byte;
// other useful information
end;
function StartServer: Integer;//开启服务
function ListenThread(params: pointer): DWORD;//监听线程
function SerVerWorkerThread(params: pointer): DWORD;//工作线程
var
hIocp: THANDLE;//完成端口句柄
sizeofPHD,sizeofPID: Integer;
SystemInfo: SYSTEM_INFO;//作用:获得Cpu个数
Listen: TSOCKET;//监听套接字
InternetAddr: sockaddr_in;
IsExit: boolean;
IsRunning: boolean;
implementation
function StartServer:Integer;
var
v_WSAData: TWSADATA;
I: Cardinal;
ThreadID,ThreadHandle: Cardinal;
begin
//Step1初始化WinSock2
if WSAStartup(MAKEWORD(2, 2), v_WSAData) <> 0 then
begin
StartServer := 1;//不能初始化Winsock2
Exit;
end;
sizeofPHD := sizeof(PER_HANDLE_DATA);
sizeofPID := sizeof(PER_IO_OPERATION_DATA);
//Step2创建完成端口(先判断系统处理器个数)
GetSystemInfo(SystemInfo);
hIocp := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, SystemInfo.dwNumberOfProcessors);
//这里最后一个参数是每次有效的最大工作线程的数量,设为0时表示等于处理器个数
if hIocp = 0 then
begin
StartServer := 2;//不能创建完全端口
Exit;
end;
//Step3创建工作线程,根据2中得到的处理器信息,在完成端口上为已完成的I/O请求提供服务
for I := 0 to SystemInfo.dwNumberOfProcessors - 1 do
begin
ThreadHandle := CreateThread(nil,0, @SerVerWorkerThread, Pointer(hIocp), 0, ThreadID);
CloseHandle(ThreadHandle);
end;
//Step4准备好一个监听套接字,监听进入的连接请求
Listen := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
InternetAddr.sin_family := AF_INET;
InternetAddr.sin_addr.s_addr := htonl(INADDR_ANY);
InternetAddr.sin_port := htons(5150);
bind(Listen, @InternetAddr, sizeof(InternetAddr));
//Step5启动侦听线程
ThreadHandle := CreateThread(nil, 0, @ListenThread, nil, 0, ThreadID);
if ThreadHandle = 0 then
begin
StartServer := 5; //侦听线程启动失败
Exit;
end;
CloseHandle(ThreadHandle);
//ListenThread(nil);
IsRunning := True;
StartServer := 0;//开始工作了
end;
//////////监听线程/////////////////////////
function ListenThread(params: pointer): DWORD;
var
PerHandleData: LPPER_HANDLE_DATA; //用于存放套接字句柄
PerIoData: LPPER_IO_OPERATION_DATA; //用于存放跟套接字句柄有关的信息
RecvBytes: Cardinal;
Flags: Cardinal;
Accept: TSOCKET;
begin
Winsock2.listen(Listen, 5);
IsExit := FALSE;
while(TRUE) do
begin
if IsExit = TRUE then
begin
break;
end;
//step5 使用accept函数 接受进入的连接请求
Accept := WSAAccept(Listen, nil, nil, nil, 0);
//为每个客户连接分配一个每连接数据块
GetMem(PerHandleData, sizeofPHD);
//printf("Socket number %d connected/n",Accept);//原文的这句我不知道是做什么用的
PerHandleData.Socket := Accept;
//将套节字与完成端口联系
CreateIoCompletionPort(Accept, hIocp, DWORD(PerHandleData), 0);
//准备接收数据
Flags := 0;
GetMem(PerIoData, sizeofPID);
PerIoData.DataBuf.len := DATA_BUFSIZE;
PerIoData.DataBuf.buf := PerIoData.Buffer;
PerIoData.OperationType := RECV_POSTED;
WSARecv(Accept, @PerIoData.DataBuf, 1, RecvBytes,
Flags, @_OVERLAPPED(PerIoData.Overlapped), nil);
//这句命名执行了,但在工作线程中就是收不到??????????????
end;
//Step6结束
IsRunning := False;
WSACleanup();
end;
///////////工作线程///////////////////////
function SerVerWorkerThread(params
ointer)
WORD;
var
PerHandleData: LPPER_HANDLE_DATA;
PerIoData: LPPER_IO_OPERATION_DATA;
BytesTransferred: DWORD; //存放完成一次I/O操作后,接受实际传入的字节数
RecvBytes, Flags: Cardinal;
ret: LongBool;
Send: TSocket;
begin
while (True) do
begin
ret := GetQueuedCompletionStatus(hIocp, BytesTransferred, DWORD(PerHandleData),
POVERLAPPED(PerIoData), INFINITE);
//执行到以上这一句,该线程就挂起了,不再动了,导致以下代码永不执行!!!!!!!??????
if not ret then
begin
//读或写操作以失败告终
continue;
end;
if(BytesTransferred = 0) and
((PerIoData.OperationType = RECV_POSTED) or
(PerIoData.OperationType = SEND_POSTED)) then
begin
//客户端已经断开套节字,释放本地套节字
closesocket(PerHandleData.Socket);
//执行了closesocket之后,所有操作都将完成
FreeMem(PerHandleData, sizeofPHD);
FreeMem(PerIoData, sizeofPID);
//GlobalFree(PerHandleData);
//GlobalFree(PerIoData);
IsExit := TRUE;//这是我做实验用的,真实的程序肯定不是在这里终结
continue;
end;
if PerIoData.OperationType = RECV_POSTED then
begin
//读取,这也是实验用的,真实的程序还有很多处理,包括数据库操作
showmessage(PerIoData.DataBuf.buf);
//fputs(PerIoData->DataBuf.buf,fp);
WSASend()
WSASend(PerHandleData.Socket,@PerIoData.DataBuf,)
end;
Flags := 0;
ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));
PerIoData.DataBuf.len := DATA_BUFSIZE;
PerIoData.DataBuf.buf := PerIoData.Buffer;
PerIoData.OperationType := RECV_POSTED;
WSARecv(PerHandleData.Socket, @PerIoData.DataBuf, 1, RecvBytes,
Flags, @_OVERLAPPED(PerIoData.Overlapped), nil);
end;
end;
end.