| | |
| | | |
| | | namespace TcpServer |
| | | { |
| | | public interface ProtoFilter |
| | | { |
| | | void input(byte[] data); |
| | | public interface ProtoFilter |
| | | { |
| | | void input(byte[] data); |
| | | |
| | | List<string> swap_msgs(); |
| | | } |
| | | List<string> swap_msgs(); |
| | | } |
| | | |
| | | public class SimpleProtocolFilter : ProtoFilter |
| | | { |
| | | /* 简单协议过滤器 |
| | | public class SimpleProtocolFilter : ProtoFilter |
| | | { |
| | | /* 简单协议过滤器 |
| | | 协议按照 [有效数据字节数][有效数据] 这种协议包的格式进行打包和解包 |
| | | [有效数据字节数]长度HEADER_SIZE字节 |
| | | [有效数据]长度有效数据字节数字节 |
| | |
| | | 所有编解码的操作在该类中完成 |
| | | */ |
| | | |
| | | private byte[] buf = new byte[0]; |
| | | private int HEADER_SIZE = 4; |
| | | private List<string> msgs = new List<string>(); |
| | | private byte[] buf = new byte[0]; |
| | | private int HEADER_SIZE = 4; |
| | | private List<string> msgs = new List<string>(); |
| | | |
| | | public void input(byte[] data) |
| | | { |
| | | buf = Combine(buf, data); |
| | | public void input(byte[] data) |
| | | { |
| | | buf = Combine(buf, data); |
| | | |
| | | while (buf.Length > HEADER_SIZE) |
| | | { |
| | | int data_size = BitConverter.ToInt32(buf, 0); |
| | | if (buf.Length >= data_size + HEADER_SIZE) |
| | | { |
| | | byte[] data_body = Slice(buf, HEADER_SIZE, data_size + HEADER_SIZE); |
| | | string content = System.Text.Encoding.Default.GetString(data_body); |
| | | msgs.Add(content); |
| | | buf = Slice(buf, data_size + HEADER_SIZE, buf.Length); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | while (buf.Length > HEADER_SIZE) |
| | | { |
| | | int data_size = BitConverter.ToInt32(buf, 0); |
| | | if (buf.Length >= data_size + HEADER_SIZE) |
| | | { |
| | | byte[] data_body = Slice(buf, HEADER_SIZE, data_size + HEADER_SIZE); |
| | | string content = System.Text.Encoding.Default.GetString(data_body); |
| | | msgs.Add(content); |
| | | buf = Slice(buf, data_size + HEADER_SIZE, buf.Length); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | public List<string> swap_msgs() |
| | | { |
| | | List<string> ret = msgs; |
| | | msgs = new List<string>(); |
| | | return ret; |
| | | } |
| | | public List<string> swap_msgs() |
| | | { |
| | | List<string> ret = msgs; |
| | | msgs = new List<string>(); |
| | | return ret; |
| | | } |
| | | |
| | | public byte[] pack(String content) |
| | | { |
| | | int len = content.Length; |
| | | byte[] size = BitConverter.GetBytes(len); |
| | | if (!BitConverter.IsLittleEndian) |
| | | { |
| | | //reverse it so we get little endian. |
| | | Array.Reverse(size); |
| | | } |
| | | byte[] body = System.Text.Encoding.Default.GetBytes(content); |
| | | byte[] ret = Combine(size, body); |
| | | return ret; |
| | | } |
| | | public byte[] pack(String content) |
| | | { |
| | | int len = content.Length; |
| | | byte[] size = BitConverter.GetBytes(len); |
| | | if (!BitConverter.IsLittleEndian) |
| | | { |
| | | //reverse it so we get little endian. |
| | | Array.Reverse(size); |
| | | } |
| | | byte[] body = System.Text.Encoding.Default.GetBytes(content); |
| | | byte[] ret = Combine(size, body); |
| | | return ret; |
| | | } |
| | | |
| | | private static byte[] Combine(byte[] first, byte[] second) |
| | | { |
| | | byte[] ret = new byte[first.Length + second.Length]; |
| | | Buffer.BlockCopy(first, 0, ret, 0, first.Length); |
| | | Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); |
| | | return ret; |
| | | } |
| | | private static byte[] Combine(byte[] first, byte[] second) |
| | | { |
| | | byte[] ret = new byte[first.Length + second.Length]; |
| | | Buffer.BlockCopy(first, 0, ret, 0, first.Length); |
| | | Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); |
| | | return ret; |
| | | } |
| | | |
| | | public byte[] Slice(byte[] source, int start, int end) |
| | | { |
| | | int length = end - start; |
| | | byte[] ret = new byte[length]; |
| | | Array.Copy(source, start, ret, 0, length); |
| | | return ret; |
| | | } |
| | | } |
| | | public byte[] Slice(byte[] source, int start, int end) |
| | | { |
| | | int length = end - start; |
| | | byte[] ret = new byte[length]; |
| | | Array.Copy(source, start, ret, 0, length); |
| | | return ret; |
| | | } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 异步TCP服务器 |
| | | /// </summary> |
| | | public class AsyncTcpServer : IDisposable |
| | | { |
| | | #region Fields |
| | | /// <summary> |
| | | /// 异步TCP服务器 |
| | | /// </summary> |
| | | public class AsyncTcpServer : IDisposable |
| | | { |
| | | #region Fields |
| | | |
| | | private TcpListener _listener; |
| | | private ConcurrentDictionary<string, TcpClientState> _clients; |
| | | private bool _disposed = false; |
| | | private TcpListener _listener; |
| | | private ConcurrentDictionary<string, TcpClientState> _clients; |
| | | private bool _disposed = false; |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Ctors |
| | | #region Ctors |
| | | |
| | | /// <summary> |
| | | /// 异步TCP服务器 |
| | | /// </summary> |
| | | /// <param name="listenPort">监听的端口</param> |
| | | public AsyncTcpServer(int listenPort) |
| | | : this(IPAddress.Any, listenPort) |
| | | { |
| | | } |
| | | /// <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="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) |
| | | { |
| | | this.Address = localIPAddress; |
| | | this.Port = listenPort; |
| | | this.Encoding = Encoding.Default; |
| | | /// <summary> |
| | | /// 异步TCP服务器 |
| | | /// </summary> |
| | | /// <param name="localIPAddress">监听的IP地址</param> |
| | | /// <param name="listenPort">监听的端口</param> |
| | | public AsyncTcpServer(IPAddress localIPAddress, int listenPort) |
| | | { |
| | | this.Address = localIPAddress; |
| | | this.Port = listenPort; |
| | | this.Encoding = Encoding.Default; |
| | | |
| | | _clients = new ConcurrentDictionary<string, TcpClientState>(); |
| | | _clients = new ConcurrentDictionary<string, TcpClientState>(); |
| | | |
| | | _listener = new TcpListener(Address, Port); |
| | | // _listener.AllowNatTraversal(true); |
| | | } |
| | | _listener = new TcpListener(Address, Port); |
| | | // _listener.AllowNatTraversal(true); |
| | | } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Properties |
| | | #region Properties |
| | | |
| | | /// <summary> |
| | | /// 服务器是否正在运行 |
| | | /// </summary> |
| | | public bool IsRunning { get; private set; } |
| | | /// <summary> |
| | | /// 服务器是否正在运行 |
| | | /// </summary> |
| | | public bool IsRunning { get; private set; } |
| | | |
| | | /// <summary> |
| | | /// 监听的IP地址 |
| | | /// </summary> |
| | | public IPAddress Address { get; private set; } |
| | | /// <summary> |
| | | /// 监听的IP地址 |
| | | /// </summary> |
| | | public IPAddress Address { get; private set; } |
| | | |
| | | /// <summary> |
| | | /// 监听的端口 |
| | | /// </summary> |
| | | public int Port { get; private set; } |
| | | /// <summary> |
| | | /// 监听的端口 |
| | | /// </summary> |
| | | public int Port { get; private set; } |
| | | |
| | | /// <summary> |
| | | /// 通信使用的编码 |
| | | /// </summary> |
| | | public Encoding Encoding { get; set; } |
| | | /// <summary> |
| | | /// 通信使用的编码 |
| | | /// </summary> |
| | | public Encoding Encoding { get; set; } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Server |
| | | #region Server |
| | | |
| | | /// <summary> |
| | | /// 启动服务器 |
| | | /// </summary> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Start() |
| | | { |
| | | Debug.Log("start server"); |
| | | return Start(10); |
| | | } |
| | | /// <summary> |
| | | /// 启动服务器 |
| | | /// </summary> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Start() |
| | | { |
| | | Debug.Log("start server"); |
| | | return Start(10); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 启动服务器 |
| | | /// </summary> |
| | | /// <param name="backlog">服务器所允许的挂起连接序列的最大长度</param> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Start(int backlog) |
| | | { |
| | | if (IsRunning) |
| | | return this; |
| | | /// <summary> |
| | | /// 启动服务器 |
| | | /// </summary> |
| | | /// <param name="backlog">服务器所允许的挂起连接序列的最大长度</param> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Start(int backlog) |
| | | { |
| | | if (IsRunning) |
| | | return this; |
| | | |
| | | IsRunning = true; |
| | | IsRunning = true; |
| | | |
| | | _listener.Start(backlog); |
| | | ContinueAcceptTcpClient(_listener); |
| | | _listener.Start(backlog); |
| | | ContinueAcceptTcpClient(_listener); |
| | | |
| | | return this; |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 停止服务器 |
| | | /// </summary> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Stop() |
| | | { |
| | | if (!IsRunning) |
| | | return this; |
| | | /// <summary> |
| | | /// 停止服务器 |
| | | /// </summary> |
| | | /// <returns>异步TCP服务器</returns> |
| | | public AsyncTcpServer Stop() |
| | | { |
| | | if (!IsRunning) |
| | | return this; |
| | | |
| | | try |
| | | { |
| | | _listener.Stop(); |
| | | try |
| | | { |
| | | _listener.Stop(); |
| | | |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | client.TcpClient.Client.Disconnect(false); |
| | | } |
| | | _clients.Clear(); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (SocketException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | client.TcpClient.Client.Disconnect(false); |
| | | } |
| | | _clients.Clear(); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (SocketException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | |
| | | IsRunning = false; |
| | | IsRunning = false; |
| | | |
| | | return this; |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | private void ContinueAcceptTcpClient(TcpListener tcpListener) |
| | | { |
| | | try |
| | | { |
| | | tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), tcpListener); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (SocketException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | private void ContinueAcceptTcpClient(TcpListener tcpListener) |
| | | { |
| | | try |
| | | { |
| | | tcpListener.BeginAcceptTcpClient(new AsyncCallback(HandleTcpClientAccepted), tcpListener); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (SocketException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Receive |
| | | #region Receive |
| | | |
| | | private void HandleTcpClientAccepted(IAsyncResult ar) |
| | | { |
| | | if (!IsRunning) |
| | | return; |
| | | private void HandleTcpClientAccepted(IAsyncResult ar) |
| | | { |
| | | if (!IsRunning) |
| | | return; |
| | | |
| | | TcpListener tcpListener = (TcpListener)ar.AsyncState; |
| | | TcpListener tcpListener = (TcpListener)ar.AsyncState; |
| | | |
| | | TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar); |
| | | if (!tcpClient.Connected) |
| | | return; |
| | | TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar); |
| | | if (!tcpClient.Connected) |
| | | return; |
| | | |
| | | byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; |
| | | SimpleProtocolFilter prot = new SimpleProtocolFilter(); |
| | | TcpClientState internalClient = new TcpClientState(tcpClient, buffer, prot); |
| | | byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; |
| | | SimpleProtocolFilter prot = new SimpleProtocolFilter(); |
| | | TcpClientState internalClient = new TcpClientState(tcpClient, buffer, prot); |
| | | |
| | | // add client connection to cache |
| | | string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
| | | _clients.AddOrUpdate(tcpClientKey, internalClient, (n, o) => |
| | | { |
| | | return internalClient; |
| | | }); |
| | | RaiseClientConnected(tcpClient); |
| | | // add client connection to cache |
| | | string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
| | | _clients.AddOrUpdate(tcpClientKey, internalClient, (n, o) => |
| | | { |
| | | return internalClient; |
| | | }); |
| | | RaiseClientConnected(tcpClient); |
| | | |
| | | // begin to read data |
| | | NetworkStream networkStream = internalClient.NetworkStream; |
| | | ContinueReadBuffer(internalClient, networkStream); |
| | | // begin to read data |
| | | NetworkStream networkStream = internalClient.NetworkStream; |
| | | ContinueReadBuffer(internalClient, networkStream); |
| | | |
| | | // keep listening to accept next connection |
| | | ContinueAcceptTcpClient(tcpListener); |
| | | } |
| | | // keep listening to accept next connection |
| | | ContinueAcceptTcpClient(tcpListener); |
| | | } |
| | | |
| | | private void HandleDatagramReceived(IAsyncResult ar) |
| | | { |
| | | if (!IsRunning) |
| | | return; |
| | | private void HandleDatagramReceived(IAsyncResult ar) |
| | | { |
| | | if (!IsRunning) |
| | | return; |
| | | |
| | | try |
| | | { |
| | | TcpClientState internalClient = (TcpClientState)ar.AsyncState; |
| | | if (!internalClient.TcpClient.Connected) |
| | | return; |
| | | try |
| | | { |
| | | TcpClientState internalClient = (TcpClientState)ar.AsyncState; |
| | | if (!internalClient.TcpClient.Connected) |
| | | return; |
| | | |
| | | NetworkStream networkStream = internalClient.NetworkStream; |
| | | NetworkStream networkStream = internalClient.NetworkStream; |
| | | |
| | | int numberOfReadBytes = 0; |
| | | try |
| | | { |
| | | // if the remote host has shutdown its connection, |
| | | // read will immediately return with zero bytes. |
| | | numberOfReadBytes = networkStream.EndRead(ar); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | numberOfReadBytes = 0; |
| | | } |
| | | int numberOfReadBytes = 0; |
| | | try |
| | | { |
| | | // if the remote host has shutdown its connection, |
| | | // read will immediately return with zero bytes. |
| | | numberOfReadBytes = networkStream.EndRead(ar); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | numberOfReadBytes = 0; |
| | | } |
| | | |
| | | if (numberOfReadBytes == 0) |
| | | { |
| | | // connection has been closed |
| | | TcpClientState internalClientToBeThrowAway; |
| | | string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
| | | _clients.TryRemove(tcpClientKey, out internalClientToBeThrowAway); |
| | | RaiseClientDisconnected(internalClient.TcpClient); |
| | | return; |
| | | } |
| | | if (numberOfReadBytes == 0) |
| | | { |
| | | // connection has been closed |
| | | TcpClientState internalClientToBeThrowAway; |
| | | string tcpClientKey = internalClient.TcpClient.Client.RemoteEndPoint.ToString(); |
| | | _clients.TryRemove(tcpClientKey, out internalClientToBeThrowAway); |
| | | RaiseClientDisconnected(internalClient.TcpClient); |
| | | return; |
| | | } |
| | | |
| | | // received byte and trigger event notification |
| | | var receivedBytes = new byte[numberOfReadBytes]; |
| | | Array.Copy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes); |
| | | // input bytes into protofilter |
| | | internalClient.Prot.input(receivedBytes); |
| | | RaiseDatagramReceived(internalClient, receivedBytes); |
| | | // RaisePlaintextReceived(internalClient.TcpClient, receivedBytes); |
| | | // received byte and trigger event notification |
| | | var receivedBytes = new byte[numberOfReadBytes]; |
| | | Array.Copy(internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes); |
| | | // input bytes into protofilter |
| | | internalClient.Prot.input(receivedBytes); |
| | | RaiseDatagramReceived(internalClient, receivedBytes); |
| | | // RaisePlaintextReceived(internalClient.TcpClient, receivedBytes); |
| | | |
| | | // continue listening for tcp datagram packets |
| | | ContinueReadBuffer(internalClient, networkStream); |
| | | } |
| | | catch (InvalidOperationException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | // continue listening for tcp datagram packets |
| | | ContinueReadBuffer(internalClient, networkStream); |
| | | } |
| | | catch (InvalidOperationException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | private void ContinueReadBuffer(TcpClientState internalClient, NetworkStream networkStream) |
| | | { |
| | | try |
| | | { |
| | | networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | private void ContinueReadBuffer(TcpClientState internalClient, NetworkStream networkStream) |
| | | { |
| | | try |
| | | { |
| | | networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Events |
| | | #region Events |
| | | |
| | | /// <summary> |
| | | /// 接收到数据报文事件 |
| | | /// </summary> |
| | | public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived; |
| | | /// <summary> |
| | | /// 接收到数据报文明文事件 |
| | | /// </summary> |
| | | public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived; |
| | | /// <summary> |
| | | /// 接收到数据报文事件 |
| | | /// </summary> |
| | | public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived; |
| | | /// <summary> |
| | | /// 接收到数据报文明文事件 |
| | | /// </summary> |
| | | public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived; |
| | | |
| | | private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) |
| | | { |
| | | if (DatagramReceived != null) |
| | | { |
| | | DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram)); |
| | | } |
| | | } |
| | | private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) |
| | | { |
| | | if (DatagramReceived != null) |
| | | { |
| | | DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram)); |
| | | } |
| | | } |
| | | |
| | | private void RaisePlaintextReceived(TcpClientState sender, byte[] datagram) |
| | | { |
| | | if (PlaintextReceived != null) |
| | | { |
| | | PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(sender, this.Encoding.GetString(datagram, 0, datagram.Length))); |
| | | } |
| | | } |
| | | private void RaisePlaintextReceived(TcpClientState 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; |
| | | /// <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 RaiseClientConnected(TcpClient tcpClient) |
| | | { |
| | | if (ClientConnected != null) |
| | | { |
| | | ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient)); |
| | | } |
| | | } |
| | | |
| | | private void RaiseClientDisconnected(TcpClient tcpClient) |
| | | { |
| | | if (ClientDisconnected != null) |
| | | { |
| | | ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient)); |
| | | } |
| | | } |
| | | private void RaiseClientDisconnected(TcpClient tcpClient) |
| | | { |
| | | if (ClientDisconnected != null) |
| | | { |
| | | ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient)); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region Send |
| | | #region Send |
| | | |
| | | private void GuardRunning() |
| | | { |
| | | if (!IsRunning) |
| | | throw new InvalidProgramException("This TCP server has not been started yet."); |
| | | } |
| | | private void GuardRunning() |
| | | { |
| | | if (!IsRunning) |
| | | throw new InvalidProgramException("This TCP server has not been started yet."); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void Send(TcpClient tcpClient, byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void Send(TcpClient tcpClient, byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | if (tcpClient == null) |
| | | throw new ArgumentNullException("tcpClient"); |
| | | if (tcpClient == null) |
| | | throw new ArgumentNullException("tcpClient"); |
| | | |
| | | if (datagram == null) |
| | | throw new ArgumentNullException("datagram"); |
| | | if (datagram == null) |
| | | throw new ArgumentNullException("datagram"); |
| | | |
| | | try |
| | | { |
| | | NetworkStream stream = tcpClient.GetStream(); |
| | | if (stream.CanWrite) |
| | | { |
| | | stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); |
| | | } |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | try |
| | | { |
| | | NetworkStream stream = tcpClient.GetStream(); |
| | | if (stream.CanWrite) |
| | | { |
| | | stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); |
| | | } |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | /// <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="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 SendToAll(byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SendToAll(byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | Send(client.TcpClient, datagram); |
| | | } |
| | | } |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | Send(client.TcpClient, datagram); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SendToAll(string datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SendToAll(string datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | SendToAll(this.Encoding.GetBytes(datagram)); |
| | | } |
| | | SendToAll(this.Encoding.GetBytes(datagram)); |
| | | } |
| | | |
| | | private void HandleDatagramWritten(IAsyncResult ar) |
| | | { |
| | | try |
| | | { |
| | | ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (InvalidOperationException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | private void HandleDatagramWritten(IAsyncResult ar) |
| | | { |
| | | try |
| | | { |
| | | ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (InvalidOperationException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSend(TcpClient tcpClient, byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSend(TcpClient tcpClient, byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | if (tcpClient == null) |
| | | throw new ArgumentNullException("tcpClient"); |
| | | if (tcpClient == null) |
| | | throw new ArgumentNullException("tcpClient"); |
| | | |
| | | if (datagram == null) |
| | | throw new ArgumentNullException("datagram"); |
| | | if (datagram == null) |
| | | throw new ArgumentNullException("datagram"); |
| | | |
| | | try |
| | | { |
| | | NetworkStream stream = tcpClient.GetStream(); |
| | | if (stream.CanWrite) |
| | | { |
| | | stream.Write(datagram, 0, datagram.Length); |
| | | } |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | try |
| | | { |
| | | NetworkStream stream = tcpClient.GetStream(); |
| | | if (stream.CanWrite) |
| | | { |
| | | stream.Write(datagram, 0, datagram.Length); |
| | | } |
| | | } |
| | | catch (ObjectDisposedException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSend(TcpClient tcpClient, string datagram) |
| | | { |
| | | SyncSend(tcpClient, this.Encoding.GetBytes(datagram)); |
| | | } |
| | | /// <summary> |
| | | /// 发送报文至指定的客户端 |
| | | /// </summary> |
| | | /// <param name="tcpClient">客户端</param> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSend(TcpClient tcpClient, string datagram) |
| | | { |
| | | SyncSend(tcpClient, this.Encoding.GetBytes(datagram)); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSendToAll(byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSendToAll(byte[] datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | SyncSend(client.TcpClient, datagram); |
| | | } |
| | | } |
| | | foreach (var client in _clients.Values) |
| | | { |
| | | SyncSend(client.TcpClient, datagram); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSendToAll(string datagram) |
| | | { |
| | | GuardRunning(); |
| | | /// <summary> |
| | | /// 发送报文至所有客户端 |
| | | /// </summary> |
| | | /// <param name="datagram">报文</param> |
| | | public void SyncSendToAll(string datagram) |
| | | { |
| | | GuardRunning(); |
| | | |
| | | SyncSendToAll(this.Encoding.GetBytes(datagram)); |
| | | } |
| | | SyncSendToAll(this.Encoding.GetBytes(datagram)); |
| | | } |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | #region IDisposable Members |
| | | #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> |
| | | /// 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(); |
| | | /// <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) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | if (_listener != null) |
| | | { |
| | | _listener = null; |
| | | } |
| | | } |
| | | catch (SocketException ex) |
| | | { |
| | | Debug.LogException(ex); |
| | | } |
| | | } |
| | | |
| | | _disposed = true; |
| | | } |
| | | } |
| | | _disposed = true; |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | } |
| | | #endregion |
| | | } |
| | | } |