.NET平台下可复用的Tcp通信层实现

2006年已经来临,回首刚走过的2005,心中感慨万千。在人生和生活的目标上,有了清晰明确的定位,终于知道了自己喜欢什么样的生活,喜欢什么样的生活方式;在技术上,成熟了不少,眼界也开阔的不少,从面向对象到组件、从.NetJ2EE、从微软到开源,颇有收获。特别值得一提的是,认识了Rod Johnson这个大牛人,也终于在自己的项目中正式使用Spring.net框架来开发了,这确实是一个优秀的框架。而在已经到来的2006年,我有一个主要目标就是B/S应用开发,来填补自己在企业级开发上的另一半空白。
以前就很想将自己在Tcp通信层的开发心得、经验共享出来,但一直没有实现,究其原因,还是自己太懒了。今天终于找到一个时机,写下这篇文章,也算是对2005年的另一种形式的回忆吧。

绝大多数C/S(包括多层)结构的系统中,终端与服务器的通信都是通过Tcp进行的(使用Udp的也有一些,但是其相对于Tcp简单许多,所以不在这里的讨论之列)。通常,这样的C/S系统都需要处理极大的并发,也就是说随时都可能有成千上万个用户在线,并且每分钟都可能有数以百计的用户上线/下线。由于每个用户都与服务器存在着一个Tcp连接,如何管理所有这些连接,并使我们的Tcp通信层稳定高效地工作,是我开发的这个“TcpTcp通信层”设计实现的主要目标。
自从20049月开始至今,我就一直负责某C/S系统的服务器端的架构设计,并负责整个通信层的实现,在探索的过程中,逐渐形成了一套可复用的“Tcp通信层框架”(“框架”这个词真的蛮吓人,呵呵),其位于EnterpriseServerBase类库的EnterpriseServerBase.Network命名空间中。现将我在通信层这一块的设计/开发经验记录于此,以便日后回顾。也期大家多多赐教。
我期望的“Tcp通信层”并不只是能接受连接、管理连接、转发用户请求这么简单,为了构建一个高度可复用的、灵活的、可接插的Tcp通信层,需要定义很多的规则、接口、契约,这需要做很多的工作。“Tcp通信层”决不仅仅只是Tcp协议通信,由于通信与消息联系紧密,不可避免的需要将“通信的消息”纳入到我们的分析中来,比如,基于Tcp传输的特性,我们可能需要对接收到的消息进行分裂、重组等(后文中会解释为什么、以及如何做)。请允许我在这里澄清一下,如果只是解决“仅仅”的Tcp通信问题,我只需要介绍Tcp组件就可以了,但是如果要解决“整个Tcp通信层”的问题,并使之可高度复用,那就需要介绍很多额外的东西,比如,上面提到的“消息”,以及“消息”所涉及的通信协议。
在我们应用的通信层中,存在以Tcp组件为核心的多个组件,这些组件相互协作,以构建/实现高度可复用的Tcp通信层。这些组件之间的关系简单图示如下:
tcp.jpg

我先解释一下上图。当网络(Tcp)组件从某个Tcp连接上接收到一个请求时,会将请求转发给消息分派器,消息分派器通过IDataStreamHelper组件获取请求消息的类型,然后根据此类型要求处理器工厂创建对应类型的请求处理器,请求处理器处理请求并返回结果。接下来再由网络组件把结果返回给终端用户。在消息分派器进行请求消息分派之前,可能涉及一系列的操作,像消息加密/解密、消息分裂/重组、消息验证等。而且,根据不同的应用,可能有其它的消息转换要求,而且这些操作可能是多样化的,为了满足这种多样性和可接插性,这就需要消息分派器提供一个插入点,让我们可以随心所欲地插入自定义的对请求/回复消息的预处理和后处理。
上图中消息分派器中可接插的操作除了消息分裂器(使用实线框)是必须的,消息加密器和消息验证器(使用虚线框)是可选的,应根据你应用的实际情况加以决定是否使用。关于这几个典型的可接插的组件的功能作用会在后文中介绍。在继续介绍Tcp组件的实现之前,有必要先提一下IDataStreamHelper接口的作用,IDataStreamHelper接口用于抽象我们实际的通信协议,并能从任何一请求/回复消息中提取关于本条消息的元数据,比如,消息的长度、类型等信息。具体的应用必须根据自己的消息协议来实现IDataStreamHelper接口。关于该接口的定义也在后文中给出。
关于上图,需要提醒的是,整个消息的流动是由Tcp组件驱动的!这篇文章以Tcp组件和消息分派器组件为索引来组织整个可复用的Tcp通信层的实现。首先,我们来深入到Tcp组件的具体实现中去。

一.Tcp组件

1Tcp组件的主要职责
Tcp组件的主要职责并不是在一个很短的时间内总结出来的,它是逐步完善的(至今可能还不够全面)。为了使Tcp组件具有高度的可复用性,需要考虑很多的需求,而所有这些需求中具有共性的、占主导位置的需求就被纳入到Tcp组件的职责中来了。这个职责的集合如下:
(1) 管理所有的Tcp连接以及连接对应的上下文(Context)。
(2) 当某用户上线或下线时,能发出事件通知。
(3) 当在线用户(连接)的数量发生变化时,能发出事件通知。
(4) 当用户的请求得到回复时,发出事件通知。这一点对于记录用户请求和跟踪用户请求非常有用)
(5) 能及时主动关闭指定连接。比如,当某一非法用户登录后,用户验证组件通知Tcp组件强行关闭该用户对应的连接。
(6) 除了能转发用户请求及对请求的应答(通过消息分派器)外,还能直接对指定的用户发送数据。这也要求我们的Tcp连接是多线程安全的。
(7) 提供绕开Tcp组件直接从Tcp连接同步接收数据的功能。比如,客户端需要上传一个Blob,我们可能希望直接从Tcp连接进行接收数据,这是有好处的,后面可以看到。
这里列出的是Tcp组件的主要职责,还有很多细节性的没有罗列出来,如果一个Tcp组件解决了上述所有问题,对我来说,应该就是一个很好用、很适用的Tcp组件了。

2Tcp组件接口定义
相信很多朋友和我一样,刚接触Tcp服务端开发的时候,通常是当一个Tcp连接建立的时候,就分配一个线程在该连接上监听请求消息,这种方式的缺点有很多,最主要的缺点是效率低、管理复杂。
我的最初的Tcp组件是C++版本的,那时很有幸接触到了windows平台上最高效的Tcp通信模型――完成端口模型,完全理解这个模型需要点时间,但是Win32 多线程程序设计》(侯捷翻译)和《windows网络编程》这两本书可以给你不少帮助。异步机制是完成端口的基础,完成端口模型的本质思想是将"启动异步操作的线程""提供服务的线程"(即工作者线程)拆伙。理解这一点很重要。在.Net中没有对应的组件或类对应于完成端口模型,解决方案有两个:一是通过P/Invoke来实现自己的完成端口组件,另一种方式是通过.Net的现有通信设施来模拟完成端口实现。
本文给出第二种方案的实现说明,另外,我也给出通过“异步+线程池”的方式的Tcp组件实现,这种方式对于大并发量也可以很好的管理。也就是我,我的EnterpriseServerBase类库中,有两种不同方式的Tcp组件实现,一个是模拟完成端口模型,一个是“异步+线程池”方式。无论是哪种方式,它们都实现了相同的接口ITcpITcp这个接口涵盖了上述的Tcp组件的所有职责,这个接口并不复杂,如果理解了,使用起来也非常简单。我们来看看这个接口的定义:

public interface ITcp:INet,ITcpEventList,ITcpClientsController
{
int ConnectionCount{ get ;} // 当前连接的数量
}

这个接口继承了另外三个接口,INet ,ITcpEventList ,ITcpClientsControllerINet接口是为了统一基于TcpUdp的通信组件而抽象出来的,它包含了以下内容:

public interface INet
{
void InitializeAll(IReqestStreamDispatcheri_dispatcher, int port, bool userValidated);
void InitializeAll();
void UnitializeAll();

NetAddinTypeGetProtocalType();
// Udp,Tcp
event CallBackDynamicMessageDynamicMsgArrived; // 通常是通信插件中一些与服务和用户无关的动态信息,如监听线程重启等
void Start();
void Stop();

IReqestStreamDispatcherDispatcher{
set ;} // 支持依赖注入
int Port{ get ; set ;}
bool UserValidated{ set ;}
}

