C#之Socket客户端全过程
C#开发Socket客户端
我们先新建一个类:SocketClientAsync。
注意点:
1、由于Socket通讯是发送到缓存区内的数据是覆盖,而不是新的,也就是说如果我们第一次发送的内容是 byte[]{0x11,0x22};而第二次发送的内容是byte[]{0x22}。那么我们的服务端在第二次接受到的数据是byte[]{0x22,0x22}。
所以我们需要在Socket.Send(byte[] mes)方法里面声明
byte[] buffer = new byte[1024]; for (int i = 0; i < buffer.Length; i++) { buffer[i] = 0x00; }
起到的作用就是每次在发送新的内容到服务端的时候,会将所有的旧的内容替换掉;
2、关闭连接之前需要将通知服务端停止发送和接受,也就是
this.clientSocket.Shutdown(SocketShutdown.Both);
中断套接字连接:通知服务器端或客户端停止接收和发送数据。
通知完成之后如果客户端还连接着再进行自己的连接断开
if (this.clientSocket.Connected) { this.clientSocket.Close(); }
3、具体类的代码见下图,可以直接使用
#region SocketClient客户端 public class SocketClientAsync { #region 声明变量 public string IPAdress; public bool connected = false; public Socket clientSocket; private IPEndPoint hostEndPoint; private int Flag = 0; private AutoResetEvent autoConnectEvent = new AutoResetEvent(false); private SocketAsyncEventArgs lisnterSocketAsyncEventArgs; public delegate void StartListeHandler(); public event StartListeHandler StartListen; public delegate void ReceiveMsgHandler(byte[] info, int i); public event ReceiveMsgHandler OnMsgReceived; private List<SocketAsyncEventArgs> s_lst = new List<SocketAsyncEventArgs>(); #endregion #region 构造函数 /// <summary> /// 构造函数 /// </summary> /// <param name="hostName"></param> /// <param name="port"></param> /// <param name="i"></param> public SocketClientAsync(string hostName, int port, int i) { Flag = i; IPAdress = hostName; IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName); this.hostEndPoint = new IPEndPoint(hostAddresses[hostAddresses.Length - 1], port); this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); } #endregion #region 开始连接服务端 /// <summary> /// 连接服务端 /// </summary> /// <returns></returns> private bool Connect() { using (SocketAsyncEventArgs args = new SocketAsyncEventArgs()) { args.UserToken = this.clientSocket; args.RemoteEndPoint = this.hostEndPoint; args.Completed += new EventHandler<SocketAsyncEventArgs>(this.OnConnect); this.clientSocket.ConnectAsync(args); bool flag = autoConnectEvent.WaitOne(5000); if (this.connected) { this.lisnterSocketAsyncEventArgs = new SocketAsyncEventArgs(); byte[] buffer = new byte[1024]; this.lisnterSocketAsyncEventArgs.UserToken = this.clientSocket; this.lisnterSocketAsyncEventArgs.SetBuffer(buffer, 0, buffer.Length); this.lisnterSocketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(this.OnReceive); this.StartListen(); return true; } return false; } } #endregion #region 判断有没有连接上服务端 /// <summary> /// 判断有没有连接上 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnConnect(object sender, SocketAsyncEventArgs e) { this.connected = (e.SocketError == SocketError.Success); autoConnectEvent.Set(); } #endregion #region 发送数据到服务端 /// <summary> /// 发送 /// </summary> /// <param name="mes"></param> public void Send(byte[] mes) { if (this.connected) { EventHandler<SocketAsyncEventArgs> handler = null; //byte[] buffer = Encoding.Default.GetBytes(mes); byte[] buffer = new byte[1024]; for (int i = 0; i < buffer.Length; i++) { buffer[i] = 0x00; } Array.Copy(mes, 0, buffer, 0, mes.Length); SocketAsyncEventArgs senderSocketAsyncEventArgs = null; lock (s_lst) { if (s_lst.Count > 0) { senderSocketAsyncEventArgs = s_lst[s_lst.Count - 1]; s_lst.RemoveAt(s_lst.Count - 1); } } if (senderSocketAsyncEventArgs == null) { senderSocketAsyncEventArgs = new SocketAsyncEventArgs(); senderSocketAsyncEventArgs.UserToken = this.clientSocket; senderSocketAsyncEventArgs.RemoteEndPoint = this.clientSocket.RemoteEndPoint; if (handler == null) { handler = delegate(object sender, SocketAsyncEventArgs _e) { lock (s_lst) { s_lst.Add(senderSocketAsyncEventArgs); } }; } senderSocketAsyncEventArgs.Completed += handler; } senderSocketAsyncEventArgs.SetBuffer(buffer, 0, buffer.Length); this.clientSocket.SendAsync(senderSocketAsyncEventArgs); } else { this.connected = false; } } #endregion #region 监听服务端 /// <summary> /// 监听服务端 /// </summary> public void Listen() { if (this.connected && this.clientSocket != null) { try { (lisnterSocketAsyncEventArgs.UserToken as Socket).ReceiveAsync(lisnterSocketAsyncEventArgs); } catch (Exception) { } } } #endregion #region 断开服务端的连接 /// <summary> /// 断开连接 /// </summary> /// <returns></returns> private int Disconnect() { int res = 0; try { this.clientSocket.Shutdown(SocketShutdown.Both); } catch (Exception) { } try { this.clientSocket.Close(); } catch (Exception) { } this.connected = false; return res; } #endregion #region 数据接收 /// <summary> /// 数据接受 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnReceive(object sender, SocketAsyncEventArgs e) { if (e.BytesTransferred == 0) { if (clientSocket.Connected) { try { this.clientSocket.Shutdown(SocketShutdown.Both); } catch (Exception) { } finally { if (this.clientSocket.Connected) { this.clientSocket.Close(); } } } byte[] info = new Byte[] { 0 }; this.OnMsgReceived(info, Flag); } else { byte[] buffer = new byte[e.BytesTransferred]; Buffer.BlockCopy(e.Buffer, 0, buffer, 0, e.BytesTransferred); this.OnMsgReceived(buffer, Flag); Listen(); } } #endregion #region 建立连接服务端的方法 /// <summary> /// 建立连接的方法 /// </summary> /// <returns></returns> public bool ConnectServer() { bool flag = false; this.StartListen += new StartListeHandler(SocketClient_StartListen); // this.OnMsgReceived += new ReceiveMsgHandler(SocketClient_OnMsgReceived); flag = this.Connect(); if (!flag) { return flag; } return true; } #endregion #region 关闭与服务端之间的连接 /// <summary> /// 关闭连接的方法 /// </summary> /// <returns></returns> public int CloseLinkServer() { return this.Disconnect(); } #endregion #region 监听方法 /// <summary> /// 监听的方法 /// </summary> private void SocketClient_StartListen() { this.Listen(); } #endregion #region IDispose member public void Dispose() { if (this.clientSocket.Connected) { this.clientSocket.Close(); } } #endregion #region 析构函数 ~SocketClientAsync() { try { if (this.clientSocket.Connected) { this.clientSocket.Close(); } } catch { } finally { } } #endregion } #endregion
4、然后就是类的调用了
//声明定义变量 private SocketClientAsync ClientLink;//客户端连接对象 private string Client_IP = "127.0.0.1";//服务端IP地址 private int Client_Port = 12345;//服务端监听的端口号 private Thread Client_Td;//通讯内部使用线程 private bool ClientLinkRes = false;//服务器通讯状态标志 private bool ThreadContinue = true;//线程轮询标志 private bool isOnline = false;//是否在线标志 /// <summary> /// 启动线程 /// </summary> private void StartServer() { Client_Td = new Thread(LinkSocketSerFunc); Client_Td.Start(); } /// <summary> /// 重连服务端线程 /// </summary> private void LinkSocketSerFunc() { object lockobj = new object(); int heartBeatCount = 0; ClientLink = new SocketClientAsync(Client_IP, Client_Port, 0); bool NotFirstIn = false; while (ThreadContinue) { try { if (!ClientLinkRes) { isOnline = false; if (NotFirstIn) { ClientLink.CloseLinkServer(); ClientLink = new SocketClientAsync(Client_IP, Client_Port, 0); } NotFirstIn = true; ClientLink.OnMsgReceived += new SocketClientAsync.ReceiveMsgHandler(Client_OnMsgReceived);//绑定接受到服务端消息的事件 ClientLinkRes = ClientLink.ConnectServer(); } else { //此处写通讯成功的逻辑处理 } } catch (Exception ex) { ClientLinkRes = false; System.Diagnostics.Debug.WriteLine(ex.ToString()); } Thread.Sleep(1000); } } /// <summary> /// 接收消息处理 /// </summary> /// <param name="info"></param> /// <param name="num"></param> private void Client_OnMsgReceived(byte[] info, int num) { try { ClientHeartBeat = 0; if (info.Length > 0 && info[0] != 0)//BCR连接错误NO { //info为接受到服务器传过来的字节数组,需要进行什么样的逻辑处理在此书写便可 } else { ClientLinkRes = false; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } /// <summary> /// 终止服务 /// </summary> public void StopServer() { if (ClientLinkRes) { ThreadContinue = false; ClientLink.CloseLinkServer(); ClientLink.Dispose(); } }
这基本的Socket客户端后台就写完了,可以直接复制使用,平时都是用这么去写Socket客户端,分享出来,大家就可以直接使用了!
C#Socket客户端异步实现
简易封装
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net; using System.Net.Sockets; namespace dclient { public delegate void DelegateMsg(object msg); public class Client { private static Socket _clientSocket; private static string _server; private static int _port; public static DelegateMsg OnConnect; public static DelegateMsg OnSend; public static DelegateMsg OnReceive; public static DelegateMsg OnServerDown; public static DelegateMsg OnErr; public static void Connect() { try { _server = System.Configuration.ConfigurationManager.AppSettings["serverIp"]; _port = int.Parse(System.Configuration.ConfigurationManager.AppSettings["serverPort"]); IPEndPoint ip = new IPEndPoint(IPAddress.Parse(_server), _port); _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _clientSocket.BeginConnect(ip, new AsyncCallback(ConnectCallBack), _clientSocket); } catch (Exception e) { throw e; } } private static void ConnectCallBack(IAsyncResult iar) { Socket client = (Socket)iar.AsyncState; try { client.EndConnect(iar); OnConnect("已连接"); } catch (SocketException e) { if (e.ErrorCode == 10061) { OnErr("服务器程序未运行或服务器端口未开放"); } else { OnErr(e.Message); } } finally { } } public static void Send(string msg) { if (_clientSocket == null || msg == string.Empty) return; msg += "\r\n"; byte[] data = Encoding.UTF8.GetBytes(msg); try { _clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult => { int length = _clientSocket.EndSend(asyncResult); OnSend(string.Format("客户端发送消息:{0}", msg)); }, null); } catch (Exception e) { OnErr(e.Message); } } public static void Recive() { byte[] data = new byte[1024]; try { _clientSocket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => { try { int length = _clientSocket.EndReceive(asyncResult); OnReceive(string.Format("收到服务器消息:长度:{1},{0}", Encoding.UTF8.GetString(data), length)); Recive(); } catch (SocketException e) { if (e.ErrorCode == 10054) { OnServerDown("服务器已断线"); } else { OnErr(e.Message); } } }, null); } catch (Exception ex) { OnErr(ex.Message); } } } }
使用
public partial class Form1 : Form { public Form1() { InitializeComponent(); Client.OnConnect += new DelegateMsg(connect); Client.OnSend += new DelegateMsg(send); Client.OnReceive += new DelegateMsg(receive); Client.OnServerDown += new DelegateMsg(svrdown); Client.OnErr += new DelegateMsg(onerr); } private void Form1_Load(object sender, EventArgs e) { Client.Connect(); } private void connect(object msg) { System.Diagnostics.Debug.WriteLine(msg.ToString()); Client.Send("DALO 发送测试"); Client.Recive(); } private void send(object msg) { System.Diagnostics.Debug.WriteLine(msg.ToString()); } private void receive(object msg) { System.Diagnostics.Debug.WriteLine(msg.ToString()); } private void svrdown(object msg) { System.Diagnostics.Debug.WriteLine(msg.ToString()); } private void onerr(object msg) { System.Diagnostics.Debug.WriteLine(msg.ToString()); } }
未实现的几个常用操作
1、接收服务器发送的大数据量的合包。
2、服务器断线后客户端自动检测并重连,需先将_clientSocket释放。
3、心跳包。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
C#开发Windows UWP系列之对话框MessageDialog和ContentDialog
这篇文章介绍了C#开发Windows UWP系列之对话框MessageDialog和ContentDialog,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-06-06
最新评论