C# 三种方式实现Socket数据接收(经典)
之前一般采用如下方式进行数据接收:
int recv;//定义接收数据长度变量IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));//接收端所监听的接口,ip也可以用IPAddress.AnySocket 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),数据接收正常。
以下分别采用三种方式实现了数据的正常接收,代码如下:
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(); // 创建用于发送和接受数据的NetworkStreamvar 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.AnySocket 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.AnySocket 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){//实例化socketSocket 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("指令发送成功");}}}
测试:
Task.Run(() => {}); 这个可以去掉;
