完成端口,谁能帮我改一点点(300分) ( 积分: 300 )

  • 主题发起人 asksomeone
  • 开始时间
A

asksomeone

Unregistered / Unconfirmed
GUEST, unregistred user!
unit frmMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Winsock2, StdCtrls, thrListen;

type
TfmMain = class(TForm)
btnStart: TButton;
ListBox1: TListBox;
btnStop: TButton;
procedure btnStartClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure btnStopClick(Sender: TObject);
private
{ Private declarations }
FListenThread : TListenThread;
public
{ Public declarations }
end;

const
LISTEN_PORT = 5005;

var
fmMain: TfmMain;

implementation

{$R *.dfm}

procedure TfmMain.btnStartClick(Sender: TObject);
begin
FListenThread := TListenThread.Create( true );
FListenThread.FreeOnTerminate := true;
FListenThread.Resume;

btnStop.Enabled := true;
btnStart.Enabled := false;
end;

procedure TfmMain.btnStopClick(Sender: TObject);
begin
FListenThread.terminate;
btnStop.Enabled := false;
btnStart.Enabled := true;
end;

procedure TfmMain.FormCreate(Sender: TObject);
var
wsa : TWSAData;
begin
if WSAStartup( $0202, wsa ) <> 0 then //WSAStartup returns zero if successful.
begin
MessageBox( 0, 'WSAStartup failed', 'Error', MB_ICONERROR );
btnStart.Enabled := False;
btnStop.Enabled := False;
end;

btnStart.Enabled := true;
btnStop.Enabled := false;
end;

procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
WSACleanup();
end;

end.
//---------------------------------------------------------------------
unit thrRecvSend;

interface

uses
Windows, Classes, Winsock2;

type
TRecvSendThread = class(TThread)
public
CompletPort : THandle;
protected
procedure Execute; override;
end;

implementation

uses thrListen, frmMain;

{ TRecvSendThread }

procedure TRecvSendThread.Execute;
var
CompletKey,
BytesTransd,
BytesRecv,
Flags : DWORD;
pPerIoDat : PPER_OPERATION_DATA;
begin
while (not self.Terminated) do
begin
BytesTransd := 0;
CompletKey := 0;
GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey,
POVERLAPPED(pPerIoDat), TIME_OUT );

if ( BytesTransd = 0 ) and
( (pPerIoDat = nil) or
(pPerIoDat^.OprtType = RECV_POSTED) or
(pPerIoDat^.OprtType = SEND_POSTED) ) then
begin
closesocket( CompletKey );
Dispose( pPerIoDat );
continue;
end;

if pPerIoDat^.OprtType = RECV_POSTED then
begin
fmmain.ListBox1.Items.Add( pPerIoDat^.BufData.buf );
end;

Flags := 0;
FillChar( pPerIoDat^.Overlap, sizeof(OVERLAPPED), 0 );
FillChar( pPerIoDat^.Buf[0], 4096, 0 );
pPerIoDat^.BufData.len := 4096;
pPerIoDat^.BufData.buf := pPerIoDat^.Buf;
pPerIoDat.OprtType := RECV_POSTED;

WSARecv( CompletKey, @(pPerIoDat^.BufData), 1, BytesRecv, Flags,
@(pPerIoDat^.Overlap), nil );
end;

end;

end.
//----------------------
unit thrListen;

interface

uses
Windows, Classes, Winsock2, thrRecvSend;

const
RECV_POSTED = 0;
SEND_POSTED = 1;
TIME_OUT = 110;
BUFFER_SIZE = 4096;

type
YPER_OPERATION_DATA = record
Overlap : OVERLAPPED;
BufData : WSABUF;
Buf : Array [0..BUFFER_SIZE-1] of Char;
OprtType : Integer;
end;
PPER_OPERATION_DATA = ^YPER_OPERATION_DATA;

YPER_HANDLE_DATA = record
Sock : TSocket;
Ip : Array [0..15] of Char;
Port : DWORD;
OprtType : Integer;
end;
PPER_HANDLE_DATA = ^YPER_HANDLE_DATA;


type
TListenThread = class(TThread)
private
{ Private declarations }
FCompletPort : THandle;
FListenSock : TSocket;
function InitSocket: BOOL;
protected
procedure Execute; override;
end;

implementation

uses frmMain;

{ TListenThread }

procedure TListenThread.Execute;
var
si : SYSTEM_INFO;
i, len : Integer;
AThread : TRecvSendThread;
AConnect : TSocket;
addr : TSockAddrIn;
BytesRecv,
Flags : DWORD;
pPerIoDat : PPER_OPERATION_DATA;
begin
if not InitSocket() then
Exit;

FCompletPort := CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0,0,0 );
if FCompletPort = 0 then
begin
MessageBox( 0, 'CreateIoCompletionPort failed.', 'Error', MB_OK );
Exit;
end;

GetSystemInfo( si );
for i:=0 to si.dwNumberOfProcessors-1 do
begin
AThread := TRecvSendThread.Create( True );
AThread.CompletPort := FCompletPort;
AThread.FreeOnTerminate := True;
AThread.Resume;
end;

while (not self.Terminated) do
begin
len := sizeof(addr);
AConnect := accept( FListenSock, addr, len);
if AConnect = INVALID_SOCKET then
begin
sleepex( TIME_OUT, false );
continue;
end;

CreateIoCompletionPort( AConnect, FCompletPort, AConnect, 0 );

New( pPerIoDat );

FillChar( pPerIoDat^.Overlap, sizeof(OVERLAPPED), 0 );
FillChar( pPerIoDat^.Buf[0], BUFFER_SIZE, 0 );
pPerIoDat^.BufData.len := BUFFER_SIZE;
pPerIoDat^.BufData.buf := pPerIoDat^.Buf;
pPerIoDat.OprtType := RECV_POSTED;

