/*
串口基础--简单文件传输协议--主机部分
从机部分:devtranfile.h
          devtranfile.c
新建工程名称:UartSendFile
时间:2013年5月23日 第一个版本
*/

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;             //使用Thread类来创建和控制线程
using System.Windows.Forms;
namespace UartSendFile
{
    public partial class Form1 : Form
    {
        /*********************************************************************************
        *********************************************************************************/
        #region //窗口的起动 关闭
        public Form1()
        {
            InitializeComponent();
        }
        //窗口起动事件
        private void Form1_Load(object sender, EventArgs e)
        {
            int i = 0;
            comboBox_comx.Items.Clear();
            while(i++<20)
            {
                comboBox_comx.Items.Add("COM" + i.ToString());
            }

comboBox_baudrate.Items.Clear();
            comboBox_baudrate.Items.Add("1200");
            comboBox_baudrate.Items.Add("2400");
            comboBox_baudrate.Items.Add("4800");
            comboBox_baudrate.Items.Add("9600");
            comboBox_baudrate.Items.Add("19200");
            comboBox_baudrate.Items.Add("38400");
            comboBox_baudrate.Items.Add("57600");
            comboBox_baudrate.Items.Add("115200");
            textBox_path.Text = "请选择文件..";
            textBox_message.Text = "消息...";
            textBox_message.Enabled = false;
        }
        //关闭事件
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (PortIsOpend == true)
            {
                PortIsOpend = false;
                serialPort1.Close();
            }
        }
        #endregion
       
        /*********************************************************************************
        *********************************************************************************/
        #region //串口相关操作
        string PortSelected;        //当前选中的串口名:COMx
        int BaudRate;               //波特率
        bool PortIsOpend = false;   //串口当前状态
        //【按钮】:打开串口,关闭串口
        private void butSirPort_Click(object sender, EventArgs e)
        {
            //获取当前波特率
            string baud = comboBox_baudrate.Text;
            serialPort1.BaudRate = Convert.ToInt32(baud.Trim());     //若baud非纯数组,会抛异常
            BaudRate = serialPort1.BaudRate;
            PortSelected = comboBox_comx.Text;

if (PortIsOpend == false)
            {
                try
                {
                    serialPort1.PortName = PortSelected;  //PortSelected==""  会异常
                    serialPort1.Open();
                    butSirPort.Text = "关闭串口";
                    label_Port.Text = "串口已经打开";
                    PortIsOpend = true;

comboBox_baudrate.Enabled = false;
                    comboBox_comx.Enabled = false;
                }
                catch (Exception ee)
                {
                    ee.GetType();
                    label_Port.Text = "连接失败";
                    PortIsOpend = false;
                }
            }
            else
            {
                backgroundWorker.CancelAsync();
                butSirPort.Text = "打开串口";
                label_Port.Text = "串口已经关闭";
                PortIsOpend = false;
                comboBox_baudrate.Enabled = true;
                comboBox_comx.Enabled = true;
                serialPort1.Close();
            }
        }
        //串口接收数据函数
        public int usartRevData(byte[] revdata, int len)
        {
            int unm = 0;
            if (serialPort1.IsOpen == false)
            {
                return 0;
            }
            serialPort1.ReadTimeout = 1;                    //接收超时1MS
            try
            {
                int cnt = 0;
                unm = 0;
                while (true)
                {   //没有可以读取的则退出
                    cnt = serialPort1.BytesToRead;
                    if (cnt <= 0)
                    {
                        break;
                    }
                    //使用最小空间储存
                    cnt = (len > cnt) ? (cnt) : (len);
                    //revdata存数据 unm存个数
                    cnt = serialPort1.Read(revdata, unm, cnt);
                    unm += cnt;
                    //计算剩余空间长度
                    len = len - cnt;
                    if (len <= 0)
                    {
                        break;
                    }
                    //等待未接收完的数据就绪
                    int t = 4 * 10 * 1000 / BaudRate;   //接收4个数据的时间
                    Thread.Sleep(t + 1);                //多给1毫秒
                }
            }
            catch (Exception e)
            {
                e.GetType();
                unm = 0;
            }
            return unm;
        }
        public int usartRevDatas(byte[] revdata, int len, int timeout)
        {
            int i = 0;
            while (true)
            {
                i = usartRevData(revdata, len);
                if (i > 0 || timeout == 0)
                {
                    break;
                }
                timeout--;
                Thread.Sleep(1);
            }
            return i;
        }
        #endregion
       
