媒介
一说到Socket,想必人人都或多或少有所触及,从最初的计算机收集课程,报告了tcp协定,而Socket就是对协定的进一步封装,使我们开发职员可以越发轻易轻松的举行软件之间的通讯。
这个礼拜恰好接收一个同享车位锁的项目,须要运用Socket与硬件举行通讯掌握,说白了也就是给锁发送指令,掌握其翻开或许封闭,再就是对App开放操纵接口,使其轻易测试以及用户的运用。这个中中心就是Socket的运用,再开发出这个功用以后,我发明运用起来很不轻易,因而耗时2天笼统其中心功用并封装成框架,末了运用这个框架将本来的项目重构并上线,极大的提高了软件的可拓展性,健壮性,容错率。
个人深信的准绳:万物皆对象
好了,不空话了,下面进入正文
正文:
1、起首简朴讲下C#中Socket的简朴运用。
第一步:效劳端监听某个端口
第二步:客户端向效劳端地点和端口提议Socket衔接要求
第三步:效劳端收到衔接要求后竖立Socket衔接,并保护这个衔接行列。
第四步:客户端和效劳端已竖立双工通讯(即双向通讯),客户端和效劳端可以轻松轻易的给相互发送信息。
至于简朴运用的详细完成代码悉数被我封装到项目中了,假如须要进修简朴的完成,可以看我的源码,也可以自行百度,有许多的教程
2、中心,框架的运用
实在,说其为框架,能够有点牵强,由于每个人对框架都有本身的明白,然则类库和框架又有什么本质区别呢?悉数都是代码~哈哈,扯远了
起首,空说无凭,先放上一切的代码:
效劳端源文件:
SocketServer.cs
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; namespace Coldairarrow.Util.Sockets { /// <summary> /// Socket效劳端 /// </summary> public class SocketServer { #region 组织函数 /// <summary> /// 组织函数 /// </summary> /// <param name="ip">监听的IP地点</param> /// <param name="port">监听的端口</param> public SocketServer(string ip, int port) { _ip = ip; _port = port; } /// <summary> /// 组织函数,监听IP地点默以为本机0.0.0.0 /// </summary> /// <param name="port">监听的端口</param> public SocketServer(int port) { _ip = "0.0.0.0"; _port = port; } #endregion #region 内部成员 private Socket _socket = null; private string _ip = ""; private int _port = 0; private bool _isListen = true; private void StartListen() { try { _socket.BeginAccept(asyncResult => { try { Socket newSocket = _socket.EndAccept(asyncResult); //立时举行下一轮监听,增添吞吐量 if (_isListen) StartListen(); SocketConnection newClient = new SocketConnection(newSocket, this) { HandleRecMsg = HandleRecMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleRecMsg), HandleClientClose = HandleClientClose == null ? null : new Action<SocketConnection, SocketServer>(HandleClientClose), HandleSendMsg = HandleSendMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleSendMsg), HandleException = HandleException == null ? null : new Action<Exception>(HandleException) }; newClient.StartRecMsg(); ClientList.AddLast(newClient); HandleNewClientConnected?.Invoke(this, newClient); } catch (Exception ex) { HandleException?.Invoke(ex); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); } } #endregion #region 外部接口 /// <summary> /// 最先效劳,监听客户端 /// </summary> public void StartServer() { try { //实例化套接字(ip4寻址协定,流式传输,TCP协定) _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //竖立ip对象 IPAddress address = IPAddress.Parse(_ip); //竖立收集节点对象包括ip和port IPEndPoint endpoint = new IPEndPoint(address, _port); //将 监听套接字绑定到 对应的IP和端口 _socket.Bind(endpoint); //设置监听行列长度为Int32最大值(同时可以处置惩罚衔接要求数目) _socket.Listen(int.MaxValue); //最先监听客户端 StartListen(); HandleServerStarted?.Invoke(this); } catch (Exception ex) { HandleException?.Invoke(ex); } } /// <summary> /// 一切衔接的客户端列表 /// </summary> public LinkedList<SocketConnection> ClientList { get; set; } = new LinkedList<SocketConnection>(); /// <summary> /// 封闭指定客户端衔接 /// </summary> /// <param name="theClient">指定的客户端衔接</param> public void CloseClient(SocketConnection theClient) { theClient.Close(); } #endregion #region 大众事宜 /// <summary> /// 非常处置惩罚顺序 /// </summary> public Action<Exception> HandleException { get; set; } #endregion #region 效劳端事宜 /// <summary> /// 效劳启动后实行 /// </summary> public Action<SocketServer> HandleServerStarted { get; set; } /// <summary> /// 当新客户端衔接后实行 /// </summary> public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; } /// <summary> /// 效劳端封闭客户端后实行 /// </summary> public Action<SocketServer, SocketConnection> HandleCloseClient { get; set; } #endregion #region 客户端衔接事宜 /// <summary> /// 客户端衔接接收新的音讯后挪用 /// </summary> public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; } /// <summary> /// 客户端衔接发送音讯后回调 /// </summary> public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; } /// <summary> /// 客户端衔接封闭后回调 /// </summary> public Action<SocketConnection, SocketServer> HandleClientClose { get; set; } #endregion } }
using System; using System.Net.Sockets; using System.Text; namespace Coldairarrow.Util.Sockets { /// <summary> /// Socket衔接,双向通讯 /// </summary> public class SocketConnection { #region 组织函数 public SocketConnection(Socket socket,SocketServer server) { _socket = socket; _server = server; } #endregion #region 私有成员 private readonly Socket _socket; private bool _isRec=true; private SocketServer _server = null; private bool IsSocketConnected() { bool part1 = _socket.Poll(1000, SelectMode.SelectRead); bool part2 = (_socket.Available == 0); if (part1 && part2) return false; else return true; } #endregion #region 外部接口 /// <summary> /// 最先接收客户端音讯 /// </summary> public void StartRecMsg() { try { byte[] container = new byte[1024 * 1024 * 2]; _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult => { try { int length = _socket.EndReceive(asyncResult); //立时举行下一轮接收,增添吞吐量 if (length > 0 && _isRec && IsSocketConnected()) StartRecMsg(); if (length > 0) { byte[] recBytes = new byte[length]; Array.Copy(container, 0, recBytes, 0, length); //处置惩罚音讯 HandleRecMsg?.Invoke(recBytes, this, _server); } else Close(); } catch (Exception ex) { HandleException?.Invoke(ex); Close(); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); Close(); } } /// <summary> /// 发送数据 /// </summary> /// <param name="bytes">数据字节</param> public void Send(byte[] bytes) { try { _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult => { try { int length = _socket.EndSend(asyncResult); HandleSendMsg?.Invoke(bytes, this, _server); } catch (Exception ex) { HandleException?.Invoke(ex); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); } } /// <summary> /// 发送字符串(默许运用UTF-8编码) /// </summary> /// <param name="msgStr">字符串</param> public void Send(string msgStr) { Send(Encoding.UTF8.GetBytes(msgStr)); } /// <summary> /// 发送字符串(运用自定义编码) /// </summary> /// <param name="msgStr">字符串音讯</param> /// <param name="encoding">运用的编码</param> public void Send(string msgStr,Encoding encoding) { Send(encoding.GetBytes(msgStr)); } /// <summary> /// 传入自定义属性 /// </summary> public object Property { get; set; } /// <summary> /// 封闭当前衔接 /// </summary> public void Close() { try { _isRec = false; _socket.Disconnect(false); _server.ClientList.Remove(this); HandleClientClose?.Invoke(this, _server); _socket.Close(); _socket.Dispose(); GC.Collect(); } catch (Exception ex) { HandleException?.Invoke(ex); } } #endregion #region 事宜处置惩罚 /// <summary> /// 客户端衔接接收新的音讯后挪用 /// </summary> public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; } /// <summary> /// 客户端衔接发送音讯后回调 /// </summary> public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; } /// <summary> /// 客户端衔接封闭后回调 /// </summary> public Action<SocketConnection, SocketServer> HandleClientClose { get; set; } /// <summary> /// 非常处置惩罚顺序 /// </summary> public Action<Exception> HandleException { get; set; } #endregion } }
using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Coldairarrow.Util.Sockets { /// <summary> /// Socket客户端 /// </summary> public class SocketClient { #region 组织函数 /// <summary> /// 组织函数,衔接效劳器IP地点默以为本机127.0.0.1 /// </summary> /// <param name="port">监听的端口</param> public SocketClient(int port) { _ip = "127.0.0.1"; _port = port; } /// <summary> /// 组织函数 /// </summary> /// <param name="ip">监听的IP地点</param> /// <param name="port">监听的端口</param> public SocketClient(string ip, int port) { _ip = ip; _port = port; } #endregion #region 内部成员 private Socket _socket = null; private string _ip = ""; private int _port = 0; private bool _isRec=true; private bool IsSocketConnected() { bool part1 = _socket.Poll(1000, SelectMode.SelectRead); bool part2 = (_socket.Available == 0); if (part1 && part2) return false; else return true; } /// <summary> /// 最先接收客户端音讯 /// </summary> public void StartRecMsg() { try { byte[] container = new byte[1024 * 1024 * 2]; _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult => { try { int length = _socket.EndReceive(asyncResult); //立时举行下一轮接收,增添吞吐量 if (length > 0 && _isRec && IsSocketConnected()) StartRecMsg(); if (length > 0) { byte[] recBytes = new byte[length]; Array.Copy(container, 0, recBytes, 0, length); //处置惩罚音讯 HandleRecMsg?.Invoke(recBytes, this); } else Close(); } catch (Exception ex) { HandleException?.Invoke(ex); Close(); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); Close(); } } #endregion #region 外部接口 /// <summary> /// 最先效劳,衔接效劳端 /// </summary> public void StartClient() { try { //实例化 套接字 (ip4寻址协定,流式传输,TCP协定) _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //竖立 ip对象 IPAddress address = IPAddress.Parse(_ip); //竖立收集节点对象 包括 ip和port IPEndPoint endpoint = new IPEndPoint(address, _port); //将 监听套接字 绑定到 对应的IP和端口 _socket.BeginConnect(endpoint, asyncResult => { try { _socket.EndConnect(asyncResult); //最先接收效劳器音讯 StartRecMsg(); HandleClientStarted?.Invoke(this); } catch (Exception ex) { HandleException?.Invoke(ex); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); } } /// <summary> /// 发送数据 /// </summary> /// <param name="bytes">数据字节</param> public void Send(byte[] bytes) { try { _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult => { try { int length = _socket.EndSend(asyncResult); HandleSendMsg?.Invoke(bytes, this); } catch (Exception ex) { HandleException?.Invoke(ex); } }, null); } catch (Exception ex) { HandleException?.Invoke(ex); } } /// <summary> /// 发送字符串(默许运用UTF-8编码) /// </summary> /// <param name="msgStr">字符串</param> public void Send(string msgStr) { Send(Encoding.UTF8.GetBytes(msgStr)); } /// <summary> /// 发送字符串(运用自定义编码) /// </summary> /// <param name="msgStr">字符串音讯</param> /// <param name="encoding">运用的编码</param> public void Send(string msgStr, Encoding encoding) { Send(encoding.GetBytes(msgStr)); } /// <summary> /// 传入自定义属性 /// </summary> public object Property { get; set; } /// <summary> /// 封闭与效劳器的衔接 /// </summary> public void Close() { try { _isRec = false; _socket.Disconnect(false); HandleClientClose?.Invoke(this); } catch (Exception ex) { HandleException?.Invoke(ex); } } #endregion #region 事宜处置惩罚 /// <summary> /// 客户端衔接竖立后回调 /// </summary> public Action<SocketClient> HandleClientStarted { get; set; } /// <summary> /// 处置惩罚接收音讯的托付 /// </summary> public Action<byte[], SocketClient> HandleRecMsg { get; set; } /// <summary> /// 客户端衔接发送音讯后回调 /// </summary> public Action<byte[], SocketClient> HandleSendMsg { get; set; } /// <summary> /// 客户端衔接封闭后回调 /// </summary> public Action<SocketClient> HandleClientClose { get; set; } /// <summary> /// 非常处置惩罚顺序 /// </summary> public Action<Exception> HandleException { get; set; } #endregion } }
上面放上的是框架代码,接下来引见下怎样运用
起首,效劳端运用体式格局:
using Coldairarrow.Util.Sockets; using System; using System.Text; namespace Console_Server { class Program { static void Main(string[] args) { //竖立效劳器对象,默许监听本机0.0.0.0,端口12345 SocketServer server = new SocketServer(12345); //处置惩罚从客户端收到的音讯 server.HandleRecMsg = new Action<byte[], SocketConnection, SocketServer>((bytes, client, theServer) => { string msg = Encoding.UTF8.GetString(bytes); Console.WriteLine($"收到音讯:{msg}"); }); //处置惩罚效劳器启动后事宜 server.HandleServerStarted = new Action<SocketServer>(theServer => { Console.WriteLine("效劳已启动************"); }); //处置惩罚新的客户端衔接后的事宜 server.HandleNewClientConnected = new Action<SocketServer, SocketConnection>((theServer, theCon) => { Console.WriteLine($@"一个新的客户端接入,当前衔接数:{theServer.ClientList.Count}"); }); //处置惩罚客户端衔接封闭后的事宜 server.HandleClientClose = new Action<SocketConnection, SocketServer>((theCon, theServer) => { Console.WriteLine($@"一个客户端封闭,当前衔接数为:{theServer.ClientList.Count}"); }); //处置惩罚非常 server.HandleException = new Action<Exception>(ex => { Console.WriteLine(ex.Message); }); //效劳器启动 server.StartServer(); while (true) { Console.WriteLine("输入:quit,封闭效劳器"); string op = Console.ReadLine(); if (op == "quit") break; } } } }
客户端运用体式格局:
using Coldairarrow.Util.Sockets; using System; using System.Text; namespace Console_Client { class Program { static void Main(string[] args) { //竖立客户端对象,默许衔接本机127.0.0.1,端口为12345 SocketClient client = new SocketClient(12345); //绑定当收到效劳器发送的音讯后的处置惩罚事宜 client.HandleRecMsg = new Action<byte[], SocketClient>((bytes, theClient) => { string msg = Encoding.UTF8.GetString(bytes); Console.WriteLine($"收到音讯:{msg}"); }); //绑定向效劳器发送音讯后的处置惩罚事宜 client.HandleSendMsg = new Action<byte[], SocketClient>((bytes, theClient) => { string msg = Encoding.UTF8.GetString(bytes); Console.WriteLine($"向效劳器发送音讯:{msg}"); }); //最先运转客户端 client.StartClient(); while (true) { Console.WriteLine("输入:quit封闭客户端,输入别的音讯发送到效劳器"); string str = Console.ReadLine(); if (str == "quit") { client.Close(); break; } else { client.Send(str); } } } } }
末了运转测试截图:
总结:
其最轻易的地方在于,将怎样竖立衔接封装掉,运用职员只需关注衔接后发送什么数据,接收到数据后应当怎样处置惩罚,等等别的的许多事宜的处置惩罚,这个中重要依托于匿名托付的运用,Lambda表达式的运用。
以上就是C#中Socket框架的运用教程的细致内容,更多请关注ki4网别的相干文章!