J
Jiams
Unregistered / Unconfirmed
GUEST, unregistred user!
客户有发数据给服务程序,服务程序WSARcev会有IO_Pending.
可是到GetQueuedCompletionStatus时塞上.各位看看有什么问题.
(winsock2.pas我用过INDY的idwinsock2.pas和http://codecentral.borland.com/codecentral/ccweb.exe/files?id=16014的winsock2.pas两者)
Server代码(可直接拷贝后变可编译)
unit ICP;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,winsock2,
Dialogs, StdCtrls,SyncObjs;
CONST
DATA_BUFSIZE=4096;
SERVER_IP='192.168.1.101';
iPort=88;
MAXTHREAD_COUNT= 8;
type
//用来标识套接字IO动作类型;
PIO_OPERATION=^IO_OPERATION;
IO_OPERATION=(
IoAccept,
IoRead, //WSARecv/recv/ReadFile
IoWrite, //WSASend/send/WriteFile
IoEnd);
//自定义结构,即“完成键”(单句柄数据)
PPER_HANDLE_DATA=^PER_HANDLE_DATA;
PER_HANDLE_DATA=packed record
Socket: TSOCKET;
ClientAddr: TSockAddr;
// 在这里还可以加入其他和客户端关联的数据
end;
//单IO数据,扩展的WSAOVERLAPPED
PPER_IO_DATA=^PER_IO_DATA;
PER_IO_DATA=packed record
overlapped: TOverlapped;
DataBuf: WSABUF;
IoOperation: IO_OPERATION;
end;
type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
sListen:TSocket;
WSAData:TWSADATA;
ExitICOP,ExitListen:Boolean;
DebugIoEvent:TEvent;
ini:Text;
ConnectCount: Integer;
function InitCompletionPort:THandle;
function BindListen(const IP:String;Port:Integer):TSocket;
Procedure WSACheckError(codeWORD);
procedure InitSock();
function ServerWorkerThread(ICointer):Integer;
procedure ServerListenThread;
procedure Read(sAccept:TSocket;Cli:TSockAddr;CompletionPortWORD);
implementation
uses Unit2, DbugIntf;
{$R *.dfm}
function ServerWorkerThread(ICointer):Integer;
var
BytesTransferred: DWORD;
SendBytes,Flags: DWORD;
rlt:LongBool;
pPerHandleData: PPER_HANDLE_DATA;
pPerIoData: PPER_IO_DATA;
CompletionPort: THandle;
buf: Array[0..DATA_BUFSIZE-1] of Ansichar;
begin
CompletionPort:=THandle(IC);
// GetMem(pPerIoData,sizeof(PER_IO_DATA));
// pPerIoData.overlapped:=overlapped;
// pPerIoData.DataBuf.buf:=buf;
// pPerIoData.DataBuf.len:=DATA_BUFSIZE;
// pPerIoData.IoOperation:=IoAccept;
// GetMem(pPerHandleData,sizeof(PER_HANDLE_DATA));
// pPerHandleData.Socket:=0;
// FillChar(pPerHandleData.ClientAddr,sizeof(TSockAddrIn),0);
pPerIoData:=nil;
pPerHandleData:=nil;
while not ExitICOP do begin
rlt:=GetQueuedCompletionStatus(CompletionPort,BytesTransferred,DWORD(pPerHandleData),POVerlapped(pPerIoData),Infinite);
if rlt=false then Begin
// ShowMessage(IntToStr(GetLastError()));
Continue;
end;
if (BytesTransferred=0) then Continue;
if pPerIoData.IoOperation=IORead then begin
DebugIoEvent.WaitFor(infinite);
DebugIoEvent.ResetEvent;
buf[0]:=pPerIoData.DataBuf.buf^;
writeln(ini,strpas(buf));
Inc(ConnectCount);
DebugIoEvent.SetEvent;
end;
Flags:=0;
ZeroMemory(@(pPerIoData.Overlapped),sizeof(OVERLAPPED));
pPerIoData.DataBuf.len := DATA_BUFSIZE;
pPerIoData.IoOperation:=IOWrite;
pPerIoData.DataBuf.buf:=buf;
WSASend(pPerHandleData.Socket,@(pPerIoData.DataBuf),1,SendBytes,Flags,@(pPerIoData.overlapped),nil);
end;
PostQueuedCompletionStatus(CompletionPort,0,0,nil);
result:=0;
end;
procedure ServerListenThread;
var
iLen: Integer;
Cli: TSockAddr;
sAccept: TSocket;
CompletionPortWORD;
begin
CompletionPort:=InitCompletionPort();
InitSock();
sListen:=BindListen(SERVER_IP,iPort);
iLen:=SizeOf(Cli);
while not ExitListen do begin
sAccept:=Accept(sListen,cli,iLen);
if(sAccept=INVALID_SOCKET) then begin
ShowMessage('INVAILID_SOKET');
end;
read(sAccept,Cli,CompletionPort);
end;
end;
procedure Read(sAccept:TSocket;Cli:TSockAddr;CompletionPortWORD);
var
pPerHandleData: PPER_HANDLE_DATA;
pPerIoData: PPER_IO_DATA;
buf:array[0..DATA_BUFSIZE-1] of Char;
RecvBytes, Flags: DWORD;
rlt,err:Integer;
begin
GetMem(pPerIOData,sizeof(PER_IO_DATA));
pPerIoData.DataBuf.len:=DATA_BUFSIZE;
FillChar(buf,DATA_BUFSIZE,0);
pPerIoData.DataBuf.buf:=buf;
FillChar(pPerIoData.overlapped,sizeof(TOverlapped),0);
pPerIoData.IoOperation:=IoRead;
GetMem(pPerHandleData,sizeof(PER_HANDLE_DATA));
pPerHandleData.Socket:=sAccept;
pPerHandleData.ClientAddr:=Cli;
if (CreateIoCompletionPort(pPerHandleData.Socket,CompletionPort,DWORD(pPerHandleData),0)=0) then exit;
Flags:=WSA_FLAG_OVERLAPPED; //▲这里Flags:=0可以通过,不然总是在GetQueuedCompletionStatus时塞住,请各位看下,给出原因
rlt:=WSARecv(pPerHandleData.Socket,@(pPerIoData.DataBuf),1,RecvBytes,Flags,@(pPerIoData.overlapped),nil);
if rlt=SOCKET_ERROR then begin
err:=WSAGetLastError();
if err<>ERROR_IO_PENDING then ShowMessage('Error Receive');
end;
ServerWorkerThread(CompletionPort);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ThreadHandle:THandle;
threadIDWORD;
begin
ThreadHandle:=BeginThread(Nil,0,@ServerListenThread,nil,0,threadID);
CloseHandle(ThreadHandle);
Button1.Enabled:=False;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ExitICOP:=True;
ExitListen:=True;
sleep(1000);
shutdown(sListen,SD_BOTH);
closesocket(sListen);
WSACleanup();
DebugIoEvent.Free;
CloseFile(ini);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AssignFile(ini,'c:/aa.txt');
ReWrite(ini);
DebugIoEvent:=TEvent.Create(nil,True,True,'');
ExitListen:=False;
ExitICOP:=False;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DebugIoEvent.WaitFor(infinite);
DebugIoEvent.ResetEvent;
Label1.Caption:=IntToStr(ConnectCount);
DebugIoEvent.SetEvent;
end;
function BindListen(const IP:String;Port:Integer):TSocket;
Var
sListen:TSocket;
SerAddr:TSockAddr;
begin
SerAddr.sin_family := AF_INET;
SerAddr.sin_port := htons(Port);
SerAddr.sin_addr.S_addr := inet_addr(Pchar(Ip));
sListen:=WSASocket(af_inet,SOCK_STREAM,IPPROTO_IP,nil,0,WSA_FLAG_OVERLAPPED);
Bind(sListen,@SerAddr,sizeof(SerAddr));
Listen(sListen,5);
Result:=sListen;
end;
procedure InitSock();
var
WSAData:TWSAData;
begin
WSACheckError(WSAStartup(MakeWord(2,2),WSAData));
end;
Procedure WSACheckError(codeWORD);
var
err:Integer;
begin
if code=INVALID_SOCKET then
Begin
err:=WSAGetLastError();
ShowMessage(IntToStr(err));
end;
end;
function InitCompletionPort:THandle;
var
i:integer;
ThreadHandle:THandle;
CompletionPort:THandle;
threadIdWORD;
begin
CompletionPort:=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
// for i:=0 to 0 do begin
// ThreadHandle:=BeginThread(Nil,0,@ServerWorkerThread,Ptr(CompletionPort),0,threadID);
// CloseHandle(ThreadHandle);
// end;
result:=CompletionPort;
end;
end.
/////////////////////////////////
Fom1.dfm
//////////////////////////////////
object Form1: TForm1
Left = 384
Top = 270
Width = 281
Height = 154
Caption = 'ICP'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 152
Top = 88
Width = 32
Height = 13
Caption = 'Label1'
end
object Button1: TButton
Left = 16
Top = 16
Width = 75
Height = 25
Caption = 'StartSvr'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 48
Top = 80
Width = 81
Height = 25
Caption = 'ConnectCount'
TabOrder = 1
OnClick = Button2Click
end
end
可是到GetQueuedCompletionStatus时塞上.各位看看有什么问题.
(winsock2.pas我用过INDY的idwinsock2.pas和http://codecentral.borland.com/codecentral/ccweb.exe/files?id=16014的winsock2.pas两者)
Server代码(可直接拷贝后变可编译)
unit ICP;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,winsock2,
Dialogs, StdCtrls,SyncObjs;
CONST
DATA_BUFSIZE=4096;
SERVER_IP='192.168.1.101';
iPort=88;
MAXTHREAD_COUNT= 8;
type
//用来标识套接字IO动作类型;
PIO_OPERATION=^IO_OPERATION;
IO_OPERATION=(
IoAccept,
IoRead, //WSARecv/recv/ReadFile
IoWrite, //WSASend/send/WriteFile
IoEnd);
//自定义结构,即“完成键”(单句柄数据)
PPER_HANDLE_DATA=^PER_HANDLE_DATA;
PER_HANDLE_DATA=packed record
Socket: TSOCKET;
ClientAddr: TSockAddr;
// 在这里还可以加入其他和客户端关联的数据
end;
//单IO数据,扩展的WSAOVERLAPPED
PPER_IO_DATA=^PER_IO_DATA;
PER_IO_DATA=packed record
overlapped: TOverlapped;
DataBuf: WSABUF;
IoOperation: IO_OPERATION;
end;
type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
sListen:TSocket;
WSAData:TWSADATA;
ExitICOP,ExitListen:Boolean;
DebugIoEvent:TEvent;
ini:Text;
ConnectCount: Integer;
function InitCompletionPort:THandle;
function BindListen(const IP:String;Port:Integer):TSocket;
Procedure WSACheckError(codeWORD);
procedure InitSock();
function ServerWorkerThread(ICointer):Integer;
procedure ServerListenThread;
procedure Read(sAccept:TSocket;Cli:TSockAddr;CompletionPortWORD);
implementation
uses Unit2, DbugIntf;
{$R *.dfm}
function ServerWorkerThread(ICointer):Integer;
var
BytesTransferred: DWORD;
SendBytes,Flags: DWORD;
rlt:LongBool;
pPerHandleData: PPER_HANDLE_DATA;
pPerIoData: PPER_IO_DATA;
CompletionPort: THandle;
buf: Array[0..DATA_BUFSIZE-1] of Ansichar;
begin
CompletionPort:=THandle(IC);
// GetMem(pPerIoData,sizeof(PER_IO_DATA));
// pPerIoData.overlapped:=overlapped;
// pPerIoData.DataBuf.buf:=buf;
// pPerIoData.DataBuf.len:=DATA_BUFSIZE;
// pPerIoData.IoOperation:=IoAccept;
// GetMem(pPerHandleData,sizeof(PER_HANDLE_DATA));
// pPerHandleData.Socket:=0;
// FillChar(pPerHandleData.ClientAddr,sizeof(TSockAddrIn),0);
pPerIoData:=nil;
pPerHandleData:=nil;
while not ExitICOP do begin
rlt:=GetQueuedCompletionStatus(CompletionPort,BytesTransferred,DWORD(pPerHandleData),POVerlapped(pPerIoData),Infinite);
if rlt=false then Begin
// ShowMessage(IntToStr(GetLastError()));
Continue;
end;
if (BytesTransferred=0) then Continue;
if pPerIoData.IoOperation=IORead then begin
DebugIoEvent.WaitFor(infinite);
DebugIoEvent.ResetEvent;
buf[0]:=pPerIoData.DataBuf.buf^;
writeln(ini,strpas(buf));
Inc(ConnectCount);
DebugIoEvent.SetEvent;
end;
Flags:=0;
ZeroMemory(@(pPerIoData.Overlapped),sizeof(OVERLAPPED));
pPerIoData.DataBuf.len := DATA_BUFSIZE;
pPerIoData.IoOperation:=IOWrite;
pPerIoData.DataBuf.buf:=buf;
WSASend(pPerHandleData.Socket,@(pPerIoData.DataBuf),1,SendBytes,Flags,@(pPerIoData.overlapped),nil);
end;
PostQueuedCompletionStatus(CompletionPort,0,0,nil);
result:=0;
end;
procedure ServerListenThread;
var
iLen: Integer;
Cli: TSockAddr;
sAccept: TSocket;
CompletionPortWORD;
begin
CompletionPort:=InitCompletionPort();
InitSock();
sListen:=BindListen(SERVER_IP,iPort);
iLen:=SizeOf(Cli);
while not ExitListen do begin
sAccept:=Accept(sListen,cli,iLen);
if(sAccept=INVALID_SOCKET) then begin
ShowMessage('INVAILID_SOKET');
end;
read(sAccept,Cli,CompletionPort);
end;
end;
procedure Read(sAccept:TSocket;Cli:TSockAddr;CompletionPortWORD);
var
pPerHandleData: PPER_HANDLE_DATA;
pPerIoData: PPER_IO_DATA;
buf:array[0..DATA_BUFSIZE-1] of Char;
RecvBytes, Flags: DWORD;
rlt,err:Integer;
begin
GetMem(pPerIOData,sizeof(PER_IO_DATA));
pPerIoData.DataBuf.len:=DATA_BUFSIZE;
FillChar(buf,DATA_BUFSIZE,0);
pPerIoData.DataBuf.buf:=buf;
FillChar(pPerIoData.overlapped,sizeof(TOverlapped),0);
pPerIoData.IoOperation:=IoRead;
GetMem(pPerHandleData,sizeof(PER_HANDLE_DATA));
pPerHandleData.Socket:=sAccept;
pPerHandleData.ClientAddr:=Cli;
if (CreateIoCompletionPort(pPerHandleData.Socket,CompletionPort,DWORD(pPerHandleData),0)=0) then exit;
Flags:=WSA_FLAG_OVERLAPPED; //▲这里Flags:=0可以通过,不然总是在GetQueuedCompletionStatus时塞住,请各位看下,给出原因
rlt:=WSARecv(pPerHandleData.Socket,@(pPerIoData.DataBuf),1,RecvBytes,Flags,@(pPerIoData.overlapped),nil);
if rlt=SOCKET_ERROR then begin
err:=WSAGetLastError();
if err<>ERROR_IO_PENDING then ShowMessage('Error Receive');
end;
ServerWorkerThread(CompletionPort);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ThreadHandle:THandle;
threadIDWORD;
begin
ThreadHandle:=BeginThread(Nil,0,@ServerListenThread,nil,0,threadID);
CloseHandle(ThreadHandle);
Button1.Enabled:=False;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ExitICOP:=True;
ExitListen:=True;
sleep(1000);
shutdown(sListen,SD_BOTH);
closesocket(sListen);
WSACleanup();
DebugIoEvent.Free;
CloseFile(ini);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AssignFile(ini,'c:/aa.txt');
ReWrite(ini);
DebugIoEvent:=TEvent.Create(nil,True,True,'');
ExitListen:=False;
ExitICOP:=False;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DebugIoEvent.WaitFor(infinite);
DebugIoEvent.ResetEvent;
Label1.Caption:=IntToStr(ConnectCount);
DebugIoEvent.SetEvent;
end;
function BindListen(const IP:String;Port:Integer):TSocket;
Var
sListen:TSocket;
SerAddr:TSockAddr;
begin
SerAddr.sin_family := AF_INET;
SerAddr.sin_port := htons(Port);
SerAddr.sin_addr.S_addr := inet_addr(Pchar(Ip));
sListen:=WSASocket(af_inet,SOCK_STREAM,IPPROTO_IP,nil,0,WSA_FLAG_OVERLAPPED);
Bind(sListen,@SerAddr,sizeof(SerAddr));
Listen(sListen,5);
Result:=sListen;
end;
procedure InitSock();
var
WSAData:TWSAData;
begin
WSACheckError(WSAStartup(MakeWord(2,2),WSAData));
end;
Procedure WSACheckError(codeWORD);
var
err:Integer;
begin
if code=INVALID_SOCKET then
Begin
err:=WSAGetLastError();
ShowMessage(IntToStr(err));
end;
end;
function InitCompletionPort:THandle;
var
i:integer;
ThreadHandle:THandle;
CompletionPort:THandle;
threadIdWORD;
begin
CompletionPort:=CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
// for i:=0 to 0 do begin
// ThreadHandle:=BeginThread(Nil,0,@ServerWorkerThread,Ptr(CompletionPort),0,threadID);
// CloseHandle(ThreadHandle);
// end;
result:=CompletionPort;
end;
end.
/////////////////////////////////
Fom1.dfm
//////////////////////////////////
object Form1: TForm1
Left = 384
Top = 270
Width = 281
Height = 154
Caption = 'ICP'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 152
Top = 88
Width = 32
Height = 13
Caption = 'Label1'
end
object Button1: TButton
Left = 16
Top = 16
Width = 75
Height = 25
Caption = 'StartSvr'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 48
Top = 80
Width = 81
Height = 25
Caption = 'ConnectCount'
TabOrder = 1
OnClick = Button2Click
end
end