public enum NetAddinType
{
Tcp,Udp
}

public delegate void CallBackDynamicMessage( string msg);

IReqestStreamDispatcher 就是我们上述图中的消息分派器,这是 Tcp 通信层中的中央,它的重要性已从前面的关系图中可见一斑了。 IReqestStreamDispatcher 需要在初始化的时候提供,或者通过 Dispatcher 属性通过 IOC 容器进行设值法注入。 UserValidated 属性用于决定当用户的第一个请求不是登录请求时,是否立即关闭 Tcp 连接。其它的属性已经加上了注释,非常容易理解。
ITcpEventList接口说明了Tcp组件应当发布的事件,主要对应于前述Tcp组件职责的(2)(3)(4)点。其定义如下:
public interface ITcpEventList
{
event CallBackForTcpUser2SomeOneConnected; // 上线
event CallBackForTcpUser1SomeOneDisConnected; // 掉线
event CallBackForTcpCountConnectionCountChanged; // 在线人数变化
event CallBackForTcpMonitorServiceCommitted; // 用户请求的服务的回复信息
event CallBackForTcpUserUserAction;
}

每一个在线用户都对应着一个Tcp连接,我们使用tcp连接的Hashcode作为ConnectID来标志每一个连接。UserAction将用户与服务器的交互分为三类:登录、退出和标准功能访问,如以下枚举所示。

public enum TcpUserAction
{
Logon,Exit,FunctionAccess,
// 标准的功能访问
}

最后一个接口ITcpClientsController,主要用来完成上述Tcp组件职责的(5)(6)(7)三点。定义如下:

/// <summary>
/// ITcpController用于服务器主动控制TCP客户的连接
/// </summary>
public interface ITcpClientsController
{
// 同步接收消息
bool SynRecieveFrom( int ConnectID, byte []buffer, int offset, int size, out int readCount);

// 主动给某个客户同步发信息
void SendData( int ConnectID, byte []data);
void SendData( int ConnectID, byte []data, int offset, int size);

// 主动关闭连接
void DisposeOneConnection( int connectID,DisconnectedCausecause);
}

这个接口中的方法的含义是一目了然的。
上述的几个接口已经完整的覆盖了前述的Tcp组件的所有职责,在了解了这些接口定义的基础上,大家已经能够使用EnterpriseServerBase类库中的Tcp组件了。如果想复用的不仅仅是Tcp组件,而是整个Tcp通信层,你就需要关注后面的内容。不管怎样,为了文章的完整性,我在这里先给出前面提到的Tcp组件的两种实现。

3Tcp组件基本元素实现
在实现Tcp组件之前,有一些基本元素需要先建立起来,比如安全的网络流、Tcp监听器、用户连接上下文、上下文管理者等。(1)安全的网络流SafeNetworkStream
前面已经提到过,为了能在Tcp组件外部 对指定的连接发送数据,必须保证我们的Tcp连接是线程安全的,而System.Net.Sockets.NetworkStream是非线程安全的,我们必须自己对其进行封装,以保证这一点。System.Net.Sockets.NetworkStream的线程安全的封装就是EnterpriseServerBase.Network.SafeNetworkStream类,它继承了ISafeNetworkStream接口:

/// <summary>
/// ISafeNetworkStream线程安全的网络流。
/// 注意:如果调用的异步的begin方法,就一定要调用对应的End方法,否则锁将得不到释放。
/// 作者:朱伟sky.zhuwei@163.com
/// </summary>
publicinterfaceISafeNetworkStream:ITcpSender,ITcpReciever
{
voidFlush();
voidClose();
}


// 用于在TCP连接上发送数据,支持同步和异步
public interface ITcpSender
{
void Write( byte []buffer, int offset, int size);
IAsyncResultBeginWrite(
byte []buffer, int offset, int size,AsyncCallbackcallback, object state);
void EndWrite(IAsyncResultasyncResult);
}

// 用于在TCP连接上接收数据,支持同步和异步
public interface ITcpReciever
{
int Read( byte []buffer, int offset, int size);
IAsyncResultBeginRead(
byte []buffer, int offset, int size,AsyncCallbackcallback, object state);
int EndRead(IAsyncResultasyncResult);
}

该接口几乎与System.Net.Sockets.NetworkStream提供的方法一样,只不过它们是线程安全的。这样,针对同一个SafeNetworkStream,我们就可以在不同的线程中同时在其上进行数据接收/发送(主要是发送)了。

2Tcp监听器EnterpriseServerBase.Network.XTcpListener
不可否认,System.Net.Sockets.TcpListener只是提供了一些最低阶的工作,为了将监听线程、端口、监听事件整合起来,我引入了EnterpriseServerBase.Network.XTcpListener类,它可以启动和停止,并且当有Tcp连接建立的时候,会触发事件。XTcpListener实现了IXTcpListener接口,其定义如下:

public interface IXTcpListener
{
void Start(); // 开始或启动监听线程
void Stop(); // 暂停,但不退出监听线程

void ExitListenThread(); // 退出监听线程

event CBackUserLogonTcpConnectionEstablished; // 新的Tcp连接成功建立
event CallBackDynamicMsgDynamicMsgArrived;
}

XTcpListener可以在不同的Tcp组件中复用,这是一种更细粒度的复用。

3)用户连接上下文ContextKey
ContextKey用于将所有的与一个用户Tcp连接相关的信息(比如接收缓冲区、连接的状态――空闲还是忙碌、等)封装起来,并且还能保存该用户的请求中上次未处理完的数据,将其放于接收缓冲区的头部,并与后面接收到的数据进行重组。说到这里,你可能不太明白,我需要解释一下。Tcp协议可以保证我们发出的消息完整的、有序的、正确的到达目的地,但是它不能保证,我们一次发送的数据对方也能一次接收完全。比如,我们发送了一个100Bytes的数据,对方可能要接收两次才能完全,先收到60Bytes,再收到40Bytes,这表明我们可能会收到“半条”消息。还有一种情况,你连续发了两条100Bytes的消息,而对方可能一次就接收了160Bytes,所以需要对消息进行分裂,从中分裂出完整的消息然后进行处理。这,就是前面所说的需要对消息进行分裂、重组的原因。知道这点后,IContextKey接口应该比较容易理解了,因为该接口的很多元素的存在都是为了辅助解决这个问题。IContextKey的定义如下:

public interface IContextKey
{
NetStreamStateStreamState{
get ; set ;} // 网络流的当前状态--空闲、忙碌
ISafeNetworkStreamNetStream{ get ; set ;}

byte []Buffer{ get ; set ;} // 接收缓冲区
int BytesRead{ get ; set ;} // 本次接收的字节数
int PreLeftDataLen{ get ; set ;}
bool IsFirstMsg{ get ; set ;} // 是否为建立连接后的第一条消息

int StartOffsetForRecieve{ get ;}
int MaxRecieveCapacity{ get ;} // 本次可以接收的最大字节数
RequestDataRequestData{ get ;}

void ResetBuffer( byte []leftData); // leftData表示上次没有处理完的数据,需要与后面来的数据进行重组,然后再次处理
}

对于消息的分裂和重组是由消息分裂器完成的,由于Tcp组件的实现不需要使用消息分裂器,所以消息分裂器的说明将在后面的消息分派器实现中讲解。

4)上下文管理者ContextKeyManager
ContextKeyManager用于管理所有的ContextKey,其实现的接口IContextKeyManager很容易理解:

public interface IContextKeyManager
{
void InsertContextKey(ContextKeycontext_key);
void DisposeAllContextKey();
bool IsAllStreamSafeToStop(); // 是否可以安全退出
void RemoveContextKey( int streamHashCode);
int ConnectionCount{ get ;}
ISafeNetworkStreamGetNetStream(
int streamHashCode);
event CallBackCountChangedStreamCountChanged;
}

在上述四个基本元素的支持下,再来实现Tcp组件就方便了许多,无论是以何种方式(如完成端口模型、异步方式)实现Tcp组件,这些基本元素都是可以通用的,所以如果你要实现自己的Tcp组件,也可以考虑复用上述的一些基本元素。复用可以在不同的粒度进行,复用真是无处不在,呵呵。