Flags := 0;
WSARecv( AConnect, @(pPerIoDat^.BufData), 1, BytesRecv, Flags,
@(pPerIoDat^.Overlap), nil );
end;

PostQueuedCompletionStatus( FCompletPort, 0,0,nil );
CloseHandle( FCompletPort );
end;

function TListenThread.InitSocket: BOOL;
var
addr : TSockAddr;
begin
result := False;

FListenSock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if FListenSock = INVALID_SOCKET then
begin
MessageBox( 0, 'Call socket() failed.', 'Error', MB_ICONERROR );
Exit;
end;

addr.sin_family := AF_INET;
addr.sin_port := htons(LISTEN_PORT);
addr.sin_addr.S_addr := htonl(INADDR_ANY);

if bind( FListenSock, @addr, sizeof(SOCKADDR) ) = SOCKET_ERROR then
begin
MessageBox( 0, 'Call bind failed.', 'Error', MB_ICONERROR );
Exit;
end;

if listen( FListenSock, 5 ) = SOCKET_ERROR then
begin
MessageBox( 0, 'Call listen failed.', 'Error', MB_ICONERROR );
Exit;
end;

result := True;
end;

end.
//--------------------------
这里明说了,这是从CSDN上转的,但是可以用,我调试好了,觉得也比较好懂,就给像我一样初学的人来学习一下.
现在没有连接数据库,我想让它连上数据库,并且客户端发来的SQL语句可以执行了并返回结果给客户端.谢谢
 
完成端口跟数据库没任何关系。

你这样就是求代码了,根本就不是学习。
 
to 白河愁
我真是被这个东西困绕了太久了,求代码,也是一种学习啊,有的时候一点代码比讲很多理论啊什么的更好点,因为有代码了,哪怕不会,一点点啃,总也是能啃下去的
 
同意白河愁的说法
你可以试着自己去做,有问题再贴出来大家讨论,这样对自己的能力也是一种提高。
 
我就是说怎么做,不知道从哪里入手啊!大家帮帮我,可能您一点就破,这里是关键了
 
求代码也是学习?那你从上面完成端口的代码学到什么了?

如果你真的学到了,论坛上数据库的帖子多如牛毛,随便弄一点就移植进去了。

你有恒心就先啃完 完成端口 再说了。
 
这个贴子如果有了结果了,很多人也就知道答案了,因为找了很多贴子,同类的贴子,很多人都有难点,为什么没有高手愿意面对呢,难道技术真的就是那么保守.我要是有能力,谁的问题我都想解答,关键是没有那个能力,我自己自己学的delphi,对于底层的socket通讯本就没有想再搞明白是怎么回事,如果大家都是这么没有人情味,说说就算了的话,大富翁还办不办了?
一个技术论坛,不会的就可以在这里讨论,是的,我可能是求会心切了点,说是要代码,就非要代码了吗?高手朋友们大可以捡重点点破了就是了~如果都是这么推来推去的,说你得自己去学习去,那还要这个论坛干什么,高手们也是从生手走过来的,我就不信你们就没有问过问题,像这些问题,并不是书上就有的,网上搜索就能搜得到的,才找到这里,不信你们可以搜搜看,有多少人在问类似的问题,又有多少人愿意回答呢?
再说了,就是身边没有可以问的人了才来网上发贴询问的,是的,知识就是金钱,但是现在哪个培训班里培训的是实用的东西,所以从一开始delphibbs就成了DELPHI开发人员从初级走下去的精神支撑,如果来问了,还是说,你回去看书去吧,有几个人以后还会来问问题.你们可以看看我的信息,会的问题,不会的问题,只要我能从网上找到答案的,就为别人解答,为什么,因为我知道,对方很急需大富翁的帮助,而不是说,你回去看看书吧,书上有之类的.他能找到大富翁,可能他已经没有办法了,他相信大富翁!
 
这个贴子为什么要发在这里,就算是没有人为我解答,至少说有些人想学习完成端口的,还可以看到这个很易懂的DELPHI完成端口的代码,他们可以回去一点点啃,不枉费他们找到了大富翁~
 
我使用的一段完成端口的代码,在别人的基础上做过修改。
如果学习,建议还是从理论开始吧


{*******************************************************}
{ }
{ Socket Models }
{ 封装了Socket的操作,包括服务端和客户端的类。使用了 }
{ WinSock2中Socket的定义和完成端口模型 }
{ }
{ Author: 这并不是我的代码,我在别人的代码上做了一些 }
{ 修改,感谢原作者 }
{ Data: 2007-03-18 }
{ Build: 2007-03-18 }
{ }
{*******************************************************}

unit UntSocket;

interface

{$IFDEF VER150}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$ENDIF}

uses
Windows, Messages, WinSock2, SysUtils, Classes;

const
MAX_BUFSIZE = 4096;
WM_CLIENTSOCKET = WM_USER + $2000;
DEF_SERVER_PORT = 5150;

type
TBuffer = array[0..MAX_BUFSIZE - 1] of Char;

TCMSocketMessage = packed record
Msg: Cardinal;
Socket: TSocket;
SelectEvent: Word;
SelectError: Word;
Result: Longint;
end;

TSocketEvent = (seInitIOPort, seInitSocket, seConnect, seDisconnect,
seListen, seAccept, seWrite, seRead);
TErrorEvent = (eeGeneral, eeSend, eeReceive, eeConnect, eeDisconnect, eeAccept);

PPerHandleData = ^TPerHandleData;
TPerHandleData = packed record
Overlapped: OVERLAPPED;
wsaBuffer: WSABUF;
Event: TSocketEvent;
IsUse: Boolean;
Buffer: TBuffer;
end;