        /*********************************************************************************
        *********************************************************************************/
        #region //文件的读取操作
        string sendfilename = "";       //要发送的文件名
        string sendfilepath = "";       //要发送的文件路径+文件名
        //【按钮】 选择文件
        private void but_filepath_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofl = new OpenFileDialog();
            if (ofl.ShowDialog() == DialogResult.OK)            //OK表示按下了“打开”   
            {
                sendfilepath = ofl.FileName;
                sendfilename = ofl.SafeFileName;
                textBox_path.Text = sendfilepath;

FileStream fs = File.OpenRead(sendfilepath);
                int i = (int)fs.Length;
                label_filelen.Text = "文件大小:" + i.ToString() + "字节";
            }
        }
        private void button_send_Click(object sender, EventArgs e)
        {
            //检测串口
            if (PortIsOpend == false)
            {
                ShowMessage("请先打开串口");
                return;
            }

//检测文件
            if (sendfilename == "")
            {
                ShowMessage("请选择文件..");
                return;
            }

//检测状态
            if (issending==true)
            {
                ShowMessage("正在传输文件,请等待...");
                return;
            }
            backgroundWorker.RunWorkerAsync();
        }
        #endregion
       
        /*********************************************************************************
        *********************************************************************************/
        #region //后台处理操作,用于显示消息,进度等
        //在调用backgroundWorker.RunWorkerAsync()后,将执行本函数。
        //本函数可以执行阻塞事件,不影响主线程
        string backgroundWorkermsg = "";            //用于传递消息
        bool issending = false;                     //是否正在传输文件标志
        private void backgroundWorker_ShowMsg(string msg)
        {
            backgroundWorkermsg = msg;
            backgroundWorker.ReportProgress(101);
        }
        //在调用backgroundWorker.ReportProgress()后,将执行本函数。需要在属性ProgressChanged中添加本函数
        //本函数是主线程函数了
        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage > 100)
            {
                ShowMessage(backgroundWorkermsg);
            }
            else
            {
                progressBar.Value = e.ProgressPercentage;
            }
        }

//在DoWork退出时被调用后,需要在属性RunWorkerCompleted中添加本函数
        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar.Value = 0;
            issending = false;
        }
        private void ShowMessage(string msg)
        {
            textBox_message.Text = msg;
        }
        #endregion

/*********************************************************************************
        *********************************************************************************/
        #region //文件传输操作
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            bool ret;
            //有线程在操作,则提出
            if (issending == true)
            {
                return;
            }
            issending = true;
            backgroundWorker_ShowMsg("正在传输文件:" + sendfilename);
           
            FileStream fs = File.OpenRead(sendfilepath);
            fdata = new byte[fs.Length];
            fs.Read(fdata, 0, fdata.Length);                //将数据读取到fdata

//第一步:发送文件名
            ret = sf_filename(sendfilename);
            if (ret == false)
            {
                backgroundWorker_ShowMsg("文件名发送超时:" + sendfilename);
                return;
            }
            //第二步:发送文件内容
            if (true == sf_filedata())
            {
                backgroundWorker_ShowMsg("发送文:" + sendfilename + "成功");
            }
            else
            {
                backgroundWorker_ShowMsg("发送文:" + sendfilename + "失败");
            }
            backgroundWorker.ReportProgress(100);
        }
        //发送文件内容
        byte[] fdata;                       //文件内容
        byte[] SendPkg = new byte[256+100]; //每次传输的数据包
        private bool sf_filedata()
        {
            int flen = fdata.Length;
            int fcnt = 1;               //当前发送的包数(从1开始)
            int per = 0;                //百分比。
            int perbe = 0;                //百分比。
            SendPkg[0] = 0xAA;
            SendPkg[1] = 0xff;      //校验值
            SendPkg[2] = 0xff;      //目的地
            SendPkg[3] = 0x01;      //类型,==1文件传输
            int timeout = 0;
            while (true)
            {
                SendPkg[4] = (byte)fcnt;        //!=0,表示传输的是文件
                SendPkg[5] = (byte)(fcnt >> 8);
                SendPkg[6] = (byte)(fcnt >> 16);
                SendPkg[7] = (byte)(fcnt >> 24);

//数据包装载
                int j;
                if (flen - fcnt * 256 > 0)
                {
                    //剩余发送数据大于256
                    j = 256;
                }
                else
                {
                    //剩余发送数据小于256
                    j = fcnt * 256 - flen;
                    if (j >= 256)
                    {
                        //数据发送完毕
                        return sf_fileEnd();
                    }
                    j = 256 - j;
                }
                int i;
                int starts;                             //起始位置
                starts = (fcnt - 1) * 256;
                for (i = 0; i < j; i++)
                {
                    SendPkg[8 + i] = fdata[starts + i];
                }
                SendPkg[1] = MathXor_2(SendPkg, j + 8);
                //发送数据包
                serialPort1.Write(SendPkg, 0, j + 8);
                //接收返回信号
                int sf_ret;
                sf_ret = sf_file_ret(1000);

if (sf_ret != 0)
                {
                    timeout = 0;
                }
                switch(sf_ret)
                {
                    case 0:     //接收数据超时
                        timeout++;
                        if (timeout > 10)       //10次后结束传输
                        {
                            return false;
                        }
                        break;
                    case 5:     //发送成功
                                fcnt++;
                        break;
                    case 4:     //请求重新发送
                        break;
                    case 6:     //请求结束发送
                        return true;
                    default:    //其他情况,发送失败
                        break;
                }
                //百分比
                per = flen / 256;           //总报数
                per = fcnt * 100 / per;     //百分比
                if (perbe != per)
                {
                    perbe = per;
                    backgroundWorker.ReportProgress(perbe);
                }
            }
        }

