怎样通过WSAIoctl 获得 AcceptEx? ( 积分: 300 )

  • 主题发起人 主题发起人 yyljt
  • 开始时间 开始时间
Y

yyljt

Unregistered / Unconfirmed
GUEST, unregistred user!
试了好长时间了,就是得不到,错误是10107 ,查了许多资料没有头续,vc下倒是很简单的,在delphi下如何得到呢?各位达人告诉我一下!
 
虽然这方面我不太了解,但是如果有VC的源码的话,应该不困难的,楼主可以试着直接翻译VC源码。
 
我就是有vc的代码啊,用在delphi中用WSAIoctl就是得不到AcceptEx的地址,错误的大概意思是不因该错误的却错误了.有谁知道啊?分不够可以加啊!
 
WSAIoctl在2.0的库中AcceptEx在1.0的库中,调用时,好像要重新动太加载1.0的地址,记的不太清楚,没有用过这样的设计,不过在那看到过的.
除非你要在连接时发附带数据。listen的 Socket用 WASAccept不行吗?


发现Indy10里面的:Line 3865
function ServiceQueryAcceptEx(sListenSocket, sAcceptSocket: TSocket;
lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;
lpOverlapped: POverlapped): BOOL;
const GuidAcceptEx:TGuid=(D1:$b5367df1;D2:$cbac;D3:$11cf;D4:($95,$ca,$00,$80,$5f,$48,$a1,$92));
var LStatus : integer;
LAcceptEx : TAcceptExProc;
begin
LStatus:=WSAIoctl(sListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, @GuidAcceptEx, sizeof(GuidAcceptEx),
@@LAcceptEx, sizeof(@LAcceptEx), nil, nil, nil);
if LStatus=0 then begin
result := LAcceptEx( sListenSocket, sAcceptSocket,
lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped);
end else begin
result := false;// WSAGetLastError returns 10022 when function is not supported
end;
End;



http://www.delphibbs.com/delphibbs/dispq.asp?lid=2422504


在部分人都认为服务器上需要专门做一个线程去定时查看是否有实际已经不存在的连接,以便腾出
更多的资源供新的连接使用。这也并不是用完成端口模型编写的服务器才需要考虑的问题,用其它
模型编写的服务器一样存在这个问题。我没有测试过这样做的实效。无论如何,对完成端口模型中
总是有一个对连接的读操作请求一直没有返回,如果连接被某种因素断开应该会导致完成端口返回
一个字节数为零的读操作结果,同样会导致服务器断开此连接。我没有从Microsoft的相关文档上
看到有关的警告。
如果接受连接采用的是Microsoft扩展的AcceptEx函数而不是Accept或WSAAccept函数的话,需要考
虑防止DoS(拒绝服务)攻击,恶意客户占用连接后并不发送数据将导致函数AcceptEx的调用不能够正
常返回,而令合法客户无法连接进来。这是另外一个问题。这时候的轮询只需要考虑每一个守候着
的AcceptEx函数是否已连接以及连接的时间长短。长时间的连接而不发送数据的连接可以主动关闭
它。AcceptEx是唯一一个支持完成端口的接受连接函数。Accept/WSAAccept函数在与客户连接后,
才返回一个新的套接字,所以无法事先与完成端口关联。与而AcceptEx是事先创建一个套接字,在
还没有与客户连接的时候就与完成端口关联,一旦连接成功,便获得完成端口的通知。只可惜MS在
设计这个函数的时候一定要接收到部分数据才返回,所以给Dos攻击者提供了机会。不过我认为这样
可以省去监听线程,而设计一个不算繁忙的轮询线程一定会带来服务器性能的提升。
 
to jfyes
你的方法我早就试过了,不行啊,用了indy的IdWinsock2.pas 来代替winsock2.pas发现它的代码也不能得到AcceptEx的地址,返回的是nil,这不知道有什么技巧?
 
没有测试过的, 关于使用AcceptEx的贴子有很多你查查看
 
我顶一下
 
var
fnAcceptEx: TAcceptEx;
fnGetAcceptExSocketAddrs :lpfnGetAcceptExSocketAddrs;

