c#Socket 异步通讯(客户端与服务端)
程序开发
2023-09-15 19:26:02
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{// 当前客户端的Socketpublic Socket workSocket = null;// 可接收的最大字节数public const int BufferSize = 20200;// 接收的数据存储public byte[] buffer = new byte[BufferSize]; }public static List 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[] 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;/// /// public delegate void MyDelegate(string S);public delegate void MyDelegate(string S);public static event MyDelegate MyEvent = null;/// /// 将事件设置成单例模式/// public class Singleton{private static Singleton _instance = null;private Singleton(){MyEvent = null;}public static Singleton CreateInstance(){if (_instance == null){_instance = new Singleton();}return _instance;}}/// public static byte[] SendBuf = new byte[] { };/// /// 接收的字节/// public static List RevBuf;/// /// 当前发送数据的客户端/// public static IPEndPoint _CurrentClient;public static IPEndPoint CurrentClient{get { return _CurrentClient; }set { _CurrentClient = value; }}/// /// 触发接收消息的委托/// 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);}}}}/// /// 存储客户端连接Socket/// public static Dictionary clientConnectionItems = new Dictionary { };/// /// 打开服务器/// /// 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;}}/// /// 连接回调/// /// 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() + "连上咯" + "rn");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);}}/// /// 接收回调/// /// 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();Buffer.BlockCopy(state.buffer, 0, a, 0, bytesRead);RevBuf.AddRange(a);//txt_Rev.AppendText(RevBuf[0].ToString() + "rn");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); }}}/// /// 发送回复客户端/// /// 客户端的Socketpublic 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{}}/// /// 发送回调/// /// 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,代码中有几个地方加入了委托,这个的话是根据我实际需求加的,有用到这个代码的朋友不需要委托可以直接去掉就好了。不影响的话在调用此方法的时候记得把委托加入到队列中,否则会报错。
说明:文中有个地方我是把委托 设置成单例模式的,不设置的话会报“未将事例引用到对象的实例”。具体缘由没弄明白。加上单例模式后 就没有报错了。有知道的大佬给小弟解惑解惑。
标签:
上一篇:
异步组件的用法
下一篇:
相关文章
-
无相关信息