没有任何连接AcceptEx 居然返回997错误???

xuxian02092213 2008-10-12 08:46:23
我以前从来没有尝试使用AcceptEx函数编写服务器网络模块,今天想使用这个函数,但是出现了问题。就是没有任何连接,但是函数调用出现了997错误(ERROR_IO_PENDING),不知何解,望路过的高手帮我解答下。代码如下(仅仅是一个简单的列子):


#include <stdio.h>
#include <winsock2.h>
#include <mswsock.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")

using namespace std;

typedef struct _PerData
{
WSAOVERLAPPED ol;
SOCKADDR_IN ClientAddr;
int ClientAddrLen;
SOCKET ClientSocket;
WSABUF Buf;
} PerData;
HANDLE ComPort;

DWROD _stdcall ServerWorkThread(LPVOID )
{
return 0;
}
void main()
{
WSADATA Wsadata;

SYSTEM_INFO Info;

PerData PD;
SOCKET ListenSocket;
HANDLE ComPort;

LPFN_ACCEPTEX lpfnAcceptEx=NULL;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs=NULL;

GUID GuidGetAcceptExSockaddrs=WSAID_GETACCEPTEXSOCKADDRS;
GUID GuidAcceptEx=WSAID_ACCEPTEX;

char Buf[1024];
DWORD NumBytes;
DWORD flag;
int rc,i;

if(WSAStartup(MAKEWORD(2,2),&Wsadata))
{ cout<<"注册失败!"<<endl;
getchar();
}
ComPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,NULL);
if(ComPort==INVALID_HANDLE_VALUE)
{ cout<<"创建端口失败"<<endl;
getchar();
}

GetSystemInfo(&Info);
for(i=0;i<Info.dwNumberOfProcessors*2;i++)
{
HANDLE Handle;
Handle=CreateThread(NULL,0,ServerWorkThread,ComPort,0,NULL);
CloseHandle(Handle);
}

ListenSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if(ListenSocket==INVALID_SOCKET)
{ cout<<"套接字创建失败!错误:"<<WSAGetLastError()<<endl;
exit(0);
}

PD.Buf.buf=Buf;
PD.Buf.len=10;
PD.ClientSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if(PD.ClientSocket==INVALID_SOCKET)
{ cout<<"套接字创建失败!错误:"<<WSAGetLastError()<<endl;
exit(0);
}

PD.ClientAddr.sin_family =AF_INET;
PD.ClientAddr.sin_port =htons(5050);
PD.ClientAddr.sin_addr.s_addr=(htonl)(INADDR_ANY);

