C# 异步TCP服务器端客户端

异步服务器端

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

namespace SocketTool
{
    public enum ClientStatus
    {
        /// <summary>
        /// 客户端链接
        /// </summary>
        connnected,
        /// <summary>
        /// 客户端正常
        /// </summary>
        normal,
        /// <summary>
        /// 客户端关闭
        /// </summary>
        disconnected
    }
    //保存客户端连接信息
    public class ConnectionInfo
    {
        public Socket Socket;/// 客户端链接实例
        public byte[] RveBuffer; /// 接收客户端数据缓冲区
        public byte[] SendBuffer; /// 发送客户端数据缓冲区
        public string Data;///客户端发的数据                      
        public ClientStatus ClientStatus;  /// 客户端状态
    }

    /// <summary>
    /// 自定义事件参数
    /// </summary>
    public class TcpMsgEventArgs : EventArgs
    {
        public string Msg { get; set; }
        public ConnectionInfo clienInfo { get; set; }

        public TcpMsgEventArgs(ConnectionInfo info, string text)
        {
            clienInfo = info;
            Msg = text;
        }
    }

    class SocketServer
    {
        private Socket sock;
        private int clientNumb = 0;
        private byte[] byText;
        public List<ConnectionInfo> clientConnections = new List<ConnectionInfo>();

        //定义收到客户端消息delegate
        public delegate void ReceiveFromClientMsgEventHandler(object sender, TcpMsgEventArgs e);
        //用event 关键字声明事件对象
        public event ReceiveFromClientMsgEventHandler ReceiveFromClientMsgEvent;

        //定义向客户端发送消息delegate
        public delegate void SendToClientMsgEventHandler(object sender, TcpMsgEventArgs e);
        //用event 关键字声明事件对象
        public event SendToClientMsgEventHandler SendToClientMsgEvent;

        /// <summary>
        /// 服务器监听tcp端口并接收信息
        /// </summary>
        public bool BeginServer()
        {
            try
            {
                string hostname = System.Net.Dns.GetHostName();
                System.Net.IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostname);//ipEntry.AddressList[0].ToString()
                IPAddress myip = IPAddress.Any;
                IPEndPoint myserver = new IPEndPoint(myip, 60000);
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sock.Bind(myserver);
                sock.Listen(50);
                sock.BeginAccept(new AsyncCallback(Accept), null);
            }
            catch (Exception ex)
            {
                Debug.Log("" + ex.Message);
                return false;
            }
            return true;
        }
        /// <summary>
        /// 监听客户端
        /// </summary>
        /// <param name="ar"></param>
        private void Accept(IAsyncResult ar)
        {
            try
            {
                Socket ClientSocket = sock.EndAccept(ar);
                IPEndPoint ep = ClientSocket.RemoteEndPoint as IPEndPoint;
                // ClientSocket[clientNumb].BeginReceive(MsgBuffer, 0, MsgBuffer.Length, 0,new AsyncCallback(Accept), ClientSocket[clientNumb]);
                Debug.Log(ep.ToString() + "客户端连接成功");

                ClientPro(ClientSocket);
                clientNumb++;
            }
            catch (Exception ex)
            {
                Debug.Log("出错:" + ex.Message);
            }
            finally
            {
                sock.BeginAccept(new AsyncCallback(Accept), null);
            }
        }
        /// <summary>
        /// 连接客户端后做处理过程启动异步接收
        /// </summary>
        /// <param name="clientSock"></param>
        private void ClientPro(Socket clientSock)
        {
            IPEndPoint ep = clientSock.RemoteEndPoint as IPEndPoint;
            ConnectionInfo ci = new ConnectionInfo();
            ci.Socket = clientSock;
            ci.RveBuffer = new byte[1024];
            lock (clientConnections)
            {
                clientConnections.Add(ci);
            }
            ///向客户端发送自己的ip和端口,来作为区别的唯一标识
            //启动异步接收过程
            clientSock.BeginReceive(ci.RveBuffer, 0, ci.RveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ci);
            //客户端首次链接成功后,置客户端状态为"连接成功"
            ci.ClientStatus = ClientStatus.normal;
        }
        /// <summary>
        /// 回调函数做数据处理
        /// </summary>
        /// <param name="result"></param>
        private void ReceiveCallback(IAsyncResult result)
        {
            ConnectionInfo ci = (ConnectionInfo)result.AsyncState;
            if (ci == null || ci.Socket == null || ci.Socket.Connected == false)
            {
                return;
            }
            try
            {
                //得到客户端信息
                IPEndPoint ep = ci.Socket.RemoteEndPoint as IPEndPoint;
                string ip = ep.Address.ToString();
                int port = ep.Port;

                if (ip == null || ip.Length == 0)
                {
                    ip = "0.0.0.0";
                    port = 0;
                }
                int bytesRead = ci.Socket.EndReceive(result);
                /*
                    若接收到的数据为0,则客户端断开链接
                */
                if (bytesRead == 0)
                {
                    CloseConnection(ci);
                    return;
                }
                byText = new byte[bytesRead];
                Array.Copy(ci.RveBuffer, 0, byText, 0, bytesRead);
                string s = Encoding.ASCII.GetString(byText);
                ci.Data = s;

                //触发接收消息事件
                if (ReceiveFromClientMsgEvent != null)
                {
                    ReceiveFromClientMsgEvent(this, new TcpMsgEventArgs(ci, s));
                }
                //读取数据成功后,置当前客户状态为 一般
                byte[] data = new byte[1024];
                //BeginServerTreatment(ci);
                ci.ClientStatus = ClientStatus.normal;
            }
            catch (SocketException ex)
            {
                CloseConnection(ci);
                Debug.Log("SocketException:" + ex.Message);

            }
            catch (Exception ex)
            {
                CloseConnection(ci);
                Debug.Log("Exception:" + ex.Message);
            }
            finally
            {
                if (ci.Socket.Connected == true)
                {
                    //等待接收数据
                    ci.Socket.BeginReceive(ci.RveBuffer, 0, ci.RveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ci);
                }
            }
        }
        /// <summary>
        /// 关闭当前链接,并从内存中清除相应记录
        /// </summary>
        /// <param name="ci"></param>
        private void CloseConnection(ConnectionInfo ci)
        {
            try
            {
                IPEndPoint ep = ci.Socket.RemoteEndPoint as IPEndPoint;

                ci.Socket.Close();

                Debug.Log("客户端" + ep.Address.ToString() + "已经断开连接");
            }
            catch (Exception ex)
            {
                Debug.Log("断开连接异常:" + ex.Message);
            }
            finally
            {
                lock (clientConnections)
                {
                    clientConnections.Remove(ci);
                }
            }
        }