PBlock = ^TBlock;
TBlock = packed record
Data: TPerHandleData;
IsUse: Boolean;
end;

EMemoryBuffer = class(Exception);
ESocketError = class(Exception);

TCustomSocket = class;
TServerClientSocket = class;

TOnDataEvent = function(Socket: TCustomSocket; Data: Pointer; Count: Integer): Integer of object;
TSocketErrorEvent = procedure(Socket: TCustomSocket; ErrorEvent: TErrorEvent; var ErrCode: Integer) of object;
TSocketEventEvent = procedure(Socket: TCustomSocket; SocketEvent: TSocketEvent) of object;

TMemoryBuffer = class
private
FList: TList;
FSocket: TCustomSocket;
function GetCount: Integer;
function GetBlock(const Index: Integer): PBlock;
protected
property Count: Integer read GetCount;
property Blocks[const Index: Integer]: PBlock read GetBlock;
public
constructor Create(ASocket: TCustomSocket); overload;
constructor Create(ASocket: TCustomSocket; BlockCount: Integer); overload;
destructor Destroy; override;
function AllocBlock: PBlock;
procedure RemoveBlock(Block: PBlock);
end;

TCustomSocket = class
private
FSocket: TSocket;
FActive: Boolean;
FName: string;
FInitLock: Boolean;
FLock: TRTLCriticalSection;
FOnRead: TOnDataEvent;
FOnErrorEvent: TSocketErrorEvent;
FOnEventEvent: TSocketEventEvent;
function GetRemoteAddress: string;
function GetLocalAddress: string;
function GetRemoteHost: string;
function GetRemotePort: string;
procedure DoRead(Data: Pointer; Count: Integer);
protected
procedure SetActive(Value: Boolean); virtual; abstract;
procedure Event(SocketEvent: TSocketEvent); virtual;
procedure Error(ErrorEvent: TErrorEvent; var ErrCode: Integer); virtual;
property OnRead: TOnDataEvent read FOnRead write FOnRead;
property OnErrorEvent: TSocketErrorEvent read FOnErrorEvent write FOnErrorEvent;
property OnEventEvent: TSocketEventEvent read FOnEventEvent write FOnEventEvent;
public
constructor Create(ASocket: TSocket);
destructor Destroy; override;
procedure Close;
procedure Open;
procedure Lock;
procedure UnLock;
function Read(var Buf; Count: Integer): Integer; virtual;
function Write(var Buf; Count: Integer): Integer; virtual;
property Socket: TSocket read FSocket;
property Active: Boolean read FActive write SetActive;
property Name: string read FName;
property RemoteHost: string read GetRemoteHost;
property LocalAddress: string read GetLocalAddress;
property RemoteAddress: string read GetRemoteAddress;
property RemotePort: string read GetRemotePort;
end;

TCustomerServerSocket = class(TCustomSocket)
private
FOnClientRead: TOnDataEvent;
FOnClientError: TSocketErrorEvent;
FOnClientEvent: TSocketEventEvent;
protected
function DoClientRead(ASocket: TCustomSocket; AData: Pointer; ACount: Integer): Integer;
procedure ClientSocketError(ASocket: TCustomSocket;
ErrorEvent: TErrorEvent; var ErrCode: Integer);
procedure ClientSocketEvent(ASocket: TCustomSocket; SocketEvent: TSocketEvent);
public
property OnClientRead: TOnDataEvent read FOnClientRead write FOnClientRead;
property OnClientError: TSocketErrorEvent read FOnClientError write FOnClientError;
property OnClientEvent: TSocketEventEvent read FOnClientEvent write FOnClientEvent;
property OnErrorEvent;
property OnEventEvent;
end;

TGetSocketEvent = procedure(Socket: TSocket; var ClientSocket: TServerClientSocket) of object;
TServerSocket = class(TCustomerServerSocket)
private
FPort: Integer;
FAddr: TSockAddr;
FAcceptThread: TThread;
FCompletionPort: THandle;
FClients: TList;
FThreads: TList;
FHandle: THandle;
FBuffer: TMemoryBuffer;
FOnGetSocket: TGetSocketEvent;
procedure SetPort(Value: Integer);
function RegisterClient(ASocket: TCustomSocket): Integer;
procedure RemoveClient(ASocket: TCustomSocket);
procedure WMClientClose(var Message: TCMSocketMessage); message WM_CLIENTSOCKET;
procedure WndProc(var Message: TMessage);
function FindClientSocket(ASocket: TSocket): TCustomSocket;
function GetClientCount: Integer;
function GetClients(const Index: Integer): TServerClientSocket;
protected
procedure InternalOpen;
procedure InternalClose;
procedure SetActive(Value: Boolean); override;
property CompletionPort: THandle read FCompletionPort;
function IsAccept(Socket: TSocket): Boolean; virtual;
public
constructor Create;
destructor Destroy; override;
procedure Accept(ASocket: TSocket; ACompletionPort: THandle);
property Handle: THandle read FHandle;
property Port: Integer read FPort write SetPort;
property ClientCount: Integer read GetClientCount;
property Clients[const Index: Integer]: TServerClientSocket read GetClients;
property OnGetSocket: TGetSocketEvent read FOnGetSocket write FOnGetSocket;
end;

TServerClientSocket = class(TCustomSocket)
private
FBlock: TList;
FBuffer: TMemoryBuffer;
FServerSocket: TServerSocket;
FClientIndex: Integer;
function AllocBlock: PBlock;
function PrepareRecv(Block: PBlock = nil): Boolean;
function WorkBlock(var Block: PBlock; Transfered: DWORD): DWORD;
protected
procedure SetActive(Value: Boolean); override;
public
constructor Create(AServerSocket: TServerSocket; ASocket: TSocket);
destructor Destroy; override;
function Read(var Buf; Count: Integer): Integer; override;
function Write(var Buf; Count: Integer): Integer; override;
property ClientIndex: Integer read FClientIndex;
end;

