1、文件结构
2、TftpConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TftpTest
{
public class TftpConfig
{
}
/// <summary>
/// 模式
/// </summary>
public enum Modes
{
NETASCII = 0, //ASCII
OCTET = 1 //二进制
}
/// <summary>
/// 操作码
/// </summary>
public enum OpCodes
{
RRQ = 1, // 读请求
WRQ = 2, // 写请求
DATA = 3, // 数据
ACK = 4, // Acknowledge
ERROR = 5, // 错误
OACK = 6 // Option Acknowledge
}
public enum TransferType
{
Get,
Put
}
public struct TransferOptions
{
private TransferType _action;
public TransferType Action
{
get { return _action; }
set { _action = value; }
}
private string _localFilename;
public string LocalFilename
{
get { return _localFilename; }
set { _localFilename = value; }
}
private string _remoteFilename;
public string RemoteFilename
{
get { return _remoteFilename; }
set { _remoteFilename = value; }
}
private string _host;
public string Host
{
get { return _host; }
set { _host = value; }
}
}
}
3、ErrorPacket.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TftpTest
{
public class ErrorPacket
{
short _code;
public short Code
{
get { return _code; }
set { _code = value; }
}
string _message;
public string Message
{
get { return _message; }
set { _message = value; }
}
public ErrorPacket(short Code, string Message)
{
Code = _code;
Message = _message;
}
}
}
4、PacketBuilder.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TftpTest
{
public class PacketBuilder
{
public byte[] Request(OpCodes OpCode, string RemoteFileName,
Modes Mode, int BlockSize, long TransferSize, int Timeout)
{
// Request packet structure
// -----------------------------------------------------------------------------
// |OpCode|FileName|0|Mode|0|BlkSize|0|BSVal|0|TSize|0|TSVal|0|Timeout|0|TVal|0|
// -----------------------------------------------------------------------------
int len;
string packetStr = "";
string mode = Mode.ToString().ToLower();
string blockSize = BlockSize.ToString();
string nullChar = "\0";
byte[] packet;
// Create packet as a string
switch (OpCode)
{
case OpCodes.RRQ:
packetStr = nullChar + (char)1;
break;
case OpCodes.WRQ:
packetStr = nullChar + (char)2;
break;
}
packetStr += RemoteFileName + nullChar + mode + nullChar + "blksize" +
nullChar + BlockSize.ToString() + nullChar + "tsize" + nullChar +
TransferSize.ToString() + nullChar + "timeout" + nullChar +
Timeout.ToString() + nullChar;
len = packetStr.Length;
packet = new byte[len];
// Encode packet as ASCII bytes
packet = System.Text.Encoding.ASCII.GetBytes(packetStr);
return packet;
}
public byte[] Ack(int Block1, int Block2)
{
// ACK packet structure
// ----------
// |04|Block|
// ----------
byte[] packet = new byte[4];
packet[0] = 0;
packet[1] = (byte)OpCodes.ACK;
packet[2] = (byte)Block1;
packet[3] = (byte)Block2;
return packet;
}
public byte[] Data(byte[] SendData, int Block1, int Block2)
{
// DATA packet structure
// ----------
// |03|Block|
// ----------
byte[] packet = new byte[SendData.Length + 4];
//packet[0] = 0;
packet[1] = (byte)OpCodes.DATA;
packet[2] = (byte)Block1;
packet[3] = (byte)Block2;
for (int h = 4; h < SendData.Length + 4; h++)
{
packet[h] = SendData[h - 4];
}
return packet;
}
public int[] IncrementBock(byte[] ReceivedData, int[] Block)
{
if (ReceivedData[3] == 255)
{
if (ReceivedData[2] < 255)
{
Block[0] = (int)ReceivedData[2] + 1; Block[1] = 0;
}
else
{
Block[0] = 0; Block[1] = 0;
}
}
else
{
Block[1] = (int)ReceivedData[3] + 1;
}
return Block;
}
}
}
5、PacketReader.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TftpTest
{
public class PacketReader
{
public OpCodes ReadOpCode(byte[] ReceivedData)
{
return (OpCodes)ReceivedData[1];
}
public int ReadTransferSize(byte[] ReceivedData)
{
int h, tSize = 0;
string searchStr, decPacket = Encoding.ASCII.GetString(ReceivedData);
char[] splitChar = { '\0' };
string[] splitPacket = decPacket.Split(splitChar);
for (h = 0; h < splitPacket.Length - 1; h++)
{
searchStr = splitPacket[h].ToLower();
if (searchStr == "tsize")
{
tSize = int.Parse(splitPacket[h + 1]);
}
}
return tSize;
}
public ErrorPacket ReadError(byte[] ReceivedData)
{
string codeStr = ReceivedData[2].ToString() + ReceivedData[3].ToString();
short code = short.Parse(codeStr);
string message = "";
for (int h = 4; h < ReceivedData.Length; h++)
{
if (ReceivedData[h] == 0)
break;
message += (char)ReceivedData[h];
}
return new ErrorPacket(code, message);
}
public bool CompareBlocks(byte[] SentData, byte[] ReceivedData)
{
if (ReceivedData[2] == SentData[2] &&
ReceivedData[3] == SentData[3])
return true;
return false;
}
}
}
6、TftpClient.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace TftpTest
{
public class TftpClient
{
// 委托
public delegate void ConnectedHandler();
public delegate void TransferringHandler(long BytesTransferred, long BytesTotal);
public delegate void TransferFailedHandler(short ErrorCode, string ErrorMessage);
public delegate void TransferFinishedHandler();
public delegate void DisconnectedHandler();
// 事件
public event ConnectedHandler Connected;
public event TransferringHandler Transferring;
public event TransferFailedHandler TransferFailed;
public event TransferFinishedHandler TransferFinished;
public event DisconnectedHandler Disconnected;
private string _host;
[Description("主机")]
public string Host
{
get { return _host; }
set { _host = value; }
}
private Modes _mode = Modes.OCTET;
[Description("模式")]
public Modes Mode
{
get { return _mode; }
set { _mode = value; }
}
private int _blockSIze = 512;
[Description("块大小")]
public int BlockSize
{
get { return _blockSIze; }
set { _blockSIze = value; }
}
private int _timeout = 10;
[Description("溢出时间")]
public int Timeout
{
get { return _timeout; }
set { _timeout = value; }
}
PacketReader _packetReader = new PacketReader();
PacketBuilder _packetBuilder = new PacketBuilder();
public bool Get(string localFile, string RemoteFile, string Host)
{
return Get(localFile, RemoteFile, Host, Mode, BlockSize, Timeout);
}
public bool Put(string localFile, string RemoteFile, string Host)
{
return Put(localFile, RemoteFile, Host, Mode, BlockSize, Timeout);
}
public bool Get(string LocalFile, string RemoteFile, string Host,
Modes Mode, int BlockSize, int Timeout)
{
int recvLen, remoteFileSize = 0, buffer = BlockSize + 4;
long bytesReceived = 0;
BinaryWriter BWriter = new BinaryWriter(File.Open(LocalFile, FileMode.Create));
OpCodes opCode = new OpCodes();
IPHostEntry hInfo = Dns.GetHostEntry(Host);
IPAddress address = hInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(address, 69);
EndPoint localEP = (remoteEP);
Socket UDPSock = new Socket
(remoteEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
// Create initial request and buffer for response
byte[] sendData = _packetBuilder.Request(OpCodes.RRQ,
RemoteFile, Mode, BlockSize, 0, Timeout);
byte[] recvData = new byte[BlockSize + 4];
UDPSock.ReceiveTimeout = Timeout * 1000;
// Send request and wait for response
UDPSock.SendTo(sendData, remoteEP);
recvLen = UDPSock.ReceiveFrom(recvData, ref localEP);
// Get TID
remoteEP.Port = ((IPEndPoint)localEP).Port;
// Invoke connected event
Connected.Invoke();
while (true)
{
// Read opcode
opCode = _packetReader.ReadOpCode(recvData);
// DATA packet
if (opCode == OpCodes.DATA)
{
bytesReceived += recvLen - 4;
// Invoke Transferring Event
Transferring.Invoke(bytesReceived, remoteFileSize);
for (int h = 4; h < recvLen; h++)
{
BWriter.Write(recvData[h]);
}
sendData = _packetBuilder.Ack(recvData[2], recvData[3]);
// Check if this packet is the last
if (recvLen < buffer)
{
// Send final ACK
UDPSock.SendTo(sendData, remoteEP);
// Invoked TransferFinished Event
TransferFinished.Invoke();
break;
}
}
// OACK packet
else if (opCode == OpCodes.OACK)
{
remoteFileSize = _packetReader.ReadTransferSize(recvData);
sendData = _packetBuilder.Ack(0, 0);
}
// ERROR packet
else if (opCode == OpCodes.ERROR)
{
ErrorPacket transferError = _packetReader.ReadError(recvData);
TransferFailed.Invoke(transferError.Code, transferError.Message);
break;
}
// Send next packet
UDPSock.SendTo(sendData, remoteEP);
recvLen = UDPSock.ReceiveFrom(recvData, ref localEP);
remoteEP.Port = ((IPEndPoint)localEP).Port;
}
BWriter.Close();
UDPSock.Close();
// Invoke Disconnected Event
Disconnected.Invoke();
return true;
}
public bool Put(string LocalFile, string RemoteFile, string Host,
Modes Mode, int BlockSize, int Timeout)
{
int[] block = new int[2];
int bufferSize = BlockSize;
long fileSize, bytesSent = 0;
BinaryReader BReader = new BinaryReader(File.Open(LocalFile, FileMode.Open));
FileInfo sendFile = new FileInfo(LocalFile);
OpCodes opCode = new OpCodes();
IPHostEntry hostInfo = Dns.GetHostEntry(Host);
IPAddress address = hostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(address, 69);
EndPoint localEP = (remoteEP);
Socket UDPSock = new Socket
(remoteEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
// Retrieve filesize for tsize option
fileSize = sendFile.Length;
// Create initial request and buffer for response
byte[] sendData = _packetBuilder.Request(OpCodes.WRQ,
RemoteFile, Mode, BlockSize, fileSize, Timeout);
byte[] recvData = new byte[bufferSize];
UDPSock.ReceiveTimeout = Timeout * 1000;
// Send request and wait for response
UDPSock.SendTo(sendData, remoteEP);
UDPSock.ReceiveFrom(recvData, ref localEP);
//Get TID
remoteEP.Port = ((IPEndPoint)localEP).Port;
// Invoke Connected Event
Connected.Invoke();
while (true)
{
// Read opcode
opCode = _packetReader.ReadOpCode(recvData);
// ACK packet
if (opCode == OpCodes.ACK)
{
block = _packetBuilder.IncrementBock(recvData, block);
sendData = BReader.ReadBytes(bufferSize);
bytesSent += sendData.Length;
// Invoke Transferring Event
Transferring.Invoke(bytesSent, fileSize);
sendData = _packetBuilder.Data(sendData, block[0], block[1]);
// Check if this packet is the last
if (sendData.Length < bufferSize + 4)
{
// Send final data packet and wait for ack
while (true)
{
UDPSock.SendTo(sendData, remoteEP);
UDPSock.ReceiveFrom(recvData, ref localEP);
remoteEP.Port = ((IPEndPoint)localEP).Port;
// Check the blocks and break free if equal
if (_packetReader.CompareBlocks(sendData, recvData))
break;
}
// Invoke TransferFinished Event
TransferFinished.Invoke();
break;
}
}
// OACK packet
else if (opCode == OpCodes.OACK)
{
sendData = BReader.ReadBytes(bufferSize);
sendData = _packetBuilder.Data(sendData, 0, 1);
bytesSent += sendData.Length - 4;
// Invoke Transferring Event
Transferring.Invoke(bytesSent, fileSize);
if (fileSize == 0)
{
// Invoke TransferFinished Event
TransferFinished.Invoke();
break;
}
else
{
// Check if this packet is the last
if (sendData.Length < bufferSize + 4)
{
// Send final data packet and wait for ack
while (true)
{
UDPSock.SendTo(sendData, remoteEP);
UDPSock.ReceiveFrom(recvData, ref localEP);
remoteEP.Port = ((IPEndPoint)localEP).Port;
// Check the blocks and break free if equal
if (_packetReader.CompareBlocks(sendData, recvData))
break;
}
// Invoke TransferFinished Event
TransferFinished.Invoke();
break;
}
}
}
else if (opCode == OpCodes.ERROR)
{
ErrorPacket transferError = _packetReader.ReadError(recvData);
TransferFailed.Invoke(transferError.Code, transferError.Message);
break;
}
// Send next packet
UDPSock.SendTo(sendData, remoteEP);
UDPSock.ReceiveFrom(recvData, ref localEP);
remoteEP.Port = ((IPEndPoint)localEP).Port;
}
BReader.Close();
UDPSock.Close();
// Invoke Disconnected Event
Disconnected.Invoke();
return true;
}
}
}
7、MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace TftpTest
{
public partial class MainForm : Form
{
private TftpClient tftpClient = new TftpClient();
private delegate void ProgressBarDelegate(int Maximum, int Value);
private delegate void TransferButtonDelegate(bool Enabled);
public MainForm()
{
InitializeComponent();
tftpClient.Connected += new TftpClient.ConnectedHandler(TftpClient_Connected);
tftpClient.Transferring += new TftpClient.TransferringHandler(TftpClient_Transferring);
tftpClient.TransferFailed += new TftpClient.TransferFailedHandler(TftpClient_TransferFailed);
tftpClient.TransferFinished += new TftpClient.TransferFinishedHandler(TftpClient_TransferFinished);
tftpClient.Disconnected += new TftpClient.DisconnectedHandler(TftpClient_Disconnected);
}
private void TftpClient_Connected()
{
TransferButtonDelegate tBtnDel = new TransferButtonDelegate(TransferBtnDelegateFunction);
btnTest.Invoke(tBtnDel, false);
Console.WriteLine("Connected");
}
private void TransferBtnDelegateFunction(bool Enabled)
{
lock (btnTest)
{
btnTest.Enabled = Enabled;
}
}
private void TftpClient_Transferring(long BytesTransferred, long BytesTotal)
{
if (BytesTotal != 0)
{
ProgressBarDelegate progressBarDel = new ProgressBarDelegate(ProgressBarDelegateFunction);
progressBarTftp.Invoke(progressBarDel,
new object[2] { (int)(BytesTotal / 10), (int)(BytesTransferred / 10) });
Console.Write("{0}/{1} Bytes Transferred\r", BytesTransferred, BytesTotal);
}
else
Console.Write(".");
}
private void ProgressBarDelegateFunction(int Maximum, int Value)
{
lock (progressBarTftp)
{
try
{
progressBarTftp.Maximum = Maximum;
progressBarTftp.Value = Value;
}
catch (Exception e) { Console.WriteLine(e.ToString()); }
}
}
private void TftpClient_TransferFailed(short ErrorCode, string ErrorMessage)
{
Console.WriteLine("Error {0}: {1}", ErrorCode, ErrorMessage);
}
private void TftpClient_TransferFinished()
{
ProgressBarDelegate progressBarDel = new ProgressBarDelegate(ProgressBarDelegateFunction);
progressBarTftp.Invoke(progressBarDel, new object[2] { 0, 0 });
Console.WriteLine("\nTransfer Finished");
MessageBox.Show("Transfer Complete", "TFTP Client",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void TftpClient_Disconnected()
{
TransferButtonDelegate tBtnDel = new TransferButtonDelegate(TransferBtnDelegateFunction);
btnTest.Invoke(tBtnDel, true);
Console.WriteLine("Disconnected\n");
}
private void btnTest_Click(object sender, EventArgs e)
{
progressBarTftp.Value = 0;
TransferOptions tOptions = new TransferOptions();
//tOptions.LocalFilename = "D:\\Project\\QDRP3\\Sw\\QDRP\\QDRP\\bin\\Debug\\Case\\PLBIN.bin";
tOptions.LocalFilename = "F:\\Test\\PLBIN.bin";
tOptions.RemoteFilename = "PLBIN.bin";
tOptions.Host = "10.11.9.62";
//tOptions.Action = getRadio.Checked == true ? TransferType.Get : TransferType.Put;
tOptions.Action = TransferType.Get;
Thread tThread = new Thread((ParameterizedThreadStart)delegate (object ScanOptions)
{
TransferOptions options = (TransferOptions)ScanOptions;
if (options.Action == TransferType.Get)
tftpClient.Get(options.LocalFilename,options.RemoteFilename,options.Host);
else
tftpClient.Put(options.LocalFilename, options.RemoteFilename, options.Host);
});
tThread.IsBackground = true;
tThread.Start(tOptions);
}
}
}