//传输文件名
        private bool sf_filename(string sendfilename)
        {
            SendPkg[0] = 0xAA;
            SendPkg[1] = 0xff;      //校验值
            SendPkg[2] = 0xff;      //目的地
            SendPkg[3] = 0x01;      //类型,==1文件传输
           
            SendPkg[4] = 0x00;      //==0,表示传输的是文件名
            SendPkg[5] = 0x00;      //
            SendPkg[6] = 0x00;      //
            SendPkg[7] = 0x00;      //
            int len = sendfilename.Length;
            if (len > 256)
            {
                return false;
            }

//获取文件名
            byte[] tmp;
            tmp = System.Text.Encoding.Default.GetBytes(sendfilename);
            int i;
            for (i = 0; i < len; i++)
            {
                SendPkg[8 + i] = tmp[i];
            }

len += 8; //整包长度
            SendPkg[1] = MathXor_2(SendPkg, len);

//尝试30次
            i = 0;
            while (i++ <= 30)
            {
                //发送数据包
                serialPort1.Write(SendPkg, 0, len);

if (5 == sf_file_ret(1000))
                {
                    //发送成功
                    return true;
                }
                backgroundWorker_ShowMsg("发送文件名:" + sendfilename + "无应答倒计时:" + (30 - i).ToString());
            }
            //发送失败
            return false;
        }

//传输结束信号
        private bool sf_fileEnd()
        {
            SendPkg[0] = 0xAA;
            SendPkg[1] = 0xff;      //校验值
            SendPkg[2] = 0xff;      //目的地
            SendPkg[3] = 0x01;      //类型,==1文件传输

SendPkg[4] = 0xff;      //==0,表示传输的是文件名
            SendPkg[5] = 0xff;      //
            SendPkg[6] = 0xff;      //
            SendPkg[7] = 0xff;      //

SendPkg[1] = MathXor_2(SendPkg, 8);

//尝试5次
            int i = 0;
            while (i++ <= 5)
            {
                //发送数据包
                serialPort1.Write(SendPkg, 0, 8);

int fs_ret=sf_file_ret(1000);
                if (5 == fs_ret)
                {
                    //发送成功
                    return true;
                }
            }
            //发送失败
            return false;
        }

//---------对从机的返回数据处理-------
        //==0 没有收到数据
        //==1 校验错误
        //==2 返回的id不对
        //==3 类型不是文件传输
        //==4 从机 请求重新传数据
        //==5 从机接收OK
        //==6 停止传输
        //>=7 未定义
        int sf_file_ret(int timeout)
        {
            byte[] tmp = new byte[256 + 100];
            int i = usartRevDatas(tmp,256+100,timeout);
            if (i <= 0)
            {
                return 0;
            }
            if (tmp[1] != MathXor_2(tmp, i))
            {
                return 1;
            }
            //if()  rtrurn 2
            if (tmp[3] != 1)
            {
                return 3;
            }
            if (tmp[4] == 0xa5)     //重新传
            {
                return 4;
            }
            if (tmp[4] == 0xaa)     //ok
            {
                return 5;
            }
            if (tmp[4] == 0x55)     //停止传输
            {
                return 6;
            }
            return 7;
        }

//从第二个地方开始异或值
        byte MathXor_2(byte[] xordata, int len)
        {
            int i = 0;
            byte xor = 0;
            byte tmp;
            i = 2;
            len -= 2;
            while (len-- > 0)
            {
                tmp = xordata[i++];
                xor = (byte)(xor ^ tmp);
            }
            return xor;
        }
        byte MathXor(byte[] xordata, int len)
        {
            int i = 0;
            byte xor = 0;
            byte tmp;
            while (len-- <= 0)
            {
                tmp = xordata[i++];
                xor = (byte)(xor ^ tmp);
            }
            return xor;
        }
        #endregion
    }
}