TClientSocket = class(TCustomSocket)
private
FServerIP: string;
FServerPort: Word;
FHandle: THandle;
FServerAddr: TSockAddr;
FBuffer: TBuffer;
procedure SetServerIP(const AValue: string);
procedure SetServerPort(const AValue: Word);
procedure InternalOpen;
procedure InternalClose;
procedure WMClientRead(var AMessage: TCMSocketMessage); message WM_CLIENTSOCKET;
procedure WndProc(var Message: TMessage);
protected
procedure SetActive(AValue: Boolean); override;
public
constructor Create;
destructor Destroy; override;
function Write(var Buf; Count: Integer): Integer; override;
property ServerIP: string read FServerIP write SetServerIP;
property ServerPort: Word read FServerPort write SetServerPort;
property OnRead;
property OnErrorEvent;
property OnEventEvent;
end;

TSocketThread = class(TThread)
private
FServer: TServerSocket;
public
constructor Create(AServer: TServerSocket);
end;

TAcceptThread = class(TSocketThread)
protected
procedure Execute; override;
end;

TWorkerThread = class(TSocketThread)
protected
procedure Execute; override;
end;

implementation

uses RTLConsts;

const
SHUTDOWN_FLAG = $FFFFFFFF;
BlockSize: Word = SizeOf(TBlock);

var
WSData: TWSAData;

{ TMemoryBuffer }

constructor TMemoryBuffer.Create(ASocket: TCustomSocket);
begin
Create(ASocket, 200);
end;

constructor TMemoryBuffer.Create(ASocket: TCustomSocket; BlockCount: Integer);
var
I: Integer;
P: PBlock;
begin
inherited Create;
FSocket := ASocket;
FList := TList.Create;
for I := 0 to BlockCount - 1 do
begin
New(P);
FillChar(P^, BlockSize, 0);
FList.Add(P);
end;
end;

destructor TMemoryBuffer.Destroy;
var
I: Integer;
begin
for I := 0 to FList.Count - 1 do
Dispose(FList);
FList.Free;
inherited Destroy;
end;

function TMemoryBuffer.AllocBlock: PBlock;
var
I: Integer;
begin
FSocket.Lock;
try
Result := nil;
for I := 0 to FList.Count - 1 do
begin
Result := FList;
if not Result.IsUse then
Break;
end;
if not Assigned(Result) or Result.IsUse then
begin
New(Result);
FList.Add(Result);
end;
FillChar(Result^.Data, SizeOf(Result^.Data), 0);
Result^.IsUse := True;
finally
FSocket.UnLock;
end;
end;

procedure TMemoryBuffer.RemoveBlock(Block: PBlock);
begin
FSocket.Lock;
try
Block.IsUse := False;
finally
FSocket.UnLock;
end;
end;

function TMemoryBuffer.GetCount: Integer;
begin
Result := FList.Count;
end;

function TMemoryBuffer.GetBlock(const Index: Integer): PBlock;
begin
if (Index >= Count) or (Index <= -1) then
raise EMemoryBuffer.CreateFmt(SListIndexError, [Index])
else
Result := FList[Index];
end;

procedure CheckError(ResultCode: Integer; const OP: string);
var
ErrCode: Integer;
begin
if ResultCode <> 0 then
begin
ErrCode := WSAGetLastError;
if (ErrCode <> WSAEWOULDBLOCK) or (ErrCode <> ERROR_IO_PENDING) then
raise ESocketError.CreateFmt(SWindowsSocketError,
[SysErrorMessage(ErrCode), ErrCode, Op]);
end;
end;

{ TCustomSocket }

constructor TCustomSocket.Create(ASocket: TSocket);
begin
inherited Create;
FInitLock := False;
FName := '';
if WSAStartup($0202, WSData) <> 0 then
raise ESocketError.Create(SysErrorMessage(GetLastError));
FSocket := ASocket;
FActive := FSocket <> INVALID_SOCKET;
end;

destructor TCustomSocket.Destroy;
begin
SetActive(False);
WSACleanup;
if FInitLock then
DeleteCriticalSection(FLock);
inherited Destroy;
end;

procedure TCustomSocket.Lock;
begin
if not FInitLock then
begin
InitializeCriticalSection(FLock);
FInitLock := True;
end;
EnterCriticalSection(FLock);
end;

procedure TCustomSocket.UnLock;
begin
if FInitLock then
LeaveCriticalSection(FLock);
end;

procedure TCustomSocket.Close;
begin
SetActive(False);
end;

procedure TCustomSocket.Open;
begin
SetActive(True);
end;

procedure TCustomSocket.DoRead(Data: Pointer; Count: Integer);
begin
if Assigned(FOnRead) then
FOnRead(Self, Data, Count);
end;

procedure TCustomSocket.Error(ErrorEvent: TErrorEvent; var ErrCode: Integer);
begin
if Assigned(FOnErrorEvent) then
FOnErrorEvent(Self, ErrorEvent, ErrCode);
end;

procedure TCustomSocket.Event(SocketEvent: TSocketEvent);
begin
if Assigned(FOnEventEvent) then
FOnEventEvent(Self, SocketEvent);
end;

function TCustomSocket.GetRemoteAddress: string;
var
SockAddrIn: TSockAddrIn;
Size: Integer;
begin
Result := '';
if not FActive then Exit;
Size := SizeOf(SockAddrIn);
CheckError(getpeername(FSocket, SockAddrIn, Size), 'getpeername');
Result := inet_ntoa(SockAddrIn.sin_addr);
end;

