下面是服务器端的代码:
#pragma once//////////////////////////////////////////////////////////////////////////
#include <Winsock2.h>
#pragma comment( lib, "WS2_32.LIB")
#include <process.h> // 编译器需要开启多线程(MT)
//////////////////////////////////////////////////////////////////////////
// 参数定义
const UINT MAX_LISTEN = 5; // 最大监听数量
const UINT MAX_WAIT_TIME = 100; // 最大等待事件
const UINT CLIENT_EACH_THREAD = 5; // 每线程具备的客户端数量
const UINT MAX_THREAD_NUM = 5; // 线程池中的最大线程数
//////////////////////////////////////////////////////////////////////////typedef struct _tagClientInfo
{
SOCKET socket;
BOOL bUsed;
}tagClientInfo, *LPClientInfo;typedef struct _tagThread
{
HANDLE m_hThread;
UINT m_uiSpare;
tagClientInfo m_aryClientInfo[CLIENT_EACH_THREAD];
WSAEVENT m_aryEvent[CLIENT_EACH_THREAD];
LPVOID m_pParam;
} tagThread, *LPThread;
//////////////////////////////////////////////////////////////////////////template <class T>
class CNetServer
{
public:
CNetServer(void);
virtual ~CNetServer(void);public:
static BOOL Initialize(void);
static BOOL Uninitialize(void); BOOL Create( USHORT usPort,
INT nType = SOCK_STREAM,
INT nProtocol = IPPROTO_TCP);
BOOL Close(void);protected:
SOCKET m_Socket;
SOCKADDR_IN m_Addr; WSAEVENT m_wsaEvent;
HANDLE m_hThread;
tagThread m_aryThread[MAX_THREAD_NUM];
BOOL m_bExit; // 线程退出标志
volatile LONG m_lThreadNum; // 线程数 进入+1 退出-1
static unsigned _stdcall ListenThread(LPVOID pVoid);
static unsigned _stdcall ClientThread(LPVOID pVoid);
BOOL OnAccept(void);
BOOL OnRead(SOCKET clientSocket);
BOOL OnSend(SOCKET clientSocket);};//////////////////////////////////////////////////////////////////////////
// 实现部分template <class T>
CNetServer<T>::CNetServer(void)
: m_hThread(NULL)
, m_wsaEvent(NULL)
{
}template <class T>
CNetServer<T>::~CNetServer(void)
{
}
//-------------------------------------------------------------------------
// Function Name :Initialize [static]
// Parameter(s) :void
// Return :成功与否
// Memo :初始化Winsock环境
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Initialize(void)
{
WSAData wsaData;
memset( &wsaData, 0, sizeof(wsaData));
return ( WSAStartup( MAKEWORD( 2, 2), &wsaData) == 0 );
}//-------------------------------------------------------------------------
// Function Name :Uninitialize [static]
// Parameter(s) :void
// Return :成功与否
// Memo :卸载Winsock环境
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Uninitialize(void)
{
return ( WSACleanup() == 0 );
}//-------------------------------------------------------------------------
// Function Name :Create
// Parameter(s) :USHORT usPort 端口号 [in]
// :INT nType 类型 [in]
// :INT nProtocol 协议 [in]
// Return :成功与否
// Memo :创建服务器
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Create( USHORT usPort,
INT nType /* = SOCK_STREAM */,
INT nProtocol /* = IPPROTO_TCP */)
{
// 创建套接字
m_Socket = socket( AF_INET, nType, nProtocol);
if( m_Socket == INVALID_SOCKET )
return FALSE; memset( &m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_port = htons(usPort);
m_Addr.sin_family = AF_INET;
m_Addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定
if( bind( m_Socket, (LPSOCKADDR)&m_Addr, sizeof(m_Addr)) == SOCKET_ERROR )
return FALSE; // 监听
if( listen( m_Socket, MAX_LISTEN) == SOCKET_ERROR )
return FALSE; // 创建Event
m_wsaEvent = WSACreateEvent();
if( m_wsaEvent == NULL )
return FALSE; // 设置异步事件
if( WSAEventSelect( m_Socket, m_wsaEvent, FD_ACCEPT) == SOCKET_ERROR )
return FALSE; // 初始化线程池
for( int i = 0; i < MAX_THREAD_NUM; i++)
{
for( int j = 0; j < CLIENT_EACH_THREAD; j++)
{
m_aryThread[i].m_aryClientInfo[j].bUsed = FALSE;
m_aryThread[i].m_aryEvent[j] = NULL;
}
m_aryThread[i].m_uiSpare = CLIENT_EACH_THREAD;
m_aryThread[i].m_pParam = this; m_aryThread[i].m_hThread = (HANDLE)_beginthreadex( NULL
, 0
, &ClientThread
, &m_aryThread[i]
, CREATE_SUSPENDED
, NULL
);
} // 启动监听线程
m_lThreadNum = 0l;
m_bExit = FALSE;
m_hThread = (HANDLE)_beginthreadex( NULL,
0,
&ListenThread,
this,
0,
NULL);
if( m_hThread == NULL )
return FALSE;
return TRUE;
}//-------------------------------------------------------------------------
// Function Name :Close
// Parameter(s) :void
// Return :成功与否
// Memo :关闭服务器
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Close(void)
{
// 等待线程退出
m_bExit = TRUE;
while( m_lThreadNum > 0 )
{
Sleep(MAX_WAIT_TIME);
} // 关闭事件
WSACloseEvent(m_wsaEvent);
m_wsaEvent = NULL; // 关闭线程
::CloseHandle(m_hThread); // 关闭Socket
closesocket(m_Socket); return TRUE;
}
#pragma once//////////////////////////////////////////////////////////////////////////
#include <Winsock2.h>
#pragma comment( lib, "WS2_32.LIB")
#include <process.h> // 编译器需要开启多线程(MT)
//////////////////////////////////////////////////////////////////////////
// 参数定义
const UINT MAX_LISTEN = 5; // 最大监听数量
const UINT MAX_WAIT_TIME = 100; // 最大等待事件
const UINT CLIENT_EACH_THREAD = 5; // 每线程具备的客户端数量
const UINT MAX_THREAD_NUM = 5; // 线程池中的最大线程数
//////////////////////////////////////////////////////////////////////////typedef struct _tagClientInfo
{
SOCKET socket;
BOOL bUsed;
}tagClientInfo, *LPClientInfo;typedef struct _tagThread
{
HANDLE m_hThread;
UINT m_uiSpare;
tagClientInfo m_aryClientInfo[CLIENT_EACH_THREAD];
WSAEVENT m_aryEvent[CLIENT_EACH_THREAD];
LPVOID m_pParam;
} tagThread, *LPThread;
//////////////////////////////////////////////////////////////////////////template <class T>
class CNetServer
{
public:
CNetServer(void);
virtual ~CNetServer(void);public:
static BOOL Initialize(void);
static BOOL Uninitialize(void); BOOL Create( USHORT usPort,
INT nType = SOCK_STREAM,
INT nProtocol = IPPROTO_TCP);
BOOL Close(void);protected:
SOCKET m_Socket;
SOCKADDR_IN m_Addr; WSAEVENT m_wsaEvent;
HANDLE m_hThread;
tagThread m_aryThread[MAX_THREAD_NUM];
BOOL m_bExit; // 线程退出标志
volatile LONG m_lThreadNum; // 线程数 进入+1 退出-1
static unsigned _stdcall ListenThread(LPVOID pVoid);
static unsigned _stdcall ClientThread(LPVOID pVoid);
BOOL OnAccept(void);
BOOL OnRead(SOCKET clientSocket);
BOOL OnSend(SOCKET clientSocket);};//////////////////////////////////////////////////////////////////////////
// 实现部分template <class T>
CNetServer<T>::CNetServer(void)
: m_hThread(NULL)
, m_wsaEvent(NULL)
{
}template <class T>
CNetServer<T>::~CNetServer(void)
{
}
//-------------------------------------------------------------------------
// Function Name :Initialize [static]
// Parameter(s) :void
// Return :成功与否
// Memo :初始化Winsock环境
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Initialize(void)
{
WSAData wsaData;
memset( &wsaData, 0, sizeof(wsaData));
return ( WSAStartup( MAKEWORD( 2, 2), &wsaData) == 0 );
}//-------------------------------------------------------------------------
// Function Name :Uninitialize [static]
// Parameter(s) :void
// Return :成功与否
// Memo :卸载Winsock环境
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Uninitialize(void)
{
return ( WSACleanup() == 0 );
}//-------------------------------------------------------------------------
// Function Name :Create
// Parameter(s) :USHORT usPort 端口号 [in]
// :INT nType 类型 [in]
// :INT nProtocol 协议 [in]
// Return :成功与否
// Memo :创建服务器
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Create( USHORT usPort,
INT nType /* = SOCK_STREAM */,
INT nProtocol /* = IPPROTO_TCP */)
{
// 创建套接字
m_Socket = socket( AF_INET, nType, nProtocol);
if( m_Socket == INVALID_SOCKET )
return FALSE; memset( &m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_port = htons(usPort);
m_Addr.sin_family = AF_INET;
m_Addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定
if( bind( m_Socket, (LPSOCKADDR)&m_Addr, sizeof(m_Addr)) == SOCKET_ERROR )
return FALSE; // 监听
if( listen( m_Socket, MAX_LISTEN) == SOCKET_ERROR )
return FALSE; // 创建Event
m_wsaEvent = WSACreateEvent();
if( m_wsaEvent == NULL )
return FALSE; // 设置异步事件
if( WSAEventSelect( m_Socket, m_wsaEvent, FD_ACCEPT) == SOCKET_ERROR )
return FALSE; // 初始化线程池
for( int i = 0; i < MAX_THREAD_NUM; i++)
{
for( int j = 0; j < CLIENT_EACH_THREAD; j++)
{
m_aryThread[i].m_aryClientInfo[j].bUsed = FALSE;
m_aryThread[i].m_aryEvent[j] = NULL;
}
m_aryThread[i].m_uiSpare = CLIENT_EACH_THREAD;
m_aryThread[i].m_pParam = this; m_aryThread[i].m_hThread = (HANDLE)_beginthreadex( NULL
, 0
, &ClientThread
, &m_aryThread[i]
, CREATE_SUSPENDED
, NULL
);
} // 启动监听线程
m_lThreadNum = 0l;
m_bExit = FALSE;
m_hThread = (HANDLE)_beginthreadex( NULL,
0,
&ListenThread,
this,
0,
NULL);
if( m_hThread == NULL )
return FALSE;
return TRUE;
}//-------------------------------------------------------------------------
// Function Name :Close
// Parameter(s) :void
// Return :成功与否
// Memo :关闭服务器
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::Close(void)
{
// 等待线程退出
m_bExit = TRUE;
while( m_lThreadNum > 0 )
{
Sleep(MAX_WAIT_TIME);
} // 关闭事件
WSACloseEvent(m_wsaEvent);
m_wsaEvent = NULL; // 关闭线程
::CloseHandle(m_hThread); // 关闭Socket
closesocket(m_Socket); return TRUE;
}
// Function Name :ListenThread
// Parameter(s) :LPVOID pVoid 线程参数 [in]
// Return :unsigned
// Memo :监听线程
//-------------------------------------------------------------------------
template <class T>
unsigned _stdcall CNetServer<T>::ListenThread(LPVOID pVoid)
{
T * pThis = static_cast<T*>(pVoid); InterlockedIncrement( &(pThis->m_lThreadNum) );
WSANETWORKEVENTS wsaEvents;
DWORD dwIndex = 0; // 循环等待Accept
while( !pThis->m_bExit )
{
dwIndex = WSAWaitForMultipleEvents( 1, &(pThis->m_wsaEvent), FALSE, MAX_WAIT_TIME, FALSE);
if( dwIndex == WSA_WAIT_FAILED ||
dwIndex == WSA_WAIT_TIMEOUT )
{
continue;
} // 枚举网络异步事件
memset( &wsaEvents, 0, sizeof(wsaEvents));
WSAEnumNetworkEvents( pThis->m_Socket, pThis->m_wsaEvent, &wsaEvents); if( (wsaEvents.lNetworkEvents & FD_ACCEPT) == FD_ACCEPT )
{
pThis->OnAccept();
}
WSAResetEvent(pThis->m_wsaEvent);
} InterlockedDecrement( &(pThis->m_lThreadNum) ); return 0;
}
//-------------------------------------------------------------------------
// Function Name :OnAccept
// Parameter(s) :void
// Return :BOOL
// Memo :接受连接
//-------------------------------------------------------------------------
template <class T>
BOOL CNetServer<T>::OnAccept(void)
{
sockaddr_in clientAddr;
memset( &clientAddr, 0, sizeof(clientAddr));
int nLen = sizeof(clientAddr); // 接受连接
SOCKET ClientSocket = accept( m_Socket, (struct sockaddr*)&clientAddr, &nLen);
if( ClientSocket == INVALID_SOCKET )
{
return FALSE;
}
// 查找可用的线程
for( int i = 0; i < MAX_THREAD_NUM; i++)
{
if( m_aryThread[i].m_uiSpare <= 0 )
{
continue;
} for( int j = 0; j < CLIENT_EACH_THREAD; j++)
{
if( m_aryThread[i].m_aryClientInfo[j].bUsed )
{
continue;
} m_aryThread[i].m_aryClientInfo[j].socket = ClientSocket;
m_aryThread[i].m_aryEvent[j] = WSACreateEvent(); if( WSAEventSelect( m_aryThread[i].m_aryClientInfo[j].socket
, m_aryThread[i].m_aryEvent[j]
, FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR )
{
WSACloseEvent( m_aryThread[i].m_aryEvent[j] );
closesocket(ClientSocket);
return FALSE;
}// if if( m_aryThread[i].m_uiSpare == CLIENT_EACH_THREAD )
{
ResumeThread(m_aryThread[i].m_hThread);
} m_aryThread[i].m_aryClientInfo[j].bUsed = TRUE;
m_aryThread[i].m_uiSpare --;
return TRUE;
}// for
} closesocket(ClientSocket); return FALSE;
}
//-------------------------------------------------------------------------
// Function Name :ClientThread
// Parameter(s) :LPVOID pVoid
// Return :unsigned
// Memo :
//-------------------------------------------------------------------------
template <class T>
unsigned _stdcall CNetServer<T>::ClientThread(LPVOID pVoid)
{
LPThread pThread = static_cast<LPThread>(pVoid);
T * pT = static_cast<T*>(pThread->m_pParam); DWORD dwIndex = 0;
WSANETWORKEVENTS wsaEvents; InterlockedIncrement( &(pT->m_lThreadNum) ); while( !pT->m_bExit )
{
dwIndex = WSAWaitForMultipleEvents( CLIENT_EACH_THREAD
, pThread->m_aryEvent
, FALSE
, MAX_WAIT_TIME
, FALSE
); if( dwIndex == WSA_WAIT_FAILED ||
dwIndex == WSA_WAIT_TIMEOUT )
{
continue;
} dwIndex = dwIndex - WSA_WAIT_EVENT_0; // 枚举网络异步事件
memset( &wsaEvents, 0, sizeof(wsaEvents));
WSAEnumNetworkEvents( pThread->m_aryClientInfo[dwIndex].socket
, pThread->m_aryEvent[dwIndex]
, &wsaEvents
); if( (wsaEvents.lNetworkEvents & FD_READ) == FD_READ )
{
pT->OnRead( pThread->m_aryClientInfo[dwIndex].socket );
}
else if( (wsaEvents.lNetworkEvents & FD_CLOSE) == FD_CLOSE )
{
closesocket( pThread->m_aryClientInfo[dwIndex].socket );
pThread->m_aryClientInfo[dwIndex].bUsed = FALSE;
pThread->m_uiSpare ++;
// 挂起线程
if( pThread->m_uiSpare == CLIENT_EACH_THREAD )
{
SuspendThread(pThread->m_hThread);
}
continue;
} WSAResetEvent(pThread->m_aryEvent[dwIndex]);
}// while InterlockedDecrement( &(pT->m_lThreadNum) );
return 0;
}
template <class T>
BOOL CNetServer<T>::OnRead(SOCKET clientSocket)
{
return TRUE;
}template <class T>
BOOL CNetServer<T>::OnSend(SOCKET clientSocket)
{
return TRUE;
}
#include "stdafx.h"
#include "NetServer.h"class CMyServer : public CNetServer<CMyServer>
{
public:
CMyServer () {};
~CMyServer() {};
BOOL OnRead(SOCKET clientSocket)
{
char szBuf[MAX_PATH] = {'\0'};;
if( recv( clientSocket, szBuf, MAX_PATH, 0) == SOCKET_ERROR )
{
return FALSE;
} return this->OnSend(clientSocket);
}; BOOL OnSend(SOCKET clientSocket)
{
int nBytes = 2048;
char szBuf[2048] = {"tttttttttt"}; int nLeft = nBytes;
int nIndex = 0;
while( nLeft > 0 )
{
int nRet = send( clientSocket, &szBuf[nIndex], nLeft, 0);
if( nRet == SOCKET_ERROR )
{
return FALSE;
}
nLeft -= nRet;
nIndex += nRet;
} return TRUE;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CMyServer::Initialize(); CMyServer server;
server.Create( 30010);
Sleep(50000); server.Close(); CMyServer::Uninitialize();
return 0;
}
2)使用固定长度的char szBuf[2048]接收数据,很容易出现粘包问题,从而导致好象“丢包”了。
3)建议楼主看看:http://www.vczx.com/article/show.php?id=1041 后再改进改进。
关键是要考虑到多种使用要求。
比如说有人可能想以最快的速度写一个程序,但不考虑错误处里和负载性能。
也有人要写专业的server程序。
所以,你的架构里要支持很多变化的功能。刚开始需求不会很快明确的,还需要很长时间才能成熟啊。
希望楼主将来能有更好的产品。