C# 三種方式實(shí)現(xiàn)Socket數(shù)據(jù)接收
Stream.Read 方法
當(dāng)在派生類中重寫時(shí),從當(dāng)前流讀取字節(jié)序列,并將此流中的位置提升讀取的字節(jié)數(shù)。
語(yǔ)法:
public abstract int Read(byte[] buffer, int offset, int count)
參數(shù):
buffer : 字節(jié)數(shù)組。此方法返回時(shí),該緩沖區(qū)包含指定的字符數(shù)組,該數(shù)組的 offset 和 ( offset + count -1) 之間的值由從當(dāng)前源中讀取的字節(jié)替換。
offset : buffer 中的從零開始的字節(jié)偏移量,從此處開始存儲(chǔ)從當(dāng)前流中讀取的數(shù)據(jù)。
count : 要從當(dāng)前流中最多讀取的字節(jié)數(shù)。
返回值:
讀入緩沖區(qū)中的總字節(jié)數(shù)。如果當(dāng)前可用的字節(jié)數(shù)沒(méi)有請(qǐng)求的字節(jié)數(shù)那么多,則總字節(jié)數(shù)可能小于請(qǐng)求的字節(jié)數(shù),或者如果已到達(dá)流的末尾,則為零 (0)。
備注:
此方法的實(shí)現(xiàn)從當(dāng)前流中讀取最多的 count 個(gè)字節(jié),并將它們存儲(chǔ)在從 offset 開始的 buffer 中。流中的當(dāng)前位置提升已讀取的字節(jié)數(shù);但是,如果出現(xiàn)異常,流中的當(dāng)前位置保持不變。實(shí)現(xiàn)返回已讀取的字節(jié)數(shù)。僅當(dāng)位置當(dāng)前位于流的末尾時(shí),返回值才為零。如果沒(méi)有任何可用的數(shù)據(jù),該實(shí)現(xiàn)將一直阻塞到至少有一個(gè)字節(jié)的數(shù)據(jù)可讀為止。僅當(dāng)流中不再有其他的數(shù)據(jù),而且也不再需要更多的數(shù)據(jù)(如已關(guān)閉的套接字或文件尾)時(shí), Read 才返回 0。 即使尚未到達(dá)流的末尾,實(shí)現(xiàn)仍可以隨意返回少于所請(qǐng)求的字節(jié)。
之前一般采用如下方式進(jìn)行數(shù)據(jù)接收:
int recv;//定義接收數(shù)據(jù)長(zhǎng)度變量
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));//接收端所監(jiān)聽的接口,ip也可以用IPAddress.Any
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化一個(gè)Socket對(duì)象
socket.Bind(ipEnd);//綁定套接字到一個(gè)IP地址和一個(gè)端口上(bind());
socket.Listen(10);
while (true)
{
byte[] data = new byte[1024];//對(duì)data清零
Socket clientSocket = socket.Accept(); //一旦接受連接,創(chuàng)建一個(gè)客戶端
recv = clientSocket.Receive(data);
if (recv == 0) //如果收到的數(shù)據(jù)長(zhǎng)度小于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";
});
}
之前用的時(shí)候沒(méi)發(fā)現(xiàn)什么問(wèn)題,但是今天在測(cè)試金屬門數(shù)據(jù)接收的時(shí)候發(fā)現(xiàn)會(huì)丟數(shù)據(jù),金屬門每隔十秒給我一次數(shù)據(jù),用上面這個(gè)差不多60秒才能收到一組數(shù)據(jù),針對(duì)以上問(wèn)題,做了如下修改:
將數(shù)據(jù)接收放到 while (true)
將數(shù)據(jù)接收放到 while (true),數(shù)據(jù)接收正常
以下分別采用三種方式實(shí)現(xiàn)了數(shù)據(jù)的正常接收,代碼如下:
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); // 當(dāng)前服務(wù)器使用的ip和端口
TcpListener tcpListener = new TcpListener(serverIPEndPoint);
tcpListener.Start();
Console.WriteLine("服務(wù)端已啟用......"); // 阻塞線程的執(zhí)行,直到一個(gè)客戶端連接
tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("已連接.");
stream = tcpClient.GetStream(); // 創(chuàng)建用于發(fā)送和接受數(shù)據(jù)的NetworkStream
var t1 = new Thread(ReceiveMsg);
t1.IsBackground = true;
t1.Start();
}
private void BGWorker_DoWork1()
{
//在這里執(zhí)行耗時(shí)的運(yùn)算。
int recv;//定義接收數(shù)據(jù)長(zhǎng)度變量
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));//接收端所監(jiān)聽的接口,ip也可以用IPAddress.Any
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化一個(gè)Socket對(duì)象
socket.Bind(ipEnd);//綁定套接字到一個(gè)IP地址和一個(gè)端口上(bind());
socket.Listen(10);
//創(chuàng)建監(jiān)聽線程
Thread thread = new Thread(Listen);
thread.IsBackground = true;
thread.Start(socket);
}
/// <summary>
/// 等待客戶端的連接 并且創(chuàng)建與之通信的Socket
/// </summary>
Socket socketSend;
void Listen(object o)
{
try
{
Socket socketWatch = o as Socket;
while (true)
{
socketSend = socketWatch.Accept();//等待接收客戶端連接
//開啟一個(gè)新線程,執(zhí)行接收消息方法
Thread r_thread = new Thread(Received);
r_thread.IsBackground = true;
r_thread.Start(socketSend);
}
}
catch { }
}
/// <summary>
/// 服務(wù)器端不停的接收客戶端發(fā)來(lái)的消息
/// </summary>
/// <param name="o"></param>
void Received(object o)
{
try
{
Socket socketSend = o as Socket;
while (true)
{
//客戶端連接服務(wù)器成功后,服務(wù)器接收客戶端發(fā)送的消息
byte[] buffer = new byte[1024 * 1024 * 3];
//實(shí)際接收到的有效字節(jié)數(shù)
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;//定義接收數(shù)據(jù)長(zhǎng)度變量
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));//接收端所監(jiān)聽的接口,ip也可以用IPAddress.Any
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化一個(gè)Socket對(duì)象
socket.Bind(ipEnd);//綁定套接字到一個(gè)IP地址和一個(gè)端口上(bind());
socket.Listen(10);
new Thread(delegate ()
{
Socket clientSocket = null;
while (true)
{
Stopwatch sw = new Stopwatch();
// 開始計(jì)時(shí)
sw.Start();
clientSocket = socket.Accept(); //一旦接受連接,創(chuàng)建一個(gè)客戶端
Task.Run(() =>
{
while (true)
{
byte[] data = new byte[50];//對(duì)data清零
recv = clientSocket.Receive(data, 0, data.Length, SocketFlags.None);
//if (recv == 0) //如果收到的數(shù)據(jù)長(zhǎng)度小于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";
});
//結(jié)束計(jì)時(shí)
sw.Stop();
long times = sw.ElapsedMilliseconds;
this.Invoke((EventHandler)delegate
{
richTextBox1.Text += "執(zhí)行查詢總共使用了" + times + "毫秒" + "\n";
});
}
});
}
})
{ IsBackground = true }.Start();
}
void ReceiveMsg()
{
byte[] buffer = new byte[1024]; // 預(yù)設(shè)最大接受1024個(gè)字節(jié)長(zhǎng)度,可修改
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)
{
//實(shí)例化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("指令發(fā)送成功");
}
}
}