function TCustomSocket.GetLocalAddress: string;
var
SockAddrIn: TSockAddrIn;
Size: Integer;
begin
Result := '';
if not FActive then Exit;
Size := SizeOf(SockAddrIn);
CheckError(getsockname(FSocket, SockAddrIn, Size), 'getsockname');
Result := inet_ntoa(SockAddrIn.sin_addr);
end;

function TCustomSocket.GetRemoteHost: string;
var
SockAddrIn: TSockAddrIn;
Size: Integer;
HostEnt: PHostEnt;
begin
Result := '';
if not FActive then Exit;
Size := SizeOf(SockAddrIn);
CheckError(getpeername(FSocket, SockAddrIn, Size), 'getpeername');
HostEnt := gethostbyaddr(@SockAddrIn.sin_addr.s_addr, 4, PF_INET);
if HostEnt <> nil then Result := HostEnt.h_name;
end;

function TCustomSocket.GetRemotePort: string;
var
SockAddrIn: TSockAddrIn;
Size: Integer;
begin
Result := '';
if not FActive then Exit;
Size := SizeOf(SockAddrIn);
CheckError(getpeername(FSocket, SockAddrIn, Size), 'getpeername');
Result := IntToStr(ntohs(SockAddrIn.sin_port));
end;

function TCustomSocket.Read(var Buf; Count: Integer): Integer;
begin
raise ESocketError.Create('Error');
end;

function TCustomSocket.Write(var Buf; Count: Integer): Integer;
begin
raise ESocketError.Create('Error');
end;

{ TCustomerServerSocket }

function TCustomerServerSocket.DoClientRead(ASocket: TCustomSocket;
AData: Pointer; ACount: Integer): Integer;
begin
if not Assigned(FOnClientRead) then
Result := 0
else
Result := FOnClientRead(ASocket, AData, ACount);
end;

procedure TCustomerServerSocket.ClientSocketError(ASocket: TCustomSocket;
ErrorEvent: TErrorEvent; var ErrCode: Integer);
begin
if Assigned(FOnClientError) then
FOnClientError(ASocket, ErrorEvent, ErrCode);
end;

procedure TCustomerServerSocket.ClientSocketEvent(ASocket: TCustomSocket;
SocketEvent: TSocketEvent);
begin
if Assigned(FOnClientEvent) then
FOnClientEvent(ASocket, SocketEvent);
end;

{ TServerSocket }

procedure TServerSocket.Accept(ASocket: TSocket; ACompletionPort: THandle);
var
Addr: TSockAddrIn;
AddrLen, Ret, ErrCode: Integer;
ClientWinSocket: TSocket;
ClientSocket: TServerClientSocket;
begin
AddrLen := SizeOf(Addr);
ClientWinSocket := WinSock2.accept(ASocket, Addr, AddrLen);
if ClientWinSocket <> INVALID_SOCKET then
begin
if not Active and not IsAccept(ClientWinSocket) then
begin
closesocket(ClientWinSocket);
Exit;
end;
try
Event(seAccept);
ClientSocket := nil;
if Assigned(FOnGetSocket) then
FOnGetSocket(ClientWinSocket, ClientSocket);
if not Assigned(ClientSocket) then
ClientSocket := TServerClientSocket.Create(Self, ClientWinSocket);
ClientSocket.FName := ClientSocket.RemoteAddress + ':' + ClientSocket.RemotePort;
except
closesocket(ClientWinSocket);
ErrCode := GetLastError;
Error(eeAccept, ErrCode);
Exit;
end;
Ret := CreateIoCompletionPort(ClientWinSocket, ACompletionPort, DWORD(ClientSocket), 0);
if Ret = 0 then
ClientSocket.Free;
end;
end;

constructor TServerSocket.Create;
begin
inherited Create(INVALID_SOCKET);
FBuffer := TMemoryBuffer.Create(Self);
FClients := TList.Create;
FThreads := TList.Create;

FPort := DEF_SERVER_PORT;
FAcceptThread := nil;
FCompletionPort := 0;
IsMultiThread := True;
FHandle := Classes.AllocateHWnd(WndProc);
end;

destructor TServerSocket.Destroy;
begin
SetActive(False);
FThreads.Free;
FClients.Free;
Classes.DeallocateHWnd(FHandle);
FBuffer.Free;
inherited Destroy;
end;

function TServerSocket.FindClientSocket(ASocket: TSocket): TCustomSocket;
var
I: Integer;
begin
Lock;
try
for I := 0 to FClients.Count - 1 do
begin
Result := FClients;
if ASocket = Result.Socket then Exit;
end;
Result := nil;
finally
UnLock;
end;
end;

function TServerSocket.GetClientCount: Integer;
begin
Result := FClients.Count;
end;

function TServerSocket.GetClients(const Index: Integer): TServerClientSocket;
begin
Result := FClients[Index];
end;

procedure TServerSocket.InternalClose;

procedure CloseObject(var Handle: THandle);
begin
if Handle <> 0 then
begin
CloseHandle(Handle);
Handle := 0;
end;
end;

var
I: Integer;
Thread: TThread;
begin
Lock;
try
while FClients.Count > 0 do
TObject(FClients.Last).Free;
FClients.Clear;

for I := FThreads.Count - 1 downto 0 do
begin
Thread := FThreads;
PostQueuedCompletionStatus(FCompletionPort, 0, 0, Pointer(SHUTDOWN_FLAG));
Thread.Terminate;
end;
FThreads.Clear;