if(bind(ListenSocket,(SOCKADDR*)&PD.ClientAddr,sizeof(PD.ClientAddr))==SOCKET_ERROR)
{ cout<<"套接字绑定失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}

rc=WSAIoctl(ListenSocket,SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&lpfnAcceptEx,
sizeof(lpfnAcceptEx),
&NumBytes,
NULL,
NULL);
if(rc==SOCKET_ERROR)
{ cout<<"加载lpfnAcceptEx函数失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}
if(listen(ListenSocket,5)==SOCKET_ERROR)
{ cout<<"监听套接字失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}

cout<<"开始接受连接!!!"<<endl;
while(TRUE)
{
memset(&PD.ol,0,sizeof(WSAOVERLAPPED));

if(!lpfnAcceptEx(ListenSocket,
PD.ClientSocket,
PD.Buf.buf,10,
sizeof(SOCKADDR_IN)+16,
sizeof(SOCKADDR_IN)+16,
&NumBytes,
(WSAOVERLAPPED*)&PD))
{
printf("接受连接失败!错误:%d\n",WSAGetLastError());
getchar();
continue;
}
printf("投递成功!\n");
}
...全文
779 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuxian02092213 2008-10-14
  • 打赏
  • 举报
回复
反映有点迟钝,楼上的代码看是看懂了,但不知道从那个地方看出它的高性能???就是因为将几个步骤放在了一起了???但是

它得必须一直调用WSAWaitForMultipleEvents()、WSAResetEvent()函数。。。。如此使用,是否没有体现出高性能呢??
xuxian02092213 2008-10-14
  • 打赏
  • 举报
回复

我刚刚试试了baihacker的例子,发现用户投递成功后,数据不能到达完成端口,只能在main()

中,不知道我是否有什么不对的地方???工作者线程中添加了GetQueuedCompletionPort()函数,但是他一直到达不了这个函

数,我在main()中使用了WSAWaitForMultipleEvents()和WSAResetEvent()函数,没有使用WSAGetOverlappedResult()

函数,是否是因为调用了一次WSAWaitForMultipleEvents()的缘故呢??如果是,那如何使完成端口知道呢???
baihacker 2008-10-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 xuxian02092213 的回复:]
acceptex函数其实做了一个简单化,将接受连接和接受第一次数据放在一起,然后就是将socket同完成端口关联起来,其实也是一样的,如果没有连接是时候,是否也会等待呢???
[/Quote]
...
acceptex把接受连接和接受第一次数据放在一起,没有意见,同完成端口关联,也没有意见.
但是楼主注意的是,但是注意到这里的重叠结构.
当完成的时候才通知内核对象,也就是说要直到收到数据才会有,在其它时候都是等待.
用完成端口不过是,在完成的时候在端口上处理罢了.

winsocket的那些模型始终在解决一个,在什么时候才能处理数据的问题,因为数据的发送和接收,调用一下就可以了,但是要等其完成才能进行处理.

所以什么事件模型,异步选择,重叠端口,完成端口,都是在解决这个问题,只是选择了不同的方式.

而acceptex如你所说,只是一个简单化...
baihacker 2008-10-13
  • 打赏
  • 举报
回复
额是
PD.ol.hEvent = 一个事件.
然后
用WaitFor函数族
接着
WSAGetOverlappedResult
...
然后该干什么就干什么.
baihacker 2008-10-13
  • 打赏
  • 举报
回复
重新看了一下,大概明白这个函数了.
你应该继续等待这个IO的完成.利用PD这个重叠结构.
baihacker 2008-10-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 xuxian02092213 的回复:]
我不同意四楼的看法。如果说acceptex调用没有连接就返回997的话,在acceptex的时候是要分配缓冲的,而系统是循环调用acceptex的,按你的意思就是返回997后表示正常,那么会进行下轮循环,这个时候,如果没有连接,系统也会不断分配内存,这样岂不是一个没有任何意义的函数,就更别提高性能了!!

我以前使用WSARecv、WSASend的时候可能会返回ERROR_IO_PENDING ,这表示的是数据正在放送,或者是正在接受,也可能是调用成功正…
[/Quote]
msdn如是说.
xuxian02092213 2008-10-13
  • 打赏
  • 举报
回复
我不同意四楼的看法。如果说acceptex调用没有连接就返回997的话,在acceptex的时候是要分配缓冲的,而系统是循环调用acceptex的,按你的意思就是返回997后表示正常,那么会进行下轮循环,这个时候,如果没有连接,系统也会不断分配内存,这样岂不是一个没有任何意义的函数,就更别提高性能了!!

我以前使用WSARecv、WSASend的时候可能会返回ERROR_IO_PENDING ,这表示的是数据正在放送,或者是正在接受,也可能是调用成功正而系统没有资源了,只能等待有资源的时候再发送或者是接受。

acceptex函数其实做了一个简单化,将接受连接和接受第一次数据放在一起,然后就是将socket同完成端口关联起来,其实也是一样的,如果没有连接是时候,是否也会等待呢???
herman~~ 2008-10-13
  • 打赏
  • 举报
回复
非阻塞的acceptex,个人没使用过
lala_benben 2008-10-13
  • 打赏
  • 举报
回复
。。。。
zhuwanglove 2008-10-13
  • 打赏
  • 举报
回复
学习.
xuxian02092213 2008-10-13
  • 打赏
  • 举报
回复
我看了你的上面的代码,很好。你在main()中投递了一个AcceptEx函数,使用一个循环去等待接受完成。。。。。。。。。。。


看你的意思就是接受完数据后再投递AcceptEx罗????如果你想在Work线程中去等待接收数据的话,在监听线程中又如何去

投递AcceptEx函数呢,你的思路是有事件已传信,才能下次投递。。。。(系统肯定是循环投递AcceptEx函数,如果循环投递,

则每次投递都会出现ERROR_IO_PENDING,则系统就会一直投递没有任何连接的AcceptEx,造成内存浪费,如果投递完AcceptEx

函数就等待的话,那么work线程就形同虚设,没有任何意义了,因为work线程就是等待数据接收完成的并处理数据)

不知可以说错的地方
baihacker 2008-10-13
  • 打赏
  • 举报
回复

//用重叠模型写了一个接收并显示的,自己改成完成端口,VC9下测试.
//很多收尾工作没有做.

#include <stdio.h>
#include <winsock2.h>
#include <mswsock.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")

using namespace std;

typedef struct _PerData
{
WSAOVERLAPPED ol;
SOCKADDR_IN ClientAddr;
int ClientAddrLen;
SOCKET ClientSocket;
WSABUF Buf;
} PerData;
HANDLE ComPort;

DWORD _stdcall ServerWorkThread(LPVOID )
{
return 0;
}
void main()
{
WSADATA Wsadata;

SYSTEM_INFO Info;

PerData PD;
SOCKET ListenSocket;
HANDLE ComPort;

LPFN_ACCEPTEX lpfnAcceptEx=NULL;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs=NULL;

GUID GuidGetAcceptExSockaddrs=WSAID_GETACCEPTEXSOCKADDRS;
GUID GuidAcceptEx=WSAID_ACCEPTEX;

char Buf[1024];
DWORD NumBytes;
DWORD flag;
int rc,i;

if(WSAStartup(MAKEWORD(2,2),&Wsadata))
{ cout<<"注册失败!"<<endl;
getchar();
}
ComPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,NULL);
if(ComPort==INVALID_HANDLE_VALUE)
{ cout<<"创建端口失败"<<endl;
getchar();
}

GetSystemInfo(&Info);
for(i=0;i<Info.dwNumberOfProcessors*2;i++)
{
HANDLE Handle;
Handle=CreateThread(NULL,0,ServerWorkThread,ComPort,0,NULL);
CloseHandle(Handle);
}

ListenSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if(ListenSocket==INVALID_SOCKET)
{ cout<<"套接字创建失败!错误:"<<WSAGetLastError()<<endl;
exit(0);
}

PD.Buf.buf=Buf;
PD.Buf.len=10;
PD.ClientSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if(PD.ClientSocket==INVALID_SOCKET)
{ cout<<"套接字创建失败!错误:"<<WSAGetLastError()<<endl;
exit(0);
}

PD.ClientAddr.sin_family =AF_INET;
PD.ClientAddr.sin_port =htons(5050);
PD.ClientAddr.sin_addr.s_addr=(htonl)(INADDR_ANY);

if(bind(ListenSocket,(SOCKADDR*)&PD.ClientAddr,sizeof(PD.ClientAddr))==SOCKET_ERROR)
{ cout<<"套接字绑定失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}

rc=WSAIoctl(ListenSocket,SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&lpfnAcceptEx,
sizeof(lpfnAcceptEx),
&NumBytes,
NULL,
NULL);
if(rc==SOCKET_ERROR)
{ cout<<"加载lpfnAcceptEx函数失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}
if(listen(ListenSocket,5)==SOCKET_ERROR)
{ cout<<"监听套接字失败!错误:"<<WSAGetLastError()<<endl;
getchar();
return ;
}

cout<<"开始接受连接!!!"<<endl;

memset(&PD.ol,0,sizeof(WSAOVERLAPPED));

PD.ol.hEvent = WSACreateEvent();
DWORD tran;
lpfnAcceptEx(ListenSocket,
PD.ClientSocket,
PD.Buf.buf,10,
sizeof(SOCKADDR_IN)+16,
sizeof(SOCKADDR_IN)+16,
&NumBytes,
(WSAOVERLAPPED*)&PD.ol);
while (1)
{
WSAWaitForMultipleEvents(1, &PD.ol.hEvent, 1, WSA_INFINITE, 0);
WSAResetEvent(PD.ol.hEvent);
WSAGetOverlappedResult(PD.ClientSocket, &PD.ol, &tran, 1, &flag);
if (tran)
{
PD.Buf.buf[tran] = 0;
printf("%s", PD.Buf.buf);
}
else
{
closesocket(PD.ClientSocket);
break;
}
WSARecv(PD.ClientSocket, &PD.Buf, 1, &tran, &flag, &PD.ol, NULL);
}
}

开始接受连接!!!
abcdefghijklmn请按任意键继续. . .

baihacker 2008-10-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 xuxian02092213 的回复:]
不行的啊,二楼的大哥,我改了,却出现了


C/C++ codeLinking...
Test.obj : error LNK2001: unresolved external symbol __imp__listen@8
Test.obj : error LNK2001: unresolved external symbol __imp__WSAIoctl@36
Test.obj : error LNK2001: unresolved external symbol __imp__bind@12
Test.obj : error LNK2001: unresolved external symbol __imp__htonl@4
Test.obj : error LNK2001: unresolved external symb…
[/Quote]
If the function fails, AcceptEx returns FALSE. The WSAGetLastError function can then be called to return extended error information. If WSAGetLastError returns ERROR_IO_PENDING, then the operation was successfully initiated and is still in progress. If the error is WSAECONNRESET, an incoming connection was indicated, but was subsequently terminated by the remote peer prior to accepting the call.
返回ERROR_IO_PENDING是正常的.
因为这个函数是非阻塞的,也就是调用就马上返回,而且用ERROR_IO_PENDING说明调用的结果,如果没有连接当然就返回了.
xuxian02092213 2008-10-12
  • 打赏
  • 举报
回复
不行的啊,二楼的大哥,我改了,却出现了

Linking...
Test.obj : error LNK2001: unresolved external symbol __imp__listen@8
Test.obj : error LNK2001: unresolved external symbol __imp__WSAIoctl@36
Test.obj : error LNK2001: unresolved external symbol __imp__bind@12
Test.obj : error LNK2001: unresolved external symbol __imp__htonl@4
Test.obj : error LNK2001: unresolved external symbol __imp__htons@4
Test.obj : error LNK2001: unresolved external symbol __imp__WSAGetLastError@0
Test.obj : error LNK2001: unresolved external symbol __imp__WSASocketA@24
Test.obj : error LNK2001: unresolved external symbol __imp__WSAStartup@8
Debug/AcceptExTest.exe : fatal error LNK1120: 8 unresolved externals
Error executing link.exe.


这个是什么原因呢,我将ws2_32.lib和MSWSOCK.lib都保留,编译没有错,但是结果还是和先前一样。???求救啊!!
chlaws 2008-10-12
  • 打赏
  • 举报
回复
AcceptEx

GetAcceptExSockaddrs

TransmitFile

WSARecvEx

These functions are not exported from the WS2_32.DLL; they are exported from MSWSOCK.DLL

把#pragma comment(lib,"ws2_32.lib")
改成
#pragma comment(lib,"MSWSOCK.lib")
帅得不敢出门 2008-10-12
  • 打赏
  • 举报
回复
帮顶

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