基于TCP异步Socket模型的介绍

TCP异步Socket模型
C#的TCP异步Socket模型是通过Begin-End模式实现的。例如提供BeginConnect、BeginAccept、 BeginSend 和 BeginReceive等。


代码如下:

IAsyncResult BeginAccept(AsyncCallback callback, object state);

AsyncCallback回调在函数执行完毕后执行。state对象被用于在执行函数和回调函数间传输信息。


代码如下:

Socket socket = new Socket(
                  AddressFamily.InterNetwork,
                  SocketType.Stream,
                  ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 8888);
socket.Bind(iep);
socket.Listen(5);
socket.BeginAccept (new AsyncCallback(CallbackAccept), socket);

private void CallbackAccept(IAsyncResult iar)
{
  Socket server = (Socket)iar.AsyncState;
  Socket client = server.EndAccept(iar);
}

则在Accept一个TcpClient,需要维护TcpClient列表。


代码如下:

private List<TcpClientState> clients;

异步TCP服务器完整实现


代码如下:

/// <summary>
   /// 异步TCP服务器
   /// </summary>
   public class AsyncTcpServer : IDisposable
   {
     #region Fields

private TcpListener listener;
     private List<TcpClientState> clients;
     private bool disposed = false;

#endregion

#region Ctors

/// <summary>
     /// 异步TCP服务器
     /// </summary>
     /// <param name="listenPort">监听的端口</param>
     public AsyncTcpServer(int listenPort)
       : this(IPAddress.Any, listenPort)
     {
     }

/// <summary>
     /// 异步TCP服务器
     /// </summary>
     /// <param name="localEP">监听的终结点</param>
     public AsyncTcpServer(IPEndPoint localEP)
       : this(localEP.Address, localEP.Port)
     {
     }

/// <summary>
     /// 异步TCP服务器
     /// </summary>
     /// <param name="localIPAddress">监听的IP地址</param>
     /// <param name="listenPort">监听的端口</param>
     public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
     {
       Address = localIPAddress;
       Port = listenPort;
       this.Encoding = Encoding.Default;

clients = new List<TcpClientState>();

listener = new TcpListener(Address, Port);
       listener.AllowNatTraversal(true);
     }

#endregion

#region Properties

/// <summary>
     /// 服务器是否正在运行
     /// </summary>
     public bool IsRunning { get; private set; }
     /// <summary>
     /// 监听的IP地址
     /// </summary>
     public IPAddress Address { get; private set; }
     /// <summary>
     /// 监听的端口
     /// </summary>
     public int Port { get; private set; }
     /// <summary>
     /// 通信使用的编码
     /// </summary>
     public Encoding Encoding { get; set; }

#endregion

#region Server

/// <summary>
     /// 启动服务器
     /// </summary>
     /// <returns>异步TCP服务器</returns>
     public AsyncTcpServer Start()
     {
       if (!IsRunning)
       {
         IsRunning = true;
         listener.Start();
         listener.BeginAcceptTcpClient(
           new AsyncCallback(HandleTcpClientAccepted), listener);
       }
       return this;
     }

/// <summary>
     /// 启动服务器
     /// </summary>
     /// <param name="backlog">
     /// 服务器所允许的挂起连接序列的最大长度
     /// </param>
     /// <returns>异步TCP服务器</returns>
     public AsyncTcpServer Start(int backlog)
     {
       if (!IsRunning)
       {
         IsRunning = true;
         listener.Start(backlog);
         listener.BeginAcceptTcpClient(
           new AsyncCallback(HandleTcpClientAccepted), listener);
       }
       return this;
     }

/// <summary>
     /// 停止服务器
     /// </summary>
     /// <returns>异步TCP服务器</returns>
     public AsyncTcpServer Stop()
     {
       if (IsRunning)
       {
         IsRunning = false;
         listener.Stop();

lock (this.clients)
         {
           for (int i = 0; i < this.clients.Count; i++)
           {
             this.clients[i].TcpClient.Client.Disconnect(false);
           }
           this.clients.Clear();
         }

}
       return this;
     }

#endregion

#region Receive

private void HandleTcpClientAccepted(IAsyncResult ar)
     {
       if (IsRunning)
       {
         TcpListener tcpListener = (TcpListener)ar.AsyncState;

TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
         byte[] buffer = new byte[tcpClient.ReceiveBufferSize];

TcpClientState internalClient
           = new TcpClientState(tcpClient, buffer);
         lock (this.clients)
         {
           this.clients.Add(internalClient);
           RaiseClientConnected(tcpClient);
         }

NetworkStream networkStream = internalClient.NetworkStream;
         networkStream.BeginRead(
           internalClient.Buffer,
           0,
           internalClient.Buffer.Length,
           HandleDatagramReceived,
           internalClient);

tcpListener.BeginAcceptTcpClient(
           new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
       }
     }

private void HandleDatagramReceived(IAsyncResult ar)
     {
       if (IsRunning)
       {
         TcpClientState internalClient = (TcpClientState)ar.AsyncState;
         NetworkStream networkStream = internalClient.NetworkStream;

int numberOfReadBytes = 0;
         try
         {
           numberOfReadBytes = networkStream.EndRead(ar);
         }
         catch
         {
           numberOfReadBytes = 0;
         }

if (numberOfReadBytes == 0)
         {
           // connection has been closed
           lock (this.clients)
           {
             this.clients.Remove(internalClient);
             RaiseClientDisconnected(internalClient.TcpClient);
             return;
           }
         }

// received byte and trigger event notification
         byte[] receivedBytes = new byte[numberOfReadBytes];
         Buffer.BlockCopy(
           internalClient.Buffer, 0,
           receivedBytes, 0, numberOfReadBytes);
         RaiseDatagramReceived(internalClient.TcpClient, receivedBytes);
         RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);

// continue listening for tcp datagram packets
         networkStream.BeginRead(
           internalClient.Buffer,
           0,
           internalClient.Buffer.Length,
           HandleDatagramReceived,
           internalClient);
       }
     }

#endregion

#region Events

/// <summary>
     /// 接收到数据报文事件
     /// </summary>
     public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
     /// <summary>
     /// 接收到数据报文明文事件
     /// </summary>
     public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;

private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)
     {
       if (DatagramReceived != null)
       {
         DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
       }
     }

