简单文件传输协议--主机部分--patr1
来源:互联网 发布:暗黑破坏神3 mac 编辑:程序博客网 时间:2024/05/13 09:36
/*
串口基础--简单文件传输协议--主机部分
从机部分: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
- 简单文件传输协议--主机部分--patr2
- TFTP(简单文件传输协议)
- TFTP 简单文件传输协议
- dev\devtranfile.h.c__简单文件传输协议_从机部分
- 基于TCP协议简单的文件传输
- tftp 简单文件传输协议的 使用
- 文件传输协议
- 文件传输协议
- 文件传输协议
- 简单文件传输协议(TFTP)--网络大典
- 文件传输协议的简单设计与实现(c语言)
- 用Python实现一个简单的文件传输协议
- 用Python实现一个简单的文件传输协议
- 用Python实现一个简单的文件传输协议
- Python3 积累一些简单文件传输协议(TFTP)的知识点
- 文件传输协议 ftp 协议
- 简单文件传输
- Java实现斐波那契数列
- Markdown 语法说明
- PHP–将session信息存储到mysql数据库中
- C#快捷键
- C#获取当前路径的7种方法
- 简单文件传输协议--主机部分--patr1
- 浅谈ANR及如何分析解决ANR
- TYPEERROR
- PHP数据库类的封装
- Php中session_set_save_handler的含义
- 如何正确理解PHP include作用域
- 【mysql】解决MySQL server has gone away问题的两种有效办法
- win7 64位下 pl/sql、toad连接oracle失败的问题
- php中global和$GLOBALS[]的分析之一