...
fnAcceptEx := WSAGetExtensionFunctionPointer(m_scktHandle,WSAID_ACCEPTEX);
fnGetAcceptExSocketAddrs := WSAGetExtensionFunctionPointer(SocketHandle,WSAID_GETACCEPTEXSOCKADDRS);

---------------------- 以下是网上的资料,我整理后的一个单元, 先uses 它

unit WinSockExt;

interface

uses
Windows, WinSock2;

const
{ Extension function pointers' GUIDs }
WSAID_ACCEPTEX: System.TGUID = '{B5367DF1-CBAC-11CF-95CA-00805F48A192}';
WSAID_CONNECTEX: System.TGUID = '{25A207B9-DDF3-4660-8EE9-76E58C74063E}';
WSAID_DISCONNECTEX: System.TGUID = '{7FDA2E11-8630-436F-A031-F536A6EEC157}';
WSAID_GETACCEPTEXSOCKADDRS: System.TGUID = '{B5367DF2-CBAC-11CF-95CA-00805F48A192}';
WSAID_TRANSMITFILE: System.TGUID = '{B5367DF0-CBAC-11CF-95CA-00805F48A192}';
WSAID_TRANSMITPACKETS: System.TGUID = '{D9689DA0-1F90-11D3-9971-00C04F68C876}';
WSAID_RECVMSG: System.TGUID = '{F689D7C8-6F1F-436B-8A53-E54FE351C322}';

type
lpfnAcceptEx = function(sListenSocket: TSocket; sAcceptSocket: TSocket; lpOutputBuffer: Pointer;
dwReceiveDataLength: DWORD; dwLocalAddressLength: DWORD; dwRemoteAddressLength: DWORD;
lpdwBytesReceived: PDWORD; lpOverlapped: POverlapped): BOOL; stdcall;
TAcceptEx = lpfnAcceptEx;

lpfnDisconnectEx = function(hSocket: TSocket; lpOverlapped: POverlapped; dwFlags: DWORD;
reserved: DWORD): BOOL; stdcall;
TDisconnectEx = lpfnDisconnectEx;

lpfnConnectEx = function(s: TSocket; const name: TSockAddr; namelen: Integer;
lpSendBuffer: Pointer; dwSendDataLength: DWORD; lpdwBytesSent: PDWORD;
lpOverlapped: POverlapped): BOOL; stdcall;
TConnectEx = lpfnConnectEx;

lpfnGetAcceptExSocketAddrs = procedure(lpOutputBuffer: Pointer; dwReceiveDataLength: DWORD;
dwLocalAddressLength : DWORD; dwRemoteAddressLength: DWORD; var LocalSockaddr: PSockAddr;
LocalSockaddrLength: PDWORD; var RemoteSockaddr: PSockAddr; RemoteSockaddrLength: PDWORD); stdcall;
TGetAcceptExSockAddrs = lpfnGetAcceptExSocketAddrs;

LPTRANSMIT_FILE_BUFFERS = ^TRANSMIT_FILE_BUFFERS;
TRANSMIT_FILE_BUFFERS = record
Head: Pointer;
HeadLength: DWORD;
Tail: Pointer;
TailLength: DWORD;
end;

TTransmitFileBuffers = TRANSMIT_FILE_BUFFERS;
PTransmitFileBuffers = LPTRANSMIT_FILE_BUFFERS;

lpfnTransmiteFile = function(hSocket: TSocket; hFile: THandle; nNumberOfBytesToWrite: DWORD;
nNumberOfBytesPerSend: DWORD; lpOverlapped: POverlapped; lpTransmitBuffers: PTransmitFileBuffers;
dwFlags: DWORD): BOOL; stdcall;
TTransmitFile = lpfnTransmiteFile;

LPTRANSMIT_PACKETS_ELEMENT = ^TRANSMIT_PACKETS_ELEMENT;

TRANSMIT_PACKETS_ELEMENT = record
dwElFlags: DWORD;
cLength: DWORD;
case Boolean of
False: (
nFileOffset: LARGE_INTEGER;
hFile: THandle;
);
True: (
pBuffer: Pointer;
);
end;

TTransmitPacketsElement = TRANSMIT_PACKETS_ELEMENT;
PTransmitPacketsElement = LPTRANSMIT_PACKETS_ELEMENT;

lpfnTransmitPackets = function(hSocket: TSocket; lpPacketArray: PTransmitPacketsElement;
nElementCount: DWORD; nSendSize: DWORD; lpOverlapped: POverlapped; dwFlags: DWORD): BOOL; stdcall;
TTransmitPackets = lpfnTransmitPackets;

LPWSAMSG = ^WSAMSG;
WSAMSG = record
name: PSockAddr;
namelen: DWORD;
lpBuffers: LPWSABUF;
dwBufferCount: DWORD;
Control: WSABUF;
dwFlags: DWORD;
end;

PWSAMsg = LPWSAMSG;
TWSAMsg = WSAMSG;

lpfnWSARecvMsg = function(s: TSocket; lpMsg: PWSAMsg; lpNumberOfBytesRecvd: PDWORD;
lpOverlapped: LPWSAOVERLAPPED; lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): Integer; stdcall;
TWSARecvMsg = lpfnWSARecvMsg;

function WSAGetExtensionFunctionPointer(s: TSocket; const gdExFuncGuid: System.TGUID): Pointer;

implementation

function WSAGetExtensionFunctionPointer(s: TSocket; const gdExFuncGuid: System.TGUID): Pointer;
var
lwOut: Longword;
begin
Result := nil;
WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, @gdExFuncGuid, SizeOf(gdExFuncGuid),
@Result, SizeOf(Result), @lwOut, nil, nil);
end;