private void RaisePlaintextReceived(TcpClient sender, byte[] datagram)
     {
       if (PlaintextReceived != null)
       {
         PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(
           sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
       }
     }

/// <summary>
     /// 与客户端的连接已建立事件
     /// </summary>
     public event EventHandler<TcpClientConnectedEventArgs> ClientConnected;
     /// <summary>
     /// 与客户端的连接已断开事件
     /// </summary>
     public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected;

private void RaiseClientConnected(TcpClient tcpClient)
     {
       if (ClientConnected != null)
       {
         ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient));
       }
     }

private void RaiseClientDisconnected(TcpClient tcpClient)
     {
       if (ClientDisconnected != null)
       {
         ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient));
       }
     }

#endregion

#region Send

/// <summary>
     /// 发送报文至指定的客户端
     /// </summary>
     /// <param name="tcpClient">客户端</param>
     /// <param name="datagram">报文</param>
     public void Send(TcpClient tcpClient, byte[] datagram)
     {
       if (!IsRunning)
         throw new InvalidProgramException("This TCP server has not been started.");

if (tcpClient == null)
         throw new ArgumentNullException("tcpClient");

if (datagram == null)
         throw new ArgumentNullException("datagram");

tcpClient.GetStream().BeginWrite(
         datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);
     }

private void HandleDatagramWritten(IAsyncResult ar)
     {
       ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
     }

/// <summary>
     /// 发送报文至指定的客户端
     /// </summary>
     /// <param name="tcpClient">客户端</param>
     /// <param name="datagram">报文</param>
     public void Send(TcpClient tcpClient, string datagram)
     {
       Send(tcpClient, this.Encoding.GetBytes(datagram));
     }

/// <summary>
     /// 发送报文至所有客户端
     /// </summary>
     /// <param name="datagram">报文</param>
     public void SendAll(byte[] datagram)
     {
       if (!IsRunning)
         throw new InvalidProgramException("This TCP server has not been started.");

for (int i = 0; i < this.clients.Count; i++)
       {
         Send(this.clients[i].TcpClient, datagram);
       }
     }

