c#Socket 异步通讯(客户端与服务端)

c#Socket 异步通讯(多个客户端与服务端)

最近公司有个项目,涉及到的通讯对象有点多,就拿其中一个库的通讯来说就用到了3个PLC,这里就涉及了一个服务器与多个客户端之间的通讯了,同时上位机既需要做客户端,也需要做服务端,因为跟PLC之间走的Modbus tcp。

下面直接上代码吧:

客户端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Communication.CommType
{
    public class AsynClient
    {
        public  class StateObject
        {
            // 当前客户端的Socket
            public   Socket workSocket = null;
            // 可接收的最大字节数
            public  const int BufferSize = 20200;
            // 接收的数据存储
            public   byte[] buffer = new byte[BufferSize];           
        }
        public static  List<byte> RevBuf;
        public static  bool _BoolRevContent = false;
        public static bool BoolRevContent
        {
            get { return _BoolRevContent; }
            set { _BoolRevContent = value; }
        }
        public static Socket clientT;
        public static bool ConnectServercer(string ip, string port)
        {
            try
            {
                IPAddress IP = IPAddress.Parse(ip);
                IPEndPoint Point = new IPEndPoint(IP, int.Parse(port));
                clientT = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                clientT.BeginConnect(Point, new AsyncCallback(ConnectCallback), clientT);
                //connectDone.WaitOne();
                //byte[] A = new byte[] { 0x00, 0x02, 0x06 };
                //Send(client, A);
                //sendDone.WaitOne();
                Receive(clientT);
                //receiveDone.WaitOne();                
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        private static void ConnectCallback(IAsyncResult ar)
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndConnect(ar);
            //connectDone.Set();
        }
        private static  void Receive(Socket client)
        {
            StateObject state = new StateObject();
            state.workSocket = client;
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }

        public static void ReceiveCallback(IAsyncResult ar)
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;
            int bytesRead = client.EndReceive(ar);
            //byte[] Conn = state.buffer;
            if (bytesRead > 0)
            {              
                BoolRevContent = true;
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                RevBuf = new List<byte>();
                byte[] ActConn = new byte[bytesRead];
                Buffer.BlockCopy(state.buffer, 0, ActConn, 0, bytesRead);
                RevBuf.AddRange(ActConn);
                BoolRevContent = false;
            }
            else
            {

            }
        }

        public static  bool Send(byte[] data)
        {          
            try
            {
                clientT.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), clientT);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        private static  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);
                // Signal that all bytes have been sent.
                //sendDone.Set();
            }
            catch (Exception e)
            {

            }
        }
    }
}

