异步实现Socket Server&Client
作者:C/S框架网  发布日期:2011/06/16 22:55:57
异步实现Socket Server&Client


异步实现Socket Server&Client

贴图图片

Introduction

I’ve been working with sockets since 2000, using Delphi 5.0 and some third-party libraries (Synapse). My very first socket application just copied files between many clients and one server. The client app checks a folder to see if files exist, asks the server where to copy the files in the network and, after copying the files, flags the database record indicating that a file has been moved. The server listens to the client connections, and both exchange XML messages indicating the state of each file copy. Synapse is a blocking socket implementation, and I needed a thread pooling mechanism that works like an HTTP server, because I couldn’t keep the connection open (one thread per connection). My solution was to use some IOCP functions to pool the client requests (code) and close the connection after the message exchange was terminated.

Now, using C#, I decided to write a socket server and client library that helps me to only have to think about the message exchange (the process) and let .NET do the hard job. So, I needed the following features:

  • Asynchronous processing
  • Some encryption and compression capabilities
  • Encapsulate the socket, and encrypt the services in the interfaces and separate them from the host implementation

介绍 Introduction

我从2000年就开始使用Delphi5.0套接字编程,并使用一些第3方控件库如(Synapse). 我编写的第一个套接字应用程序是基于一个服务端和多个客户端之间的文件复制. 当开始复制文件时客户端程序需要检查文件存在,如果存在则反馈信息给服务端确认. 复制完成后在数据库对应的记录上打上标记, 标志该文件已经移动到客户端。服务端监听客户连接状态,两端通过交换XML文件来跟踪每个文件的复制情况。Synapse是通过阻塞套接字实现,我需要一个像HTTP服务器线程池的机制,因为我不能保持每个连接线程的Open状态.我的解决方案是在信息交换终止后使用IOCP功能建立客户端请求(代码)和关闭连接池.

注: IOCP全称I/O Completion Port,中文译为I/O完成端口。IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。

现在, 我决定用C#开发一个服务端与客户端基于套接字通讯的功能库, 我只关心信息交换相关工作,让.Net去完成那些艰巨的任务。

我需要设计以下功能:
1.异步处理
2.加密及压缩功能
3.在服务端,封装套接字及加密接口中的服务分开实现.

www.csframework.com

Socket Connection



The ISocketConnection is the base interface for the socket connections, and describes all the connection properties and the methods. The ConnectionID property defines a unique connection ID using a GUID string. The CustomData property defines a custom object that can be associated with the connection. The Header property is the socket service header used in each message that is encapsulated in a packet message. Only messages with a defined header will be accepted. The LocalEndPoint and RemoteEndPoint are the socket IP end points used in the connection. SocketHandle is the socket handle given by the OS.

The IClientSocketConnection and IServerSocketConnection inherit the ISocketConnection, and each one has special functions. The IClientSocketConnection can reconnect to the server using the BeginReconnect method, and the IServerSocketConnection can communicate with other connections in the server host using the BeginSendTo and BeginSendToAll methods, and can get the ConnectionId using the GetConnectionById method. Every connection knows the host, the encryption, the compression type, and can send, receive, and disconnect itself from the other part. This interface is used in the ISocketService interface to allow the user to interact with socket connections.


Socket Connection

原始接口IsocketConnection用于套接字连接,定义所有连接属性及方法。ConnectionID属性定义一个GUID连接编号. CustomData属性是一个用于连接传输的自定义对象. Header属性是封装在数据包头部用于套接字服务的信息.(Message:数据包或消息,服务端与客户端传输的内容). 只有定义特殊头部的消息才能被接受。LocalEndPoint和RemoteEndPoint用于记录套接字IP地址. SocketHandle是操作系统分配的句柄(Handle)

IClientSocketConnection和IServerSocketConnection接口继承ISocketConnection接口,它们分别定义特有的功能。IClientSocketConnection接口用BeginReconnect方法重新建立与服务器的连接。IServerSocketConnection接口使用BeginSendTo和BeginSendToAll方法与每一个已建立连接的客户端通讯, 可以通过GetConnectionById方法获取连接(ConnectionId)。每个连接知道主机的位置,加密方式,压缩类型及发送/接收和断线。此接口通过ISocketService接口允许用户之间互相通讯。


 


 