/// <summary>
     /// 发送报文至所有客户端
     /// </summary>
     /// <param name="datagram">报文</param>
     public void SendAll(string datagram)
     {
       if (!IsRunning)
         throw new InvalidProgramException("This TCP server has not been started.");

SendAll(this.Encoding.GetBytes(datagram));
     }

#endregion

#region IDisposable Members

/// <summary>
     /// Performs application-defined tasks associated with freeing,
     /// releasing, or resetting unmanaged resources.
     /// </summary>
     public void Dispose()
     {
       Dispose(true);
       GC.SuppressFinalize(this);
     }

/// <summary>
     /// Releases unmanaged and - optionally - managed resources
     /// </summary>
     /// <param name="disposing"><c>true</c> to release
     /// both managed and unmanaged resources; <c>false</c>
     /// to release only unmanaged resources.</param>
     protected virtual void Dispose(bool disposing)
     {
       if (!this.disposed)
       {
         if (disposing)
         {
           try
           {
             Stop();

if (listener != null)
             {
               listener = null;
             }
           }
           catch (SocketException ex)
           {
             ExceptionHandler.Handle(ex);
           }
         }

disposed = true;
       }
     }

#endregion
   }

使用举例


代码如下:

class Program
   {
     static AsyncTcpServer server;

static void Main(string[] args)
     {
       LogFactory.Assign(new ConsoleLogFactory());

server = new AsyncTcpServer(9999);
       server.Encoding = Encoding.UTF8;
       server.ClientConnected +=
         new EventHandler<TcpClientConnectedEventArgs>(server_ClientConnected);
       server.ClientDisconnected +=
         new EventHandler<TcpClientDisconnectedEventArgs>(server_ClientDisconnected);
       server.PlaintextReceived +=
         new EventHandler<TcpDatagramReceivedEventArgs<string>>(server_PlaintextReceived);
       server.Start();

Console.WriteLine("TCP server has been started.");
       Console.WriteLine("Type something to send to client...");
       while (true)
       {
         string text = Console.ReadLine();
         server.SendAll(text);
       }
     }

static void server_ClientConnected(object sender, TcpClientConnectedEventArgs e)
     {
       Logger.Debug(string.Format(CultureInfo.InvariantCulture,
         "TCP client {0} has connected.",
         e.TcpClient.Client.RemoteEndPoint.ToString()));
     }

static void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
     {
       Logger.Debug(string.Format(CultureInfo.InvariantCulture,
         "TCP client {0} has disconnected.",
         e.TcpClient.Client.RemoteEndPoint.ToString()));
     }

static void server_PlaintextReceived(object sender, TcpDatagramReceivedEventArgs<string> e)
     {
       if (e.Datagram != "Received")
       {
         Console.Write(string.Format("Client : {0} --> ",
           e.TcpClient.Client.RemoteEndPoint.ToString()));
         Console.WriteLine(string.Format("{0}", e.Datagram));
         server.Send(e.TcpClient, "Server has received you text : " + e.Datagram);
       }
     }
   }

(0)