end.
 
如果接受连接采用的是Microsoft扩展的AcceptEx函数而不是Accept或WSAAccept函数的话,需要考
虑防止DoS(拒绝服务)攻击,恶意客户占用连接后并不发送数据将导致函数AcceptEx的调用不能够正
常返回,而令合法客户无法连接进来。这是另外一个问题。这时候的轮询只需要考虑每一个守候着
的AcceptEx函数是否已连接以及连接的时间长短。长时间的连接而不发送数据的连接可以主动关闭
它。AcceptEx是唯一一个支持完成端口的接受连接函数。Accept/WSAAccept函数在与客户连接后,
才返回一个新的套接字,所以无法事先与完成端口关联。与而AcceptEx是事先创建一个套接字,在
还没有与客户连接的时候就与完成端口关联,一旦连接成功,便获得完成端口的通知。只可惜MS在
设计这个函数的时候一定要接收到部分数据才返回,所以给Dos攻击者提供了机会。不过我认为这样
可以省去监听线程,而设计一个不算繁忙的轮询线程一定会带来服务器性能的提升。


--------------------------
我不这样认为,你要 AcceptEx 时,不传 InputBuffer 与 OutputBuffer 就可以了。这样只要有连接过来就马上返回,与 Accept 差不多。如果用了 OutputBuffer ,那它要等到有数据收到才从完成端口中返回。

它与 Accept 最大的区别就是可以在 accept 以前就建立一个 socket 句柄。这样有新连接来时就没有了创建句柄时的开销。这样就可以建立一个连接池。比如你在建立完成端口时就建一个 1000个Socet句柄的池。每次 AcceptEx 时从里面拿一个出来,用完了,再建

但据我的测试,效率也没有想象中好。也许我水平不够
 
QSmile 提供的代码可以得到acceptex的地址,不知是不是WSAID_ACCEPTEX: System.TGUID = '{B5367DF1-CBAC-11CF-95CA-00805F48A192}'; 与const GuidAcceptEx:TGuid=(D1:$b5367df1;D2:$cbac;D3:$11cf;D4:($95,$ca,$00,$80,$5f,$48,$a1,$92));这里不同的原因,我用const GuidAcceptEx:TGuid=(D1:$b5367df1;D2:$cbac;D3:$11cf;D4:($95,$ca,$00,$80,$5f,$48,$a1,$92));这个得不到acceptex的地址,如用上面的,编译出错。在新开的工程里用WSAID_ACCEPTEX: System.TGUID = '{B5367DF1-CBAC-11CF-95CA-00805F48A192}就行了,其它的代码样的。结贴了.
 
后退
顶部