4.完成端口Tcp组件实现
前面已经提到,完成端口模型本质思想是将"启动异步操作的线程""提供服务的线程"(即工作者线程)拆伙。只要做到这一点,就模拟了完成端口。
分析一下我们需要几种类型的线程,首先我们需要一个线程来接收TCP连接请求,这就是所谓监听线程,当成功的接收到一个连接后,就向连接发送一个异步接收数据的请求,由于是异步操作,所以会立即返回,然后再去接收新的连接请求,如此监听线程就循环运作起来了(已经封装成前述的XTcpListener组件了)。值得提出的是,在异步接收的回调函数中,应该对接收到的数据进行处理,完成端口模型所做的就是将接收到的数据放在了完成端口队列中,注意,是一个队列。第二种线程类型,就是工作者线程。工作者线程的个数有个经验值是( Cpu个数×2 2),当然具体取多少,还要取决于你的应用的要求。工作者线程的任务就是不断地从完成端口队列中取出数据,并处理它,然后如果有回复,再将回复写入对应的连接。
好,让我们来定义接口IRequestQueueManager,用于模拟完成端口的队列,该队列是线程安全的,用于将所有的请求进行排队,然后由工作者线程来轮流处理这些请求。

public interface IRequestQueueManager:IRequestPusher
{
object Pop(); // 弹出队列中的下一个请求
void Clear();
int Length{ get ;} // 队列长度
}

public interface IRequestPusher
{
void Push( object package); // 向队列中压入一个请求
}

IRequestQueueManager的基础上,可以将工作者线程和启动异步操作的线程拆开了。由于工作者线程只与端口队列相关,所以我决定将它们一起封装起来--成为IIOCPManager,用于管理请求队列和工作者线程。

/// <summary>
/// IIOCPManager完成端口管理者,主要管理工作者线程和完成端口队列。
/// </summary>
public interface IIOCPManager:IRequestPusher
{
void Initialize(IOCPPackageHandleri_packageHandler, int threadCount);
void Start(); // 启动工作者线程
void Stop(); // 退出工作者线程

int WorkThreadCount{ get ;}

event CallBackPackageHandledPackageHandled;
}

// IOCPPackageHandler用于处理从完成端口队列中取出的package
public interface IOCPPackageHandler
{
void HandlerPackage( object package); // 一般以同步实现
}

有了IRequestQueueManagerIIOCPManager的支持,实现基于完成端口模型的Tcp组件就非常简单了。当然,你也可以单独使用IIOCPManager。你只要提供一个监听者线程接收连接,并将从连接接收到的数据通过IRequestPusher接口放入端口队列就可以了。 当然,为了处理接收到的数据,我们需要提供一个实现了IOCPPackageHandler接口的对象给IOCPManager。值得提出的是,你可以在数据处理并发送了回复数据后,再次投递一个异步接收请求,以保证能源源不断的从对应的TCP连接接收数据。下面,我们来看基于完成端口模型的Tcp组件的完整实现。

ContractedBlock.gif ExpandedBlockStart.gif 完成端口Tcp组件
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->1ExpandedBlockStart.gifContractedBlock.gif/**////<summary>
2InBlock.gif///IocpTcp完成端口Tcp组件。
3ExpandedBlockEnd.gif///</summary>

4None.gifpublicclassIocpTcp:ITcp,IOCPPackageHandler
5ExpandedBlockStart.gifContractedBlock.gifdot.gif{
6ContractedSubBlock.gifExpandedSubBlockStart.gifmembers#regionmembers
7InBlock.gifprivateconstintBufferSize=1024;
8InBlock.gifprivateconstintMaxWorkThreadNum=50;
9InBlock.gif
10InBlock.gifprivateIXTcpListenerxtcpListener;
11InBlock.gifprivateIIOCPManageriocpMgr=null;
12InBlock.gifprivateITcpReqStreamDispatchermessageDispatcher=null;
13InBlock.gifprivateContextKeyManagercontextKeyMgr=newContextKeyManager();
14InBlock.gifprivateboolstateIsStop=true;
15InBlock.gifprivateboolvalidateRequest=false;
16InBlock.gifprivateintcurPort=8888;
17ExpandedSubBlockEnd.gif#endregion

18InBlock.gif
19InBlock.gifpublicIocpTcp()
20ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
21InBlock.gif
22ExpandedSubBlockEnd.gif}

23ContractedSubBlock.gifExpandedSubBlockStart.gifITcp成员#regionITcp成员
24InBlock.gifpublicintConnectionCount
25ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
26InBlock.gifget
27ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
28InBlock.gifreturnthis.contextKeyMgr.ConnectionCount;
29ExpandedSubBlockEnd.gif}

30ExpandedSubBlockEnd.gif}

31InBlock.gif
32ExpandedSubBlockEnd.gif#endregion

33InBlock.gif
34ContractedSubBlock.gifExpandedSubBlockStart.gifINet成员#regionINet成员
35InBlock.gif
36ContractedSubBlock.gifExpandedSubBlockStart.gifInitializeAll,UnitializeAll#regionInitializeAll,UnitializeAll
37InBlock.gifpublicvoidInitializeAll(IReqestStreamDispatcheri_dispatcher,intport,booluserValidated)
38ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
39InBlock.gifthis.messageDispatcher=i_dispatcherasITcpReqStreamDispatcher;
40InBlock.gifif(this.messageDispatcher==null)
41ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
42InBlock.gifthrownewException("Can'tconvertIReqestStreamDispatchertoITcpReqStreamDispatcherinCompletePortManager.InitializeAllmethod!");
43ExpandedSubBlockEnd.gif}

44InBlock.gif
45InBlock.gifthis.validateRequest=userValidated;
46InBlock.gifthis.curPort=port;
47InBlock.gif
48InBlock.gifthis.InitializeAll();
49ExpandedSubBlockEnd.gif}

50InBlock.gif
51InBlock.gifpublicvoidInitializeAll()
52ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
53InBlock.gifthis.xtcpListener=newXTcpListener(this.curPort);
54InBlock.gifthis.xtcpListener.TcpConnectionEstablished+=newCBackUserLogon(xtcpListener_TcpConnectionEstablished);
55InBlock.gifthis.xtcpListener.DynamicMsgArrived+=newCallBackDynamicMsg(this.PutoutDynamicMsg);
56InBlock.gifthis.contextKeyMgr.StreamCountChanged+=newCallBackCountChanged(this.OnStreamCountChanged);
57InBlock.gif
58InBlock.gifthis.iocpMgr=newIOCPManager();
59InBlock.gifthis.iocpMgr.Initialize(this,IocpTcp.MaxWorkThreadNum);
60ExpandedSubBlockEnd.gif}

61InBlock.gif
62InBlock.gifpublicvoidUnitializeAll()
63ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
64InBlock.gifthis.Stop();
65InBlock.gifthis.xtcpListener.ExitListenThread();
66InBlock.gif
67InBlock.gif//将事件容器清空==》防止外部框架再多次初始化的过程中将一个事件预定多次
68InBlock.gifthis.ConnectionCountChanged=null;
69InBlock.gifthis.DynamicMsgArrived=null;
70InBlock.gifthis.ServiceCommitted=null;
71InBlock.gifthis.SomeOneConnected=null;
72InBlock.gifthis.SomeOneDisConnected=null;
73InBlock.gifthis.UserAction=null;
74ExpandedSubBlockEnd.gif}

75ExpandedSubBlockEnd.gif#endregion

76InBlock.gif
77ContractedSubBlock.gifExpandedSubBlockStart.gifStart,Stop#regionStart,Stop
78InBlock.gifpublicvoidStart()
79ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
80InBlock.giftry
81ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
82InBlock.gifif(this.stateIsStop)
83ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
84InBlock.gifthis.stateIsStop=false;
85InBlock.gifthis.xtcpListener.Start();
86InBlock.gifthis.iocpMgr.Start();
87ExpandedSubBlockEnd.gif}

88ExpandedSubBlockEnd.gif}

89InBlock.gifcatch(Exceptionee)
90ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
91InBlock.gifthrowee;
92ExpandedSubBlockEnd.gif}

93ExpandedSubBlockEnd.gif}

94InBlock.gif
95InBlock.gifpublicvoidStop()
96ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
97InBlock.gifif(this.stateIsStop)
98ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
99InBlock.gifreturn;
100ExpandedSubBlockEnd.gif}