相关推荐

  • TCP Wrappers防火墙介绍与封锁IP地址的方法

    Tcp_Wrappers是一个用来分析TCP/IP封包的软件,类似的IP封包软件还有iptables,linux默认都安装了此软件,作为一个安全的系统,Linux本身有两层安全防火墙,通过IP过滤机制的iptables实现第一层防护,iptables防火墙通过直观地监视系统的运行状况,阻挡网络中的一些恶意攻击,保护整个系统正常运行,免遭攻击和破坏.如果通过了第一层防护,那么下一层防护就是tcp_wrappers了,通过Tcp_Wrappers可以实现对系统中提供的某些服务的开放与关闭.允许和禁止

  • TCP关闭问题详细介绍

    摘要: 三次握手,四次挥手 意思是tcp建立连接时需要三次交互来完成,A发起连接 A --- SYN --> B A <-- SYN + ACK --- B (1) A --- ACK --> B 而关闭tcp连接需要四次交互,A发起关闭 A --- FIN --> B A <-- ACK --- B (1) A <-- FIN --- B A --- ACK --> B (2) 这里在(1)时B开始处于CLOSE_WAIT状态,一直到收到ACK后B才转为CLOS

  • TCP/IP 中的二进制反码求和算法

    以4bit(计算方便一点,和16bit是一样的)做检验和来验证. 建设原始数据为 1100 , 1010 , 0000(校验位) 那么把他们按照4bit一组进行按位取反相加. 1100取反0011 , 1010取反是0101,0011加上0101 是1000,填入到校验位后 1100 , 1010 , 1000 那么这个就是要发送的数据.收到数据后同样进行按位取反相加.0011+0101+0111 =1111:全为1表示正确 另外注意,当地一步计算校验和的时候,有可能相加后最高位会有进位,那么不

  • TCPIP是什么

    TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的.它是由ARPANET网的研究机构发展起来的.有时我们将TCP/IP描述为互联网协议集"Internet Protocol Suite",TCP和IP是其中的两个协议(后面将会介绍).由于TCP和IP是大家熟悉的协议,以至于用TCP/IP或IP/TCP这个词代替了整个协议集.这尽管有点奇怪,但没有必

  • TCP版backshell的VBS脚本代码

    '搞一个特殊的站准备用的,没想到,等写完了,洞补上了,郁闷 'by 009, baicker@hotmail.com 'date:071221 Dim revdata set sock=WScript.createobject( "MSWinsock.Winsock" , "WSEvent_" ) set sc=createobject( "WScript.Shell" ) Set fso =CreateObject( "Scripti

  • 使用批处理重置TCP_IP协议

    在XP系统的ghost xp网络组件列表里,有一个Internet 协议,Internet 协议又称为TCP或IP,该"卸载"按钮显示是灰色--不可选状态,如果在特殊情况下我们需要重新安装TCP/IP协议可以通过下面的批处理来完成 复制代码 代码如下: @echo off echo. echo 即将重置 TCP/IP 协议.重置可能会导致网络程序工作异常. echo 只有在 TCP/IP 被破坏导致不能上网时才建议尝试本重置操作. echo. echo 任意键开始重置 TCP/IP,C

  • tcp、udp、ip协议分析_动力节点Java学院整理

    互连网早期的时候,主机间的互连使用的是NCP协议.这种协议本身有很多缺陷,如:不能互连不同的主机,不能互连不同的操作系统,没有纠错功能.为了改善这种缺点,大牛弄出了TCP/IP协议.现在几乎所有的操作系统都实现了TCP/IP协议栈. TCP/IP协议栈主要分为四层:应用层.传输层.网络层.数据链路层,每层都有相应的协议,如下图 所谓的协议就是双方进行数据传输的一种格式.整个网络中使用的协议有很多,所幸的是每一种协议都有RFC文档.在这里只对IP.TCP.UDP协议头做一个分析. 首先来看看在网络

  • TCP三次握手及原理

    TCP/IP是很多的不同的协议组成,实际上是一个协议组,TCP用户数据报表协议(也称作TCP传输控制协议,Transport Control Protocol.可靠的主机到主机层协议.这里要先强调一下,传输控制协议是OSI网络的第四层的叫法,TCP传输控制协议是TCP/IP传输的6个基本协议的一种.两个TCP意思非相同. ).TCP是一种可靠的面向连接的传送服务.它在传送数据时是分段进行的,主机交换数据必须建立一个会话.它用比特流通信,即数据被作为无结构的字节流. 通过每个TCP传输的字段指定顺

  • 常用类之TCP连接类-socket编程

    tcp一般用于维持一个可信任的连接,比起udp更为安全可靠,在vs.net,分别有tcpclient和udpclient以及tcplistener,一般开发中基本可以满足需要,但是这个有个很大的弊端,对于维持一个时间较长的,相互交互的来说,数据处理不是很明朗,vs/net中还有一个socket类,用他来做一个客户/服务器段,同时在接发数据的时候,能相互独立,这需要一个异步通讯过程 先实现服务器段: using System; using System.Net; using System.Net.

  • tcp socket客户端和服务端示例分享

    以下是tcp socket客户端和服务端源码,代码简单大家参考使用吧 Tcp Server 复制代码 代码如下: #include <WinSock2.h>#include <stdio.h>#pragma comment(lib, "ws2_32.lib")int main(){// initial socket libraryWORD wVerisonRequested;WSADATA wsaData;int err;wVerisonRequested =

随机推荐