ok, 我投降。 关于GetAcceptExSockAddrs(300分)

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

Another_eYes

Unregistered / Unconfirmed
GUEST, unregistred user!
用AcceptEx接收客户端连接后 调用GetAcceptExSockAddrs试图获取local ip和remote ip,结果@#$%%^&*@@#!!
不断尝试各种可能15小时终告失败。 只得放弃GetAcceptExSockAddrs而直接从那块buffer中特定偏移量处复制获取了ip. 心有不甘,特向各位大富翁求教。

部分关键代码:

说明:
fnextsocket是TCPServer中的一个类变量,
fnextsocket.FOV.ov是个_OVERLAPPED结构
fnextsocket.fsockethandle是一个socket句柄
fnextsocket.faddr是TSockAddrIn结构,用于存储address信息
fhandle是TCPServer中的变量,用来listen的socket句柄
fSockAddrs是TCPServer中的一个数组:array [0..63] of byte;

procedure TCPServer.AcceptNext;
var
l: Cardinal;
begin
fillchar(fnextsocket.FOV.ov, sizeof(_OVERLAPPED), #0);
fnextsocket.FSocketHandle := winsock2.socket(AF_INET, SOCK_STREAM, 6);
if acceptex(fhandle, fnextsocket.fSocketHandle, @fsockaddrs, 0, 32,
32, l, poverlapped(@(fnextsocket.fov))) then
tryacceptuser
else if getlasterror <> ERROR_IO_PENDING then
close;
end;

procedure TCPServer.TryAcceptUser;
var
name: TSockAddrIn;
l1, l2: Integer;
flg : Boolean;
begin
GetAcceptExSockaddrs(pointer(@fsockaddrs), 6, 32,
32, name, l1, fnextsocket.faddr, l2);
flg := true;
if assigned(fcanaccept) then
FCanAccept(inet_ntoa(fnextsocket.fAddr.sin_addr), flg);
if flg then
。。。。
end;

-->中断于GetAcceptExSockaddrs,察看fsockaddrs得到数据:
(1, 0, 0, 0, 1, 0, 0, 0, 14, 0, 2, 0, 4, 210, 192, 168, 100, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 14, 0, 2, 0, 15, 191, 192, 168, 100, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
很明显,通过肉眼观察可以发现local ip和 remote ip都是 192.168.100.80
继续运行GetAcceptExSockaddrs后却得到:
name为:
(sin_family:9824, sin_port:208, sin_addr:(s_un_b:(s_b1:'$',s_b2: '
 
书上说GetAcceptExSockaddrs的前4个参数必须与AcceptEx的参数数值匹配(也就是说参数值一样),会不会是因为这个原因?
 
不好意思,GetAcceptExSockaddrs(pointer(@fsockaddrs), 6, 32,
32, name, l1, fnextsocket.faddr, l2);中的6原来是0, 测试n次(从0-16都试过)后忘了改回来了.不过这个值不管是几答案都不对
 
给你继续关注。。。。。。
 
数据类型转换错了?
 
我想看看大哥的代码,EMAIL已发。。。
 
我的邮箱:smhp@163.net
 
凑个热闹 [:D]
goofree@163.com
 
呵呵,我刚才作了一个例子,测试通过了,一点问题都没有,显示的IP和端口都是正确的,
[:D]
 
同时我的AcceptEx;GetAcceptExSockaddrs是用WSAIoctl导入的,实话说
太麻烦了,一些细节问题很讨嫌。
 
张兄, 代码已发, 拜托拜托......
虽然我现在是直接读取buffer获取address的,不过我怀疑在其他操作系统上是否还正确(我用的是2000 professional)
 
邮件已回复,谢谢你提供的那几个很好用的类,[:D]
 
晕死,原来delphi的winsock.pas中的定义是错的。
procedure GetAcceptExSockaddrs(lpOutputBuffer: Pointer;
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
var LocalSockaddr: TSockAddr; var LocalSockaddrLength: Integer;
var RemoteSockaddr: TSockAddr; var RemoteSockaddrLength: Integer); stdcall;

应当改成:
procedure GetAcceptExSockaddrs(lpOutputBuffer: Pointer;
dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
var LocalSockaddr: PSockAddr; var LocalSockaddrLength: Integer;
var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: Integer); stdcall;
才对啊。

感谢张无忌帮我发现了delphi的一个bug......

不过你赚了,我可亏大了......[:(]
 
[:D]DELPHI的函数声名里还有一些BUG。。。[:(]
 
老大最近很忙吧,下面是我的完成端口类库中的CListenClient的实现,可以用,但还没仔细测试过。连续加班2个星期了,没时间写这个了

#include "StdAfx.h"
#include "./acceptclient.h"
#include "./ListenClient.h"

CListenClient::CListenClient(HANDLE completionPort,CIOCPServer* owner)
: CIOCPClient(1,owner,completionPort)
, m_fnAcceptEx(NULL)
, m_alertCount(0)
{
}

CListenClient::~CListenClient(void)
{
}

// 开始监听端口并投递异步的接收请求
bool CListenClient::listen(unsigned long address, unsigned short port,unsigned long initCount,unsigned long alertCount)
{
bool result=false;
SOCKADDR_IN saLocal;

//创建Socket并绑定到完成端口
if(loadAcceptExFn() && loadGetAcceptExSockaddrs())
{
//绑定端口
saLocal.sin_family=AF_INET;
saLocal.sin_port=htons(port);
saLocal.sin_addr.s_addr=htonl(address);
if(bind(getSocket(),(SOCKADDR *)&saLocal,sizeof(saLocal))!=SOCKET_ERROR)
{
if(::listen(getSocket(),SOMAXCONN)!=SOCKET_ERROR)
{
//投递initCount个异步接收请求
doAcceptExCall(initCount);
result=true;
}
}
}

return result;
}


// 加载AcceptEx函数
bool CListenClient::loadAcceptExFn(void)
{
bool result=false;
GUID GuidAcceptEx=WSAID_ACCEPTEX;
DWORD bytesReturned=0;

if(WSAIoctl(getSocket(),
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&m_fnAcceptEx,
sizeof(m_fnAcceptEx),
&bytesReturned,
NULL,
NULL)!=SOCKET_ERROR)
{
result=true;
}

return result;
}

// 装载GetAcceptExSockaddrs函数
bool CListenClient::loadGetAcceptExSockaddrs(void)
{
bool result=false;
GUID GuidGetAcceptExSockaddrs=WSAID_GETACCEPTEXSOCKADDRS;
DWORD bytesReturned=0;

if(WSAIoctl(getSocket(),
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidGetAcceptExSockaddrs,
sizeof(GuidGetAcceptExSockaddrs),
&m_fnGetAcceptExSockaddrs,
sizeof(LPFN_GETACCEPTEXSOCKADDRS),
&bytesReturned,
NULL,
NULL)!=SOCKET_ERROR)
{
result=true;
}

return result;
}

// 解析地址
void CListenClient::parseAddr(char* buf, SOCKADDR* localAddr, SOCKADDR* remoteAddr, int* localAddrLen, int* remoteAddrLen)
{
m_fnGetAcceptExSockaddrs(buf,
0,
sizeof(SOCKADDR_IN)+16,
sizeof(SOCKADDR_IN)+16,
&localAddr,
localAddrLen,
&remoteAddr,
remoteAddrLen);
}

// 停止监听
void CListenClient::stop(void)
{
closeSocket();
}

// 投递一定数量的异步AcceptEx请求
void CListenClient::doAcceptExCall(unsigned int count)
{
CAcceptClient* acceptClient=NULL;
CBuffer* recvBuffer=NULL;
DWORD bytesDone=0;

for(unsigned long i=0;i<count;i++)
{
//由CIOCPServer生成client
acceptClient=getOwner()->createAcceptClient();
if(acceptClient!=NULL)
{
//为这次异步请求增加引用
acceptClient->addRef();
//生成缓冲区
recvBuffer=acceptClient->createBuffer(4*1024,4*1024,BUFFER_ACCEPTEX);
//投递异步接收请求
if(!m_fnAcceptEx(getSocket(),
acceptClient->getSocket(),
recvBuffer->getBufferBase(),
0,//recvBuffer->getBufferSize()-((sizeof(SOCKADDR_IN)+16)*2),不接收数据
sizeof(SOCKADDR_IN)+16,
sizeof(SOCKADDR_IN)+16,
&bytesDone,
recvBuffer))
{
if(WSAGetLastError()!=ERROR_IO_PENDING)
{
//操作失败
acceptClient->release();
getOwner()->dropClient(acceptClient);
}
}
}
else
{
getOwner()->dropClient(acceptClient);
}
}
}
 
to gxcooo:
服务器的呢?一并贴出来吧!谢谢了!
 
to ego:
目前只有9个类,基本功能基本实现,目前就是在做投递异步AcceptEx请求,基本完成,还差一个监控已投递异步AcceptEx请求数量的线程(低于一定数量要补上)
我打算再做完投递异步连接请求后发布一个版本,我会在这里发布的[:)]
让你失望了,不好意思
 
连续忙了一个月了,一直没时间做啊[:(]
 
不好意思的是我,呵呵,平白无故地要人家的代码......
等你做好再贴出来吧,谢谢了!
 
你不要也要公布啊,以前做的小东西都是在大富翁公布源码的[:D]
 
后退
顶部