服务端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Communication.CommType
{
    public class AsynServer
    {
        public class StateObject
        {
            // Client socket.
            public Socket workSocket = null;
            // Size of receive buffer.
            public const int BufferSize = 22000;
            // Receive buffer.
            public byte[] buffer = new byte[BufferSize];
            // Received data string.
            public StringBuilder sb = new StringBuilder();
        }

        public static string ErrorMsg = string.Empty;
        /// <summary>
        /// public delegate void MyDelegate(string S);
        public delegate void MyDelegate(string S);
        public static event MyDelegate MyEvent = null;
        /// <summary>
        /// 将事件设置成单例模式
        /// </summary>
        public class Singleton
        {
            private static Singleton _instance = null;

            private Singleton()
            {
                MyEvent = null;
            }
            public static Singleton CreateInstance()
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
                return _instance;
            }
        }
        /// </summary>
        public static  byte[] SendBuf = new byte[] { };
        /// <summary>
        /// 接收的字节
        /// </summary>
        public static  List<byte> RevBuf;
        /// <summary>
        /// 当前发送数据的客户端
        /// </summary>
        public static  IPEndPoint _CurrentClient;
        public static  IPEndPoint CurrentClient
        {
            get { return _CurrentClient; }
            set { _CurrentClient = value; }
        }

        /// <summary>
        /// 触发接收消息的委托
        /// </summary>
        public static bool _RevBool = false;
        public static event EventHandler RevBoolChanged = null;
        public static bool RevBool
        {
            get { return _RevBool; }
            set
            {
                if (_RevBool != value)
                {
                    _RevBool = value;
                    if (_RevBool)
                    {
                        RevBoolChanged?.Invoke(0, EventArgs.Empty);
                    }
                }
            }
        }
        /// <summary>
        /// 存储客户端连接Socket
        /// </summary>
        public static  Dictionary<string, Socket> clientConnectionItems = new Dictionary<string, Socket> { };
        /// <summary>
        /// 打开服务器
        /// </summary>
        /// <returns></returns>
        public static  bool OpenServer(string Ip, string Port)
        {
            try
            {
                IPAddress IP = IPAddress.Parse(Ip);
                IPEndPoint Point = new IPEndPoint(IP, int.Parse(Port));
                Socket ServerClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ServerClient.Bind(Point);
                ServerClient.Listen(10);
                ServerClient.BeginAccept(new AsyncCallback(AcceptCallback), ServerClient);
                MyEvent("服务器打开成功");
                //thServer = new Thread(new ThreadStart(RevState));
                //thServer.IsBackground = true;
                //thServer.Start();
                return true;
            }
            catch (Exception ex)
            {
                ErrorMsg = ex.Message;
                MyEvent("服务器打开失败:"+ex.Message);
                return false;
            }
        }
        /// <summary>
        /// 连接回调
        /// </summary>
        /// <param name="ar"></param>
        public static  void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                Socket listener = ar.AsyncState as Socket;
                if (listener != null)
                {
                    Socket handler = listener.EndAccept(ar);
                    StateObject state = new StateObject();
                    state.workSocket = handler;
                    IPEndPoint clientipe = (IPEndPoint)handler.RemoteEndPoint;
                    //txt_State.AppendText(clientipe.ToString() + "连上咯" + "\r\n");
                    clientConnectionItems.Add(clientipe.ToString(), handler);
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(RevCallback), state);
                    MyEvent(clientipe.ToString()+"----已连上服务器");
                }
                if (listener != null)
                {
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
                }
            }
            catch (Exception ex)
            {
                ErrorMsg = ex.Message;
                MyEvent(ErrorMsg);
            }
        }
        /// <summary>
        /// 接收回调
        /// </summary>
        /// <param name="ar"></param>
        public static  void RevCallback(IAsyncResult ar)
        {
            StateObject state = (StateObject)ar.AsyncState;
            //Socket socketClient= ar.AsyncState as Socket;
            Socket handler = state.workSocket;
            if (handler != null)
            {
                IPEndPoint clientipe = (IPEndPoint)handler.RemoteEndPoint;
                try
                {
                    // Read data from the client socket.
                    int bytesRead = handler.EndReceive(ar);
                    if (bytesRead > 0)
                    {
                        byte[] a = new byte[bytesRead]; 
                        RevBuf = new List<byte>();
                        Buffer.BlockCopy(state.buffer, 0, a, 0, bytesRead);
                        RevBuf.AddRange(a);
                        //txt_Rev.AppendText(RevBuf[0].ToString() + "\r\n");
                        CurrentClient = clientipe;
                        //Send(handler, new byte[] { 0x00, 0x01, 0x02 });
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(RevCallback), state);
                        RevBool = true;
                        RevBool = false;
                    }
                }
                catch (Exception ex)
                {
                    ErrorMsg = clientipe.ToString() + "退出";
                    MyEvent(clientipe.ToString() + "----退出"+ex.Message);
                    //txt_State.AppendText(clientipe.ToString() + "退出" + ex.Message);                   
                }
            }

        }
        /// <summary>
        /// 发送回复客户端
        /// </summary>
        /// <param name="handle">客户端的Socket</param>
        public static  void Send(Socket handle)
        {
            // Convert the string data to byte data using ASCII encoding.           
            // Begin sending the data to the remote device.
            if (SendBuf.Length != 0)//确保发送的字节长度不为0
            {
                handle.BeginSend(SendBuf, 0, SendBuf.Length, 0, new AsyncCallback(SendCallback), handle);
            }
            else
            {

            }
        }
        /// <summary>
        /// 发送回调
        /// </summary>
        /// <param name="ar"></param>
        private static void SendCallback(IAsyncResult ar)
        {
            Socket handler = (Socket)ar.AsyncState;
            int bytesSent = handler.EndSend(ar);
            //handler.Shutdown(SocketShutdown.Both);
            //handler.Close();
        }
    }
}

这两个端都是经过实际测试的,PLC都是用的1200的。
在这里插入图片描述
我做的策略是打开服务端的同时连接3个PLC,代码中有几个地方加入了委托,这个的话是根据我实际需求加的,有用到这个代码的朋友不需要委托可以直接去掉就好了。不影响的话在调用此方法的时候记得把委托加入到队列中,否则会报错。

说明:文中有个地方我是把委托 设置成单例模式的,不设置的话会报“未将事例引用到对象的实例”。具体缘由没弄明白。加上单例模式后 就没有报错了。有知道的大佬给小弟解惑解惑。

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值