C# 客户端服务器开发 异步实现

  利用TcpListener和TcpClient类在同步方式下监听客户端连接、接受、发送数据时,在操作没有完成之前,一直处于阻塞状态,这对于接收、发送数据量不大的情况下,或者操作用时比较短的情况下是比较方便的。但对于执行完成时间较长的任务,例如传送大文件等,最好使用异步操作。

  异步操作的最大优点是可以在一个操作没有完成之前同时进行其他的操作。.NET框架提供了一种成为AsyncCallBack(异步回调)的委托,该委托允许启动异步的功能,并在条件具备时,调用提供的回调方法(一种在操作或活动完成时,由委托自动调用的方法),然后在这个方法中完成并结束未完成的工作。

1、AsyncCallback委托

  AsyncCallback委托用于引用异步操作完成时调用的回调方法。在异步操作方式下,由于程序可以在启动异步操作后继续执行其他代码,因此必须有一种机制,以保证该异步操作完成时能及时通知调用者。这种机制可以通过AsyncCakkback委托实现。

  异步操作的每一个方法都有一个Begin...函数和一个End...函数。当程序调用Begin...方法时,系统会自动在线程池中创建对应的线程进行异步操作,从而保证调用方法和被调用方法同时执行,当线程池中的Begin...方法执行完毕时,会自动通过AsyncCallback委托调用Begin...函数的参数中指定的回调函数。

  回调函数是在程序中事先定义好的,在回调函数中,通过End...函数获取Begin...函数的返回值和所有输入/输出参数,从而达到异步操作方式下完成参数传递的目的。

2、BeginAcceptTcpClient函数和EndAcceptTcpClient函数

  在异步Tcp应用变成中,服务端可以使用TcpListener提供的BeginAcceptTcpClient函数开始接受新的额客户端连接请求。在这个方法中,系统自动利用线程池创建需要的线程,并在操作完成时利用异步回调机制调用提供给他的方法,同时返回相应的状态参数。例:

AsyncCallback callback = new AsyncCallback(AcceptTcpClientCallback);
tcpListener.BeginAcceptTcpClient(callback,tcpListener);

  上面的例子,当程序执行BeginAcceptTcpClient函数后,立即在线程池中创建需要的线程,同时在自动创建的线程中监听客户端连接请求。一旦接受了客户端连接请求,就自动通过委托调用提供给委托的方法AcceptTcpClientCallback函数,并通过tcpListener这个实例对象来返回状态信息。AcceptTcpClientCallback函数是自己定义的,定义格式为:

void AcceptTcpClientCallback(IAsyncResult ar)
{
        //HFY::回调函数中执行的代码
        //...
        TcpListener myListener = (TcpListener)ar.AsyncState;
        TcpClient client = myListener.EndAcceptTcpClient(ar);
       //...
}

  上面自己定义的回调函数中传递的参数必须是IAsyncResult类型的接口,它表示异步操作的状态。通过委托,系统会自动将该异步操作的状态信息从关联的BeginAcceptTcpClient函数传递到自定义的AcceptTcpClientCallback函数。

  此外,注意:在回调代码中,必须调用EndAcceptTcpClient函数,完成客户端连接。程序执行完EndAcceptTcpClient函数后,会自动完成客户端的连接请求,并返回包含底层套接字的TcpClient对象,之后就可以利用这个对象与客户端通信了。

  在默认情况下,程序执行BeginAcceptTcpClient函数后,在该函数返回状态信息之前,不会想同步TCP方式那样阻塞等待客户端连接,而是继续往下执行。如果我们希望在其返回状态信息之前阻塞当前线程的执行,可以调用ManualResetEvent对象的WaitOne函数。