if FSocket <> INVALID_SOCKET then
begin
Event(seDisconnect);
closesocket(FSocket);
FSocket := INVALID_SOCKET;
end;
FAcceptThread.Terminate;
CloseObject(FCompletionPort);
finally
UnLock;
FActive := False;
end;
end;

procedure TServerSocket.InternalOpen;
var
I: Integer;
Thread: TThread;
SystemInfo: TSystemInfo;
begin
Lock;
try
try
FCompletionPort := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if FCompletionPort = 0 then
raise ESocketError.Create(SysErrorMessage(GetLastError));

Event(seInitIOPort);
GetSystemInfo(SystemInfo);
for I := 0 to SystemInfo.dwNumberOfProcessors * 2 - 1 do
begin
Thread := TWorkerThread.Create(Self);
FThreads.Add(Thread);
end;

FSocket := WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
if FSocket = INVALID_SOCKET then
raise ESocketError.Create(SysErrorMessage(GetLastError));
Event(seInitSocket);

FillChar(FAddr, SizeOf(FAddr), 0);
FAddr.sin_family := AF_INET;
FAddr.sin_port := htons(FPort);
FAddr.sin_addr.S_addr := INADDR_ANY;
CheckError(bind(FSocket, @FAddr, SizeOf(FAddr)), 'bind');

Event(seListen);
CheckError(listen(FSocket, SOMAXCONN), 'listen');
FAcceptThread := TAcceptThread.Create(Self);
except
InternalClose;
raise;
end;
finally
UnLock;
end;
end;

function TServerSocket.IsAccept(Socket: TSocket): Boolean;
begin
Result := True;
end;

function TServerSocket.RegisterClient(ASocket: TCustomSocket): Integer;
begin
Lock;
try
if FClients.IndexOf(ASocket) = -1 then
begin
FClients.Add(ASocket);
WSAAsyncSelect(ASocket.Socket, FHandle, WM_CLIENTSOCKET, FD_CLOSE);
end;
Result := FClients.IndexOf(ASocket);
finally
UnLock;
end;
end;

procedure TServerSocket.RemoveClient(ASocket: TCustomSocket);
var
Index: Integer;
begin
Lock;
try
Index := FClients.IndexOf(ASocket);
if Index <> -1 then
FClients.Delete(Index);
finally
UnLock;
end;
end;

procedure TServerSocket.SetActive(Value: Boolean);
begin
if FActive = Value then Exit;
FActive := Value;
if Value then
InternalOpen
else
InternalClose;
end;

procedure TServerSocket.SetPort(Value: Integer);
begin
if Active then
raise ESocketError.Create('Cann''t change port');
FPort := Value;
end;

procedure TServerSocket.WMClientClose(var Message: TCMSocketMessage);
var
ClientSocket: TCustomSocket;
begin
ClientSocket := FindClientSocket(Message.Socket);
if Assigned(ClientSocket) then
ClientSocket.Free;
end;

procedure TServerSocket.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;

{ TServerClientSocket }

constructor TServerClientSocket.Create(AServerSocket: TServerSocket;
ASocket: TSocket);
begin
inherited Create(ASocket);
FServerSocket := AServerSocket;
FBuffer := FServerSocket.FBuffer;
FBlock := TList.Create;
FClientIndex := FServerSocket.RegisterClient(Self);
FOnRead := FServerSocket.OnClientRead;
OnErrorEvent := FServerSocket.ClientSocketError;
OnEventEvent := FServerSocket.ClientSocketEvent;
PrepareRecv;
Event(seConnect);
end;

destructor TServerClientSocket.Destroy;
var
I: Integer;
begin
FServerSocket.RemoveClient(Self);
for I := FBlock.Count - 1 downto 0 do
FBuffer.RemoveBlock(FBlock);
FBlock.Free;
inherited Destroy;
end;

procedure TServerClientSocket.SetActive(Value: Boolean);
var
Linger: TLinger;
begin
if FActive = Value then Exit;
if not Value then
begin
if FSocket <> INVALID_SOCKET then
begin
Event(seDisconnect);
FillChar(Linger, SizeOf(Linger), 0);
setsockopt(FSocket, SOL_SOCKET, SO_LINGER, @Linger, Sizeof(Linger));
closesocket(FSocket);
FSocket := INVALID_SOCKET;
end;
end else
raise ESocketError.Create('当前socket不支持连接操作');
FActive := Value;
end;

function TServerClientSocket.AllocBlock: PBlock;
var
I: Integer;
begin
for I := 0 to FBlock.Count - 1 do
begin
Result := FBlock;
if not Result.Data.IsUse then
begin
Result.Data.IsUse := True;
Exit;
end;
end;
Result := FBuffer.AllocBlock;
FBlock.Add(Result);
Result.Data.IsUse := True;
end;

function TServerClientSocket.Read(var Buf; Count: Integer): Integer;
begin
{ 读操作由DoReceive触发OnRead进行读 }
raise ESocketError.Create('读操作错误');
end;

function TServerClientSocket.Write(var Buf; Count: Integer): Integer;
var
Block: PBlock;
ErrCode: Integer;
Flags, BytesSend: Cardinal;
begin
Result := Count;
if Result = 0 then Exit;
Block := AllocBlock;
with Block^.Data do
begin
Flags := 0;
Event := seWrite;
wsaBuffer.buf := @Buf;
wsaBuffer.len := Result;
if SOCKET_ERROR = WSASend(FSocket, @wsaBuffer, 1, BytesSend, Flags, @Overlapped, nil) then
begin
ErrCode := WSAGetLastError;
if ErrCode <> ERROR_IO_PENDING then
begin
Result := SOCKET_ERROR;
Error(eeSend, ErrCode);
end;
end;
end;
end;

