您的位置:首页 > 其它

Visual Studio 2005 智能设备开发

2009-06-07 03:35 218 查看
接:一个简单的IOCP(IO完成端口)服务器/客户端类(1/2)

5.1文件传输

使用Winsock2.0的TransmitFile函数传输文件。TransmitFile函数在连接的套接字句柄上传输文件数据。此函数使用操作系统的缓冲管理机制接收文件数据,在套接字上提供高性能的文件传输。在异步文件传输上有以下几个重要方面:
l除非TransmitFile函数返回,否则不能再对套接字执行发送或写入操作,不然会破坏文件的传输。在执行PrepareSendFile(..)函数后,所有对ASend函数的调用都是不允许的。
l由于系统是连续读文件数据,打开文件句柄的FILE_FLAG_SEQUENTIAL_SCAN特性可以提高缓存性能。
l在发送文件(TF_USE_KERNEL_APC)时,我们使用内核的异步程序调用。TF_USE_KERNEL_APC的使用可以带来明显的性能提升。很可能(尽管不一定),带有TransmitFile的线程的上下文环境的初始化会有沉重的计算负担;这种情况下可以防止反复执行APC(异步程序调用)。
文件传输的顺序如下:服务器通过调用PrepareSendFile(..)函数初始化文件传输。客户端接收到文件信息时,通过调用PrepareReceiveFile(..)函数准备接收,并且给服务器发送一个包来开始文件传输。在服务器收到包后,它调用使用高性能的TransmitFile函数的StartSendFile(..)函数传输指定的文件。

6源代码例子

提供的源代码是一个模拟客户端/服务器的例子,它也提供了文件传输功能。在源码中,从类IOCP派生出的类MyIOCP处理客户端和服务器端的通信。在4.1.1部分提到了这个虚函数的用法。
在客户端,或者服务器端的代码中,虚函数
NotifyReceivedPackage
是重点。描述如下:
voidMyIOCP::NotifyReceivedPackage(CIOCPBuffer*pOverlapBuff,
intnSize,ClientContext*pContext)
{
BYTEPackageType=pOverlapBuff->GetPackageType();
switch(PackageType)
{
caseJob_SendText2Client:
Packagetext(pOverlapBuff,nSize,pContext);
break;
caseJob_SendFileInfo:
PackageFileTransfer(pOverlapBuff,nSize,pContext);
break;
caseJob_StartFileTransfer:
PackageStartFileTransfer(pOverlapBuff,nSize,pContext);
break;
caseJob_AbortFileTransfer:
DisableSendFile(pContext);
break;};
}

这个函数处理进来的消息和远程连接发送的请求。在这种情形下,它只不过进行一个简单的回复或者传输文件。源代码分为两部分,IOCP和IOCPClient,
它们是连接的双方。

6.1编译器问题

在使用VC++6.0或者.NT时,在处理类CFile时可能会出现一些奇怪的错误。像下面这样:
“if(pContext->m_File.m_hFile!=
INVALID_HANDLE_VALUE)<-errorC2446:'!=':noconversion"
"from'void*'to'unsignedint'”

在你更新头文件(*.h),或者更新你的VC++6.0版本后,或者只是改变类型转换错误,都可能会解决这些问题。经过一些修改,这个客户端/服务器的源代码在没有MFC的情况下也能使用。

7注意点和解决规则

在你将此代码用于其它类型的程序时,有一些编程的陷阱和源代码有关,使用“多线程编程”可以避免。不确定的错误是那些随时发生的错误,并且通过执行相同的出错的任务的顺序这种方式很难降低这些不确定的错误。这类错误是存在的最严重的错误,一般情况下,它们出错是因为源代码设计执行的内核的出错上。当服务器运行多个IO工作线程时,为连接的客户端服务,假如编程人员没有考虑源代码的多线程环境,就可能会发生像违反权限这种不确定的错误。

解决规则#1:

像下面例子那样,绝不在使用上下文“锁”之前锁定客户端的上下文(例如
ClientContext
)之前进行读/写。通知函数(像:
Notify*(ClientContext*pContext)
)已经是“线程安全的”,你访问
ClientContext
的成员函数,而不考虑上下文的加锁和解锁。
//Donotdoitinthisway
//…
If(pContext->m_bSomeData)
pContext->m_iSomeData=0;
//…
//Doitinthisway.
//….
pContext->m_ContextLock.Lock();
If(pContext->m_bSomeData)
pContext->m_iSomeData=0;
pContext->m_ContextLock.Unlock();
//…
当然,你要明白,当你锁定一个上下文时,其他的线程或GUI都将等待它。

解决规则#2:

要避免,或者“特别注意”使用那些有复杂的“上下文锁”,或在一个“上下文锁”中有其他类型的锁的代码。因为它们很容易导致“死锁”。(例如:A等待B,B等待C,而C等待A=>死锁)。
pContext->m_ContextLock.Lock();
//…codecode..
pContext2->m_ContextLock.Lock();
//codecode..
pContext2->m_ContextLock.Unlock();
//codecode..
pContext->m_ContextLock.Unlock();

上面的代码可以导致一个死锁。

解决规则#3:

绝不要在通知函数(像
Notify*(ClientContext*pContext)
)的外面访问一个客户端的上下文。假如你必须这样做,务必使用
m_ContextMapLock.Lock();
m_ContextMapLock.Unlock()
对它进行封装。如下面代码所示:
ClientContext*pContext=NULL;
m_ContextMapLock.Lock();
pContext=FindClient(ClientID);
//safetoaccesspContext,ifitisnotNULL
//andareLocked(Ruleofthumbs#1:)
//code..code..
m_ContextMapLock.Unlock();
//HerepContextcansuddenlydisappearbecauseofdisconnect.
//donotaccesspContextmembershere.


8下一步的工作
下一步,代码会被更新,在时间顺序上会具有下面的特性:
1.可以接受新的连接的
AcceptEx(..)
函数的应用将添加到源代码中,用来处理短时的连接爆炸(shortlivedconnectionbursts)和DOS攻击。
2.源代码可以很容易的用于其它平台,像Win32,STL,和WTL。

说明:最近比较忙,各种事情应接不暇。终于弄完了,呵呵。
源代码可以到网上下载,我分析了,很好,可以应用到我的项目中,嘿嘿。
出处http://www.codeproject.com/KB/IP/iocp_server_client.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