101InBlock.gif
102InBlock.gifthis.stateIsStop=true;
103InBlock.gifthis.xtcpListener.Stop();
104InBlock.gifthis.iocpMgr.Stop();
105InBlock.gif
106InBlock.gif//关闭所有连接
107InBlock.gifintcount=0;
108InBlock.gifwhile(!this.contextKeyMgr.IsAllStreamSafeToStop())//等待所有流到达停止安全点
109ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
110InBlock.gifThread.Sleep(200);
111InBlock.gifif(10==count++)
112ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
113InBlock.gifbreak;
114ExpandedSubBlockEnd.gif}

115ExpandedSubBlockEnd.gif}

116InBlock.gifthis.contextKeyMgr.DisposeAllContextKey();
117ExpandedSubBlockEnd.gif}

118ExpandedSubBlockEnd.gif#endregion

119InBlock.gif
120InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackDynamicMessageDynamicMsgArrived;
121InBlock.gif
122InBlock.gifpublicNetAddinTypeGetProtocalType()
123ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
124InBlock.gifreturnNetAddinType.Tcp;
125ExpandedSubBlockEnd.gif}

126InBlock.gif
127ExpandedSubBlockEnd.gif#endregion

128InBlock.gif
129ContractedSubBlock.gifExpandedSubBlockStart.gifITcpEventList成员#regionITcpEventList成员
130InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUser2SomeOneConnected;
131InBlock.gif
132InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpMonitorServiceCommitted;
133InBlock.gif
134InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpCountConnectionCountChanged;
135InBlock.gif
136InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUser1SomeOneDisConnected;
137InBlock.gif
138InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUserUserAction;
139InBlock.gif
140ExpandedSubBlockEnd.gif#endregion

141InBlock.gif
142ContractedSubBlock.gifExpandedSubBlockStart.gifITcpClientsController成员#regionITcpClientsController成员
143InBlock.gif
144InBlock.gifpublicvoidSendData(intConnectID,byte[]data)
145ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
146InBlock.gifthis.SendData(ConnectID,data,0,data.Length);
147ExpandedSubBlockEnd.gif}

148InBlock.gif
149InBlock.gifpublicvoidSendData(intConnectID,byte[]data,intoffset,intsize)
150ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
151InBlock.gifif((data==null)||(data.Length==0)||(offset<0)||(size<0)||(offset+size>data.Length))
152ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
153InBlock.gifreturn;
154ExpandedSubBlockEnd.gif}

155InBlock.gif
156InBlock.gifISafeNetworkStreamnetStream=this.contextKeyMgr.GetNetStream(ConnectID);
157InBlock.gifif(netStream==null)
158ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
159InBlock.gifreturn;
160ExpandedSubBlockEnd.gif}

161InBlock.gif
162InBlock.gifnetStream.Write(data,offset,size);
163ExpandedSubBlockEnd.gif}

164InBlock.gif
165InBlock.gifpublicboolSynRecieveFrom(intConnectID,byte[]buffer,intoffset,intsize,outintreadCount)
166ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
167InBlock.gifreadCount=0;
168InBlock.gifISafeNetworkStreamnetStream=this.contextKeyMgr.GetNetStream(ConnectID);
169InBlock.gifif(netStream==null)
170ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
171InBlock.gifreturnfalse;
172ExpandedSubBlockEnd.gif}

173InBlock.gif
174InBlock.gifreadCount=netStream.Read(buffer,offset,size);
175InBlock.gif
176InBlock.gifreturntrue;
177ExpandedSubBlockEnd.gif}

178InBlock.gif
179InBlock.gifpublicvoidDisposeOneConnection(intconnectID,EnterpriseServerBase.Network.DisconnectedCausecause)
180ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
181InBlock.gifthis.DisposeOneConnection(connectID);
182InBlock.gif
183InBlock.gifif(this.SomeOneDisConnected!=null)
184ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
185InBlock.gifthis.SomeOneDisConnected(connectID,cause);
186ExpandedSubBlockEnd.gif}

187InBlock.gif
188InBlock.gifthis.ActivateUserActionEvent(connectID,TcpUserAction.Exit);
189ExpandedSubBlockEnd.gif}

190InBlock.gif
191ExpandedSubBlockStart.gifContractedSubBlock.gif/**////<summary>
192InBlock.gif///DisposeOneConnection主要由用户管理模块调用--当无法检测到掉线情况时,该方法保证资源被释放
193ExpandedSubBlockEnd.gif///</summary>

194InBlock.gifprivatevoidDisposeOneConnection(intconnectID)
195ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
196InBlock.gifthis.contextKeyMgr.RemoveContextKey(connectID);
197ExpandedSubBlockEnd.gif}

198InBlock.gif
199ExpandedSubBlockEnd.gif#endregion

200InBlock.gif
201ContractedSubBlock.gifExpandedSubBlockStart.gifprivate#regionprivate
202ContractedSubBlock.gifExpandedSubBlockStart.gifBindRequestToQueue#regionBindRequestToQueue
203InBlock.gifprivatevoidBindRequestToQueue(IAsyncResultar)
204ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
205InBlock.giftry
206ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
207InBlock.gifContextKeykey=(ContextKey)ar.AsyncState;
208InBlock.gifkey.BytesRead=key.NetStream.EndRead(ar);
209InBlock.gifif(!this.CheckData(key))
210ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
211InBlock.gifreturn;
212ExpandedSubBlockEnd.gif}

213InBlock.gif
214InBlock.gifthis.iocpMgr.Push(key);
215ExpandedSubBlockEnd.gif}

216InBlock.gifcatch(Exceptionee)
217ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
218InBlock.gifee=ee;
219ExpandedSubBlockEnd.gif}

220ExpandedSubBlockEnd.gif}

221InBlock.gif
222ContractedSubBlock.gifExpandedSubBlockStart.gifCheckData#regionCheckData
223InBlock.gifprivateboolCheckData(ContextKeykey)
224ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
225InBlock.gifintstreamHashcode=key.NetStream.GetHashCode();
226InBlock.gifif(this.stateIsStop)
227ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
228InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.ServerStopped);
229InBlock.gifreturnfalse;
230ExpandedSubBlockEnd.gif}

231InBlock.gif
232InBlock.gifif(key.BytesRead==0)//表示客户端掉线或非正常关闭连接
233ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
234InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.LineOff);
235InBlock.gifreturnfalse;
236ExpandedSubBlockEnd.gif}

237InBlock.gif
238InBlock.gifif(key.BytesRead==8)//表示客户端正常关闭连接
239ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
240InBlock.gifstringss=System.Text.Encoding.BigEndianUnicode.GetString(key.Buffer,0,8);
241InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.LineOff);
242InBlock.gifreturnfalse;
243ExpandedSubBlockEnd.gif}

244InBlock.gif
245InBlock.gifreturntrue;
246ExpandedSubBlockEnd.gif}

247ExpandedSubBlockEnd.gif#endregion

248ExpandedSubBlockEnd.gif#endregion

249InBlock.gif
250ContractedSubBlock.gifExpandedSubBlockStart.gifxtcpListener_TcpConnectionEstablished#regionxtcpListener_TcpConnectionEstablished
251InBlock.gifprivatevoidxtcpListener_TcpConnectionEstablished(NetworkStreamstream)
252ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
253InBlock.gifISafeNetworkStreamsafeStream=newSafeNetworkStream(stream);
254InBlock.gifContextKeykey=newContextKey(safeStream,IocpTcp.BufferSize);
255InBlock.gifkey.ResetBuffer(null);
256InBlock.gifthis.contextKeyMgr.InsertContextKey(key);
257InBlock.gifintconnectID=key.NetStream.GetHashCode();
258InBlock.gifif(this.SomeOneConnected!=null)
259ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
260InBlock.gifthis.SomeOneConnected(connectID);
261ExpandedSubBlockEnd.gif}

262InBlock.gif
263InBlock.gifthis.ActivateUserActionEvent(connectID,TcpUserAction.Logon);
264InBlock.gif
265InBlock.gifkey.IsFirstMsg=true;
266InBlock.gifthis.RecieveDataFrom(key);
267ExpandedSubBlockEnd.gif}

268ExpandedSubBlockEnd.gif#endregion

269InBlock.gif
270ContractedSubBlock.gifExpandedSubBlockStart.gifActivateUserActionEvent#regionActivateUserActionEvent
271InBlock.gifprivatevoidActivateUserActionEvent(intConnectID,TcpUserActionaction)
272ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
273InBlock.gifif(this.UserAction!=null)
274ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
275InBlock.gifthis.UserAction(ConnectID,action);
276ExpandedSubBlockEnd.gif}