function TServerClientSocket.PrepareRecv(Block: PBlock = nil): Boolean;
var
ErrCode: Integer;
Flags, Transfer: Cardinal;
begin
if not Assigned(Block) then
Block := AllocBlock;
with Block^.Data do
begin
Flags := 0;
Event := seRead;
FillChar(Buffer, SizeOf(Buffer), 0);
FillChar(Overlapped, SizeOf(Overlapped), 0);
wsaBuffer.buf := Buffer;
wsaBuffer.len := MAX_BUFSIZE;
Result := SOCKET_ERROR <> WSARecv(FSocket, @wsaBuffer, 1, Transfer, Flags, @Overlapped, nil);
if not Result then
begin
ErrCode := WSAGetLastError;
Result := ErrCode = ERROR_IO_PENDING;
if not Result then
begin
Block.Data.IsUse := False;
Error(eeReceive, ErrCode);
end;
end;
end;
end;

const
RESPONSE_UNKNOWN = $0001;
RESPONSE_SUCCESS = $0002;
RESPONSE_FAIL = $FFFF;

function TServerClientSocket.WorkBlock(var Block: PBlock; Transfered: DWORD): DWORD;
var
ErrCode: Integer;
Flag, BytesSend: Cardinal;
begin
Result := RESPONSE_SUCCESS;
with Block^.Data do
try
case Block^.Data.Event of
seRead:
begin
Self.Event(seRead);
DoRead(@Buffer, Transfered);
if not PrepareRecv(Block) then
Result := RESPONSE_FAIL;
end;
seWrite:
begin
Self.Event(seWrite);
Dec(wsaBuffer.len, Transfered);
if wsaBuffer.len <= 0 then
begin
{ 发送完成,将Block置空,返回到FBlock的可使用的缓区中 }
Block.Data.IsUse := False;
Block := nil;
end else
begin
{ 数据还没发送完成,继续发送 }
Flag := 0;
Inc(wsaBuffer.buf, Transfered);
FillChar(Overlapped, SizeOf(Overlapped), 0);
if SOCKET_ERROR = WSASend(FSocket, @wsaBuffer, 1, BytesSend,
Flag, @Overlapped, nil) then
begin
ErrCode := WSAGetLastError;
if ErrCode <> ERROR_IO_PENDING then
Error(eeSend, ErrCode);
end;
end;
end;
end;
except
Result := RESPONSE_FAIL;
end;
end;

{ TSocketThread }

constructor TSocketThread.Create(AServer: TServerSocket);
begin
FServer := AServer;
inherited Create(False);
FreeOnTerminate := True;
end;

{ TAcceptThread }

procedure TAcceptThread.Execute;
begin
with FServer do
while not Terminated and Active do
Accept(Socket, CompletionPort);
end;

{ TWorkerThread }

procedure TWorkerThread.Execute;
var
Block: PBlock;
Transfered: DWORD;
ClientSocket: TServerClientSocket;
begin
while FServer.Active do
begin
Block := nil;
Transfered := 0;
ClientSocket := nil;
if not GetQueuedCompletionStatus(FServer.CompletionPort, Transfered,
DWORD(ClientSocket), POverlapped(Block), INFINITE) then
begin
if Assigned(ClientSocket) then
FreeAndNil(ClientSocket);
Continue;
end;

{ 客户可能超时?? 或是断开连接,I/O失败 }
if Transfered = 0 then
begin
FreeAndNil(ClientSocket);
Continue;
end;
{ 通知结束 }
if Cardinal(Block) = SHUTDOWN_FLAG then
Break;
if not FServer.Active then
Break;

case ClientSocket.WorkBlock(Block, Transfered) of
RESPONSE_UNKNOWN:
{ 操作未知的话,应该返回给客户端:...不应该Close....保留 }
FreeAndNil(ClientSocket);
RESPONSE_FAIL:
FreeAndNil(ClientSocket);
end;
end;
end;

{ TClientSocket }

constructor TClientSocket.Create;
begin
inherited Create(INVALID_SOCKET);
FServerIP := '127.0.0.1';
FServerPort := DEF_SERVER_PORT;
FHandle := Classes.AllocateHWnd(WndProc);
FillChar(FBuffer, SizeOf(FBuffer), 0);

FillChar(FServerAddr, SizeOf(FServerAddr), 0);
end;

destructor TClientSocket.Destroy;
begin
SetActive(False);
Classes.DeallocateHWnd(FHandle);
inherited;
end;

procedure TClientSocket.InternalOpen;
begin
Lock;
try
try
FSocket := WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
if FSocket = INVALID_SOCKET then
raise ESocketError.Create(SysErrorMessage(GetLastError));
Event(seInitSocket);

FServerAddr.sin_family := AF_INET;
FServerAddr.sin_port := htons(FServerPort);
FServerAddr.sin_addr.S_addr := inet_addr(PAnsiChar(FServerIP));
CheckError(WinSock2.WSAConnect(FSocket, @FServerAddr, SizeOf(FServerAddr), nil, nil, nil, nil), 'WSAConnect');
Event(seConnect);

WSAAsyncSelect(FSocket, FHandle, WM_CLIENTSOCKET, FD_READ);
except
InternalClose;
raise;
end;
finally
UnLock;
end;
end;

procedure TClientSocket.InternalClose;
begin
Lock;
try
if FSocket <> INVALID_SOCKET then
begin
Event(seDisconnect);
ShutDown(FSocket, SD_BOTH);
closesocket(FSocket);
FSocket := INVALID_SOCKET;
end;
finally
UnLock;
end;
end;

procedure TClientSocket.SetActive(AValue: Boolean);
begin
if FActive = AValue then Exit;
if AValue then
InternalOpen
else
InternalClose;
FActive := AValue;
end;

