经常需要用socket读取设备的数据,包括现在很多串口转以太网的东西,需要发送数据事先定义好的字节数据,然后等待返回字节数据。发送和接收的数据往往是固定长度,并且短时间要收到回复的。于是就手动做这么一个简单的类。
使用方法很简单,new 一个socketclient同时定义好ip和端口,直接send(数据,超时时间,返回的数据长度),然后返回RetData,这里表明了返回是否成功,接收到的长度和数据
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Common { public class SocketClient { public SocketClient(string ip, int port) { Ip = ip; Port = port; //定义一个套字节监听 包含3个参数(IP4寻址协议,流式连接,TCP协议) socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); result = new RetData(); } //创建 1个客户端套接字 和1个负责监听服务端请求的线程 Socket socketClient = null; Thread threadClient = null; public EventHandler EvenNewData; string Ip = "127.0.0.1"; int Port = 8888; public bool Connected { get { return socketClient.Connected; } } byte[] DataBuf = new byte[1024 * 1024]; //定义一个1M的内存缓冲区 用于临时性存储接收到的信息 public byte[] Data { get { return DataBuf; } } //默认为0表示不检测接收数据长度,如果不为0表示数据接收超过这个长度才会触发接收完成事件 int _rcvDataLength = 0; //最大长度1024*1024 public int FixRcvLength { get { return _rcvDataLength; } set { if (value <= DataBuf.Length) _rcvDataLength = value; } } RetData result; public bool ConnectToServer() { //定义一个套字节监听 包含3个参数(IP4寻址协议,流式连接,TCP协议) //socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //需要获取文本框中的IP地址 IPAddress ipaddress = IPAddress.Parse(Ip); //将获取的ip地址和端口号绑定到网络节点endpoint上 IPEndPoint endpoint = new IPEndPoint(ipaddress, Port); //这里客户端套接字连接到网络节点(服务端)用的方法是Connect 而不是Bind if (!socketClient.Connected) { try { socketClient.Connect(endpoint); //创建一个线程 用于监听服务端发来的消息 threadClient = new Thread(RecMsg); //将窗体线程设置为与后台同步 threadClient.IsBackground = true; //启动线程 threadClient.Start(); } catch (Exception ex) { Log.WriteLogs(ex.Message.ToString()); return false; } } return socketClient.Connected; } public void DisconnectFromServer() { if (socketClient.Connected) socketClient.Disconnect(true); } /// <summary> /// 接收服务端发来信息的方法 /// </summary> private void RecMsg() { while (true) //持续监听服务端发来的消息 { //将客户端套接字接收到的数据存入内存缓冲区, 并获取其长度 int length = socketClient.Receive(DataBuf); //将数据拷贝,并根据已经接收到的数据数量累加到数据缓存区, Buffer.BlockCopy(DataBuf, 0, DataBuf, result.revLength, length); //累加已经接收到的数据长度 result.revLength += length; if (result.revLength >= FixRcvLength) {//如果累加的数据长度超过指定的长度 if (FixRcvLength == 0 || result.revLength == FixRcvLength) {//如果没有指定数据长度,或者累加的数据长度==指定的长度则触发事件,并发送数据,否则丢弃数据 byte[] arrData = new byte[result.revLength]; Array.Copy(DataBuf, arrData, result.revLength); result.Data = arrData; result.Code = 0; result.Message = "successful"; result.IsSuccessful = true; } result.revLength = 0; } } } /// <summary> /// 发送数据并等待返回数据 /// </summary> /// <param name="sendMsg">发送的字符串数据</param> /// <param name="monitorTime">等待的超时毫秒,如果超过时间还没收到返回指定的数据长度,则返回读取错误</param> /// <param name="returnBytes">等待返回的数据长度,0表示不管多长都返回</param> /// <returns></returns> public RetData Send(string sendMsg, int monitorTime, int returnBytes = 0) { byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg); return Send(sendMsg, monitorTime, returnBytes); } /// <summary> /// 发送数据并等待返回数据 /// </summary> /// <param name="sendMsg">发送的数据</param> /// <param name="monitorTime">等待的超时毫秒,如果超过时间还没收到返回指定的数据长度,则返回读取错误</param> /// <param name="returnBytes">等待返回的数据长度,0表示不管多长都返回</param> /// <returns></returns> public RetData Send(byte[] sendMsg, int monitorTime, int returnBytes = 0) { result = new RetData(); MonitorTime = monitorTime; FixRcvLength = returnBytes; if (socketClient != null) { if (!Connected) { ConnectToServer(); Thread.Sleep(500); } if (Connected) { //调用客户端套接字发送字节数组 socketClient.Send(sendMsg); //将发送的信息追加到聊天内容文本框中 } else { result.Message = "connect to server failure"; } Monitor(MonitorTime); } else { result.Message = "socketClient is null"; } return result; } /// <summary> /// 发送数据并等待返回数据 /// </summary> /// <param name="sendMsg">发送的数据</param> /// <param name="monitorTime">等待的超时毫秒,如果超过时间还没收到返回指定的数据长度,则返回读取错误</param> /// <param name="returnBytes">等待返回的数据长度,0表示不管多长都返回</param> /// <returns></returns> public Task<RetData> SendAsync(byte[] sendMsg, int monitorTime, int returnBytes = 0) { return Task.Run(() => { return Send(sendMsg, monitorTime, returnBytes) ; }); } int MonitorTime = 0; private void Monitor(int monitortime) { int _time = monitortime; while (!result.IsSuccessful && _time > 0) { Thread.Sleep(10); _time -= 10; } result.Message = "time out"; } ~SocketClient() { socketClient.Disconnect(false); socketClient.Dispose(); } } [Serializable] public class RetData { public bool IsSuccessful { get; set; } = false; public byte[] Data { get; set; } public string Message { get; set; } public int Code { get; set; } = 0; public int revLength { get; set; } = 0; } }