Internally, in the library implementation, all the connection interfaces are created using the base connection implementations: BaseSocketConnection, ClientSocketConnection, and ServerSocketConnection.


剖析类库内部实现,所有连线接口是使用原始接口实现:BaseSocketConnection,ClientSocketConnection和ServerSocketConnection。

Socket Service



The ISocketService describes the connection events. These events are fired by the host, and have a ConnectionEventArgs argument which has an ISocketConnection that identifies the connection. In the OnReceived and OnSent events, a MessageEventArgs is passed, which has the sent or received array of bytes. In the OnDisconnected event, a DisconnectedEventArgs is passed; the Exception property indicates if the disconnection has been caused by an exception.

Here is an example of a ISocketService implementation:


Socket Service

ISocketService接口定义一些连接事件。这些事件由主机引发,事件的ConnectionEventArgs参数记录一个标识连接的ISocketConnection接口。OnReceived 和 OnSent 事件传递一个MessageEventArgs参数,该参数记录传输的字节数组.OnDisconnected事件传递一个DisconnectedEventArgs 参数。Exception属性记录断线后引发的异常。

ISocketService接口实现:


 

public class SimpleEchoService : ISocketService
{
   public void OnConnected(ConnectionEventArgs e)
   {
      //----- Check the host!
      
      if (e.Connection.HostType == HostType.htServer)
      {
         //----- Enqueue receive!
         
         e.Connection.BeginReceive();
      }
      else
      {
         //----- Enqueue send a custom message!
         
         byte[] b =
         GetMessage(e.Connection.SocketHandle.ToInt32());
         e.Connection.BeginSend(b);
      }
   }
   
   public void OnSent(MessageEventArgs e)
   {
      //----- Check the host. In this case both start a receive!
      
      if (e.Connection.HostType == HostType.htServer)
      {
         //----- Enqueue receive!
         
         e.Connection.BeginReceive();
      }
      else
      {
         //----- Enqueue receive!
         
         e.Connection.BeginReceive();
      }
   }
   
   public override void OnReceived(MessageEventArgs e)
   {
      //----- Check the host!
      
      if (e.Connection.HostType == HostType.htServer)
      {
         //----- If server, send the data buffer received!
         
         byte[] b = e.Buffer;
         e.Connection.BeginSend(b);
      }
      else
      {
         //----- If client, generate another
         
         //----- custom message and send it!
         
         byte[] b = GetMessage(e.Connection.SocketHandle.ToInt32());
         e.Connection.BeginSend(b);
      }
   }
   
   public override void OnDisconnected(DisconnectedEventArgs e)
   {
      //----- Check the host!
      
      if (e.Connection.HostType == HostType.htServer)
      {
         //----- Nothing!
         
      }
      else
      {
         //----- Reconnect with server!
         
         e.Connection.AsClientConnection().BeginReconnect();
      }
   }
}


The ISocketService implementation can be done in the same host assembly, or another assembly referenced by the host. This allows the user to separate the host implementation from the socket service, helping the administration in a server or a domain.

Connection Host


With the ISocketService created, you need to host the service and the service connections. Both the server and the client host have the same parent class, BaseSocketConnectionHost, which keeps a list of connections, encrypts and compresses the data buffers, enqueues the service requests and ensures that all data buffer has been sent or received, checks messages headers, and checks for idle connections. The CheckTimeoutTimer, periodically, at IdleCheckInterval, checks if the connections become idle, using the IdleTimeOutValue as the idle timeout. Header is the socket service header used by the host. HostType indicates if a host is a server or a client host. SocketBufferSize defines the size of the socket send and receive buffer. SocketService is the instance of ISocketService that drives the message exchange between the connections.


Connection Host