277ExpandedSubBlockEnd.gif}

278ExpandedSubBlockEnd.gif#endregion

279InBlock.gif
280ContractedSubBlock.gifExpandedSubBlockStart.gifPutoutDynamicMsg#regionPutoutDynamicMsg
281InBlock.gifprivatevoidPutoutDynamicMsg(stringmsg)
282ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
283InBlock.gifif(this.DynamicMsgArrived!=null)
284ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
285InBlock.gifthis.DynamicMsgArrived(msg);
286ExpandedSubBlockEnd.gif}

287ExpandedSubBlockEnd.gif}

288ExpandedSubBlockEnd.gif#endregion

289InBlock.gif
290ContractedSubBlock.gifExpandedSubBlockStart.gifOnStreamCountChanged#regionOnStreamCountChanged
291InBlock.gifprivatevoidOnStreamCountChanged(intcount)
292ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
293InBlock.gifif(this.ConnectionCountChanged!=null)
294ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
295InBlock.gifthis.ConnectionCountChanged(count);
296ExpandedSubBlockEnd.gif}

297ExpandedSubBlockEnd.gif}

298ExpandedSubBlockEnd.gif#endregion

299InBlock.gif
300ContractedSubBlock.gifExpandedSubBlockStart.gifRecieveDataFrom#regionRecieveDataFrom
301InBlock.gifprivatevoidRecieveDataFrom(ContextKeykey)
302ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
303InBlock.giftry
304ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
305InBlock.gifkey.StreamState=NetStreamState.Reading;
306InBlock.gifkey.NetStream.BeginRead(key.Buffer,key.StartOffsetForRecieve,key.MaxRecieveCapacity,newAsyncCallback(this.BindRequestToQueue),key);
307ExpandedSubBlockEnd.gif}

308InBlock.gifcatch(Exceptionee)
309ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
310InBlock.gifee=ee;
311ExpandedSubBlockEnd.gif}

312InBlock.gif
313ExpandedSubBlockEnd.gif}

314ExpandedSubBlockEnd.gif#endregion

315ExpandedSubBlockEnd.gif#endregion

316InBlock.gif
317ContractedSubBlock.gifExpandedSubBlockStart.gifIOCPPackageHandler成员#regionIOCPPackageHandler成员
318InBlock.gif
319InBlock.gifpublicvoidHandlerPackage(objectpackage)
320ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
321InBlock.gifContextKeykey=packageasContextKey;
322InBlock.gifif(key==null)
323ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
324InBlock.gifreturn;
325ExpandedSubBlockEnd.gif}

326InBlock.gif
327InBlock.gifintstreamHashCode=key.NetStream.GetHashCode();//是SafeNetworkStream的hashcode
328InBlock.gif
329InBlock.gif//处理请求
330InBlock.giftry
331ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
332InBlock.gifbyte[]leftData=null;
333InBlock.gifArrayListrepondList=this.messageDispatcher.DealRequestMessage(key.RequestData,outleftData,refkey.Validation);
334InBlock.gif
335InBlock.gifif(this.validateRequest)
336ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
337InBlock.gifif(key.Validation.gotoCloseConnection)
338ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
339InBlock.gifthis.DisposeOneConnection(streamHashCode,key.Validation.cause);
340InBlock.gifreturn;
341ExpandedSubBlockEnd.gif}

342ExpandedSubBlockEnd.gif}

343InBlock.gif
344InBlock.gifkey.StreamState=NetStreamState.Writing;
345InBlock.gifif(repondList!=null&&(repondList.Count!=0))
346ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
347InBlock.gifforeach(objectobjinrepondList)
348ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
349InBlock.gifbyte[]respond_stream=(byte[])obj;
350InBlock.gifkey.NetStream.Write(respond_stream,0,respond_stream.Length);
351InBlock.gifif(this.ServiceCommitted!=null)
352ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
353InBlock.gifRespondInformationinfo=newRespondInformation();
354InBlock.gifinfo.ConnectID=streamHashCode;
355InBlock.gifinfo.ServiceKey=this.messageDispatcher.GetServiceKey(respond_stream);
356InBlock.gifinfo.repondData=respond_stream;
357InBlock.gifthis.ServiceCommitted(info);
358ExpandedSubBlockEnd.gif}

359InBlock.gifthis.ActivateUserActionEvent(streamHashCode,TcpUserAction.FunctionAccess);
360ExpandedSubBlockEnd.gif}

361ExpandedSubBlockEnd.gif}

362InBlock.gif
363InBlock.gifif(key.IsFirstMsg)
364ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
365InBlock.gifif(repondList==null||(repondList.Count==0))//表示第一条消息还未接收完全
366ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
367InBlock.gifkey.IsFirstMsg=true;
368ExpandedSubBlockEnd.gif}

369InBlock.gifelse
370ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
371InBlock.gifkey.IsFirstMsg=false;
372ExpandedSubBlockEnd.gif}

373ExpandedSubBlockEnd.gif}

374InBlock.gif
375InBlock.gifkey.StreamState=NetStreamState.Idle;
376InBlock.gif
377InBlock.gifkey.ResetBuffer(leftData);
378InBlock.gif
379InBlock.gifif(!this.stateIsStop)
380ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
381InBlock.gif//继续接收请求
382InBlock.gifthis.RecieveDataFrom(key);
383ExpandedSubBlockEnd.gif}

384InBlock.gifelse//停止服务
385ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
386InBlock.gifthis.DisposeOneConnection(streamHashCode,DisconnectedCause.ServerStopped);
387ExpandedSubBlockEnd.gif}

388ExpandedSubBlockEnd.gif}

389InBlock.gifcatch(Exceptionee)
390ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
391InBlock.gifif(eeisSystem.IO.IOException)//正在读写流的时候,连接断开
392ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
393InBlock.gifthis.DisposeOneConnection(streamHashCode,DisconnectedCause.ServerStopped);
394ExpandedSubBlockEnd.gif}

395InBlock.gif
396InBlock.gifee=ee;
397ExpandedSubBlockEnd.gif}

398ExpandedSubBlockEnd.gif}

399InBlock.gif
400ExpandedSubBlockEnd.gif#endregion

401InBlock.gif
402ContractedSubBlock.gifExpandedSubBlockStart.gifINet成员#regionINet成员
403InBlock.gif
404InBlock.gifpublicIReqestStreamDispatcherDispatcher
405ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
406InBlock.gifset
407ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
408InBlock.gifthis.messageDispatcher=(ITcpReqStreamDispatcher)value;
409ExpandedSubBlockEnd.gif}

410ExpandedSubBlockEnd.gif}

411InBlock.gif
412InBlock.gifpublicintPort
413ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
414InBlock.gifset
415ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
416InBlock.gifthis.curPort=value;
417ExpandedSubBlockEnd.gif}

418InBlock.gifget
419ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
420InBlock.gifreturnthis.curPort;
421ExpandedSubBlockEnd.gif}

422ExpandedSubBlockEnd.gif}

423InBlock.gif
424InBlock.gifpublicboolUserValidated
425ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
426InBlock.gifset
427ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
428InBlock.gifthis.validateRequest=value;
429ExpandedSubBlockEnd.gif}

430ExpandedSubBlockEnd.gif}

431InBlock.gif
432ExpandedSubBlockEnd.gif#endregion

433ExpandedBlockEnd.gif}



5.异步Tcp组件实现
这种方式的主要思想是:当一个新的Tcp连接建立时,就在该连接上发送一个异步接收的请求(BeginRead),并在异步回调中处理该请求,当请求处理完毕,再次发送异步接收请求,如此循环下去。异步接收启用的是系统默认线程池中的线程,所以,在异步Tcp组件中不用显式管理工作线程。异步Tcp组件的实现相对于完成端口模型而言简单许多,也单纯一些,不用管理请求队列,不需使用工作者线程等等。但是,相比于完成端口模型,其也有明显的缺陷:一个Tcp连接绑定到了一个线程,即使这个线程是后台线程池中的。如果用户数量巨大,这对性能是极其不利的;而完成端口模型,则可以限定工作者线程的个数,并且可以根据应用的类型进行灵活调节。
异步Tcp组件实现源码。

ContractedBlock.gif ExpandedBlockStart.gif 异步Tcp组件
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->1ExpandedBlockStart.gifContractedBlock.gif/**////<summary>
2InBlock.gif///AsynTcp异步Tcp组件。
3ExpandedBlockEnd.gif///</summary>