        /// <summary>
        /// 向所有客户端发送 单个客户端状态数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool ServerSendAll(byte[] data)
        {
            for (int i = 0; i < clientConnections.Count; i++)
            {
                IPEndPoint ep = clientConnections[i].Socket.RemoteEndPoint as IPEndPoint;
                NetworkStream ns = new NetworkStream(clientConnections[i].Socket);
                try
                {
                    ns.Write(data, 0, data.Length);
                    if (SendToClientMsgEvent != null)
                    {
                        SendToClientMsgEvent(this, new TcpMsgEventArgs(clientConnections[i], System.Text.Encoding.ASCII.GetString(data)));
                    }
                }
                catch (Exception ex)
                {
                    Debug.Log("所有客户端NS数据流对象写入失败" + ex.Message);
                    return false;
                }

            }
            return true;

        }
        /// <summary>
        /// 向所有客户端发送状态数据一般状态
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool ServerSendAll(string msg)
        {
            for (int i = 0; i < clientConnections.Count; i++)
            {
                string serverdata = msg;
                byte[] data = new byte[1024];
                data = Encoding.Unicode.GetBytes(serverdata);
                try
                {
                    for (int j = 0; j < clientConnections.Count; j++)
                    {
                        IPEndPoint ep = clientConnections[i].Socket.RemoteEndPoint as IPEndPoint;

                        NetworkStream ns = new NetworkStream(clientConnections[j].Socket);
                        ns.Write(data, 0, data.Length);
                        if (SendToClientMsgEvent != null)
                        {
                            SendToClientMsgEvent(this, new TcpMsgEventArgs(clientConnections[i], msg));
                        }

                        Thread.Sleep(100);
                    }

                }
                catch (Exception ex)
                {
                    Debug.Log("所有客户端NS数据流对象写入失败" + ex.Message);
                    return false;
                }

            }
            return true;

        }
        /// <summary>
        /// 向单独客户端发送数据
        /// </summary>
        /// <param name="ci"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool ServerSendOne(ConnectionInfo ci, byte[] data)
        {
            IPEndPoint ep = ci.Socket.RemoteEndPoint as IPEndPoint;
            NetworkStream ns = new NetworkStream(ci.Socket);
            try
            {
                ns.Write(data, 0, data.Length);
                if (SendToClientMsgEvent != null)
                {
                    SendToClientMsgEvent(this, new TcpMsgEventArgs(ci, System.Text.Encoding.ASCII.GetString(data)));
                }
            }
            catch (Exception ex)
            {
                Debug.Log("单独客户端NS数据流对象写入失败" + ex.Message);
                return false;
            }
            return true;
        }
    }
}

服务器使用方法