创建ISocketService接口后需要管理服务和连接。服务端和客户端主机实现同一个父类BaseSocketConnectionHost, 该类实现这些功能:管理连线列表,加密和压缩数据,查询服务请求, 确保所有数据发送或接收,检查消息头部和空闲的连接。CheckTimeoutTimer: 定期检查连接超时,IdleCheckInterval: 检查空闲连接的时间间隔, IdleTimeOutValue: 闲置连接超时间隔。Header:套接字服务头部消息.
HostType标识主机是服务端还是客户端。SocketBufferSize:定义发送和接收的字节数大小.SocketService是实现ISocketService接口的类实例,用于管理和交换连线之间的消息。


Encrypt and Compress



Every time you send and receive messages, the host checks if the data must be encrypted and/or compressed, and this work is made by the CryptUtils static class. The CreateSymmetricAlgoritm creates an ISymmetricAlgoritm based on the encryptType parameter. The DecryptData and DecryptDataForAuthenticate are used, respectively, to decrypt the received message and check the hash sign on the authenticate procedure. The EncryptData and EncryptDataForAuthenticate, respectively, encrypt the data to be sent and sign the authenticated message.


Encrypt and Compress 加密及解压

在任何时间发送和接收消息,主机需要检查数据是否是加密或压缩的,由静态类CryptUtils完成. CreateSymmetricAlgoritm方法创建一
个实现ISymmetricAlgoritm接口的类的实例, 由encryptType参数指定加密类型.也使用了DecryptData
和DecryptDataForAuthenticate方法。分别是解密收到的消息和解密通过授权程序哈希签名的消息。EncryptData
和EncryptDataForAuthenticate分别是加密发送的数据和消息授权签名。





The encrypted data buffer is labelled with the service header and the data buffer length, becoming a packet buffer. This packet buffer is controlled by the MessageBuffer class that keeps information about the packet buffer offset, length, the remaining bytes, and the raw buffer.

加密后的数据标记了消息头部及数据长度因此变成了另一个数据包, 该数据包由MessageBuffer类控制,它的功能是保持缓冲区的偏移量,
长度,剩余字节及原始缓冲区信息.


Check Message Header

If the socket service uses some header, all the send and receive processes need to create a packet message indicating the header and the message length. This packet label is created using the following structure:


检查消息头部

如在传输中需要使用消息头部, 发送和接收时需要处理包的消息头部及消息长度,使用下面的结构创建包的标签。





SocketServer and SocketListener





SocketServer Constructor and Methods



In the SocketServer constructor, the socketService parameter defines the ISocketService instance used by the server. The header parameters define the array of bytes used in the message header exchange. The socketBufferSize adjusts the socket buffer size. The messageBufferSize defines the maximum message size of the service. The idleCheckInterval indicates the interval for idle connections checking, in milliseconds. The idleTimeoutValue defines the timeout, in milliseconds, to be compared to each connection LastAction property.

To add SocketListener items in SocketServer, the method AddListener must be used. The localEndPoint parameter defines the local socket IP endpoint used to listen to connections. The encryptType and compressionType defines, respectively, the encryption and compression methods used in the new accepted connection. The cryptoService defines the ICryptoService used to authenticate the encryption method chosen. The backLog limits the listen queue of the OS socket to the defined number, and acceptThreads sets the calling number of the socket’s BeginAccept to increase the accepted performance.





SocketClient and SocketConnector




The SocketClient and SocketConnector are the classes needed to create a socket client. SocketClient is derived from BaseSocketConnectionHost and, like SocketServer, manages ISocketConnections. The SocketConnector is derived from BaseSocketConnectionCreator, and it connects with the socket server and creates a new ISocketConnection to be used. A SocketClient can have as many SocketConnectors attached as required, each one connecting to a socket server, and they can be assigned to a local address and a local port to start the connection.

SocketClient Constructor and Methods




原文:
http://www.codeproject.com/KB/IP/AsyncSocketServerandClien.aspx

www.csframework.com
点击下载附件 点击下载附件 (如下载失败,请邮件通知我们寄回给您,或QQ:23404761留言.)
上一篇 下一篇