4None.gifpublicclassAsynTcp:ITcp
5ExpandedBlockStart.gifContractedBlock.gifdot.gif{
6ContractedSubBlock.gifExpandedSubBlockStart.gifmembers#regionmembers
7InBlock.gifprivateconstintBufferSize=1024;
8InBlock.gif
9InBlock.gifprivateIXTcpListenerxtcpListener=null;
10InBlock.gifprivateITcpReqStreamDispatchermessageDispatcher=null;
11InBlock.gifprivateContextKeyManagercontextKeyMgr=newContextKeyManager();
12InBlock.gifprivateboolstateIsStop=true;
13InBlock.gifprivateboolvalidateRequest=false;
14InBlock.gifprivateintcurPort=8888;
15ExpandedSubBlockEnd.gif#endregion

16InBlock.gif
17InBlock.gif
18InBlock.gifpublicAsynTcp()
19ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
20InBlock.gif
21ExpandedSubBlockEnd.gif}

22InBlock.gif
23ContractedSubBlock.gifExpandedSubBlockStart.gifINet成员#regionINet成员
24InBlock.gif
25InBlock.gifpubliceventCallBackDynamicMessageDynamicMsgArrived;
26InBlock.gif
27InBlock.gifpublicNetAddinTypeGetProtocalType()
28ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
29InBlock.gif
30InBlock.gifreturnNetAddinType.Tcp;
31ExpandedSubBlockEnd.gif}

32InBlock.gif
33ContractedSubBlock.gifExpandedSubBlockStart.gifInitializeAll,UnitializeAll#regionInitializeAll,UnitializeAll
34InBlock.gifpublicvoidInitializeAll(IReqestStreamDispatcheri_dispatcher,intport,booluserValidated)
35ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
36InBlock.gifthis.messageDispatcher=i_dispatcherasITcpReqStreamDispatcher;
37InBlock.gifif(this.messageDispatcher==null)
38ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
39InBlock.gifthrownewException("Can'tconvertIReqestStreamDispatchertoITcpReqStreamDispatcherinCompletePortManager.InitializeAllmethod!");
40ExpandedSubBlockEnd.gif}

41InBlock.gif
42InBlock.gifthis.curPort=port;
43InBlock.gifthis.validateRequest=userValidated;
44InBlock.gif
45InBlock.gifthis.InitializeAll();
46ExpandedSubBlockEnd.gif}

47InBlock.gif
48InBlock.gifpublicvoidInitializeAll()
49ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
50InBlock.gifthis.xtcpListener=newXTcpListener(this.curPort);
51InBlock.gifthis.xtcpListener.TcpConnectionEstablished+=newCBackUserLogon(xtcpListener_TcpConnectionEstablished);
52InBlock.gifthis.xtcpListener.DynamicMsgArrived+=newCallBackDynamicMsg(this.PutoutDynamicMsg);
53InBlock.gifthis.contextKeyMgr.StreamCountChanged+=newCallBackCountChanged(this.OnStreamCountChanged);
54ExpandedSubBlockEnd.gif}

55InBlock.gif
56InBlock.gifpublicvoidUnitializeAll()
57ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
58InBlock.gifthis.Stop();
59InBlock.gifthis.xtcpListener.ExitListenThread();
60InBlock.gif
61InBlock.gif//将事件容器清空==》防止外部框架再多次初始化的过程中将一个事件预定多次
62InBlock.gifthis.ConnectionCountChanged=null;
63InBlock.gifthis.DynamicMsgArrived=null;
64InBlock.gifthis.ServiceCommitted=null;
65InBlock.gifthis.SomeOneConnected=null;
66InBlock.gifthis.SomeOneDisConnected=null;
67InBlock.gifthis.UserAction=null;
68ExpandedSubBlockEnd.gif}

69InBlock.gif
70ExpandedSubBlockEnd.gif#endregion

71InBlock.gif
72ContractedSubBlock.gifExpandedSubBlockStart.gifStart,Stop#regionStart,Stop
73InBlock.gifpublicvoidStart()
74ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
75InBlock.gifif(this.stateIsStop)
76ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
77InBlock.gifthis.xtcpListener.Start();
78InBlock.gifthis.stateIsStop=false;
79ExpandedSubBlockEnd.gif}

80ExpandedSubBlockEnd.gif}

81InBlock.gif
82InBlock.gifpublicvoidStop()
83ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
84InBlock.gifif(this.stateIsStop)
85ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
86InBlock.gifreturn;
87ExpandedSubBlockEnd.gif}

88InBlock.gif
89InBlock.gifthis.stateIsStop=true;
90InBlock.gifthis.xtcpListener.Stop();
91InBlock.gif
92InBlock.gif//关闭所有连接
93InBlock.gifintcount=0;
94InBlock.gifwhile(!this.contextKeyMgr.IsAllStreamSafeToStop())//等待所有流到达停止安全点
95ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
96InBlock.gifThread.Sleep(200);
97InBlock.gifif(10==count++)
98ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
99InBlock.gifbreak;
100ExpandedSubBlockEnd.gif}

101ExpandedSubBlockEnd.gif}

102InBlock.gifthis.contextKeyMgr.DisposeAllContextKey();
103ExpandedSubBlockEnd.gif}

104ExpandedSubBlockEnd.gif#endregion

105InBlock.gif
106ExpandedSubBlockEnd.gif#endregion

107InBlock.gif
108ContractedSubBlock.gifExpandedSubBlockStart.gifITcpEventList成员#regionITcpEventList成员
109InBlock.gif
110InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUser2SomeOneConnected;
111InBlock.gif
112InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpMonitorServiceCommitted;
113InBlock.gif
114InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpCountConnectionCountChanged;
115InBlock.gif
116InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUser1SomeOneDisConnected;
117InBlock.gif
118InBlock.gifpubliceventEnterpriseServerBase.Network.CallBackForTcpUserUserAction;
119InBlock.gif
120ExpandedSubBlockEnd.gif#endregion

121InBlock.gif
122ContractedSubBlock.gifExpandedSubBlockStart.gifITcpClientsController成员#regionITcpClientsController成员
123InBlock.gif
124InBlock.gifpublicboolSynRecieveFrom(intConnectID,byte[]buffer,intoffset,intsize,outintreadCount)
125ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
126InBlock.gifreadCount=0;
127InBlock.gifISafeNetworkStreamnetStream=this.contextKeyMgr.GetNetStream(ConnectID);
128InBlock.gifif(netStream==null)
129ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
130InBlock.gifreturnfalse;
131ExpandedSubBlockEnd.gif}

132InBlock.gif
133InBlock.gifreadCount=netStream.Read(buffer,offset,size);
134InBlock.gif
135InBlock.gifreturntrue;
136ExpandedSubBlockEnd.gif}

137InBlock.gif
138InBlock.gifpublicvoidSendData(intConnectID,byte[]data)
139ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
140InBlock.gifthis.SendData(ConnectID,data,0,data.Length);
141ExpandedSubBlockEnd.gif}

142InBlock.gif
143InBlock.gifpublicvoidSendData(intConnectID,byte[]data,intoffset,intsize)
144ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
145InBlock.gifif((data==null)||(data.Length==0)||(offset<0)||(size<0)||(offset+size>data.Length))
146ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
147InBlock.gifreturn;
148ExpandedSubBlockEnd.gif}

149InBlock.gif
150InBlock.gifISafeNetworkStreamnetStream=this.contextKeyMgr.GetNetStream(ConnectID);
151InBlock.gifif(netStream==null)
152ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
153InBlock.gifreturn;
154ExpandedSubBlockEnd.gif}

155InBlock.gif
156InBlock.gifnetStream.Write(data,offset,size);
157ExpandedSubBlockEnd.gif}

158InBlock.gif
159InBlock.gifpublicvoidDisposeOneConnection(intconnectID,DisconnectedCausecause)
160ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
161InBlock.gifthis.DisposeOneConnection(connectID);
162InBlock.gif
163InBlock.gifif(this.SomeOneDisConnected!=null)
164ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
165InBlock.gifthis.SomeOneDisConnected(connectID,cause);
166ExpandedSubBlockEnd.gif}

167InBlock.gif
168InBlock.gifthis.ActivateUserActionEvent(connectID,TcpUserAction.Exit);
169ExpandedSubBlockEnd.gif}

