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);
}
}
}到此这篇关于c#实现tftp客户端的文章就介绍到这了,更多相关c# tftp客户端内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论