AcceptEx 调用问题,非常郁闷!倾家荡产求SOCKET 大虾们解答!(200)

  • 主题发起人 主题发起人 heroicdragon
  • 开始时间 开始时间
H

heroicdragon

Unregistered / Unconfirmed
GUEST, unregistred user!
procedure Main2;var vWsatata:WSAData; Listsocket:TSocket; serverAddr:sockaddr_in; lpfnAcceptEx:LPFN_ACCEPTEX; guidAcceptEx:TGUID; num,rc:DWORD; p:Pointer;begin lpfnAcceptEx:=nil; ZeroMemory(@serveraddr,SizeOf(serverAddr)); guidAcceptEx:=WSAID_ACCEPTEX;// WSAData wsadata;// SOCKET Listsocket;// SOCKADDR_IN ServerAddr={0};// LPFN_ACCEPTEX lpfnAcceptEx=NULL;// GUID guidAcceptEx=WSAID_ACCEPTEX;//// if (WSAStartup(MAKEWORD(2,2),&wsadata))// {//// } WSAStartup(MakeWord(2,2),vWsatata);// Listsocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED); Listsocket:=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,nil,0,WSA_FLAG_OVERLAPPED);//// in_addr in={0};// ServerAddr.sin_family=AF_INET;// ServerAddr.sin_port=htons(5050);//// ServerAddr.sin_addr=in;// ServerAddr.sin_addr.s_addr=htonl(INADDR_ANY); serverAddr.sin_family:=AF_INET; serverAddr.sin_port:=htons(5050); serverAddr.sin_addr.S_addr:=htonl(INADDR_ANY);//// bind(Listsocket,(sockaddr*)&ServerAddr,sizeof(ServerAddr));// bind(Listsocket,psockaddr(@serverAddr),SizeOf(serverAddr));// DWORD numBytes;// DWORD rc;// rc=WSAIoctl(Listsocket,// SIO_GET_EXTENSION_FUNCTION_POINTER,// &guidAcceptEx,// sizeof(guidAcceptEx),// &lpfnAcceptEx,// sizeof(lpfnAcceptEx),// &numBytes,// NULL,// NULL); p:=nil; rc:=WSAIoctl(Listsocket, SIO_GET_EXTENSION_FUNCTION_POINTER, @guidAcceptEx, SizeOf(guidAcceptEx), p, SizeOf(LPFN_ACCEPTEX), num, nil, nil); if rc<>0 then ShowMessage(Format('错误!<$%x>',[WSAGetLastError])); @lpfnAcceptEx:=p;// if (rc==SOCKET_ERROR)// {// MessageBox("错误");// }//}end;以上是我用DELPHI 实现的 AcceptEx 函数的调用过程,其中注释部分是用VC6实现的.问题为: 程序的最后面: RC 返回的不是0 ,P 的值也是为NIL ,也就是说明没有取到AcceptEx 函数的地址;而让人气奋的是,用同样的VC 代码,却能正确的取得AcceptEx 地址。一切都正常!
 