170InBlock.gif
171ExpandedSubBlockEnd.gif#endregion

172InBlock.gif
173ContractedSubBlock.gifExpandedSubBlockStart.gifITcp成员#regionITcp成员
174InBlock.gifpublicintConnectionCount
175ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
176InBlock.gifget
177ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
178InBlock.gifreturnthis.contextKeyMgr.ConnectionCount;
179ExpandedSubBlockEnd.gif}

180ExpandedSubBlockEnd.gif}

181InBlock.gif
182ExpandedSubBlockEnd.gif#endregion

183InBlock.gif
184ContractedSubBlock.gifExpandedSubBlockStart.gifprivate#regionprivate
185InBlock.gif
186ContractedSubBlock.gifExpandedSubBlockStart.gifActivateUserActionEvent#regionActivateUserActionEvent
187InBlock.gifprivatevoidActivateUserActionEvent(intConnectID,TcpUserActionaction)
188ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
189InBlock.gifif(this.UserAction!=null)
190ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
191InBlock.gifthis.UserAction(ConnectID,action);
192ExpandedSubBlockEnd.gif}

193ExpandedSubBlockEnd.gif}

194ExpandedSubBlockEnd.gif#endregion

195InBlock.gif
196ContractedSubBlock.gifExpandedSubBlockStart.gifDisposeOneConnection#regionDisposeOneConnection
197ExpandedSubBlockStart.gifContractedSubBlock.gif/**////<summary>
198InBlock.gif///DisposeOneConnection主要由用户管理模块调用--当无法检测到掉线情况时,该方法保证资源被释放
199ExpandedSubBlockEnd.gif///</summary>

200InBlock.gifprivatevoidDisposeOneConnection(intconnectID)
201ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
202InBlock.gifthis.contextKeyMgr.RemoveContextKey(connectID);
203ExpandedSubBlockEnd.gif}

204ExpandedSubBlockEnd.gif#endregion

205InBlock.gif
206ContractedSubBlock.gifExpandedSubBlockStart.gifxtcpListener_TcpConnectionEstablished#regionxtcpListener_TcpConnectionEstablished
207InBlock.gifprivatevoidxtcpListener_TcpConnectionEstablished(NetworkStreamstream)
208ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
209InBlock.gifISafeNetworkStreamsafeStream=newSafeNetworkStream(stream);
210InBlock.gif
211InBlock.gifContextKeykey=newContextKey(safeStream,AsynTcp.BufferSize);
212InBlock.gifkey.ResetBuffer(null);
213InBlock.gifthis.contextKeyMgr.InsertContextKey(key);
214InBlock.gifintconnectID=key.NetStream.GetHashCode();
215InBlock.gif
216InBlock.gifif(this.SomeOneConnected!=null)
217ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
218InBlock.gifthis.SomeOneConnected(connectID);
219ExpandedSubBlockEnd.gif}

220InBlock.gifthis.ActivateUserActionEvent(connectID,TcpUserAction.Logon);
221InBlock.gif
222InBlock.gifkey.IsFirstMsg=true;
223InBlock.gifthis.RecieveDataFrom(key);
224ExpandedSubBlockEnd.gif}

225ExpandedSubBlockEnd.gif#endregion

226InBlock.gif
227ContractedSubBlock.gifExpandedSubBlockStart.gifPutoutDynamicMsg#regionPutoutDynamicMsg
228InBlock.gifprivatevoidPutoutDynamicMsg(stringmsg)
229ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
230InBlock.gifif(this.DynamicMsgArrived!=null)
231ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
232InBlock.gifthis.DynamicMsgArrived(msg);
233ExpandedSubBlockEnd.gif}

234ExpandedSubBlockEnd.gif}

235ExpandedSubBlockEnd.gif#endregion

236InBlock.gif
237ContractedSubBlock.gifExpandedSubBlockStart.gifOnStreamCountChanged#regionOnStreamCountChanged
238InBlock.gifprivatevoidOnStreamCountChanged(intcount)
239ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
240InBlock.gifif(this.ConnectionCountChanged!=null)
241ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
242InBlock.gifthis.ConnectionCountChanged(count);
243ExpandedSubBlockEnd.gif}

244ExpandedSubBlockEnd.gif}

245ExpandedSubBlockEnd.gif#endregion

246InBlock.gif
247ContractedSubBlock.gifExpandedSubBlockStart.gifRecieveDataFrom#regionRecieveDataFrom
248InBlock.gifprivatevoidRecieveDataFrom(ContextKeykey)
249ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
250InBlock.gifkey.StreamState=NetStreamState.Reading;
251InBlock.gifkey.NetStream.BeginRead(key.Buffer,key.StartOffsetForRecieve,key.MaxRecieveCapacity,newAsyncCallback(this.ServeOverLap),key);
252InBlock.gif
253ExpandedSubBlockEnd.gif}

254ExpandedSubBlockEnd.gif#endregion

255InBlock.gif
256ContractedSubBlock.gifExpandedSubBlockStart.gifServeOverLap#regionServeOverLap
257InBlock.gifprivatevoidServeOverLap(IAsyncResultar)
258ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
259InBlock.gifContextKeykey=(ContextKey)ar.AsyncState;
260InBlock.gifintstreamHashCode=key.NetStream.GetHashCode();//是SafeNetworkStream的hashcode
261InBlock.gif
262InBlock.giftry
263ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
264InBlock.gifkey.BytesRead=key.NetStream.EndRead(ar);
265InBlock.gif
266InBlock.gifif(!this.CheckData(key))
267ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
268InBlock.gifreturn;
269ExpandedSubBlockEnd.gif}

270InBlock.gif
271InBlock.gif//处理请求
272InBlock.gifbyte[]leftData=null;
273InBlock.gifArrayListrepondList=this.messageDispatcher.DealRequestMessage(key.RequestData,outleftData,refkey.Validation);
274InBlock.gif
275InBlock.gifif(this.validateRequest)
276ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
277InBlock.gifif(key.Validation.gotoCloseConnection)
278ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
279InBlock.gifthis.DisposeOneConnection(streamHashCode,key.Validation.cause);
280ExpandedSubBlockEnd.gif}

281ExpandedSubBlockEnd.gif}

282InBlock.gif
283InBlock.gifkey.StreamState=NetStreamState.Writing;
284InBlock.gifif(repondList!=null&&(repondList.Count!=0))
285ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
286InBlock.gifforeach(objectobjinrepondList)
287ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
288InBlock.gifbyte[]respond_stream=(byte[])obj;
289InBlock.gifkey.NetStream.Write(respond_stream,0,respond_stream.Length);
290InBlock.gifif(this.ServiceCommitted!=null)
291ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
292InBlock.gifRespondInformationinfo=newRespondInformation();
293InBlock.gifinfo.ConnectID=streamHashCode;
294InBlock.gifinfo.ServiceKey=this.messageDispatcher.GetServiceKey(respond_stream);
295InBlock.gifinfo.repondData=respond_stream;
296InBlock.gifthis.ServiceCommitted(info);
297ExpandedSubBlockEnd.gif}

298InBlock.gif
299InBlock.gifthis.ActivateUserActionEvent(streamHashCode,TcpUserAction.FunctionAccess);
300ExpandedSubBlockEnd.gif}

301ExpandedSubBlockEnd.gif}

302InBlock.gif
303InBlock.gifif(key.IsFirstMsg)
304ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
305InBlock.gifif(repondList==null||(repondList.Count==0))//表示第一条消息还未接收完全
306ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
307InBlock.gifkey.IsFirstMsg=true;
308ExpandedSubBlockEnd.gif}

309InBlock.gifelse
310ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
311InBlock.gifkey.IsFirstMsg=false;
312ExpandedSubBlockEnd.gif}

313ExpandedSubBlockEnd.gif}

314InBlock.gif
315InBlock.gifkey.StreamState=NetStreamState.Idle;
316InBlock.gif
317InBlock.gifkey.ResetBuffer(leftData);
318InBlock.gif
319InBlock.gifif(!this.stateIsStop)
320ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
321InBlock.gif//继续接收请求
322InBlock.gifthis.RecieveDataFrom(key);
323ExpandedSubBlockEnd.gif}

324InBlock.gifelse//停止服务
325ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
326InBlock.gifthis.DisposeOneConnection(streamHashCode,DisconnectedCause.ServerStopped);
327ExpandedSubBlockEnd.gif}

328ExpandedSubBlockEnd.gif}

