【网络编程】之十二、wsaeventselect+线程池 服务器实现
#include<WinSock2.h>
#include<iostream>
using namespace std; #pragma comment(lib, "WS2_32.lib") typedef struct _SOCKET_OBJ{
SOCKET s;
HANDLE event;
sockaddr_in addrRemote;
_SOCKET_OBJ *pNext;
}SOCKET_OBJ, *PSOCKET_OBJ; typedef struct _THREAD_OBJ{
HANDLE events[WSA_MAXIMUM_WAIT_EVENTS];
int nSocketCount;
PSOCKET_OBJ pSocketHeader;
PSOCKET_OBJ pSocketTail;
CRITICAL_SECTION cs;
_THREAD_OBJ *pNext;
}THREAD_OBJ, *PTHREAD_OBJ; PTHREAD_OBJ g_pThreadList;
CRITICAL_SECTION g_cs; LONG g_nTatolConnections;
LONG g_nCurrentConnections; DWORD WINAPI ServerThread(LPVOID lpParam);
//******************************************************************************//
PSOCKET_OBJ GetSocketObj(SOCKET s)
{
PSOCKET_OBJ pSocket = (PSOCKET_OBJ)::GlobalAlloc(GPTR, sizeof(SOCKET_OBJ));
if(pSocket != NULL)
{
pSocket->s = s;
pSocket->event = ::WSACreateEvent();
} return pSocket;
} void FreeSocketObj(PSOCKET_OBJ pSocket)
{
::CloseHandle(pSocket->event);
if(pSocket->s != INVALID_SOCKET)
{
closesocket(pSocket->s);
}
::GlobalFree(pSocket);
} //*************************************************************************// PTHREAD_OBJ GetThreadObj()
{
PTHREAD_OBJ pThread = (PTHREAD_OBJ)::GlobalAlloc(GPTR, sizeof(THREAD_OBJ));
if(pThread != NULL)
{
::InitializeCriticalSection(&pThread->cs); pThread->events[0] = ::WSACreateEvent(); ::EnterCriticalSection(&g_cs);
pThread->pNext = g_pThreadList;
g_pThreadList = pThread;
::LeaveCriticalSection(&g_cs);
} return pThread;
} void FreeThreadObj(PTHREAD_OBJ pThread)
{
::EnterCriticalSection(&g_cs);
PTHREAD_OBJ p = g_pThreadList;
if(p == pThread)
{
g_pThreadList = p->pNext;
}
else
{
while(p != NULL && p->pNext != pThread)
{
p = p->pNext;
}
if(p != NULL)
{
p->pNext = pThread->pNext;
}
}
::LeaveCriticalSection(&g_cs); ::CloseHandle(pThread->events[0]);
::DeleteCriticalSection(&pThread->cs);
::GlobalFree(pThread);
} void RebulidArray(PTHREAD_OBJ pThread)
{
::EnterCriticalSection(&pThread->cs);
PSOCKET_OBJ pSocket = pThread->pSocketHeader;
int n = 1;
while(pSocket != NULL)
{
pThread->events[n++] = pSocket->event;
pSocket = pSocket->pNext;
} ::LeaveCriticalSection(&pThread->cs);
} //********************************************************************// BOOL insertSocketObj(PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket)
{
BOOL bRet = FALSE;
::EnterCriticalSection(&pThread->cs);
if(pThread->nSocketCount < WSA_MAXIMUM_WAIT_EVENTS - 1)
{
if(pThread->pSocketHeader == NULL)
{
pThread->pSocketHeader = pThread->pSocketTail = pSocket;
}
else
{
pThread->pSocketTail->pNext = pSocket;
pThread->pSocketTail = pSocket;
}
pThread->nSocketCount++;
bRet = TRUE;
} ::LeaveCriticalSection(&pThread->cs); if(bRet)
{
::InterlockedIncrement(&g_nTatolConnections);
::InterlockedIncrement(&g_nCurrentConnections);
}
return bRet;
} void AssignToFreeThread(PSOCKET_OBJ pSocket)
{
pSocket->pNext = NULL;
::EnterCriticalSection(&g_cs);
PTHREAD_OBJ pThread = g_pThreadList; while(pThread != NULL)
{
if(insertSocketObj(pThread, pSocket))
break;
pThread = pThread->pNext;
} if(pThread == NULL)
{
pThread = GetThreadObj();
insertSocketObj(pThread, pSocket);
::CreateThread(NULL, 0, ServerThread, pThread, 0, NULL); } ::LeaveCriticalSection(&g_cs); ::WSASetEvent(pThread->events[0]);
} void RemoveSocketObj(PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket)
{
::EnterCriticalSection(&pThread->cs); PSOCKET_OBJ pTest = pThread->pSocketHeader;
if(pTest == pSocket)
{
if(pThread->pSocketHeader == pThread->pSocketTail)
pThread->pSocketTail = pThread->pSocketHeader = pTest->pNext;
else
pThread->pSocketHeader = pTest->pNext;
}
else
{
while(pTest != NULL && pTest->pNext != pSocket)
pTest = pTest->pNext;
if(pTest != NULL)
{
if(pThread->pSocketTail == pSocket)
pThread->pSocketTail = pTest;
pTest->pNext = pSocket->pNext;
}
} pThread->nSocketCount--; ::LeaveCriticalSection(&pThread->cs); ::WSASetEvent(pThread->events[0]);
::InterlockedDecrement(&g_nCurrentConnections);
} //********************************************************************//
PSOCKET_OBJ FindSocketObj(PTHREAD_OBJ pThread, int nIndex)
{
PSOCKET_OBJ pSocket = pThread->pSocketHeader;
while(--nIndex)
{
if(pSocket == NULL)
return NULL;
pSocket = pSocket->pNext;
}
return pSocket;
} BOOL HandleIO(PTHREAD_OBJ pThread, PSOCKET_OBJ pSocket)
{
WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(pSocket->s, pSocket->event, &event);
do{
if(event.lNetworkEvents & FD_READ)
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{
char szText[256];
int nRecv = ::recv(pSocket->s, szText, strlen(szText), 0);
if(nRecv > 0)
{
szText[nRecv] = '\0';
cout << "接收到数据:" << szText << endl;
}
}
else
break;
}
else
{
if(event.lNetworkEvents &FD_CLOSE)
{
break;
}
else
{
if(event.lNetworkEvents & FD_WRITE)
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{
char szText[256];
int nRecv = ::recv(pSocket->s, szText, strlen(szText), 0);
if(nRecv > 0)
{
szText[nRecv] = '\0';
cout << "接收到数据:" << szText << endl;
}
}
else
break;
}
}
}
return TRUE; }while(FALSE); RemoveSocketObj(pThread, pSocket);
FreeSocketObj(pSocket);
return FALSE;
} DWORD WINAPI ServerThread(LPVOID lpParam)
{
PTHREAD_OBJ pThread = (PTHREAD_OBJ)lpParam;
while(TRUE)
{
int nIndex = ::WSAWaitForMultipleEvents(pThread->nSocketCount + 1, pThread->events, FALSE, WSA_INFINITE, FALSE);
nIndex = nIndex - WSA_WAIT_EVENT_0; for(int i = nIndex; i < pThread->nSocketCount + 1; ++i)
{
nIndex = ::WSAWaitForMultipleEvents(1, &pThread->events[i], TRUE, 1000, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
if(i == 0)
{
RebulidArray(pThread); if(pThread->nSocketCount == 0)
{
FreeThreadObj(pThread);
return 0;
}
::WSAResetEvent(pThread->events[0]);
}
else
{
PSOCKET_OBJ pSocket = (PSOCKET_OBJ)FindSocketObj(pThread, i);
if(pSocket != NULL)
{
if(!HandleIO(pThread, pSocket))
RebulidArray(pThread);
}
else
cout << "Unable to find socket object" << endl;
}
}
}
}
return 0;
} //******************************************************************************// int main(void)
{ WSADATA wsaData;
WORD sockVersion = MAKEWORD(2,0);//指定版本号
::WSAStartup(sockVersion, &wsaData);//载入winsock的dll
//创建套接字基于TCP
SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sListen == INVALID_SOCKET)
{
printf("error");
::WSACleanup();//清理,释放资源
return 0;
} sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);//端口号8888
sin.sin_addr.S_un.S_addr = INADDR_ANY;//地址全是0,也就是所有的地址
//绑定socket
if(::bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("error");
::WSACleanup();//清理释放资源
return 0;
}
//监听socket
if(::listen(sListen, 2) == SOCKET_ERROR)
{
printf("error");
::WSACleanup();//释放资源
return 0;
} WSAEVENT event = ::WSACreateEvent();
::WSAEventSelect(sListen, event, FD_ACCEPT | FD_CLOSE);
::InitializeCriticalSection(&g_cs); //处理请求
while(TRUE)
{
int nRet = ::WaitForSingleObject(event, 5 * 1000);
if(nRet == WAIT_FAILED)
{
cout << "failed waitforsingleobject" << endl;
break;
}
else if(nRet == WSA_WAIT_TIMEOUT)
{
cout << endl;
cout << " tatolconnections:" << g_nTatolConnections << endl;
cout << " currentconnections: " << g_nCurrentConnections << endl;
continue;
}
else
{
::ResetEvent(event); //新连接 while(TRUE)
{
sockaddr_in si;
int nLen = sizeof(si);
SOCKET sNew = ::accept(sListen, (sockaddr*)&si, &nLen);
if(sNew == SOCKET_ERROR)
break;
PSOCKET_OBJ pSocket = GetSocketObj(sNew);
pSocket->addrRemote = si;
::WSAEventSelect(pSocket->s, pSocket->event, FD_READ | FD_CLOSE | FD_WRITE);
AssignToFreeThread(pSocket);
}
}
} ::DeleteCriticalSection(&g_cs);
::WSACleanup();
return 0;
}
【网络编程】之十二、wsaeventselect+线程池 服务器实现的更多相关文章
- java并发编程(十五)----(线程池)java线程池简介
好的软件设计不建议手动创建和销毁线程.线程的创建和销毁是非常耗 CPU 和内存的,因为这需要 JVM 和操作系统的参与.64位 JVM 默认线程栈是大小1 MB.这就是为什么说在请求频繁时为每个小的请 ...
- Java并发编程(十四)-- 线程池实现原理
在上一章我们从宏观上介绍了ThreadPoolExecutor,本文将深入解析一下线程池的具体实现原理 原理解析 线程池状态 在ThreadPoolExecutor中定义了一个volatile变量,另 ...
- Java线程和多线程(十二)——线程池基础
Java 线程池管理多个工作线程,其中包含了一个队列,包含着所有等待被执行的任务.开发者可以通过使用ThreadPoolExecutor来在Java中创建线程池. 线程池是Java中多线程的一个重要概 ...
- java并发编程(十八)----(线程池)java线程池框架Fork-Join
还记得我们在初始介绍线程池的时候提到了Executor框架的体系,到现在为止我们只有一个没有介绍,与ThreadPoolExecutor一样继承与AbstractExecutorService的For ...
- java并发编程(十六)----(线程池)java线程池的使用
上节我们简单介绍了线程池,这次我们就来使用一下.Executors提供四种线程池,分别是:newCachedThreadPool,newFixedThreadPool ,newScheduledThr ...
- python网络编程(十二)
协程 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 首先我们得知道协程是啥?协程其实可以认为是比线程更小的执行单元. 为啥说他是一个执行单元,因为他自带CPU上下文.这样只要在合适的时 ...
- Linux网络编程学习(十二) ----- 结语
该书提前看完了,重点看了第四章和第六章,第七章以后只是大致浏览了一下,如果以后工作中涉及这一块再仔细研究一下,大概花了二十天的样子,主要了解了进程间的通信方式.socket编程以及五种I/O模式,看的 ...
- Java并发编程(十二)线程安全性的委托
在组合对象中如果每个组件都已经是线程安全的,是否需要再加一个额外的"线程安全层",需要视情况而定. final可以修饰未复制的属性,只要在静态代码块或者构造函数中赋值了即可. 独立 ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
随机推荐
- listview的tag
tag,记录一行数据的唯一标识,小DEMO: lsShow.Items.Add("洗衣机"); lsShow.Items[].Tag = "我不愿让你一个人"; ...
- 结构类模式(六):享元(Flyweight)
定义 运用共享技术有效的支持大量细粒度的对象. 两个状态 内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的. 外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保 ...
- kafka分布式消息队列 — 基本概念介绍
[http://www.inter12.org/archives/818] 这个应该算是之前比较火热的词了,一直没时间抽出来看看.一个新东西出来,肯定是为了解决某些问题,不然不会有它的市场.先简单看下 ...
- webstorm 主题设置 皮肤设置
推荐个编辑器主题下载的一个网站. Color Themes 网址:http://color-themes.com [点这里直接跳转] 但是,只支持几个编辑器. 各种颜色搭配的主题,随你选择!我个 ...
- ExtJs FormPanel布局
FormPanel有两种布局:form和column,form是纵向布局,column为横向布局.默认为后者.使用layout属性定义布局类型.对于一个复杂的布局表单,最重要的是正确分割,分割结果直接 ...
- HDU 4941 Magical Forest 【离散化】【map】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4941 题目大意:给你10^5个点.每一个点有一个数值.点的xy坐标是0~10^9.点存在于矩阵中.然后 ...
- 【JavsScript】父子页面之间跨域通信的方法
由于同源策略的限制,JavaScript跨域的问题,一直是一个比较棘手的问题,为了解决页面之间的跨域通信,大家煞费苦心,研究了各种跨域方案.之前也有小网同学分享过一篇“跨域,不再纠结” 开始照着尝试时 ...
- 项目优化经验分享(八)TeamLeader经验总结
引言 通过前面的七篇博客.我把自己在项目优化过程的经验进行了分享,今天这篇博客,作为一个总结,就来讲讲作为一个TeamLeader,在项目管理中遇到的问题和解决经验! 正文 问题一:团队之间怎么沟通? ...
- iOS开发——动画编程Swift篇&(三)CATransition动画
CATransition动画 // MARK: - CATransition动画 // /* 动画样式 */ // let kCATransitionFade: NSString! //翻页 // l ...
- python 列表函数(转)
list函数: 功能:将字符创转化为列表,例: 列表基本函数: 1.元素赋值,例: 注意:通过list[0]= 'hel',如果原来位置上有值,会覆盖掉原来的. 2.分片操作 1)显示序列,例: 注意 ...