向你请教一个疑问.
在发送32 个字节正常.( 这里好奇怪,字节数多一点也正常..现在就是40个不正常.)我用IOCP出现这样的情况:
C 端发送40 个字节.
S 端的
GetQueuedCompletionStatus(pThis->m_hIocp,&lenght,&key, (OVERLAPPED **) &pov,INFINITE);这个lenght值是32.
要投递一个读操作( 可以读出来后面的8个字节.)
if(ov.dwTotol>lenght)
{//在第一次没有读被完的情况...这时的读才真正的生效,,
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-lenght, 0, (OVERLAPPED *)&ov);
//或 WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,& ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 ); 把后8 个字节读完.
return false;
}
接收数据正常.
但下次C端再发送数据.
GetQueuedCompletionStatus 还在阻塞着.
不能调度.
用TCPVIEW 监视. 端口 是 ESTABLISHED 状态.
有什么办法可以让 S 端 一次投递完成接收.
或者二次接收之后.
下次 数据到来能正常投递?逢UP给分....可以开贴再给... int COICPServer::InitServer( UINT nPort )
{
HL thread; // vector of thread handles
HLI hli; // iterator into that vector
OICPOL ovl; // linked list of OVERLAPPED derivates
OICPOLI ovi; // iterator into that list
HANDLE h; // temporary thread handle
int i;
unsigned int dummy;
m_hsuicideEvent = CreateEvent( 0, TRUE, FALSE, 0 );
m_hEvenWaitingSocketClose=CreateEvent(NULL,TRUE,FALSE,0);
m_hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0, 0, 0 );
VERIFY(m_hIocp);
// create threads
SYSTEM_INFO si={ 0 };
GetSystemInfo(&si);
si.dwNumberOfProcessors=1;
for ( i = 0; i < (int)si.dwNumberOfProcessors; ++ i )
{
h = (HANDLE) _beginthreadex( 0, 0, s_Worker, this, 0, &dummy );
if ( VALID( h ) )
thread.push_back(h);
}WSADATA wd = { 0 };
LRESULT e;
e = WSAStartup( MAKEWORD( 2, 2 ), &wd );
// create listen socket
SOCKADDR_IN addr;
m_slistener = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
HANDLE hListen=CreateIoCompletionPort( (HANDLE) m_slistener, m_hIocp, 0, 0 );
if(hListen==NULL)
{
ASSERT(FALSE);
return FALSE;
}addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons( (short) nPort );
VERIFY(bind( m_slistener, (SOCKADDR *) &addr, sizeof SOCKADDR )==ERROR_SUCCESS) ;
VERIFY(listen( m_slistener, 20 )==ERROR_SUCCESS);
// wait until end indicated
// kick socket scavenger loose
for ( i = 0; i < MAX_CLIENT_SOCK; ++ i )
{
OV *o = new OV;
o->state = stAccepting;
o->sktbuf=new char [MAX_RECV_BUF+2*IPADDRLENGHT];
ReinitContext( *o );
if ( o->skt != INVALID_SOCKET )
ovl.push_back( o );
}WaitForSingleObject( m_hsuicideEvent, INFINITE );
closesocket( m_slistener );
m_slistener = INVALID_SOCKET;
// 关闭的.不贴代码了.
return LRESULT();
}
void COICPServer::ReinitContext(OV &ov)
{
int zero = 0;
if(ov.skt!=SOCKET_ERROR)
closesocket(ov.skt);
ov.skt = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if ( ov.skt != INVALID_SOCKET )
{
ov.state = stAccepting;
setsockopt( ov.skt, SOL_SOCKET, SO_SNDBUF, (char *) &zero, sizeof zero );
setsockopt( ov.skt, SOL_SOCKET, SO_RCVBUF, (char *) &zero, sizeof zero );
if(ov.sktbuf!=NULL)
memset( ov.sktbuf, '\0', MAX_RECV_BUF );
if(!AcceptEx( m_slistener, ov.skt, ov.sktbuf,MAX_LISTEN_BUF_SIZE, IPADDRLENGHT,IPADDRLENGHT, &ov.dwLenght, &ov ))
{
int n=IPADDRLENGHT;
LRESULT lErrcode=WSAGetLastError();
if(lErrcode!=ERROR_IO_PENDING)
{
ASSERT(FALSE);
}
}
}
}void COICPServer::DoClose( OV& ov, bool clientforceClose/*=FALSE*/, bool listenAgain/*=TRUE*/ )
{
struct linger li = { 0, 0 };
if ( clientforceClose )
{
li.l_onoff = 1;
}
ASSERT(ov.skt!=NULL);
setsockopt( ov.skt, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof li );
closesocket( ov.skt );
ov.skt=SOCKET_ERROR;
if ( listenAgain )
ReinitContext( ov );
}
BOOL COICPServer::PostRead( OV &ov,DWORD dwReadLenght/*=MAX_RECV_BUF*/,BOOL fForceRead )
{
long result,errcoe;
errcoe=WSAGetLastError();
if(ov.state==stReadBegin)
{
LPNETCLIENT pNccLogo=(LPNETCLIENT)ov.sktbuf;
ov.dwAlreadyOp=0;
if(pNccLogo->szHead[0]!='B' ¦ ¦ pNccLogo->szHead[1]!='J')
return FALSE;
ov.dwTotol=pNccLogo->lenght;
TRACE("----------------- time_off=%08x recv lenght=%d SOCKET %08x headflag %c%c---------------\n",pNccLogo->nTimerSycn,pNccLogo->lenght,ov.skt,pNccLogo->szHead[0],pNccLogo->szHead[1]);
}
ov.dwAlreadyOp+=dwReadLenght;
ov.recvFlags=0;
ov.state=stReading;
ov.dwLenght=0;
ov.wbuf.len=ov.dwTotol;//-ov.dwAlreadyOp-dwReadLenght;
ov.wbuf.buf=ov.sktbuf;//+ov.dwAlreadyOp+dwReadLenght;
if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
{//在第一次没有读被完的情况..
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
return FALSE;
}
result = WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,&ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 );
ov.dwAlreadyOp+=ov.dwLenght;
if(ov.dwLenght!=0)
{
TRACE("---------读取多少字节-------- recv lenght=%d---------------\n",ov.dwLenght);
return FALSE;
}
if ( result==SOCKET_ERROR )
{//WSAENOBUFS
errcoe=WSAGetLastError();
if(errcoe!=WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
}
if(dwReadLenght+ov.dwAlreadyOp>= ov.dwTotol)
{
ParseWorker(ov);
}
return FALSE;}
UINT __stdcall COICPServer::s_Worker( void * arg )
{
DWORD n;
ULONG key;
BOOL result;
OV *pov;
COICPServer *pThis=(COICPServer*) arg;
InterlockedIncrement( &pThis->m_lrunningThreads );
for ( ; ; )
{
InterlockedDecrement( &pThis->m_lrunningThreads );
result = GetQueuedCompletionStatus(pThis->m_hIocp,&n,&key, (OVERLAPPED **) &pov,INFINITE);
InterlockedIncrement( &pThis->m_lrunningThreads );
if ( result == FALSE ) // something gone awry?
{
DWORD dwIOError = GetLastError();
if(WAIT_TIMEOUT!=dwIOError && 0x000003e3 != dwIOError)
{
pThis->DoClose( *pov, true, pThis->m_slistener == INVALID_SOCKET? false: true );
}
}
else if(pov!=NULL) // GQCS() returned TRUE
{
int locallen, remotelen;
sockaddr_in *plocal = 0, *premote = 0;
char bValue;
// what was that socket doing, anyway?
UINT lerrcode=0;
switch (pov->state)
{
case stAccepting:
GetAcceptExSockaddrs( pov->sktbuf, MAX_LISTEN_BUF_SIZE,IPADDRLENGHT,IPADDRLENGHT, (sockaddr **) &plocal, &locallen,(sockaddr **) &premote, &remotelen );
memcpy( &pov->peer, premote, sizeof sockaddr_in );
setsockopt( pov->skt, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,(char *) &pThis->m_slistener, sizeof SOCKET );
// we still need to associate the newly connected socket to our IOCP:
CreateIoCompletionPort( (HANDLE) pov->skt, pThis->m_hIocp, 0, 0);
lerrcode=setsockopt(pov->skt,IPPROTO_TCP,TCP_NODELAY,&bValue,sizeof(char)); // add by Auly
pov->state=stReadBegin;
pThis->PostRead(*pov,n);
break; // nothing read yet, don't attempt to buffer it
case stReadBegin:
pThis->PostRead(*pov,n);
break;
case stReading:
//pov->dwAlreadyOp+=n;
if(pov->dwTotol <=pov->dwAlreadyOp+n)
pThis->ParseWorker(*pov);
else
pThis->PostRead(*pov,n);
break;
case stWriting:
pov->dwAlreadyOp+=n;
if(pov->dwTotol>pov->dwAlreadyOp)
pThis->PostWrite(*pov);
else
pov->state=stReadBegin;
break;
case stReadCompleted:
ASSERT(FALSE);
pov->state=stReading;
break;
}
}
}
InterlockedDecrement( &pThis->m_lrunningThreads );
TRACE("s_Worker end\n");
return 0;
}BOOL COICPServer::PostWrite(OV& ov)
{
ov.state=stWriting;
ov.wbuf.buf+=ov.dwAlreadyOp;
ov.wbuf.len-=ov.dwAlreadyOp;
memset(ov.sktbuf,0,ov.wbuf.len);
LRESULT lErrcode=WSASend(ov.skt,&ov.wbuf,1,&ov.dwLenght,/*flag*/0,&ov,NULL);
if ( lErrcode==SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
TRACE("PostWrite()--------------------lenght %d\n",ov.dwLenght);
ov.dwLenght=0;
return TRUE;
}
在发送32 个字节正常.( 这里好奇怪,字节数多一点也正常..现在就是40个不正常.)我用IOCP出现这样的情况:
C 端发送40 个字节.
S 端的
GetQueuedCompletionStatus(pThis->m_hIocp,&lenght,&key, (OVERLAPPED **) &pov,INFINITE);这个lenght值是32.
要投递一个读操作( 可以读出来后面的8个字节.)
if(ov.dwTotol>lenght)
{//在第一次没有读被完的情况...这时的读才真正的生效,,
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-lenght, 0, (OVERLAPPED *)&ov);
//或 WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,& ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 ); 把后8 个字节读完.
return false;
}
接收数据正常.
但下次C端再发送数据.
GetQueuedCompletionStatus 还在阻塞着.
不能调度.
用TCPVIEW 监视. 端口 是 ESTABLISHED 状态.
有什么办法可以让 S 端 一次投递完成接收.
或者二次接收之后.
下次 数据到来能正常投递?逢UP给分....可以开贴再给... int COICPServer::InitServer( UINT nPort )
{
HL thread; // vector of thread handles
HLI hli; // iterator into that vector
OICPOL ovl; // linked list of OVERLAPPED derivates
OICPOLI ovi; // iterator into that list
HANDLE h; // temporary thread handle
int i;
unsigned int dummy;
m_hsuicideEvent = CreateEvent( 0, TRUE, FALSE, 0 );
m_hEvenWaitingSocketClose=CreateEvent(NULL,TRUE,FALSE,0);
m_hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0, 0, 0 );
VERIFY(m_hIocp);
// create threads
SYSTEM_INFO si={ 0 };
GetSystemInfo(&si);
si.dwNumberOfProcessors=1;
for ( i = 0; i < (int)si.dwNumberOfProcessors; ++ i )
{
h = (HANDLE) _beginthreadex( 0, 0, s_Worker, this, 0, &dummy );
if ( VALID( h ) )
thread.push_back(h);
}WSADATA wd = { 0 };
LRESULT e;
e = WSAStartup( MAKEWORD( 2, 2 ), &wd );
// create listen socket
SOCKADDR_IN addr;
m_slistener = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
HANDLE hListen=CreateIoCompletionPort( (HANDLE) m_slistener, m_hIocp, 0, 0 );
if(hListen==NULL)
{
ASSERT(FALSE);
return FALSE;
}addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons( (short) nPort );
VERIFY(bind( m_slistener, (SOCKADDR *) &addr, sizeof SOCKADDR )==ERROR_SUCCESS) ;
VERIFY(listen( m_slistener, 20 )==ERROR_SUCCESS);
// wait until end indicated
// kick socket scavenger loose
for ( i = 0; i < MAX_CLIENT_SOCK; ++ i )
{
OV *o = new OV;
o->state = stAccepting;
o->sktbuf=new char [MAX_RECV_BUF+2*IPADDRLENGHT];
ReinitContext( *o );
if ( o->skt != INVALID_SOCKET )
ovl.push_back( o );
}WaitForSingleObject( m_hsuicideEvent, INFINITE );
closesocket( m_slistener );
m_slistener = INVALID_SOCKET;
// 关闭的.不贴代码了.
return LRESULT();
}
void COICPServer::ReinitContext(OV &ov)
{
int zero = 0;
if(ov.skt!=SOCKET_ERROR)
closesocket(ov.skt);
ov.skt = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if ( ov.skt != INVALID_SOCKET )
{
ov.state = stAccepting;
setsockopt( ov.skt, SOL_SOCKET, SO_SNDBUF, (char *) &zero, sizeof zero );
setsockopt( ov.skt, SOL_SOCKET, SO_RCVBUF, (char *) &zero, sizeof zero );
if(ov.sktbuf!=NULL)
memset( ov.sktbuf, '\0', MAX_RECV_BUF );
if(!AcceptEx( m_slistener, ov.skt, ov.sktbuf,MAX_LISTEN_BUF_SIZE, IPADDRLENGHT,IPADDRLENGHT, &ov.dwLenght, &ov ))
{
int n=IPADDRLENGHT;
LRESULT lErrcode=WSAGetLastError();
if(lErrcode!=ERROR_IO_PENDING)
{
ASSERT(FALSE);
}
}
}
}void COICPServer::DoClose( OV& ov, bool clientforceClose/*=FALSE*/, bool listenAgain/*=TRUE*/ )
{
struct linger li = { 0, 0 };
if ( clientforceClose )
{
li.l_onoff = 1;
}
ASSERT(ov.skt!=NULL);
setsockopt( ov.skt, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof li );
closesocket( ov.skt );
ov.skt=SOCKET_ERROR;
if ( listenAgain )
ReinitContext( ov );
}
BOOL COICPServer::PostRead( OV &ov,DWORD dwReadLenght/*=MAX_RECV_BUF*/,BOOL fForceRead )
{
long result,errcoe;
errcoe=WSAGetLastError();
if(ov.state==stReadBegin)
{
LPNETCLIENT pNccLogo=(LPNETCLIENT)ov.sktbuf;
ov.dwAlreadyOp=0;
if(pNccLogo->szHead[0]!='B' ¦ ¦ pNccLogo->szHead[1]!='J')
return FALSE;
ov.dwTotol=pNccLogo->lenght;
TRACE("----------------- time_off=%08x recv lenght=%d SOCKET %08x headflag %c%c---------------\n",pNccLogo->nTimerSycn,pNccLogo->lenght,ov.skt,pNccLogo->szHead[0],pNccLogo->szHead[1]);
}
ov.dwAlreadyOp+=dwReadLenght;
ov.recvFlags=0;
ov.state=stReading;
ov.dwLenght=0;
ov.wbuf.len=ov.dwTotol;//-ov.dwAlreadyOp-dwReadLenght;
ov.wbuf.buf=ov.sktbuf;//+ov.dwAlreadyOp+dwReadLenght;
if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
{//在第一次没有读被完的情况..
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
return FALSE;
}
result = WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,&ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 );
ov.dwAlreadyOp+=ov.dwLenght;
if(ov.dwLenght!=0)
{
TRACE("---------读取多少字节-------- recv lenght=%d---------------\n",ov.dwLenght);
return FALSE;
}
if ( result==SOCKET_ERROR )
{//WSAENOBUFS
errcoe=WSAGetLastError();
if(errcoe!=WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
}
if(dwReadLenght+ov.dwAlreadyOp>= ov.dwTotol)
{
ParseWorker(ov);
}
return FALSE;}
UINT __stdcall COICPServer::s_Worker( void * arg )
{
DWORD n;
ULONG key;
BOOL result;
OV *pov;
COICPServer *pThis=(COICPServer*) arg;
InterlockedIncrement( &pThis->m_lrunningThreads );
for ( ; ; )
{
InterlockedDecrement( &pThis->m_lrunningThreads );
result = GetQueuedCompletionStatus(pThis->m_hIocp,&n,&key, (OVERLAPPED **) &pov,INFINITE);
InterlockedIncrement( &pThis->m_lrunningThreads );
if ( result == FALSE ) // something gone awry?
{
DWORD dwIOError = GetLastError();
if(WAIT_TIMEOUT!=dwIOError && 0x000003e3 != dwIOError)
{
pThis->DoClose( *pov, true, pThis->m_slistener == INVALID_SOCKET? false: true );
}
}
else if(pov!=NULL) // GQCS() returned TRUE
{
int locallen, remotelen;
sockaddr_in *plocal = 0, *premote = 0;
char bValue;
// what was that socket doing, anyway?
UINT lerrcode=0;
switch (pov->state)
{
case stAccepting:
GetAcceptExSockaddrs( pov->sktbuf, MAX_LISTEN_BUF_SIZE,IPADDRLENGHT,IPADDRLENGHT, (sockaddr **) &plocal, &locallen,(sockaddr **) &premote, &remotelen );
memcpy( &pov->peer, premote, sizeof sockaddr_in );
setsockopt( pov->skt, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,(char *) &pThis->m_slistener, sizeof SOCKET );
// we still need to associate the newly connected socket to our IOCP:
CreateIoCompletionPort( (HANDLE) pov->skt, pThis->m_hIocp, 0, 0);
lerrcode=setsockopt(pov->skt,IPPROTO_TCP,TCP_NODELAY,&bValue,sizeof(char)); // add by Auly
pov->state=stReadBegin;
pThis->PostRead(*pov,n);
break; // nothing read yet, don't attempt to buffer it
case stReadBegin:
pThis->PostRead(*pov,n);
break;
case stReading:
//pov->dwAlreadyOp+=n;
if(pov->dwTotol <=pov->dwAlreadyOp+n)
pThis->ParseWorker(*pov);
else
pThis->PostRead(*pov,n);
break;
case stWriting:
pov->dwAlreadyOp+=n;
if(pov->dwTotol>pov->dwAlreadyOp)
pThis->PostWrite(*pov);
else
pov->state=stReadBegin;
break;
case stReadCompleted:
ASSERT(FALSE);
pov->state=stReading;
break;
}
}
}
InterlockedDecrement( &pThis->m_lrunningThreads );
TRACE("s_Worker end\n");
return 0;
}BOOL COICPServer::PostWrite(OV& ov)
{
ov.state=stWriting;
ov.wbuf.buf+=ov.dwAlreadyOp;
ov.wbuf.len-=ov.dwAlreadyOp;
memset(ov.sktbuf,0,ov.wbuf.len);
LRESULT lErrcode=WSASend(ov.skt,&ov.wbuf,1,&ov.dwLenght,/*flag*/0,&ov,NULL);
if ( lErrcode==SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
TRACE("PostWrite()--------------------lenght %d\n",ov.dwLenght);
ov.dwLenght=0;
return TRUE;
}
解决方案 »
- VC给word里添加图片
- 怎么样设置完全自绘的控件的颜色,UpdateLayeredWindow才能显示?
- 请问关于建立菜单的问题
- 数据库重连无效,大家来讨论一下,分不多了,以后会补
- UTF-8编码转换成十六进制编码??
- ■■没办法了,来这里请教VB问题,谢谢!■■
- 请问,如何在创建窗口时指定同一文档的不同类?(是在程序中手工创建,不是用VC提供的“新建”命令)
- 在datagrid如何单击确定其行值,列值、或者单击那一行的pSet。
- 一个简单问题,在线等待!
- 给定一个已打开的IE窗口的IWebBrowser2指针,欲新开一个IE,并使之显示的内容和已打开的IE窗口的一模一样,即模仿IE的“文件 | 新建 | 窗口”菜单的功能,该怎么做?
- RichEdit控件怎么用?
- 在vc下,我想把从sqlserver数据库里的数据,按照一定的格式输出到word中,我该怎么办?在线等,多谢帮忙。
//
// Description:
//
// This sample illustrates how to develop a simple echo server Winsock
// application using the completeion port I/O model. This
// sample is implemented as a console-style application and simply prints
// messages when connections are established and removed from the server.
// The application listens for TCP connections on port 5150 and accepts them
// as they arrive. When this application receives data from a client, it
// simply echos (this is why we call it an echo server) the data back in
// it's original form until the client closes the connection.
//
// Compile:
//
// cl -o iocmplt iocmplt.cpp ws2_32.lib
//
// Command Line Options:
//
// iocmplt.exe
//
// Note: There are no command line options for this sample.
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);
void main(void)
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret;
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
}
// Setup an I/O completion port.
if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
printf( "CreateIoCompletionPort failed with error: %d\n", GetLastError());
return;
}
// Determine how many processors are on the system.
GetSystemInfo(&SystemInfo);
// Create worker threads based on the number of processors available on the
// system. Create two worker threads for each processor.
for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
{
HANDLE ThreadHandle;
// Create a server worker thread and pass the completion port to the thread.
if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,
0, &ThreadID)) == NULL)
{
printf("CreateThread() failed with error %d\n", GetLastError());
return;
}
// Close the thread handle
CloseHandle(ThreadHandle);
}
// Create a listening socket
if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return;
}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
}
// Prepare socket for listening
if (listen(Listen, 5) == SOCKET_ERROR)
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
}
while(TRUE)
{
if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
{
printf("WSAAccept() failed with error %d\n", WSAGetLastError());
return;
}
// Create a socket information structure to associate with the socket
if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return;
}
// Associate the accepted socket with the original completion port.
printf("Socket number %d connected\n", Accept);
PerHandleData->Socket = Accept;
if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
0) == NULL)
{
printf("CreateIoCompletionPort failed with error %d\n", GetLastError());
return;
}
// Create per I/O socket information structure to associate with the
// WSARecv call below.
if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return;
}
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->BytesSEND = 0;
PerIoData->BytesRECV = 0;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
Flags = 0;
if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return;
}
}
}
}
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;
while(TRUE)
{
if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
printf("GetQueuedCompletionStatus failed with error %d\n", GetLastError());
return 0;
}
// First check to see if an error has occured on the socket and if so
// then close the socket and cleanup the SOCKET_INFORMATION structure
// associated with the socket.
if (BytesTransferred == 0)
{
printf("Closing socket %d\n", PerHandleData->Socket);
if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
return 0;
}
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
// Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call.
if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
}
if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{
// Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;
if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
return 0;
}
}
}
else
{
PerIoData->BytesRECV = 0;
// Now that there are no more bytes to send post another WSARecv() request.
Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return 0;
}
}
}
}
}
这个代码是微软官方的IOCP代码 在实际的项目中 我想并没有实际的意义期待laiyiling 兄发表一下您真实项目中的感受 让大家学习一下 谢谢
在 PostRead()函数中, 下面这段代码是有问题的.if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
{//在第一次没有读被完的情况..
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
return FALSE;
}其问题在于:
1.它是错的.用PostQueuedCompletionStatus并不能提交给内核一个读操作,它只是发了一个消息到IOCP队列中.
2.它是多余的.如果第1次没读玩,第2次也不一定就完成.一个packet可能被拆分成很多分.
不要幻想可以将某packet一次读完,它不受应用程序控制.
删掉这段,基本就可以了.
{//在第一次没有读被完的情况..
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
return FALSE;
}其问题在于:
1.它是错的.用PostQueuedCompletionStatus并不能提交给内核一个读操作,它只是发了一个消息到IOCP队列中.
2.它是多余的.如果第1次没读玩,第2次也不一定就完成.一个packet可能被拆分成很多分.
不要幻想可以将某packet一次读完,它不受应用程序控制.
删掉这段,基本就可以了.