| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- #include "StdAfx.h"
- #include "NetServer.h"
- #include "NetClient.h"
- #include "NetLinkMain.h"
- CNetServer::CNetServer(CNetLinkMain* pParent) : CSocketBase(pParent), m_lpfnAcceptEx(NULL), m_lpfnGetAcceptExSockAddrs(NULL)
- {
- }
- CNetServer::~CNetServer(void)
- {
- // 释放掉所有的IO上下文数据
- for( int i = 0; i < m_ArrayIoContext.GetCount(); ++i)
- {
- delete m_ArrayIoContext.GetAt(i);
- }
- m_ArrayIoContext.RemoveAll();
- }
- /*****************************************************************
- **【函数名称】 __newIoContext
- **【函数功能】 创建IoContext用于接收客户端连接
- **【参数】
- **【返回值】
- ****************************************************************/
- CNetServer::PPER_IO_CONTEXT CNetServer::__newIoContext( void )
- {
- PPER_IO_CONTEXT pContext = new PER_IO_CONTEXT;
- ASSERT(pContext != NULL);
- m_ArrayIoContext.Add( pContext );
- return pContext;
- }
- /*****************************************************************
- **【函数名称】 __deleteIoContext
- **【函数功能】 删除废弃的IoContext
- **【参数】
- **【返回值】
- ****************************************************************/
- void CNetServer::__deleteIoContext( PPER_IO_CONTEXT pIoContext )
- {
- ASSERT( pIoContext != NULL );
- for( int i=0; i<m_ArrayIoContext.GetCount(); ++i )
- {
- if( pIoContext == m_ArrayIoContext.GetAt(i) )
- {
- m_ArrayIoContext.RemoveAt(i);
- delete pIoContext;
- pIoContext = NULL;
- break;
- }
- }
- }
- /*****************************************************************
- **【函数名称】 __postAccept
- **【函数功能】 投递Accept请求
- **【参数】
- **【返回值】
- ****************************************************************/
- bool CNetServer::__postAccept( PPER_IO_CONTEXT pIoContext )
- {
- ASSERT( INVALID_SOCKET != m_Socket );
- // 准备参数
- DWORD dwBytes = 0;
- pIoContext->resetBuffer();
- WSABUF *pWsaBuf = &pIoContext->m_wsaBuf;
- OVERLAPPED *pOl = &pIoContext->m_Overlapped;
- // 为以后新连入的客户端先准备好Socket( 这个是与传统accept最大的区别 )
- pIoContext->m_sockAccept = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
- if( INVALID_SOCKET == pIoContext->m_sockAccept )
- return false;
- // 投递AcceptEx
- if(FALSE == m_lpfnAcceptEx(m_Socket, pIoContext->m_sockAccept, pWsaBuf->buf, 0, sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, &dwBytes, pOl))
- {
- if(WSA_IO_PENDING != WSAGetLastError())
- return false;
- }
- return true;
- }
- /*****************************************************************
- **【函数名称】 doJob
- **【函数功能】 开始创建客户端并投递Accept请求
- **【参数】
- **【返回值】
- ****************************************************************/
- void CNetServer::doJob( OVERLAPPED* pOverLapped, DWORD BytesTransfered )
- {
- ASSERT(pOverLapped != NULL);
- SOCKADDR_IN* ClientAddr = NULL;
- SOCKADDR_IN* LocalAddr = NULL;
- int remoteLen = sizeof(SOCKADDR_IN), localLen = sizeof(SOCKADDR_IN);
- PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverLapped, PER_IO_CONTEXT, m_Overlapped);
- ASSERT(pIoContext != NULL);
- // 1. 首先取得连入客户端的地址信息
- m_lpfnGetAcceptExSockAddrs(pIoContext->m_wsaBuf.buf, 0, sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16,
- (LPSOCKADDR*)&LocalAddr, &localLen, (LPSOCKADDR*)&ClientAddr, &remoteLen);
- // 2. 创建客户端
- CNetClient* pClient = new CNetClient(m_pParent, PDU_LINK_TYPE_SERVER, false);
- ASSERT(pClient != NULL);
- pClient->assoSocket() = pIoContext->m_sockAccept;
- pClient->setFarLinkInfo(inet_ntoa(ClientAddr->sin_addr), ntohs(ClientAddr->sin_port));
- // 3. 使用完毕之后,投递新的AcceptEx
- __postAccept( pIoContext );
- // 4. 通知上层新客户端到来
- m_pParent->onConnEstablished(pClient);
- }
- /*****************************************************************
- **【函数名称】 create
- **【函数功能】 创建
- **【参数】
- **【返回值】
- ****************************************************************/
- bool CNetServer::create( int a_ListenPort )
- {
- m_Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
- if (INVALID_SOCKET == m_Socket)
- return false;
- // 将Listen Socket绑定至完成端口中
- if(!m_pParent->waitNetEnd(this))
- return false;
- struct sockaddr_in ServerAddress;
- // 填充地址信息
- ZeroMemory(&ServerAddress, sizeof(ServerAddress));
- ServerAddress.sin_family = AF_INET;
- ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);
- ServerAddress.sin_port = htons(a_ListenPort);
- // 绑定地址和端口
- if (SOCKET_ERROR == bind(m_Socket, (struct sockaddr *) &ServerAddress, sizeof(ServerAddress)))
- return false;
- // 开始进行监听
- if (SOCKET_ERROR == listen(m_Socket, SOMAXCONN))
- return false;
- // 使用AcceptEx函数,因为这个是属于WinSock2规范之外的微软另外提供的扩展函数
- // 所以需要额外获取一下函数的指针
- GUID GuidAcceptEx = WSAID_ACCEPTEX;
- GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;
- DWORD dwBytes = 0;
- if(SOCKET_ERROR == WSAIoctl(m_Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx),
- &m_lpfnAcceptEx, sizeof(m_lpfnAcceptEx), &dwBytes, NULL, NULL))
- {
- return false;
- }
- // 获取GetAcceptExSockAddrs函数指针,也是同理
- if(SOCKET_ERROR == WSAIoctl(m_Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockAddrs, sizeof(GuidGetAcceptExSockAddrs),
- &m_lpfnGetAcceptExSockAddrs, sizeof(m_lpfnGetAcceptExSockAddrs), &dwBytes, NULL, NULL))
- {
- return false;
- }
- // 为AcceptEx 准备参数,然后投递AcceptEx I/O请求
- for( int i = 0; i < MAX_POST_ACCEPT; ++i )
- {
- PER_IO_CONTEXT* pAcceptIoContext = __newIoContext();
- if(!__postAccept(pAcceptIoContext))
- {
- __deleteIoContext(pAcceptIoContext);
- return false;
- }
- }
- return true;
- }
|