C# 三种方式实现Socket数据接收(经典)
Stream.Read 方法
当在派生类中重写时,从当前流读取字节序列,并将此流中的位置提升读取的字节数。
语法:
public abstract int Read(byte[] buffer, int offset, int count)
参数:
-
buffer: 字节数组。此方法返回时,该缓冲区包含指定的字符数组,该数组的 offset 和 (offset + count -1) 之间的值由从当前源中读取的字节替换。
-
offset: buffer 中的从零开始的字节偏移量,从此处开始存储从当前流中读取的数据。
-
count: 要从当前流中最多读取的字节数。
返回值:
读入缓冲区中的总字节数。如果当前可用的字节数没有请求的字节数那么多,则总字节数可能小于请求的字节数,或者如果已到达流的末尾,则为零 (0)。
备注:
此方法的实现从当前流中读取最多的 count 个字节,并将它们存储在从 offset 开始的 buffer 中。流中的当前位置提升已读取的字节数;但是,如果出现异常,流中的当前位置保持不变。实现返回已读取的字节数。仅当位置当前位于流的末尾时,返回值才为零。如果没有任何可用的数据,该实现将一直阻塞到至少有一个字节的数据可读为止。仅当流中不再有其他的数据,而且也不再需要更多的数据(如已关闭的套接字或文件尾)时,Read 才返回 0。即使尚未到达流的末尾,实现仍可以随意返回少于所请求的字节。
之前一般采用如下方式进行数据接收:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | int recv; //定义接收数据长度变量 IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int .Parse(textBox2.Text)); //接收端所监听的接口,ip也可以用IPAddress.Any Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //初始化一个Socket对象 socket.Bind(ipEnd); //绑定套接字到一个IP地址和一个端口上(bind()); socket.Listen(10); while ( true ) { byte [] data = new byte [1024]; //对data清零 Socket clientSocket = socket.Accept(); //一旦接受连接,创建一个客户端 recv = clientSocket.Receive(data); if (recv == 0) //如果收到的数据长度小于0,则退出 break ; string stringData = "0x" + BitConverter.ToString(data).Replace( "-" , " 0x" ).ToLower(); this .Invoke((EventHandler) delegate { richTextBox1.Text += DateTime.Now.ToString( "yy-MM-dd hh:mm:ss" ) + stringData + "\n" ; }); } |
之前用的时候没发现什么问题,但是今天在测试金属门数据接收的时候发现会丢数据,金属门每隔十秒给我一次数据,用上面这个差不多60秒才能收到一组数据,针对以上问题,做了如下修改:
将数据接收放到 while (true),数据接收正常。
以下分别采用三种方式实现了数据的正常接收,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace MetalGate { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private BackgroundWorker demoBGWorker = new BackgroundWorker(); static TcpClient tcpClient; static NetworkStream stream; private void MainForm_Load( object sender, EventArgs e) { textBox1.Text = "192.168.1.99" ; textBox2.Text = "8234" ; } //private void BGWorker_DoWork(object sender, DoWorkEventArgs e) private void BGWorker_DoWork() { var serverIPEndPoint = new IPEndPoint(IPAddress.Parse( "192.168.1.99" ), 8234); // 当前服务器使用的ip和端口 TcpListener tcpListener = new TcpListener(serverIPEndPoint); tcpListener.Start(); Console.WriteLine( "服务端已启用......" ); // 阻塞线程的执行,直到一个客户端连接 tcpClient = tcpListener.AcceptTcpClient(); Console.WriteLine( "已连接." ); stream = tcpClient.GetStream(); // 创建用于发送和接受数据的NetworkStream var t1 = new Thread(ReceiveMsg); t1.IsBackground = true ; t1.Start(); } private void BGWorker_DoWork1() { //在这里执行耗时的运算。 int recv; //定义接收数据长度变量 IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int .Parse(textBox2.Text)); //接收端所监听的接口,ip也可以用IPAddress.Any Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //初始化一个Socket对象 socket.Bind(ipEnd); //绑定套接字到一个IP地址和一个端口上(bind()); socket.Listen(10); //创建监听线程 Thread thread = new Thread(Listen); thread.IsBackground = true ; thread.Start(socket); } /// <summary> /// 等待客户端的连接 并且创建与之通信的Socket /// </summary> Socket socketSend; void Listen( object o) { try { Socket socketWatch = o as Socket; while ( true ) { socketSend = socketWatch.Accept(); //等待接收客户端连接 //开启一个新线程,执行接收消息方法 Thread r_thread = new Thread(Received); r_thread.IsBackground = true ; r_thread.Start(socketSend); } } catch { } } /// <summary> /// 服务器端不停的接收客户端发来的消息 /// </summary> /// <param name="o"></param> void Received( object o) { try { Socket socketSend = o as Socket; while ( true ) { //客户端连接服务器成功后,服务器接收客户端发送的消息 byte [] buffer = new byte [1024 * 1024 * 3]; //实际接收到的有效字节数 int len = socketSend.Receive(buffer); if (len == 0) { break ; } // string str = Encoding.UTF8.GetString(buffer, 0, len); string stringData = "0x" + BitConverter.ToString(buffer, 0, len).Replace( "-" , " 0x" ).ToLower(); this .Invoke((EventHandler) delegate { richTextBox1.Text += DateTime.Now.ToString( "yy-MM-dd hh:mm:ss -*- " ) + stringData + "\n" ; }); } } catch { } } private void BGWorker_DoWork2() { int recv; //定义接收数据长度变量 IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int .Parse(textBox2.Text)); //接收端所监听的接口,ip也可以用IPAddress.Any Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //初始化一个Socket对象 socket.Bind(ipEnd); //绑定套接字到一个IP地址和一个端口上(bind()); socket.Listen(10); new Thread( delegate () { Socket clientSocket = null ; while ( true ) { Stopwatch sw = new Stopwatch(); // 开始计时 sw.Start(); clientSocket = socket.Accept(); //一旦接受连接,创建一个客户端 Task.Run(() => { while ( true ) { byte [] data = new byte [50]; //对data清零 recv = clientSocket.Receive(data, 0, data.Length, SocketFlags.None); //if (recv == 0) //如果收到的数据长度小于0,则退出 // break; string stringData = "0x" + BitConverter.ToString(data, 0, recv).Replace( "-" , " 0x" ).ToLower(); this .Invoke((EventHandler) delegate { richTextBox1.Text += DateTime.Now.ToString( "yy-MM-dd hh:mm:ss -*- " ) + stringData + "\n" ; }); //结束计时 sw.Stop(); long times = sw.ElapsedMilliseconds; this .Invoke((EventHandler) delegate { richTextBox1.Text += "执行查询总共使用了" + times + "毫秒" + "\n" ; }); } }); } }) { IsBackground = true }.Start(); } void ReceiveMsg() { byte [] buffer = new byte [1024]; // 预设最大接受1024个字节长度,可修改 int count = 0; try { while ((count = stream.Read(buffer, 0, buffer.Length)) != 0) { string stringData = "0x" + BitConverter.ToString(buffer, 0, count).Replace( "-" , " 0x" ).ToLower(); Console.WriteLine($ "{tcpClient.Client.LocalEndPoint.ToString()}:{DateTime.Now.ToString(" yy-MM-dd hh:mm:ss -*- ") + stringData + " \n "}" ); this .Invoke((EventHandler) delegate { richTextBox1.Text += DateTime.Now.ToString( "yy-MM-dd hh:mm:ss -*- " ) + stringData + "\n" ; }); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } private void SendData(IPAddress remoteIP, int Port, byte [] bits) { //实例化socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ipep = new IPEndPoint(remoteIP, Port); socket.Connect(ipep); //socket.Send(bits, 8, SocketFlags.None); socket.Send(bits); socket.Close(); } private void btnListen_Click( object sender, EventArgs e) { //demoBGWorker.DoWork += BGWorker_DoWork; //demoBGWorker.RunWorkerAsync(); //Task.Run(() => // { BGWorker_DoWork2(); //}); } private void btnSend_Click( object sender, EventArgs e) { byte [] order = new byte [8]; order = new byte [] { 0x80, 0x04, 0x00, 0x7F }; SendData(IPAddress.Parse( "192.168.1.100" ), int .Parse( "49558" ), order); MessageBox.Show( "指令发送成功" ); } } } |
----------------------------------------------------
以上就是本节的全部内容,如果感觉有用,请多多的点击在看和分享,需要进技术交流群的,请加小编微信zls20210502,切记备注 进群!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)