65,179
社区成员




int reVal;
//初始化Windows Sockets DLL
WSADATA wsData;
reVal = WSAStartup(MAKEWORD(2,2),&wsData);
//创建套接字
sServer = socket(AF_INET, SOCK_STREAM, 0);
if(INVALID_SOCKET== sServer)
return FALSE;
//设置套接字非阻塞模式
unsigned long ul = 1;
reVal = ioctlsocket(sServer, FIONBIO, (unsigned long*)&ul);
if (SOCKET_ERROR == reVal)
return FALSE;
//绑定套接字
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(SERVERPORT);
serAddr.sin_addr.S_un.S_addr = INADDR_ANY;
reVal = bind(sServer, (struct sockaddr*)&serAddr, sizeof(serAddr));
if(SOCKET_ERROR == reVal )
return FALSE;
//监听
reVal = listen(sServer, SOMAXCONN);
if(SOCKET_ERROR == reVal)
return FALSE;
bServerRunning = TRUE;//设置服务器为运行状态
//创建释放资源线程
unsigned long ulThreadId;
hThreadHelp = CreateThread(NULL, 0, HelperThread, NULL, 0, &ulThreadId);
if( NULL == hThreadHelp)
{
bServerRunning = FALSE;
return FALSE;
}else{
CloseHandle(hThreadHelp);
}
//创建接收客户端请求线程
hThreadAccept = CreateThread(NULL, 0, AcceptThread, NULL, 0, &ulThreadId);
/**
* 接受客户端连接
*/
DWORD __stdcall AcceptThread(void* pParam)
{
SOCKET sAccept; //接受客户端连接的套接字
sockaddr_in addrClient; //客户端SOCKET地址
for (;bServerRunning;) //服务器的状态
{
memset(&addrClient, 0, sizeof(sockaddr_in)); //初始化
int lenClient = sizeof(sockaddr_in); //地址长度
sAccept = accept(sServer, (sockaddr*)&addrClient, &lenClient); //接受客户请求
if(INVALID_SOCKET == sAccept )
{
int nErrCode = WSAGetLastError();
if(nErrCode == WSAEWOULDBLOCK) //无法立即完成一个非阻挡性套接字操作
{
Sleep(TIMEFOR_THREAD_SLEEP);
continue;//继续等待
}else {
return 0;//线程退出
}
}
else//接受客户端的请求
{
CClient *pClient = new CClient(sAccept,addrClient); //创建客户端对象
EnterCriticalSection(&csClientList); //进入在临界区
clientlist.push_back(pClient); //加入链表
LeaveCriticalSection(&csClientList); //离开临界区
pClient->StartRuning(); //为接受的客户端建立接收数据和发送数据线程
}
}
return 0;//线程退出
}
class CClient
{
public:
CClient(const SOCKET sClient,const sockaddr_in &addrClient);
virtual ~CClient();
public:
BOOL StartRuning(void); //创建发送和接收数据线程
void HandleData(const char* pExpr); //计算表达式
BOOL IsConning(void){ //是否连接存在
return m_bConning;
}
void DisConning(void){ //断开与客户端的连接
m_bConning = FALSE;
}
BOOL IsExit(void){ //接收和发送线程是否已经退出
return m_bExit;
}
public:
static DWORD __stdcall RecvDataThread(void* pParam); //接收客户端数据
static DWORD __stdcall SendDataThread(void* pParam); //向客户端发送数据
private:
CClient();
private:
SOCKET m_socket; //套接字
sockaddr_in m_addr; //地址
DATABUF m_data; //数据
HANDLE m_hEvent; //事件对象
HANDLE m_hThreadSend; //发送数据线程句柄
HANDLE m_hThreadRecv; //接收数据线程句柄
CRITICAL_SECTION m_cs; //临界区对象
BOOL m_bConning; //客户端连接状态
BOOL m_bExit; //线程退出
};
#endif
CClient::CClient(const SOCKET sClient, const sockaddr_in &addrClient)
{
//初始化变量
m_hThreadRecv = NULL;
m_hThreadSend = NULL;
m_socket = sClient;
m_addr = addrClient;
m_bConning = FALSE;
m_bExit = FALSE;
memset(m_data.buf, 0, MAX_NUM_BUF);
//创建事件
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//手动设置信号状态,初始化为无信号状态
//初始化临界区
InitializeCriticalSection(&m_cs);
}
/*
* 析构函数
*/
CClient::~CClient()
{
closesocket(m_socket); //关闭套接字
m_socket = INVALID_SOCKET; //套接字无效
DeleteCriticalSection(&m_cs); //释放临界区对象
CloseHandle(m_hEvent); //释放事件对象
}
/*
* 创建发送和接收数据线程
*/
BOOL CClient::StartRuning(void)
{
m_bConning = TRUE;//设置连接状态
//创建接收数据线程
unsigned long ulThreadId;
m_hThreadRecv = CreateThread(NULL, 0, RecvDataThread, this, 0, &ulThreadId);
if(NULL == m_hThreadRecv)
{
return FALSE;
}else{
CloseHandle(m_hThreadRecv);
}
//创建接收客户端数据的线程
m_hThreadSend = CreateThread(NULL, 0, SendDataThread, this, 0, &ulThreadId);
if(NULL == m_hThreadSend)
{
return FALSE;
}else{
CloseHandle(m_hThreadSend);
}
return TRUE;
}
/*
* 接收客户端数据
*/
DWORD CClient::RecvDataThread(void* pParam)
{
CClient *pClient = (CClient*)pParam; //客户端对象指针
int reVal; //返回值
char temp[MAX_NUM_BUF]; //临时变量
memset(temp, 0, MAX_NUM_BUF);
for (;pClient->m_bConning;) //连接状态
{
reVal = recv(pClient->m_socket, temp, MAX_NUM_BUF, 0); //接收数据
//处理错误返回值
if (SOCKET_ERROR == reVal)
{
int nErrCode = WSAGetLastError();
if ( WSAEWOULDBLOCK == nErrCode ) //接受数据缓冲区不可用
{
continue; //继续循环
}else if (WSAENETDOWN == nErrCode ||//客户端关闭了连接
WSAETIMEDOUT == nErrCode ||
WSAECONNRESET == nErrCode )
{
break; //线程退出
}
}
//客户端关闭了连接
if ( reVal == 0)
{
break;
}
//收到数据
if (reVal > HEADERLEN)
{
pClient->HandleData(temp); //处理数据
SetEvent(pClient->m_hEvent); //通知发送数据线程
memset(temp, 0, MAX_NUM_BUF); //清空临时变量
}
Sleep(TIMEFOR_THREAD_CLIENT); //线程睡眠
}
pClient->m_bConning = FALSE; //与客户端的连接断开
SetEvent(pClient->m_hEvent); //通知发送数据线程退出
return 0; //线程退出
}
/*
* //向客户端发送数据
*/
DWORD CClient::SendDataThread(void* pParam)
{
CClient *pClient = (CClient*)pParam;//转换数据类型为CClient指针
for (;pClient->m_bConning;)//连接状态
{
//收到事件通知
if (WAIT_OBJECT_0 == WaitForSingleObject(pClient->m_hEvent, INFINITE))
{
//当客户端的连接断开时,接收数据线程先退出,然后该线程后退出,并设置退出标志
if (!pClient->m_bConning)
{
pClient->m_bExit = TRUE;
break ;
}
//进入临界区
EnterCriticalSection(&pClient->m_cs);
//发送数据
phdr pHeader = (phdr)pClient->m_data.buf;
int nSendlen = pHeader->len;
int val = send(pClient->m_socket, pClient->m_data.buf, nSendlen,0);
//处理返回错误
if (SOCKET_ERROR == val)
{
int nErrCode = WSAGetLastError();
if (nErrCode == WSAEWOULDBLOCK)//发送数据缓冲区不可用
{
continue;
}else if ( WSAENETDOWN == nErrCode ||
WSAETIMEDOUT == nErrCode ||
WSAECONNRESET == nErrCode)//客户端关闭了连接
{
//离开临界区
LeaveCriticalSection(&pClient->m_cs);
pClient->m_bConning = FALSE; //连接断开
pClient->m_bExit = TRUE; //线程退出
break;
}else {
//离开临界区
LeaveCriticalSection(&pClient->m_cs);
pClient->m_bConning = FALSE; //连接断开
pClient->m_bExit = TRUE; //线程退出
break;
}
}
//成功发送数据
//离开临界区
LeaveCriticalSection(&pClient->m_cs);
//设置事件为无信号状态
ResetEvent(&pClient->m_hEvent);
}
}
return 0;
}
/*
* 计算表达式,打包数据
*/
void CClient::HandleData(const char* pExpr)
{
memset(m_data.buf, 0, MAX_NUM_BUF);//清空m_data
//如果是“byebye”或者“Byebye”
if (BYEBYE == ((phdr)pExpr)->type)
{
EnterCriticalSection(&m_cs);
phdr pHeaderSend = (phdr)m_data.buf; //发送的数据
pHeaderSend->type = BYEBYE; //单词类型
pHeaderSend->len = HEADERLEN + strlen("OK"); //数据包长度
memcpy(m_data.buf + HEADERLEN, "OK", strlen("OK")); //复制数据到m_data"
LeaveCriticalSection(&m_cs);
}else{//算数表达式
int nFirNum; //第一个数字
int nSecNum; //第二个数字
char cOper; //算数运算符
int nResult; //计算结果
//格式化读入数据
sscanf(pExpr + HEADERLEN, "%d%c%d", &nFirNum, &cOper, &nSecNum);
//计算
switch(cOper)
{
case '+'://加
{
nResult = nFirNum + nSecNum;
break;
}
case '-'://减
{
nResult = nFirNum - nSecNum;
break;
}
case '*'://乘
{
nResult = nFirNum * nSecNum;
break;
}
case '/'://除
{
if (ZERO == nSecNum)//无效的数字
{
nResult = INVALID_NUM;
}else
{
nResult = nFirNum / nSecNum;
}
break;
}
default:
nResult = INVALID_OPERATOR;//无效操作符
break;
}
//将算数表达式和计算的结果写入字符数组中
char temp[MAX_NUM_BUF];
char cEqu = '=';
sprintf(temp, "%d%c%d%c%d",nFirNum, cOper, nSecNum,cEqu, nResult);
//打包数据
EnterCriticalSection(&m_cs);
phdr pHeaderSend = (phdr)m_data.buf; //发送的数据
pHeaderSend->type = EXPRESSION; //数据类型为算数表达式
pHeaderSend->len = HEADERLEN + strlen(temp); //数据包的长度
memcpy(m_data.buf + HEADERLEN, temp, strlen(temp)); //复制数据到m_data
LeaveCriticalSection(&m_cs);
}
}
现在勉强实现到一个客户端连接到服务器可以传输字符串,但是现在要求我至少可以让50个客户端连接上服务器。每个客户端需要我新建一个SOCKET对应,我用了下SOCKET soc[50]好像是不能这样用的,请问要怎么实现啊??刚刚学socket.还有能解释下socket传输数据的原理吗?为什么还需要有socketaddr_in这样的结构体存在,它是用来干嘛的?
[quote=引用 15 楼 u010020198 的回复:] [quote=引用 13 楼 yanasdf789 的回复:] [quote=引用 9 楼 u010020198 的回复:] [quote=引用 6 楼 yanasdf789 的回复:] 每个socket 开辟个线程
楼主是写的是什么代码,如果是VC/MFC的话,使用异步套接字吧,CAsyncSocket类,你可以去继承这个类,分别CAsyClient,CAsySrv,CAsyStream(CAsyncSrv创建的用来和客户端通信的),CAsyStream创建的时候 使用指针 CAsyStream *ps=new CAsyStream ()这样可以防止局部变量导致的问题。 如果不想使用mfc类,用windows提供的异步机制一样可以实现,不过会比较麻烦一些
楼主你该好好看看socket的模型,或者你直接根据自己的需要实现模型http://blog.csdn.net/normalnotebook/article/details/999840
多线程可以吧
[quote=引用 13 楼 yanasdf789 的回复:] [quote=引用 9 楼 u010020198 的回复:] [quote=引用 6 楼 yanasdf789 的回复:] 每个socket 开辟个线程
[quote=引用 9 楼 u010020198 的回复:] [quote=引用 6 楼 yanasdf789 的回复:] 每个socket 开辟个线程
就像服务器建立了50个通道,服务器利用这50个通道与客户端分别通信。 select或者线程都可以解决这个问题,不过要建立一个50个socket还真没遇到过。
[quote=引用 6 楼 yanasdf789 的回复:] 每个socket 开辟个线程
用IO 模型 selsect 什么什么的。
每个socket 开辟个线程