以下文章来源于CSharp编程大全 ,作者zls365
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。即使尚未到达流的末尾,实现仍可以随意返回少于所请求的字节。
之前一般采用如下方式进行数据接收:
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),数据接收正常。
以下分别采用三种方式实现了数据的正常接收,代码如下:
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("指令发送成功"); | |
} | |
} | |
} |
测试:
Task.Run(() => {}); 这个可以去掉;