C#串口通信传输文件实例(带注释)

参考: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;
            }

        }

    }
}

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值