329InBlock.gifcatch(Exceptionee)
330ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
331InBlock.gifif(eeisSystem.IO.IOException)//正在读写流的时候,连接断开
332ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
333InBlock.gifthis.DisposeOneConnection(streamHashCode,DisconnectedCause.ServerStopped);
334ExpandedSubBlockEnd.gif}

335InBlock.gif
336InBlock.gifee=ee;
337ExpandedSubBlockEnd.gif}

338ExpandedSubBlockEnd.gif}

339ExpandedSubBlockEnd.gif#endregion

340InBlock.gif
341ContractedSubBlock.gifExpandedSubBlockStart.gifCheckData#regionCheckData
342InBlock.gifprivateboolCheckData(ContextKeykey)
343ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
344InBlock.gifintstreamHashcode=key.NetStream.GetHashCode();
345InBlock.gifif(this.stateIsStop)
346ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
347InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.ServerStopped);
348InBlock.gifreturnfalse;
349ExpandedSubBlockEnd.gif}

350InBlock.gif
351InBlock.gifif(key.BytesRead==0)//表示客户端掉线或非正常关闭连接
352ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
353InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.LineOff);
354InBlock.gifreturnfalse;
355ExpandedSubBlockEnd.gif}

356InBlock.gif
357InBlock.gifif(key.BytesRead==8)//表示客户端正常关闭连接
358ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
359InBlock.gifstringss=System.Text.Encoding.BigEndianUnicode.GetString(key.Buffer,0,8);
360InBlock.gifthis.DisposeOneConnection(streamHashcode,DisconnectedCause.LineOff);
361InBlock.gifreturnfalse;
362ExpandedSubBlockEnd.gif}

363InBlock.gif
364InBlock.gifreturntrue;
365ExpandedSubBlockEnd.gif}

366ExpandedSubBlockEnd.gif#endregion

367ExpandedSubBlockEnd.gif#endregion

368InBlock.gif
369ContractedSubBlock.gifExpandedSubBlockStart.gifINet成员#regionINet成员
370InBlock.gif
371InBlock.gifpublicIReqestStreamDispatcherDispatcher
372ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
373InBlock.gifset
374ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
375InBlock.gifthis.messageDispatcher=(ITcpReqStreamDispatcher)value;
376ExpandedSubBlockEnd.gif}

377ExpandedSubBlockEnd.gif}

378InBlock.gif
379InBlock.gifpublicintPort
380ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
381InBlock.gifset
382ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
383InBlock.gifthis.curPort=value;
384ExpandedSubBlockEnd.gif}

385InBlock.gifget
386ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
387InBlock.gifreturnthis.curPort;
388ExpandedSubBlockEnd.gif}

389ExpandedSubBlockEnd.gif}

390InBlock.gif
391InBlock.gifpublicboolUserValidated
392ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
393InBlock.gifset
394ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
395InBlock.gifthis.validateRequest=value;
396ExpandedSubBlockEnd.gif}

397ExpandedSubBlockEnd.gif}

398InBlock.gif
399ExpandedSubBlockEnd.gif#endregion

400ExpandedBlockEnd.gif}


今天介绍了Tcp通信层中的核心――Tcp组件,仅仅复用Tcp组件已经能为我们省去很多麻烦了,如果想进行更高层次的复用――整个Tcp通信层的复用,请关注本篇的续文。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
.net 稳定 高效 易用 可同步 TCP 通信框架 使用平台: WinXP,WIN7,WIN8,WINCE,WINPHONE。 使用.net 2.0 框架。 主要功能介绍: 1、可以代替 Oracle,Mysql客户端 在不安装Oracle,MySql客户端的情况下访问, 对数据库进行间接访问(需开始框架的服务器端)。 2、可以使本来没有网经功能的Sqlite具有网络访问的能力。(也是需要开启服务器端) 以上两点可以兼容现有代码生成器时,客户端代码仅需要特别小的改动就可以。 3、基本功能。可以实现聊天,传文件,图片。 4、使用长连接,有断线自动连接功能,心跳包。 5、使用自定义数据包协议,自建Session机制加强数据连接安全。 6、框架稳定,支持高并发。 7、简单的事件处理机制。使用更加简单。 8、支持同步处理,使程序的开发更架简单,不需要另行回调处理。 下载地址: 使用方式: 首选需要 引用 DataUtils.v1.1.dll。DataUtils 内包含客户端与服务器端 处理类。 1、服务器端 代码示例。 设置服务器端默认端口 ,不设置端口会使用默认端口 TcpSettings.DefultPort = 8511; 既可以使用静态默认对象,也可以创建服务器端对象。 SocketListener server= new SocketListener(); 对象创建后 注册一些事件,以接收客户端发送的信息。 SocketListener.Server.RegeditSession += new Feng.Net.Tcp.SocketListener.RegeditSessionEventHandler(server_RegeditSession); RegeditSession 事件用于是否允许客户端连接此服务器。可以使用用户名,密码的核对方式。 SocketListener.Server.DataReceive += new SocketListener.DataReceiveEventHandler(server_DataReceive); DataReceive 在这个事件里处理接收到的数据。 事件注册完成就可以打开监听 SocketListener.Server.StartListening(); 2、客户端 代码示例 设置服务器的IP地址 TcpSettings.DeafultIPAddress = "192.168.1.3"; TcpSettings.DefultPort = 8511;//不设置端口会使用默认端口。 这样就可以使用默认的静态客户端了。 也可以自己创建对象。 客户端创建后需要在Connected事件注册用户,以限制某些用户是否可以使此链接。用户来源可以是数据库等。 void client_Connected(object sender, SocketClient sh) { Client.RegeditSession("aaa", "bbb"); } 发送文字消息给其他用户 SocketClient.Client.SendToOtherUser(string user, string text); //USER代表发达的目白用户,text表示为发送的内容。 发送图片,音频,视屏可以使用 SocketClient..SendToOtherUser(string user, byte[] data)////USER代表发达的目白用户,data表示为发送的内容。 data数据中数据有多种类型时可以使用 using (Feng.IO.BufferWriter bw = new Feng.IO.BufferWriter()) { bw.WriteBitmap(new Bitmap(100, 100)); bw.Write(text);
非常好用的C#.netTCP控件,this.vmTcpIpServer1.Collapse = false; this.vmTcpIpServer1.EnableLog = false; this.vmTcpIpServer1.IdleTime = -1; this.vmTcpIpServer1.LocalUsingIpAddr = "127.0.0.1"; this.vmTcpIpServer1.Location = new System.Drawing.Point(9, 17); this.vmTcpIpServer1.LogFilePath = "D:\\AppLog"; this.vmTcpIpServer1.MaxLogShownLines = 30; this.vmTcpIpServer1.Name = "vmTcpIpServer1"; this.vmTcpIpServer1.PackageHeader = UNYC.TcpIp.PackageHeader.None; this.vmTcpIpServer1.PackageTailer = UNYC.TcpIp.PackageTailer.None; this.vmTcpIpServer1.PortNum = 30000; this.vmTcpIpServer1.SaveToLogFile = false; this.vmTcpIpServer1.ShowTransContents = false; this.vmTcpIpServer1.Size = new System.Drawing.Size(266, 405); this.vmTcpIpServer1.TabIndex = 0; // // vmTcpIpClient1 // this.vmTcpIpClient1.AutoRecover = false; this.vmTcpIpClient1.Collapse = false; this.vmTcpIpClient1.ConnRetries = -1; this.vmTcpIpClient1.EnableLog = false; this.vmTcpIpClient1.IdleTime = -1; this.vmTcpIpClient1.IpAddr = "192.168.100.231"; this.vmTcpIpClient1.Location = new System.Drawing.Point(311, 17); this.vmTcpIpClient1.LogFilePath = "D:\\AppLog"; this.vmTcpIpClient1.MaxLogShownLines = 100; this.vmTcpIpClient1.Name = "vmTcpIpClient1"; this.vmTcpIpClient1.PackageHeader = UNYC.TcpIp.PackageHeader.None; this.vmTcpIpClient1.PackageTailer = UNYC.TcpIp.PackageTailer.None; this.vmTcpIpClient1.PingInterval = 500; this.vmTcpIpClient1.PortNum = 912815; this.vmTcpIpClient1.SaveToLogFile = false; this.vmTcpIpClient1.ShowTransContents = false; this.vmTcpIpClient1.Size = new System.Drawing.Size(266, 405);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值