这种情况一般都是因为翻译和调用不一致造成的。你先把p 换成 @p试试吧rc:=WSAIoctl(Listsocket, SIO_GET_EXTENSION_FUNCTION_POINTER, @guidAcceptEx, SizeOf(guidAcceptEx), @p, //先改这里看看 SizeOf(LPFN_ACCEPTEX), num, //如果不行,把这里改成@num或者nil nil, nil);
 
感谢tseug, 果然是这个原因,就是应该是 @p 或者 @@lpfnAcceptEx 。最后 还有一个问题。先看代码: TPackedStatus = (PS_send, PS_Recv, PS_Close,PS_AcceptEx); pPER_IO_OPERATION_DATA = ^rPER_IO_OPERATION_DATA; rPER_IO_OPERATION_DATA = packed record Overlapped: OVERLAPPED; DataBuf: WSABUF; Statu: TPackedStatus; Socket: TSocket; BufferLen: Integer; Buffer: array[0..DATA_BUFSIZE - 1] of CHAR; end;// 创建NUM 个套接字procedure TIOCPServer.CreateNewAccept(num: Integer);var i:Integer; AcceptSocket:TSocket; pk:pPER_IO_OPERATION_DATA; retu:Cardinal; rv:Cardinal;begin for i:=0 to num-1 do begin AcceptSocket:=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP, nil,0,WSA_FLAG_OVERLAPPED); if AcceptSocket=invalid_socket then Exit; New(pk); FillChar(pk^,SizeOf(pk^),#0); pk.DataBuf.buf:=@pk.Buffer[0]; pk.DataBuf.len:=DATA_BUFSIZE; pk.BufferLen:=DATA_BUFSIZE; pk.Statu:=PS_AcceptEx; if not fAcceptEx(vListenSocketHandle,AcceptSocket,@pk.Buffer[0], DATA_BUFSIZE-(SizeOf(sockaddr_in)+16)*2-1, SizeOf(sockaddr_in)+16, SizeOf(sockaddr_in)+16, retu, @pk.Overlapped) then begin rv:=WSAGetLastError; if rv<>ERROR_IO_PENDING then begin Log(Format('Acceptex 分配错误:0x%x',[WSAGetLastError])); end; end; end;end;其中的fAcceptEx 即为WSAIoctl 取得的 AcceptEx 函数地址;现在的问题是:一,fAcceptEx总是返回失败,错误代码为:ERROR_IO_PENDING 这个错误在MSDN 上说是套接字与完成端口已经绑定成功了,但我不明白为什么不直接返回 True 二,GetQueuedCompletionStatus 无法取得连接包及任何数据包。 这是最关键的问题。所以不清楚是少了什么关键代码还是调用不对?
 
1.这样是对的...就是说IOCP已经接收了你的投递.....2.其实还是acceptex的事情....一般情况下...客户端connect的时候..GetQueuedCompletionStatus 是没有收到处理的...但客户端那边是连接成功,这时你发一个数据过来,GetQueuedCompletionStatus 就有返回了..顺便说一下,这可是可以设置的,也是在AcceptEx函数中...到底是哪个你看看,我忘了..
 
用netstat 命令查看时,套接字间确实是已经建立连接了,但是客户端发送数据时,GetQueuedCompletionStatus 依然没有响应。不知道是何原因,这种现象应该是说 fAcceptEx 调用不成功,使套接字与完成端口并没有绑定。
 
看看你的 GetQueuedCompletionStatus 第 2 个参数 是否与 AcceptEx 第 4 个参数一致
 
function GetQueuedCompletionStatus(CompletionPort: THandle; var lpNumberOfBytesTransferred, lpCompletionKey: DWORD; var lpOverlapped: POverlapped; dwMilliseconds: DWORD): BOOL; stdcall;lpNumberOfBytesTransferred:负责在完成了一次I/O操作后(如WSASend或WSARecv),接收实际传输的字节数BOOL AcceptEx( SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, DWORD dwReceiveDataLength,//以字节为单位,指定了在lpOutputBuffer缓冲区中,保留多大的空间,用于数据的接收。//如这个参数设为0,那么在连接的接受过程中,不会再一道接收任何数据 DWORD dwLocalAddressLength, DWORD dwRemoteAddressLength, LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped);我把这GetQueuedCompletionStatus 第 2 个参数 是否与 AcceptEx的第四个参数改为一至了,还是不行。同样的收不到任何信息。
 
你调用 AcceptEx时 第4个参数 是 0 吗? 如果不希望AcceptEx建立连接后等待用户发送数据,那么必须将第四个参数设为0。第5、6参数必须是对应SOCKET的地址类型的大小再加上16个字节。
 
// 创建NUM 个套接字procedure TIOCPServer.CreateNewAccept(num: Integer);var i:Integer; AcceptSocket:TSocket; pk:pPER_IO_OPERATION_DATA; retu:Cardinal; rv:Cardinal;begin for i:=0 to num-1 do begin AcceptSocket:=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP, nil,0,WSA_FLAG_OVERLAPPED); if AcceptSocket=invalid_socket then Exit; New(pk); FillChar(pk^,SizeOf(pk^),#0); pk.DataBuf.buf:=@pk.Buffer[0]; pk.DataBuf.len:=DATA_BUFSIZE; pk.BufferLen:=DATA_BUFSIZE; pk.Statu:=PS_AcceptEx; if not fAcceptEx( vListenSocketHandle, AcceptSocket, @pk.Buffer[0],// DATA_BUFSIZE - (SizeOf(sockaddr_in) + 16) * 2 - 1, 0, SizeOf(sockaddr_in) + 16, SizeOf(sockaddr_in) + 16, retu, @pk.OL) then begin rv:=WSAGetLastError; if rv<>ERROR_IO_PENDING then begin Log(Format('Acceptex 分配错误:0x%x',[WSAGetLastError])); end; end; end;end;接收部分为:var byteTransFerred: Cardinal; perIoData: pPER_IO_OPERATION_DATA; flags: Cardinal;begin flags:=0; byteTransFerred:=0; if (GetQueuedCompletionStatus( vIocp.vIocpHandle, byteTransFerred, flags, POverlapped(perIoData), INFINITE) = False) then begin //网络异常 if perIoData <> nil then begin shutdown(perIoData.Socket, 2); closesocket(perIoData.Socket); GlobalFree(dword(perIoData)); end; raise Exception.Create('网络异常:' + inttostr(WSAGetLastError)); end;如此改代码还是不对啊,偶快被气晕了。tseug 兄有空帮偶看看代码吗? QQ:42098527 谢谢!
 
有空发邮箱吧 tseug@263.net
 
太感谢楼兄的帮助了,我已经把程序发到你邮箱。静候佳音!
 
代码收到,里面缺少jedi的单元文件和winsock2,虽然修改后可以编译,但依然出错,没有时间研究是否由于我手头winsock2文件是否与你一致,最好能把相关文件一起打包发给我。
 
我发过去了。注意查收一下。
 
不知道tseug兄有没收到邮件。在此贴上还能加分吗?我计划再加上100分。
 
搞DELPHI的人真的越来越少了。哎。。。。。
 
也不少吧....只是很忙....
 
可能tseug 最近很忙,不过我还是把帖结了。由于是tseug解决了主要问题,因为分给180分。再次感谢tseug的帮助!
 
后退
顶部