参考:https://www.cnblogs.com/s0611163/p/4137943.html
Client端与Server端窗体,如下图所示:
Client与Server握手状态描述:
程序主要用到的两个类:
System.IO.Ports.SerialPort和System.IO.FileStream
Client端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace SerialPortClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//串口资源
private static SerialPort serialPort = new SerialPort();
//文件
private static FileStream fs = null;
private static long index = 0;
private static long blockCount;
private static int size = 4095;//4095+1=2M
private static DateTime dt;
/// <summary>
/// 约定
/// </summary>
public enum Protocol
{
/// <summary>
/// Client端发送文件名
/// </summary>
Client_Send_FileName = 0,
/// <summary>
/// Client端发送数据块
/// </summary>
Client_Send_DataBlock = 1,
/// <summary>
/// Client端发送最后数据块
/// </summary>
Client_Send_Last_DataBlock = 2,
/// <summary>
/// Server端本次接受完毕
/// </summary>
Server_ThisTime_Received = 3,
/// <summary>
/// Server端结束
/// </summary>
Server_Reveived_Over = 4
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (string item in SerialPort.GetPortNames())
{
comb_ports.Items.Add(item);
}
comb_ports.SelectedIndex = 0;
int[] baudRateArr = { 110, 300, 600, 900, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000 };
foreach (int item in baudRateArr)
{
comb_baudRate.Items.Add(item);
}
comb_baudRate.SelectedItem = baudRateArr[7];
int[] dataBitsArr = { 5, 6, 7, 8 };
foreach (int item in dataBitsArr)
{
comb_dataBits.Items.Add(item);
}
comb_dataBits.SelectedItem = dataBitsArr[3];
StopBits[] stopBitsArr = { StopBits.One, StopBits.OnePointFive, StopBits.Two };
foreach (var item in stopBitsArr)
{
comb_stopBits.Items.Add(item);
}
comb_stopBits.SelectedItem = StopBits.One;
Parity[] parityArr = { Parity.None, Parity.Odd, Parity.Even, Parity.Mark, Parity.Space };
foreach (var item in parityArr)
{
comb_parity.Items.Add(item);
}
comb_parity.SelectedItem = Parity.None;
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
private void btn_openPort_Click_1(object sender, EventArgs e)
{
if (!serialPort.IsOpen)
{
//设置串口号
string serialName = comb_ports.SelectedItem.ToString();
serialPort.PortName = serialName;
//设置波特率
serialPort.BaudRate = Convert.ToInt32(comb_baudRate.SelectedItem.ToString());
//设置数据位
serialPort.DataBits = Convert.ToInt32(comb_dataBits.SelectedItem.ToString());
//设置停止位
switch (comb_stopBits.SelectedItem.ToString())
{
case "One":
serialPort.StopBits = StopBits.One;
break;
case "OnePointFive":
serialPort.StopBits = StopBits.OnePointFive;
break;
case "Two":
serialPort.StopBits = StopBits.Two;
break;
}
//设置校验和
switch (comb_parity.SelectedItem.ToString())
{
case "None":
serialPort.Parity = Parity.None;
break;
case "Odd":
serialPort.Parity = Parity.Odd;
break;
case "Even":
serialPort.Parity = Parity.Even;
break;
case "Mark":
serialPort.Parity = Parity.Mark;
break;
case "Space":
serialPort.Parity = Parity.Space;
break;
}
if (serialPort.IsOpen == true)
{
serialPort.Close();
}
serialPort.Open();
//设置控件状态
btn_openPort.Text = "关闭串口";
btn_openPort.BackColor = Color.FromArgb(148, 148, 194);
comb_ports.Enabled = false;
comb_baudRate.Enabled = false;
comb_dataBits.Enabled = false;
comb_stopBits.Enabled = false;
comb_parity.Enabled = false;
}
else
{
serialPort.Close(); //关闭串口
btn_openPort.Text = "打开串口";
btn_openPort.BackColor = Color.FromArgb(229, 241, 251);
comb_ports.Enabled = true;
comb_baudRate.Enabled = true;
comb_dataBits.Enabled = true;
comb_stopBits.Enabled = true;
comb_parity.Enabled = true;
}
}
private void btn_openFile_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
txt_filePath.Text = openFileDialog1.FileName;
}
}
/// <summary>
/// Client接受串口数据事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort.BytesToRead == 0) return;
int bt = serialPort.ReadByte();//从System.IO.Ports.SerialPort输入缓冲区中同步读取一个字节 读取握手状态
switch (bt)
{
case (int)Protocol.Server_ThisTime_Received://Server接受到
if (index != blockCount - 1)//判断是否最后一次发送数据块
{
byte[] bArr = new byte[size + 1];//创建一个4Kb的byte[]
bArr[0] = (int)Protocol.Client_Send_DataBlock;//告知Server发送数据块
fs.Read(bArr, 1, size);//每次读入4Kb
index++;
Thread.Sleep(1);
serialPort.Write(bArr, 0, bArr.Length);//每次发送4Kb
}
else
{
byte[] bArr = new byte[fs.Length - (size * index) + 1];
bArr[0] = (int)Protocol.Client_Send_Last_DataBlock;//告知Server发送最后一次数据块
fs.Read(bArr, 1, bArr.Length - 1);
index++;
serialPort.Write(bArr, 0, bArr.Length);
}
break;
case (int)Protocol.Server_Reveived_Over://Server接受完毕
index = 0;
double totalSeconds = DateTime.Now.Subtract(dt).TotalSeconds;//计算从点击发送按钮时到发送完毕的时间
MessageBox.Show("完成,耗时" + totalSeconds + "秒,速度" + (fs.Length / 1024.0 / totalSeconds).ToString("#.0") + "KB/S");
fs.Close();
fs.Dispose();
break;
}
}
private void btn_sendData_Click(object sender, EventArgs e)
{
dt = DateTime.Now;//点击发送按钮记录开始时间
fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);//实例化FileStream
blockCount = (fs.Length - 1) / size + 1;//计算FileStream需要发送多少次 如文件大小18Kb每次发送4Kb则需要发送5次
List<byte> bList = new List<byte>();
bList.Add((int)Protocol.Client_Send_FileName);//第一个字节为约定 记录Client-Server握手
bList.AddRange(ASCIIEncoding.UTF8.GetBytes(openFileDialog1.FileName));//文件名
byte[] bArr = bList.ToArray();
serialPort.Write(bArr, 0, bArr.Length);//发送
}
}
}
Server端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SerialPortServer
{
public partial class Form1 : Form
{
#region 变量
/// <summary>
/// 串口资源
/// </summary>
private static SerialPort serialPort = new SerialPort();
/// <summary>
/// 文件
/// </summary>
private static FileStream fs = null;
/// <summary>
/// 文件路径
/// </summary>
private static string filePath = "";
/// <summary>
/// 约定
/// </summary>
public enum Protocol
{
/// <summary>
/// Client端发送文件名
/// </summary>
Client_Send_FileName = 0,
/// <summary>
/// Client端发送数据块
/// </summary>
Client_Send_DataBlock = 1,
/// <summary>
/// Client端发送最后数据块
/// </summary>
Client_Send_Last_DataBlock = 2,
/// <summary>
/// Server端本次接受完毕
/// </summary>
Server_ThisTime_Received = 3,
/// <summary>
/// Server端结束
/// </summary>
Server_Reveived_Over = 4
}
#endregion
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (string item in SerialPort.GetPortNames())
{
comb_ports.Items.Add(item);
}
comb_ports.SelectedIndex = 0;
int[] baudRateArr = { 110, 300, 600, 900, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000 };
foreach (int item in baudRateArr)
{
comb_baudRate.Items.Add(item);
}
comb_baudRate.SelectedItem = baudRateArr[7];
int[] dataBitsArr = { 5, 6, 7, 8 };
foreach (int item in dataBitsArr)
{
comb_dataBits.Items.Add(item);
}
comb_dataBits.SelectedItem = dataBitsArr[3];
StopBits[] stopBitsArr = { StopBits.One, StopBits.OnePointFive, StopBits.Two };
foreach (var item in stopBitsArr)
{
comb_stopBits.Items.Add(item);
}
comb_stopBits.SelectedItem = StopBits.One;
Parity[] parityArr = { Parity.None, Parity.Odd, Parity.Even, Parity.Mark, Parity.Space };
foreach (var item in parityArr)
{
comb_parity.Items.Add(item);
}
comb_parity.SelectedItem = Parity.None;
filePath = Application.StartupPath + "\\_临时文件";
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
private void btn_openPort_Click_1(object sender, EventArgs e)
{
if (!serialPort.IsOpen)
{
//设置串口号
string serialName = comb_ports.SelectedItem.ToString();
serialPort.PortName = serialName;
//设置波特率
serialPort.BaudRate = Convert.ToInt32(comb_baudRate.SelectedItem.ToString());
//设置数据位
serialPort.DataBits = Convert.ToInt32(comb_dataBits.SelectedItem.ToString());
//设置停止位
switch (comb_stopBits.SelectedItem.ToString())
{
case "One":
serialPort.StopBits = StopBits.One;
break;
case "OnePointFive":
serialPort.StopBits = StopBits.OnePointFive;
break;
case "Two":
serialPort.StopBits = StopBits.Two;
break;
}
//设置校验和
switch (comb_parity.SelectedItem.ToString())
{
case "None":
serialPort.Parity = Parity.None;
break;
case "Odd":
serialPort.Parity = Parity.Odd;
break;
case "Even":
serialPort.Parity = Parity.Even;
break;
case "Mark":
serialPort.Parity = Parity.Mark;
break;
case "Space":
serialPort.Parity = Parity.Space;
break;
}
if (serialPort.IsOpen == true)
{
serialPort.Close();
}
serialPort.Open();
//设置控件状态
btn_openPort.Text = "关闭串口";
btn_openPort.BackColor = Color.FromArgb(148, 148, 194);
comb_ports.Enabled = false;
comb_baudRate.Enabled = false;
comb_dataBits.Enabled = false;
comb_stopBits.Enabled = false;
comb_parity.Enabled = false;
}
else
{
serialPort.Close(); //关闭串口
btn_openPort.Text = "打开串口";
btn_openPort.BackColor = Color.FromArgb(229, 241, 251);
comb_ports.Enabled = true;
comb_baudRate.Enabled = true;
comb_dataBits.Enabled = true;
comb_stopBits.Enabled = true;
comb_parity.Enabled = true;
}
}
/// <summary>
/// Server接受事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
if (serialPort.BytesToRead == 0) return;
#region 接收数据
int bt = serialPort.ReadByte();//从System.IO.Ports.SerialPort输入缓冲区同步读取一个字节 读取握手状态
List<byte> bList = new List<byte>();
while (serialPort.BytesToRead > 0)
{
byte[] bArr = new byte[serialPort.BytesToRead];
serialPort.Read(bArr, 0, bArr.Length);
bList.AddRange(bArr);//循环读取接受缓冲区数据
}
byte[] receiveData = bList.ToArray();//接受到的数据
#endregion
switch (bt)
{
case (int)Protocol.Client_Send_FileName://Client 发送文件名 握手状态
string path = ASCIIEncoding.UTF8.GetString(receiveData);
string fileName = Path.GetFileName(path);
fs = new FileStream(filePath + "\\" + fileName, FileMode.Create, FileAccess.Write);//指定FileStream对象,用于接受Client端发送的数据
byte[] bArr = new byte[1];
bArr[0] = (int)Protocol.Server_ThisTime_Received;
serialPort.Write(bArr, 0, bArr.Length);
break;
case (int)Protocol.Client_Send_DataBlock://Client 发送数据块 握手状态
fs.Write(receiveData, 0, receiveData.Length);
fs.Flush();
bArr = new byte[1];
bArr[0] = (int)Protocol.Server_ThisTime_Received;
serialPort.Write(bArr, 0, bArr.Length);
break;
case (int)Protocol.Client_Send_Last_DataBlock://Client 发送最后数据库 握手状态
fs.Write(receiveData, 0, receiveData.Length);//通过FileStream将读取的数据写入本地
fs.Flush();
bArr = new byte[1];
bArr[0] = (int)Protocol.Server_Reveived_Over;//告知Client Server接受完毕
serialPort.Write(bArr, 0, bArr.Length);
fs.Close();
fs.Dispose();
break;
}
}
}
}