简单文件传输协议--主机部分--patr1相关推荐

  1. LinuxProbe 0x14 虚拟网站主机功能(基于端口)、Vsftpd服务传输文件、TFTP简单文件传输协议

    虚拟网站主机功能 基于端口号 基于端口号的虚拟主机功能可以让用户通过指定的端口号来访问服务器上的网站资源.在使用Apache配置虚拟网站主机功能时,基于端口号的配置方式是最复杂的. 因此我们不仅要考虑 ...

  2. 简单文件传输协议TFTP分析还原

    " 介绍TFTP协议及传输内容的还原." TFTP,全称为Trivial File Transfer Protocol,即简单文件传输协议,是一个用来在客户端与服务器之间进行简单文 ...

  3. TFTP 简单文件传输协议

    1 协议介绍: TFTP (Trivial File Transfer Protocol, 简单文件传输协议也称小型文件传输协议) 是一种于1981年在RFC 783中定义的简化的文件传输协议(FTP ...

  4. 简单文件传输协议TFTP

    一.简单文件传输协议介绍 文件传输协议规范了本地从远程服务器上访问文件的方式. 文件传输协议分为两类:1.online-access 和 2.whole file copying.前者的代表协议为NF ...

  5. 计算机网络之应用层:3、文件传输协议FTP、简单文件传输协议TFTP

    应用层:3.FTP.TFTP FTP要解决的问题: 文件传输协议: FTP客户端和服务器: FTP工作原理: FTP要解决的问题: 1.不同计算机存储数据的格式不同 2.文件的目录结构和文件的命名规则 ...

  6. 华为数通笔记-文件传输协议FTP

    文件传输协议 主机之间传输文件是IP网络的一个重要功能,如今人们可以方便地使用网页.邮箱进行文件传输. 然而在互联网早期,Web(World Wide Web,万维网)还未出现,操作系统使用命令行的时 ...

  7. 文件传输协议FTP/TFTP/SSH/SCP——应用层

    常见的文件传输协议:FTP.TFTP.SSH.SCP 一.FTP(英文:File Transfer Protocol,缩写:FTP) 1.概念 FTP是在网络层传输文件的应用层协议,基于TCP连接,使 ...

  8. FTP文件传输协议与部署,包括Linux系统、Windows系统和H3C路由交换设备部署

    1.FTP 1.1 定义 文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层, TCP 模型的第四层, 即应用 ...

  9. 常见文件传输协议(ftp、tftp、scp)及其特点

    在工作中,我们经常要涉及到文件传输,windows 与windows, linux 与linux,windows 与linux 之间的文件传输,可供选择的途径有好多种. 可是常见的无非那么几种. 常见 ...

最新文章

  1. php截取中文字符串时乱码问题
  2. K-Means 聚类实例sample
  3. 5位随机数重复的概率 php_PHP产生不重复随机数的5个方法总结
  4. 等待队列中为什么需要互斥锁?一个线程在等待时被唤醒后会做什么?安全队列的代码实现
  5. Java字符串流学习
  6. SQLite的查询优化
  7. ZIGBEE通过协议栈点对点通信流程
  8. 软件工程的知识思维导图
  9. SCI论文下载之chrome插件
  10. 计算机发挥cpu全部,怎样提升CPU性能?怎么让CPU发挥最大的性能
  11. 你需要来自trustedinstaller的权限才能删除
  12. iOS开发之SEL用法
  13. 随便做各种题(无规律)
  14. <C++>初识多态,剖析virtual关键字
  15. 100个python算法超详细讲解:三色旗
  16. 知己知彼,一起来了解中国在线音频市场现状!
  17. 2020工商银行信息技术岗校招笔试经历
  18. MFC添加界面的背景图片方法总结
  19. python数据可视化(一)
  20. JS中“创建对象”及“通过原型创建对象”浅析

热门文章

  1. 优品购精选:中国跨境电商加速奔跑
  2. CodeForces 707B Bakery
  3. 【看表情包学Linux】系统下的文件操作 | 文件系统接口 | 系统调用与封装 | open,write,close 接口 | 系统传递标记位 O_RDWR,O_RDONLY,O_WRONLY...
  4. Python之动态规划算法
  5. 李嘉诚先生的家训与格言
  6. 蓝桥软件竞赛 预选赛
  7. Oracle View及dbms_metadata.get_ddl看对象生成的代码
  8. 第13章 面向对象编程
  9. [M贪心] lc1846. 减小和重新排列数组后的最大元素(贪心+双周赛51_3)
  10. 多屏幕炒股计算机配置,多屏幕股票交易计算机配置建议使用i59400F计算机主机配置(最多六个屏幕)...