到此這篇關(guān)于C# 三種方式實(shí)現(xiàn)Socket數(shù)據(jù)接收的文章就介紹到這了,更多相關(guān)C# 實(shí)現(xiàn)Socket數(shù)據(jù)接收內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)驗(yàn)證字符串的長(zhǎng)度的方法詳解
這篇文章主要為大家詳細(xì)介紹了C#如何使用正則表達(dá)或者計(jì)算字符數(shù)組長(zhǎng)度或字符串的長(zhǎng)度來(lái)驗(yàn)證驗(yàn)證字符串的長(zhǎng)度,感興趣的小伙伴可以學(xué)習(xí)一下2024-02-02
使用C#發(fā)送Http請(qǐng)求實(shí)現(xiàn)模擬登陸實(shí)例
本文主要介紹了使用C#發(fā)送Http請(qǐng)求實(shí)現(xiàn)模擬登陸實(shí)例,模擬登陸的原理簡(jiǎn)單,想要了解的朋友可以了解一下。2016-10-10
ScriptControl控件執(zhí)行自定義VBS腳本示例分析
這篇文章主要介紹ScriptControl控件 msscript.ocx msscript.oca執(zhí)行自定義VBS腳本的示例代碼,需要的朋友可以參考下2013-04-04
C#找不到類型名"SqlConnection"的有效解決方法
最近在使用c#鏈接SqlServer的時(shí)候遇到了錯(cuò)誤,通過(guò)查找相關(guān)資料終于解決了,所以下面這篇文章主要給大家介紹了關(guān)于C#找不到類型名"SqlConnection"的有效解決方法,需要的朋友可以參考下2023-02-02

