[疑难] 请教iocp AcceptEx问题
hurd
2009-03-21
源文件: http://dlang.group.iteye.com/topics/download/d3707525-c01d-37ad-9adf-62ba64fbe719
iocp线程GetQueuedCompletionStatus 后, 在accept时setsockopt出现WSAENOTSOCK = 10038 错误。 检查了acceptSocket和ListSocket值和之前的都一样, 不知道什么原因? 有空的朋友给看下。。 |
|
DavidL
2009-03-22
貌似是网上找来的代码, 我把它们拼凑了一下,c++的版本和你有点出入,不懂你为什么要那样写:
// geez.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <mswsock.h> //微软扩展的类库 #include <windows.h> using namespace std; #define SEND 0 #define RECV 1 #define ACCEPT 2 #define DATA_LENGTH 1000 //单句柄数据定义 typedef struct _PER_HANDLE_DATA { SOCKET socket; //相关的套接字 SOCKADDR_STORAGE clientAddr; //客户端的地址 }PER_HANDLE_DATA,*LPPER_HANDLE_DATA; #define OP_READ 1 #define OP_WRITE 2 #define OP_ACCEPT 3 //但IO操作数据 typedef struct{ OVERLAPPED overlapped; WSABUF buffer; //一个数据缓冲区,用于WSASend/WSARecv中的第二个参数 char dataBuffer[DATA_LENGTH]; //实际的数据缓冲区 int dataLength; //实际的数据缓冲区长度 int operatorType; //操作类型,可以为SEND/RECV两种 SOCKET client; //分别表示发送的字节数和接收的字节数 }PER_IO_DATA,*LPPER_IO_DATA; DWORD WINAPI ServerThread( LPVOID lpParam ); int _tmain(int argc, _TCHAR* argv[]) { HANDLE CompletionPort; WSADATA data; SYSTEM_INFO info; SOCKADDR_IN addr; SOCKET Listen; unsigned int i; WSAStartup(MAKEWORD(2,2),&data); //创建一个IO完成端口 CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); //确定处理器的数量 GetSystemInfo(&info); //创建线城 for(i=0;i<info.dwNumberOfProcessors * 2;i++) { //根据处理器的数量创建相应多的处理线程 HANDLE thread = CreateThread(NULL,0,ServerThread,CompletionPort,0,NULL); CloseHandle(thread); } //创建一个监听套接字(进行重叠操作) Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); //将监听套接字与完成端口绑定 LPPER_HANDLE_DATA perDandleData; perDandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)); perDandleData->socket = Listen; CreateIoCompletionPort((HANDLE)Listen,CompletionPort,(ULONG_PTR)perDandleData,0); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(5500); bind(Listen,(PSOCKADDR)&addr,sizeof(addr)); listen(Listen,5); LPFN_ACCEPTEX lpfnAcceptEx = NULL; //AcceptEx函数指针 //Accept function GUID GUID guidAcceptEx = WSAID_ACCEPTEX; //get acceptex function pointer DWORD dwBytes = 0; if(WSAIoctl(Listen,SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx,sizeof(guidAcceptEx),&lpfnAcceptEx,sizeof(lpfnAcceptEx), &dwBytes,NULL,NULL)==0) cout<<"WSAIoctl success..."<<endl; else{ cout<<"WSAIoctl failed..."<<endl; switch(WSAGetLastError()) { case WSAENETDOWN: cout<<""<<endl; break; case WSAEFAULT: cout<<"WSAEFAULT"<<endl; break; case WSAEINVAL: cout<<"WSAEINVAL"<<endl; break; case WSAEINPROGRESS: cout<<"WSAEINPROGRESS"<<endl; break; case WSAENOTSOCK: cout<<"WSAENOTSOCK"<<endl; break; case WSAEOPNOTSUPP: cout<<"WSAEOPNOTSUPP"<<endl; break; case WSA_IO_PENDING: cout<<"WSA_IO_PENDING"<<endl; break; case WSAEWOULDBLOCK: cout<<"WSAEWOULDBLOCK"<<endl; break; case WSAENOPROTOOPT: cout<<"WSAENOPROTOOPT"<<endl; break; } return 1; } //while(true) //{ //准备调用 AcceptEx 函数,该函数使用重叠结构并于完成端口连接 LPPER_IO_DATA perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA)); memset(&(perIoData->overlapped),0,sizeof(OVERLAPPED)); perIoData->operatorType = ACCEPT; //在使用AcceptEx前需要事先重建一个套接字用于其第二个参数。这样目的是节省时间 //通常可以创建一个套接字库 perIoData->client = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,WSA_FLAG_OVERLAPPED); perIoData->dataLength = DATA_LENGTH; DWORD flags = 0; //调用AcceptEx函数,地址长度需要在原有的上面加上16个字节 //注意这里使用了重叠模型,该函数的完成将在与完成端口关联的工作线程中处理 cout<<"Process AcceptEx function wait for client connect..."<<endl; int rc = lpfnAcceptEx(Listen,perIoData->client,perIoData->dataBuffer, perIoData->dataLength-((sizeof(SOCKADDR_IN)+16)*2), sizeof(SOCKADDR_IN)+16,sizeof(SOCKADDR_IN)+16,&dwBytes, &(perIoData->overlapped)); if(rc == FALSE) { if(WSAGetLastError()!=ERROR_IO_PENDING) cout<<"lpfnAcceptEx failed.."<<endl; } cin>>i; closesocket(Listen); WSACleanup(); } DWORD WINAPI ServerThread( LPVOID lpParam ) { HANDLE hIocp = ( HANDLE )lpParam; if( hIocp == NULL ) { return -1; } DWORD dwTrans = 0; LPPER_HANDLE_DATA pPerHandle; LPPER_IO_DATA pPerIo; while( TRUE ) { // 在关联到此完成端口的所有套接字上等待I/O完成 BOOL bRet = ::GetQueuedCompletionStatus( hIocp, &dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIo, WSA_INFINITE ); if( !bRet ) // 发生错误 { ::closesocket( pPerHandle->socket ); ::GlobalFree( pPerHandle ); ::GlobalFree( pPerIo ); cout << "error" << endl; continue; } // 套接字被对方关闭 if( dwTrans == 0 && ( pPerIo->operatorType == OP_READ || pPerIo->operatorType == OP_WRITE ) ) { ::closesocket( pPerHandle->socket ); ::GlobalFree( pPerHandle ); ::GlobalFree( pPerIo ); cout << "client closed" << endl; continue; } switch ( pPerIo->operatorType ) { case OP_READ: // 完成一个接收请求 { pPerIo->dataBuffer[dwTrans] = '\0'; printf( "%.*s\n", pPerIo->dataLength, pPerIo->dataBuffer ); // 继续投递接受操作 WSABUF buf; buf.buf = pPerIo->dataBuffer; buf.len = pPerIo->dataLength; pPerIo->operatorType = OP_READ; DWORD dwRecv = 0; DWORD dwFlags = 0; ::WSARecv( pPerHandle->socket, &buf, 1, &dwRecv, &dwFlags, &pPerIo->overlapped, NULL ); } break; case OP_WRITE: case OP_ACCEPT: break; } } return 0; } 另外,把你的代码改成下面的样子的时候: scope(exit){ Stdout("closesocket\n").flush;closesocket(Listen);} 0Xc8000006 Line:43 CompletionPort = 7a8 Line:48 Listen = 1924 Line:53 CompletionPort = 7a8 Line:67 lpfnAcceptEx = 719c753b line:68 AcceptEx 41c636 line:72 sizeof PER_IO_DATA:1040 OVERLAPPED:20 WSABUF :8 line:77 perIoData.client 1888 d closesocket line:123 GetQueuedCompletionStatus return 0, 0 line:137 ACCEPT new socket WSAGetLastError 995 line:140 setsockopt AcceptSocket:1888, ListenSocket:1924 line:143 WSAGetLastError 10038 Line:153 re = 1960 line:159 wait for data arrive(Accept).. line:173 WSAGetLastError: 10057 你的Listen已经关闭了. 如果去掉scope(exit) closesocket(Listen);你的程序就没报错,停在那儿了 貌似这个东西和D关联不大,更接近windows编程比较吧 为什么要自己写个这个玩意儿呢,mango不是提供了http服务的实现了吗? |
|
hurd
2009-03-22
楼上的大哥, 我写的哪个w32api里的alias ProtocolType.IP IPPROTO_TCP;是错的。
应该 alias ProtocolType.TCP IPPROTO_TCP; 改了后对了。。。 |
|
DavidL
2009-03-22
我之前拿到你的代码已经是alias ProtocolType.TCP IPPROTO_TCP;
编译运行后和你帖子里描述的错误一样. |
|
hurd
2009-03-22
http://dlang.group.iteye.com/topics/download/d3707525-c01d-37ad-9adf-62ba64fbe719
现在可以了,运行example.exe后, 在浏览器输入http://127.0.0.1:5500/就可以在控制台看到接收的数据。 现在还不会发送数据。。。 |
|
hurd
2009-03-22
mango的哪个也不错,不过我想写个fcgi的服务端,计划用这个。
mango哪个程序运行时间长了可能出现空指针错误。找不到原因,可能我应用部分写的有问题。 |
|
ww21xx
2009-03-24
强烈希望 完善 IOCP EOPLL 这样写服务器 就莫得问题了!急等!
|
|
llemmx
2009-03-28
用D写IOCP有一个隐藏的问题我使用的D版本是1.28,其它的版本不知道,一开始也是反复遇到该问题,但后来调试后发现一个恶心的问题,就是结构体字节对齐问题,所以我这么修改了结构体就成功了。
struct IOData{ align(4): WSAOVERLAPPED Overlapped;// 完成结构 ubyte op; // 操作类型 ubyte buf[MAX_BUFSIZE];// 连接缓冲 ubyte len; // 缓冲区实际长度 } 解释,由于windows与D的子对齐是不一样的,结果导致在发生事件后地址偏移错误从而引发异常 |
|
ideage
2009-03-29
Tango曾经计划IOCP.可惜还没有进展.
试验了下Tango的SSL,还是不能用. |
相关讨论
相关资源推荐
- Tomcat服务器配置(catalina.policy、catalina.properties、context.xml、server.xml、tomcat-users.xml、web.xml )
- Tomcat 安全管理 Catalina.policy
- Tomcat配置文件catalina.policy 相关
- 利用Tomcat catalina.policy实现禁止文件读写demo(window版)
- Tomcat 的 catalina.properties 配置文件说明及使用配置文件处理异常
- Tomcat中Error copying file to /usr/share/tomcat7/backup/catalina.policy: /usr/share/tomcat7/backup/ca
- java jdpa指定jre_(二)catalina.bat
- catalina.bat 讲解
- windows系统tomcat日志输出至catalina.out配置说明
- catalina.bat详解