- 浏览: 4333469 次
- 性别:
- 来自: 湛江
博客专栏
-
SQLite源码剖析
浏览量:79428
-
WIN32汇编语言学习应用...
浏览量:68376
-
神奇的perl
浏览量:101498
-
lucene等搜索引擎解析...
浏览量:281206
-
深入lucene3.5源码...
浏览量:14608
-
VB.NET并行与分布式编...
浏览量:65559
-
silverlight 5...
浏览量:31320
-
算法下午茶系列
浏览量:45206
文章分类
最新评论
-
yoyo837:
counters15 写道目前只支持IE吗?插件的东西是跨浏览 ...
Silverlight 5 轻松开启绚丽的网页3D世界 -
shuiyunbing:
直接在前台导出方式:excel中的单元格样式怎么处理,比如某行 ...
Flex导出Excel -
di1984HIT:
写的很好~
lucene入门-索引网页 -
rjguanwen:
在win7 64位操作系统下,pygtk的Entry无法输入怎 ...
pygtk-entry -
ldl_xz:
http://www.9958.pw/post/php_exc ...
PHPExcel常用方法汇总(转载)
///////////////////////////////////////////////////////
// OverlappedServer.cpp文件
//基于重叠I/0模型的简单的回显TCP服务器,它接受客户端连接之后,将从客
//户端接收到的数据再发送给客户端。本例采用了单线程。
//使用重叠I/O模型必须使用WSASocket函数创建套接字,传送数据使用
//WSASend、WSARecv、WSARecvFrom
//WSASocket函数创建套接字,这个套接字允许多个I/O同时占用。并使用pBuff
//er->pSocket->nOutstandingOps来统计其上的I/O数量。
//其中SOCKET_OBJ结构用来记录与套接字相关的信息,BUFFER_OBJ记录I/O信息。
//程序每投递一个I/O请求,都要申请一个BUFFER_OBJ对象,使用嵌在对象中
//的OVERLAPPED结构。所有未完成的I/O请求对应的BUFFER_OBJ对象组成了一个
//表,表头指针为全局变量g_pBufferHead。
//提交重叠I/O是重叠模型的关键,通过调用AcceptEx、WSARecv和WSASend函
//数实现。提交这些I/O后,线程便在重叠结构中的事件对象上等等,一旦I/O完成
//事件受信,等待函数返回。
//WSAGetLastError函数报告了WSA_IO_PENDING出错状态,表示I/O操作正在进行。
//AccepEx函数将几个套接字函数的功能集合成在了一起。如果它投递的请求成功完成,则执行了3个操作:
//1、接受了新的连接
//2、新连接的本地地址和远程地址都会返回
//3、接收到了远程主机发来的第一块数据
//
#include "../common/initsock.h"
#include<Mswsock.h>
#include <stdio.h>
#include <windows.h>
CInitSock theSock;
#define BUFFER_SIZE 1024
typedef struct _SOCKET_OBJ
{
SOCKETs;//套节字句柄
intnOutstandingOps;//记录此套节字上的重叠I/O数量
LPFN_ACCEPTEXlpfnAcceptEx;//扩展函数AcceptEx的指针(仅对监听套节字而言)
} SOCKET_OBJ, *PSOCKET_OBJ;
//重叠I/O都要提交到特定套节字上。在这些I/O完成之前,对方关闭了连接,
//或者连接发生错误,释放对应的SOCEKET_OBJ对象。
typedef struct _BUFFER_OBJ
{
OVERLAPPEDol;//重叠结构
char*buff;//send/recv/AcceptEx所使用的缓冲区
intnLen;//buff的长度
PSOCKET_OBJ pSocket;//此I/O所属的套节字对象
intnOperation;//提交的操作类型
#define OP_ACCEPT1
#define OP_READ2
#define OP_WRITE3
SOCKETsAccept;//用来保存AcceptEx接受的客户套节字(仅对监听套节字而言)
_BUFFER_OBJ *pNext;
} BUFFER_OBJ, *PBUFFER_OBJ;
HANDLEg_events[WSA_MAXIMUM_WAIT_EVENTS];//I/O事件句柄数组
intg_nBufferCount;//上数组中有效句柄数量
PBUFFER_OBJ g_pBufferHead, g_pBufferTail;//记录缓冲区对象组成的表的地址
// 申请套节字对象和释放套节字对象的函数
PSOCKET_OBJ GetSocketObj(SOCKET s)
{
PSOCKET_OBJ pSocket =(PSOCKET_OBJ)::GlobalAlloc(GPTR, sizeof(SOCKET_OBJ));
if(pSocket != NULL)
{
pSocket->s =s;
}
return pSocket;
}
void FreeSocketObj(PSOCKET_OBJ pSocket)
{
if(pSocket->s !=INVALID_SOCKET)
::closesocket(pSocket->s);
::GlobalFree(pSocket);
}
PBUFFER_OBJ GetBufferObj(PSOCKET_OBJ pSocket,ULONG nLen)
{
if(g_nBufferCount >WSA_MAXIMUM_WAIT_EVENTS - 1)
return NULL;
PBUFFER_OBJ pBuffer =(PBUFFER_OBJ)::GlobalAlloc(GPTR, sizeof(BUFFER_OBJ));
if(pBuffer != NULL)
{
pBuffer->buff =(char*)::GlobalAlloc(GPTR, nLen);
pBuffer->ol.hEvent= ::WSACreateEvent();
pBuffer->pSocket= pSocket;
pBuffer->sAccept= INVALID_SOCKET;
//将新的BUFFER_OBJ添加到列表中
if(g_pBufferHead == NULL)
{
g_pBufferHead= g_pBufferTail = pBuffer;
}
else
{
g_pBufferTail->pNext= pBuffer;
g_pBufferTail= pBuffer;
}
g_events[++ g_nBufferCount] =pBuffer->ol.hEvent;
}
return pBuffer;
}
void FreeBufferObj(PBUFFER_OBJ pBuffer)
{
// 从列表中移除BUFFER_OBJ对象
PBUFFER_OBJ pTest = g_pBufferHead;
BOOL bFind = FALSE;
if(pTest == pBuffer)
{
g_pBufferHead = g_pBufferTail =NULL;
bFind = TRUE;
}
else
{
while(pTest != NULL&& pTest->pNext !=pBuffer)
pTest =pTest->pNext;
if(pTest != NULL)
{
pTest->pNext= pBuffer->pNext;
if(pTest->pNext== NULL)
g_pBufferTail= pTest;
bFind =TRUE;
}
}
// 释放它占用的内存空间
if(bFind)
{
g_nBufferCount --;
::CloseHandle(pBuffer->ol.hEvent);
::GlobalFree(pBuffer->buff);
::GlobalFree(pBuffer);
}
}
PBUFFER_OBJ FindBufferObj(HANDLE hEvent)
{
PBUFFER_OBJ pBuffer = g_pBufferHead;
while(pBuffer != NULL)
{
if(pBuffer->ol.hEvent== hEvent)
break;
pBuffer =pBuffer->pNext;
}
return pBuffer;
}
void RebuildArray()
{
PBUFFER_OBJ pBuffer = g_pBufferHead;
int i = 1;
while(pBuffer != NULL)
{
g_events[i++] =pBuffer->ol.hEvent;
pBuffer =pBuffer->pNext;
}
}
BOOL PostAccept(PBUFFER_OBJ pBuffer)
{
PSOCKET_OBJ pSocket =pBuffer->pSocket;
if(pSocket->lpfnAcceptEx !=NULL)
{
// 设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation= OP_ACCEPT;
pSocket->nOutstandingOps++;
//投递此重叠I/O
DWORD dwBytes;
pBuffer->sAccept=
::WSASocket(AF_INET,SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
BOOL b =pSocket->lpfnAcceptEx(pSocket->s,
pBuffer->sAccept,
pBuffer->buff,
BUFFER_SIZE -((sizeof(sockaddr_in) + 16) * 2),
sizeof(sockaddr_in)+ 16,
sizeof(sockaddr_in)+ 16,
&dwBytes,
&pBuffer->ol);
if(!b)
{
if(::WSAGetLastError()!= WSA_IO_PENDING)
returnFALSE;
}
return TRUE;
}
return FALSE;
};
BOOL PostRecv(PBUFFER_OBJ pBuffer)
{
// 设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation =OP_READ;
pBuffer->pSocket->nOutstandingOps++;
// 投递此重叠I/O
DWORD dwBytes;
DWORD dwFlags = 0;
WSABUF buf;
buf.buf = pBuffer->buff;
buf.len = pBuffer->nLen;
if(::WSARecv(pBuffer->pSocket->s,&buf, 1, &dwBytes,&dwFlags,&pBuffer->ol, NULL) !=NO_ERROR)
{
if(::WSAGetLastError() !=WSA_IO_PENDING)
returnFALSE;
}
return TRUE;
}
BOOL PostSend(PBUFFER_OBJ pBuffer)
{
// 设置I/O类型,增加套节字上的重叠I/O计数
pBuffer->nOperation =OP_WRITE;
pBuffer->pSocket->nOutstandingOps++;
// 投递此重叠I/O
DWORD dwBytes;
DWORD dwFlags = 0;
WSABUF buf;
buf.buf = pBuffer->buff;
buf.len = pBuffer->nLen;
if(::WSASend(pBuffer->pSocket->s,
&buf,1, &dwBytes, dwFlags,&pBuffer->ol, NULL) !=NO_ERROR)
{
if(::WSAGetLastError() !=WSA_IO_PENDING)
returnFALSE;
}
return TRUE;
}
BOOL HandleIO(PBUFFER_OBJ pBuffer)
{
PSOCKET_OBJ pSocket =pBuffer->pSocket; //从BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用
pSocket->nOutstandingOps--;
// 获取重叠操作结果
DWORD dwTrans;
DWORD dwFlags;
BOOL bRet =::WSAGetOverlappedResult(pSocket->s,&pBuffer->ol,&dwTrans, FALSE, &dwFlags);
if(!bRet)
{
//在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。
//如果没有其它抛出的I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它I/O也完成
if(pSocket->s !=INVALID_SOCKET)
{
::closesocket(pSocket->s);
pSocket->s= INVALID_SOCKET;
}
if(pSocket->nOutstandingOps== 0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
return FALSE;
}
// 没有错误发生,处理已完成的I/O
switch(pBuffer->nOperation)
{
case OP_ACCEPT://接收到一个新的连接,并接收到了对方发来的第一个封包
{
//为新客户创建一个SOCKET_OBJ对象
PSOCKET_OBJpClient = GetSocketObj(pBuffer->sAccept);
//为发送数据创建一个BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放
PBUFFER_OBJpSend = GetBufferObj(pClient, BUFFER_SIZE);
if(pSend ==NULL)
{
printf("Too much connections! \n");
FreeSocketObj(pClient);
returnFALSE;
}
RebuildArray();
//将数据复制到发送缓冲区
pSend->nLen= dwTrans;
memcpy(pSend->buff,pBuffer->buff, dwTrans);
//投递此发送I/O(将数据回显给客户)
if(!PostSend(pSend))
{
//万一出错的话,释放上面刚申请的两个对象
FreeSocketObj(pSocket);
FreeBufferObj(pSend);
returnFALSE;
}
//继续投递接受I/O
PostAccept(pBuffer);
}
break;
case OP_READ:// 接收数据完成
{
if(dwTrans> 0)
{
//创建一个缓冲区,以发送数据。这里就使用原来的缓冲区
PBUFFER_OBJpSend = pBuffer;
pSend->nLen= dwTrans;
//投递发送I/O(将数据回显给客户)
PostSend(pSend);
}
else//套节字关闭
{
//必须先关闭套节字,以便在此套节字上投递的其它I/O也返回
if(pSocket->s!= INVALID_SOCKET)
{
::closesocket(pSocket->s);
pSocket->s= INVALID_SOCKET;
}
if(pSocket->nOutstandingOps== 0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
returnFALSE;
}
}
break;
caseOP_WRITE:// 发送数据完成
{
if(dwTrans> 0)
{
//继续使用这个缓冲区投递接收数据的请求
pBuffer->nLen= BUFFER_SIZE;
PostRecv(pBuffer);
}
else//套节字关闭
{
//同样,要先关闭套节字
if(pSocket->s!= INVALID_SOCKET)
{
::closesocket(pSocket->s);
pSocket->s= INVALID_SOCKET;
}
if(pSocket->nOutstandingOps== 0)
FreeSocketObj(pSocket);
FreeBufferObj(pBuffer);
returnFALSE;
}
}
break;
}
return TRUE;
}
void main()
{
// 创建监听套节字,绑定到本地端口,进入监听模式
int nPort = 4567;
SOCKET sListen =
::WSASocket(AF_INET,SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
//plisten可被多个重叠I/O占用
SOCKADDR_INsi;
si.sin_family = AF_INET;
si.sin_port = ::ntohs(nPort);
si.sin_addr.S_un.S_addr = INADDR_ANY;
::bind(sListen, (sockaddr*)&si,sizeof(si));
::listen(sListen, 200);
// 为监听套节字创建一个SOCKET_OBJ对象
PSOCKET_OBJ pListen = GetSocketObj(sListen);
// 加载扩展函数AcceptEx
GUID GuidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes;
WSAIoctl(pListen->s,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&pListen->lpfnAcceptEx,
sizeof(pListen->lpfnAcceptEx),
&dwBytes,
NULL,
NULL);
// 创建用来重新建立g_events数组的事件对象
g_events[0] = ::WSACreateEvent();
// 在此可以投递多个接受I/O请求
for(int i=0; i<5; i++)
{
PostAccept(GetBufferObj(pListen,BUFFER_SIZE));
}
::WSASetEvent(g_events[0]);
while(TRUE)
{
int nIndex =
::WSAWaitForMultipleEvents(g_nBufferCount+ 1, g_events, FALSE, WSA_INFINITE, FALSE);
if(nIndex ==WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents()failed \n");
break;
}
nIndex = nIndex -WSA_WAIT_EVENT_0;
for(int i=0;i<=nIndex; i++)
{
int nRet =::WSAWaitForMultipleEvents(1, &g_events[i], TRUE,0, FALSE);
if(nRet ==WSA_WAIT_TIMEOUT)
continue;
else
{
::WSAResetEvent(g_events[i]);
//重新建立g_events数组
if(i== 0)
{
RebuildArray();
continue;
}
//处理这个I/O
PBUFFER_OBJpBuffer = FindBufferObj(g_events[i]);
if(pBuffer!= NULL)
{
if(!HandleIO(pBuffer))
RebuildArray();
}
}
}
}
}
发表评论
-
win下开发跨平台GUI程序的另类选择
2011-05-03 17:21 2146GTK+ ● GTK+的网站:www.gtk. ... -
win32汇编-送消息给其它应用程序
2010-02-20 16:42 28692个函数invoke postmessage,hwnd,msg ... -
WIN32汇编之菜单、加速键、快捷键
2010-02-20 16:38 3077(一)Invoke checkmenuitem,h ... -
WIN32汇编学习应用之defwindowproc
2010-02-20 16:36 2664defwindowproc窗口过程对一些消息的默认处理方式WM ... -
windows中WM_CLOSE消息和WM_DESTORY消息的不同之处
2010-02-20 16:33 23871、WM_CLOSE仅代表用户发出了关闭的指令,但窗口过程可以 ... -
WIN32汇编获取应用程序句柄
2010-02-20 16:32 2119getmodulehandle使用方法invoke getm ... -
WIN32汇编语言学习应用之消息获取
2010-02-20 16:31 1679MSG结构:MSG STURCTHwnd DWORD ?Mes ... -
一个WIN32汇编的完整窗口入门程序的理解与注释
2010-02-20 16:28 3656;WIN32汇编的注释是;,其实WIN32汇编和VC有很多 ... -
汇编中通用寄存器的目的
2010-02-20 16:24 21001、EAX和AX:累加器,所有的I/O指令用它来与外部设备 ... -
汇编几个段
2010-02-17 16:39 4179反汇编后几个段的含义 预定义段 一个WindowsNT ... -
WIN32汇编语言解析
2010-02-17 16:36 2517win32汇编中的sizeof win32汇编中的s ... -
设置与获取窗口标题文本
2010-02-17 16:32 1959获得: CString xx=""; ... -
win32汇编快速入门
2010-02-17 16:31 4618汇编可以开发WINDOWS程序 ... -
WIN32汇编-HELLO,WORLD!
2010-02-17 16:29 4338我们用WIN32汇编构建 ... -
保护模式下段寄存器的作用
2010-02-17 14:39 31531、保护模式一,虽然在寻址上没有分段的限制问题,但对要对一个地 ... -
WIN32汇编-反汇编
2010-02-17 14:33 2745学好WIN32汇编,平时需 ... -
玩转菜单-菜单资源
2010-02-08 17:31 1893菜单资源 WINDOWS程序的菜单通常编译前定义在资 ... -
二进制资源和自定义资源使用定义
2010-02-08 17:29 21451、二进制资源 (1)定义格式: 资源IDRCDA ... -
LISTBOX和LIST CONTROL的项目增加方法
2010-02-08 17:28 53991、LIST CONTROL(report方式): (1)类 ... -
取IP寄存器的当前值
2010-02-08 17:27 1864call $+3 POP CX 把IP寄存器的当前值放 ...
相关推荐
1.1 网络编程相关的基本概念 1 1.1.1 网络编程与进程通信 1 1.1.2 Internet中网间进程的标识 3 1.1.3 网络协议的特征 7 1.2 三类网络编程 10 1.2.1 基于TCP/IP协议栈的网络编程 10 1.2.2 基于WWW应用的...
第一部分 传统网络API第1章 NetBIOS11.1 Microsoft NetBIOS21.1.1 LANA编号21.1.2 NetBIOS名字41.1.3 NetBIOS特性61.2 NetBIOS编程基础71.3 常规NetBIOS例程81.3.1 会话服务器:异步回调模型151.3.2 会话服务器:...
4.2.3 overlapped异步i/o重叠结构 94 4.2.4 通信错误与通信设备状态 95 4.2.5 串行通信事件 96 4.3 windows api串行通信函数 97 4.4 win32 api串口通信编程的一般流程和特殊实例 116 4.4.1 win32 api串口通信...
目者者录译者序前言第一部分 传统网络API第1章 NetBIOS11.1 Microsoft NetBIOS21.1.1 LANA编号21.1.2 NetBIOS名字41.1.3 NetBIOS特性61.2 NetBIOS编程基础71.3 常规NetBIOS例程81.3.1 会话服务器:异步回调模型151.3...
目者者录译者序前言第一部分 传统网络API第1章 NetBIOS11.1 Microsoft NetBIOS21.1.1 LANA编号21.1.2 NetBIOS名字41.1.3 NetBIOS特性61.2 NetBIOS编程基础71.3 常规NetBIOS例程81.3.1 会话服务器:异步回调模型151.3...
本书适合中、高级程序设计人员以及网络设计与管理人员参考。目者者录译者序前言第一部分 传统网络API第1章 NetBIOS11.1 Microsoft NetBIOS21.1.1 LANA编号21.1.2 NetBIOS名字41.1.3 NetBIOS特性61.2 NetBIOS编程基础...
本书专门讨论Windows网络编程技术,覆盖Windows 95/98/NT 4/2000/CE平台,内容包括NetBIOS和Windows重定向器方法、Winsock方法、客户端远程访问服务器方法,本书论述深入浅出、用大量实例详解了微软网络API函数的...
4.2.3 overlapped异步i/o重叠结构 94 4.2.4 通信错误与通信设备状态 95 4.2.5 串行通信事件 96 4.3 windows api串行通信函数 97 4.4 win32 api串口通信编程的一般流程和特殊实例 116 4.4.1 win32 api串口通信...
4.2.3 overlapped异步i/o重叠结构 94 4.2.4 通信错误与通信设备状态 95 4.2.5 串行通信事件 96 4.3 windows api串行通信函数 97 4.4 win32 api串口通信编程的一般流程和特殊实例 116 4.4.1 win32 api串口通信...
4.2.3 OVERLAPPED异步I/O重叠结构 94 4.2.4 通信错误与通信设备状态 95 4.2.5 串行通信事件 96 4.3 Windows API串行通信函数 97 4.4 Win32 API串口通信编程的一般流程和特殊实例 116 4.4.1 Win32 API串口通信编程的...