3、BeginConnect函数和EndConnect函数

  在异步TCP应用变成中,BeginConnect函数通过异步的方式向远程主机发出连接请求。BeginConnect函数在操作完成前不会阻塞,在程序中调用BeginConnect函数时,系统会自动用独立的线程来执行该方法,直到与远程主机连接成功或抛出一场nag。如果在调用BeginConnect函数之后想阻塞当前线程,也可以调用ManualResetEvent对象的WaitOne函数。

  异步BeginConnect函数只有在调用了EndConnect函数之后才算执行完毕,因此程序中需要在提供给委托调用的方法中调用TcpClient对象的EndConnect函数。关键代码为:

AsyncCallback requestCallback = new AsyncCallback(RequestCallBack);
tcpClient.BeginConnect("10.204.64.77",8088,requestCallback,tcpClient);

//HFY::回调函数
void RequestCallBack(IAsyncResult ar)
{
        //...
        tcpClient = (TcpClient)ar.AsyncState;
        //...
        tcpClient.EndConnect(ar);
        //...
}

4、发送数据

  在异步TCP编程中,如果本机已经和远程主机建立连接,就可以使用BeginWrite函数发送数据。BeginWrite函数用于向一个已经成功连接的套接字异步发送数据。在程序中调用BeginWrite函数后,系统会自动在内部产生的单独执行的线程中发送数据。

  使用BeginWrite异步发送数据,程序必须创建实现AsyncCallback委托的回调函数,并将回调函数的名称传递给BeginWrite函数。在回调函数中,必须调用EndWrite函数,并在EndWrite后,系统会自动使用单独的线程来执行指定的回调函数,并在EndWrite上一直处于阻塞状态,直到NetworkStream对象发送请求的字节数或者引发异常。

5、接收数据

  与发送数据类似,如果本机已经和远程主机建立连接,就可以使用BeginRead函数发送数据。BeginRead方法启动从传入网路缓冲区中异步读取数据的操作。在调用BeginRead函数后,系统自动在单独的执行线程中接受数据。

  在程序中必须创建实现AsyncCallback委托的回调函数,并将其名称传递给BeginRead。一般情况下,我们希望在回调函数中获得所接收的数据,因此因创建小型的类或者结构来保存读取缓冲区,以及其他有用的信息。

  在回调函数中,必须调用EndRead函数来完成读取操作。系统在执行BeginRead时,将一直等待知道数据接收完毕或者遇到错误,从而得到可用的字节数,再自动使用一个单独的线程来执行指定的回调函数,并阻塞EndRead,直到所提供的NetworkStream对象将可用的数据读取完毕,或者达到指定读取的字节数。

时间: 2024-10-27 12:16:42

C# 客户端服务器开发 异步实现的相关文章

C# 客户端服务器开发(一)

1.流程图 首先看一下C#中面向连接的套接字(TCP)的编程流程: 2.服务器建立连接.收发数据.关闭连接程序段: 1)建立连接 //创建本地套接字对象,IPV4寻址方式,基于TCP的Stream Socket(流式套接字0) Socket localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPHostEntry local = Dns.GetHostByName(

GCM(谷歌云推送)客户端服务器端开发全指南(服务器篇)

今天我们按照之前所说的步骤介绍GCM云推送服务端的开发,因为服务端的开发比客户端的开发较简单,遵从由易到难,一步一步攻破的原则,所以我先于客户端讲服务端的开发,话不多说,让我们开始吧! 首先我们依旧来到首页 这次我们点击指南,进入到GCM开发Overview,这里概括了GCM客户端服务器端开发流程. 根据以下的流程图我们不难看出服务端和GCM的通信方式有两种 1.Http协议 2.Xmpp协议 Xmpp协议常用于双向通信,我们这里暂时不需要,因此果断选择Http协议来开发. 英语比较好的朋友可以

手游服务器开发技术详解