SocketServer sckServer = new SocketServer();
	sckServer.ReceiveFromClientMsgEvent += SckServer_ReceiveClientMsgEvent;
    sckServer.SendToClientMsgEvent += SckServer_SendToClientMsgEvent;
    bool bSuc = sckServer.BeginServer();
		
	private void SckServer_SendToClientMsgEvent(object sender, TcpMsgEventArgs e)
    {
        
    }

    //消息接收事件处理
    private void SckServer_ReceiveClientMsgEvent(object sender, TcpMsgEventArgs e)
    {
        
    }

异步客户端

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Timers;

namespace MotionDetectorSample.Custom
{    
    public class StateObject
    {
        // Client socket.     
        public Socket workSocket = null;
        // Size of receive buffer.     
        public const int BufferSize = 256;
        // Receive buffer.     
        public byte[] buffer = new byte[BufferSize];
        // Received data string.     
        public StringBuilder sb = new StringBuilder();
    }
    public class SocketClient
    {
        public bool IsConnect = false;

        //定义收到服务器端消息delegate
        public delegate void ReceiveFromServerMsgEventHandler(object sender, TcpMsgEventArgs e);
        //用event 关键字声明事件对象
        public event ReceiveFromServerMsgEventHandler ReceiveFromServerMsgEvent;

        // The port number for the remote device.     
        private const int port = 11000;
        // ManualResetEvent instances signal completion.     
        private  ManualResetEvent connectDone = new ManualResetEvent(false);
        private  ManualResetEvent sendDone = new ManualResetEvent(false);
        private  ManualResetEvent receiveDone = new ManualResetEvent(false);
        // The response from the remote device.     
        private  String response = String.Empty;
        private Socket client;
        public  void StartConnectServer(string newIp, int newPort)
        {
            // Connect to a remote device.     
            try
            {
                IPAddress ipAddress = IPAddress.Parse(newIp);
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, newPort);
                // Create a TCP/IP socket.     
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // Connect to the remote endpoint.     
                client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                IsConnect = false;
            }
        }

        public void Close()
        {
            try
            {
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                IsConnect = false;
            }
            
        }
        private  void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.     
                Socket client = (Socket)ar.AsyncState;
                // Complete the connection.     
                client.EndConnect(ar);
                Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
                // Signal that the connection has been made.     
                connectDone.Set();

                Receive(client);
                IsConnect = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                IsConnect = false;
            }
        }
        private  void Receive(Socket client)
        {
            try
            {
                // Create the state object.     
                StateObject state = new StateObject();
                state.workSocket = client;
                // Begin receiving the data from the remote device.     
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                IsConnect = false;
            }
        }
        private  void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the state object and the client socket     
                // from the asynchronous state object.     
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
                // Read data from the remote device.     
                int bytesRead = client.EndReceive(ar);
                if (bytesRead > 0)
                {
                    // There might be more data, so store the data received so far.     

                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                    string rec = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
                    Console.WriteLine("received:" + rec);
                    ReceiveFromServerMsgEvent(this, new TcpMsgEventArgs(rec));
                    IsConnect = true;
                    // Get the rest of the data.     
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                }
                else
                {
                    // All the data has arrived; put it in response.     
                    if (state.sb.Length > 1)
                    {
                        response = state.sb.ToString();
                        Console.WriteLine("response:" + response);
                    }
                    // Signal that all bytes have been received.     
                    receiveDone.Set();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        public void SendCommand(String data)
        {
            try
            {
                // Convert the string data to byte data using ASCII encoding.     
                byte[] byteData = Encoding.ASCII.GetBytes(data);
                // Begin sending the data to the remote device.     
                client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
                IsConnect = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                IsConnect = false;
            }
        }
        private  void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.     
                Socket client = (Socket)ar.AsyncState;
                // Complete sending the data to the remote device.     
                int bytesSent = client.EndSend(ar);
                //Console.WriteLine("Sent {0} bytes to server.", bytesSent);
                // Signal that all bytes have been sent.     
                sendDone.Set();
                IsConnect = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
    /// <summary>
    /// 自定义事件参数
    /// </summary>
    public class TcpMsgEventArgs : EventArgs
    {
        public string Msg { get; set; }

        public TcpMsgEventArgs(string text)
        {
            Msg = text;
        }
    }
}
Custom.SocketClient sckClient = new Custom.SocketClient();
sckClient.ReceiveFromServerMsgEvent += SckClient_ReceiveFromServerMsgEvent;
sckClient.StartConnectServer(RemoteTcpServerIp, RemoteTcpServerPort);

private void SckClient_ReceiveFromServerMsgEvent(object sender, TcpMsgEventArgs e)
        {
           
        }

客户端使用
 

猜你喜欢

转载自blog.csdn.net/zouxin_88/article/details/80701795