procedure TClientSocket.SetServerIP(const AValue: string);
var
I, TmpCount: Integer;
begin
if FServerIP = AValue then
Exit;
if inet_addr(PAnsiChar(AValue)) = INADDR_NONE then
Exit;
if Length(AValue) > 15 then
Exit;
TmpCount := 0;
for I := 1 to Length(AValue) do
if AValue = '.' then
Inc(TmpCount);
if TmpCount <> 3 then
Exit;
FServerIP := AValue;
end;

procedure TClientSocket.SetServerPort(const AValue: Word);
begin
if FServerPort = AValue then
Exit;
FServerPort := AValue;
end;

procedure TClientSocket.WMClientRead(var AMessage: TCMSocketMessage);
var
TmpBufLength, TmpErrCode: Integer;
begin
FillChar(FBuffer, SizeOf(FBuffer), 0);
Self.Event(seRead);
try
TmpBufLength := WinSock2.recv(FSocket, FBuffer, SizeOf(FBuffer), 0);
if TmpBufLength = SOCKET_ERROR then
begin
TmpErrCode := WSAGetLastError;
Error(eeReceive, TmpErrCode);
Exit;
end;
if Assigned(FOnRead) then
FOnRead(Self, @FBuffer, TmpBufLength);
except
TmpErrCode := WSAGetLastError;
Error(eeReceive, TmpErrCode);
end;
end;

procedure TClientSocket.WndProc(var Message: TMessage);
begin
try
Dispatch(Message);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;

function TClientSocket.Write(var Buf; Count: Integer): Integer;
var
TmpBuf: PChar;
TmpSend, TmpLeft, TmpPosition, TmpErrCode: Integer;
begin
if not FActive then
begin
Result := SOCKET_ERROR;
Exit;
end;
Result := Count;
if Result = 0 then
Exit;
TmpBuf := @Buf;
TmpLeft := Count;
TmpPosition := 0;
try
while TmpLeft > 0 do
begin
TmpSend := WinSock2.send(FSocket, TmpBuf^, TmpLeft, 0);
if TmpSend = SOCKET_ERROR then
begin
Result := SOCKET_ERROR;
TmpErrCode := WSAGetLastError;
Error(eeSend, TmpErrCode);
Exit;
end;
TmpLeft := TmpLeft - TmpSend;
TmpPosition := TmpPosition + TmpSend;
Inc(TmpBuf, TmpPosition);
end;
except
Result := SOCKET_ERROR;
TmpErrCode := WSAGetLastError;
Error(eeSend, TmpErrCode);
end;
end;

end.
 
您给我的,我看过了,是一个叫用类封装的完成端口及测试,但是还是没有和数据库相连的部分,比我的多了发服务端返回值,我再看看
 
楼主别生气,白河愁说的不无道理,完成端口确实和数据库没有任何关系。你急于求成的心理大家是可以理解的,如果真的是想学习,我建议你先学习最基本的网络编程,就是那种用控件的方法,特别要弄清楚数据在网络上的传送和接收原理,然后再试着用socket代替控件编程,然后再学习各种模型如你感兴趣的完成端口等,然后再学习数据库编程,其中又分为控件法和原生ado之类的。因为如果用完成端口一般是那种无界面的控制台程序,所以要用到原生ado。你的程序不是改动一点点而是要整个重写服务端和客户端的数据传输部分及补写数据库操纵部分,大家都很忙估计不会有时间帮你写那么多代码。学习过程中如有疑问你可以先查本论坛的离线数据库,那种chm版的比较便于查阅。祝好运!
 
呵呵,谢谢这么多人的帮助,我在努力
 
给我你的信箱,我可以给你一个完成端口的程序
不过不涉及到数据库
可能对你用处不大
 
我的邮箱是asksomeone2002@yahoo.com.cn.我敢肯定,以后,这个贴子,学完成端口的要搜得多了,呵呵
 
如果你当初讨论的只是完成端口,我就不会这样说,但你求的却是数据库修改。

看起来就是随便找一段代码做幌子然后求代码,另外同意 newsmile 的说法。

数据库操作(原生ADO)本来是很简单的过程,如果这样都不懂把那点代码(可以搜索到的)嵌入网络中使用,那原因只有3点。

1 Delphi 基本操作 基本不懂。
解救方法:学懂基本再说。

1 网络操作,数据库操作 完全不懂。
解救方法:无。

2 懒。
解救方法:无。
 
白GG说话总是这么一针见血啊!
我倒觉得楼主还是不懂IOCP这种IO模型的,虽然楼主自己说看懂了,但看懂了没理由不会加一些简单的数据处理啊。
 
看到了完成端口,得研下,楼上得这段代码没问题吧,我可是现学啊,不要让我绕弯路,其实以前也看过,后来没时间就没弄了,现在感觉好像是忘了,记性怎么就这么差呢!哎,主要是没真正得做过,公司这方面不要我作,又想学点,技术又不过关,看书又看不进去,看进去了,过段时间又忘记了,如果装个芯片什么得就好了!
 
强烈建议搂住研究下,http://hi.baidu.com/zhaokaien/blog/item/99e7b8d6c5ec592d06088b67.html
 
多谢大家,不是懒,我在继续找资料,关于数据库的操作,我就会用adoqery,clientdataset,正在学习,谢谢白哥让我认识到哪里有问题,继续深挖中~
 
现在发现问题了,原来在LISTEN线程里有这样一段
pPerIoDat.OprtType := RECV_POSTED;

Flags := 0;
WSARecv(AConnect, @(pPerIoDat^.BufData), 1, BytesRecv, Flags,
@(pPerIoDat^.Overlap), nil);
这只是收数据,没有发数据WSASEND(),呵呵
 
顶部