从事游戏服务器开发差不多两年时间,两年间参与了不少项目,学到了很多游戏服务器开发技术,参与过几个不同架构的服务器开发,就随便聊聊游戏服务器开发需要的技术.(以下所指游戏服务器更偏向于手游,因为我对端游和页游开发接触并不多) 一.聊聊服务器开发有哪些东西要考虑. 1.开发语言的选择: 工欲善其事,必先利其器,选择一门适合的开发语法对后期开发有着事半功倍的作用. 业界主要的是c/c++ + Python/lua模式做游戏服务器.c/c++做网络通讯数据传输,python/lua做业务逻辑.这样既保持

Socket编程(简易聊天室客户端/服务器编写、CocoaAsyncSocket)

Socket编程(简易聊天室客户端/服务器编写.CocoaAsyncSocket) 一.Socket 1.1 Socket简介 Socket就是为网络服务提供的一种机制.网络通信其实就是Socket间的通信,通信的两端都是Socket,数据在两个Socket间通过IO传输. 在Web服务大行其道的今天,调用Web服务的代价是高昂的,尤其是仅仅是抓取少量数据的时候尤其如此.而使用Socket,可以只传送数据本身而不用进行XML封装,大大降低数据传输的开销.Socket允许使用长连接,允许应用程序运

Netty:一个非阻塞的客户端/服务器框架

Netty:一个非阻塞的客户端/服务器框架 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Netty是一个异步事件驱动的网络应用框架,为Java网络应用的开发带来了一些新活力.Netty由协议服务器和客户端所组成,可用于快速开发可维护的高性能软件.Netty应用框架及其工具简化了网络编程,而且由Netty社区进行维护. Netty还被归类为NIO客户端/服务器框架,用它能够快速.简易地开发网络应用,使得TCP和UDP套接字服务器的网络编程得以简化和

服务器开发-纠正之前的错误

最近一阵子没有更新Egret客户端的博客.这里要解释一下,是因为最近在忙着重写服务器. 为什么说是重写呢?之前封装了一个websocket的中间件,已经可以实现基本的ws通信了.但是最近和游戏那边的同事交流中发现之前对游戏服务器开发的认知错误. 错误有以下几点 服务器逻辑是单线程的.单线程逻辑更加简单,理论上不会出现数据错误问题 服务器逻辑是顺序执行的.意思就是每个客户端的请求必须按顺序去执行,不然会出现客户端处理混乱的情况 了解到这些之后,我重新设计了一下服务器的"架构" ,或许算不

游戏服务器开发技术选型

开发语言的选择 业界主要的是c/c++ + Python/lua模式做游戏服务器.c/c++做网络通讯数据传输,python/lua做业务逻辑.这样既保持了网络传输的效率(c++),又提升开发效率(Python/lua),同时也支持热更新. 当然,也有其他服务器开发语言,erlang(页游公司用的多),node.js(少量游戏用的,还有一个node.js写的引擎叫pemolo) 开源服务器引擎 1.firefly(9秒社团开发的一款python游戏服务器框架) 2.kbengine(作者说他按b

NIO原理剖析与Netty初步----浅谈高性能服务器开发(一)

除特别注明外,本站所有文章均为原创,转载请注明地址 在博主不长的工作经历中,NIO用的并不多,由于使用原生的Java NIO编程的复杂性,大多数时候我们会选择Netty,mina等开源框架,但理解NIO的原理就不重要了吗?恰恰相反,理解NIO底层机制是理解这一切的基础,由此我总结一下当初学习NIO时的笔记,以便后续复习. 以下是我理解的Java原生NIO开发大致流程: 上图大致描述的是服务端的NIO操作. 第一步,绑定一个服务的端口 这与传统阻塞IO中的ServerSocket类似,没什么好说的

Python服务器开发二:Python网络基础

Python服务器开发二:Python网络基础 网络由下往上分为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. HTTP是高层协议,而TCP/IP是个协议集,包过许多的子协议.包括:传输层的 FTP,UDP,TCP协议等,网络层的ip协议等,高层协议如HTTP,telnet协议等,HTTP是TCP/IP的一个子协议. socket是对TCP/IP协议的封装和应用(程序员层面上).也可以说,TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如