java网络编程之TFTP(二)
来源:互联网 发布:java redis作用 编辑:程序博客网 时间:2024/04/29 01:00
java网络编程之TFTP(二)
今天在这里贴一个TFTP客户端实现的实例,希望可以帮助到有需要的人。【标准服务器端大家自行下载,推荐tftpd32】
首先构建一个TftpSocket类(基于UDP通信):
import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;class TftpSocket { private static final String Server_IP ="127.0.0.1"; //指明服务器IP private static final int Server_port =69; //指明服务器监听端口 private static final byte RRQ = 1; //请求读 private static final byte DAT = 3; //文件数据 private static final byte ACK = 4; //确认,继续进行传输 private static final byte ERROR = 5; //发生错误 private static final int PACKET_SIZE = 516; //数据为0~512字节,加上2字节的操作码和2字节的块编号 private DatagramSocket datagramSocket = null; //基于UDP,所以使用DatagramSocket private InetAddress address = null; private byte[] requestArray; //数据包数组 private byte[] buf; //数据缓存区 private DatagramPacket outDatagramPacket; //发出数据包 private DatagramPacket inDatagramPacket; //接收数据包 //该方法设置为public属性,作为与主程序的接口,通过传入文件名进行获取文件 public void get(String fileName) throws Exception { address = InetAddress.getByName(Server_IP); //使用InetAddress的静态方法getByName(String host)得到服务器的IP地址 datagramSocket = new DatagramSocket(); //基于UDP数据报,所以用到DatagramSocket requestArray = createRequest(RRQ, fileName, "octet"); //通过createRequest(RRQ, fileName, "octet")方法得到一个请求读报文 outDatagramPacket = new DatagramPacket(requestArray,requestArray.length, address, Server_port); //发到服务器的数据包 datagramSocket.send(outDatagramPacket); ByteArrayOutputStream byteOut = receiveFile(); //利用receiveFile()从服务器接收文件 writeFile(byteOut, fileName); //利用writeFile()把文件写到当地磁盘 } //该方法用于从服务器接收文件,保存到一个字符数组并返回 private ByteArrayOutputStream receiveFile() throws Exception{ ByteArrayOutputStream byteOutOS = new ByteArrayOutputStream(); int block = 1; do { System.out.println("接收到第"+block+"个数据包"); //block最为一个计数器,计算收到的数据包 block++; buf = new byte[PACKET_SIZE]; //设置数据缓冲区 inDatagramPacket = new DatagramPacket(buf,buf.length, address,datagramSocket.getLocalPort()); datagramSocket.receive(inDatagramPacket); byte[] opCode = { buf[0], buf[1] }; //获取接收报文中前两个字节的操作码 if (opCode[1] == ERROR) { reportError(); } else if (opCode[1] == DAT) { byte[] blockNumber = { buf[2], buf[3] }; //获取接收报文中操作码之后的两个字节的块编号 DataOutputStream dos = new DataOutputStream(byteOutOS); dos.write(inDatagramPacket.getData(), 4,inDatagramPacket.getLength() - 4); sendAcknowledgment(blockNumber); //发送ACK,确认收到该块编号的报文 } } while (!isLastPacket(inDatagramPacket)); System.out.println("文件接收完毕!!"); return byteOutOS; } //该方法是发送ACK数据包,用于确认收到该块编号的数据包 private void sendAcknowledgment(byte[] blockNumber){ byte[] ACKArray = { 0, ACK, blockNumber[0], blockNumber[1] }; DatagramPacket ack = new DatagramPacket(ACKArray, ACKArray.length,address, inDatagramPacket.getPort()); //ACK数据包 try { datagramSocket.send(ack); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //该方法用于将接收到的文件写入到本地磁盘中 private void writeFile(ByteArrayOutputStream b, String fileName){ try { OutputStream outputStream = new FileOutputStream(fileName); b.writeTo(outputStream); // 将此 byte 数组输出流的全部内容写入到指定的输出流参数中 } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private boolean isLastPacket(DatagramPacket datagramPacket) { //判断是否是最后一个数据包 if (datagramPacket.getLength() < 512) return true; else return false; } //该方法为构造请求读/写数据包(包括操作码、文件名、模式串) private byte[] createRequest(final byte opCode, final String fileName, final String mode) { byte zeroByte = 0; int ByteLength = 2 + fileName.length() + 1 + mode.length() + 1; //文件名和模式串都是以0字节终止 byte[] ByteArray = new byte[ByteLength]; int position = 0; ByteArray[position] = zeroByte; position++; ByteArray[position] = opCode; //设置操作码(读或写) position++; for (int i = 0; i < fileName.length(); i++) { ByteArray[position] = (byte) fileName.charAt(i); //返回指定索引处的 char 值,强转为byte类型 position++; } ByteArray[position] = zeroByte; //文件名以0字节作为终止 position++; for (int i = 0; i < mode.length(); i++) { ByteArray[position] = (byte) mode.charAt(i); //返回指定索引处的 char 值,强转为byte类型 position++; } ByteArray[position] = zeroByte; //模式以0字节作为终止 return ByteArray; } //该方法为显示差错码和差错信息 private void reportError() { String errorCode = new String(buf, 3, 1); //获取差错码 String errorText = new String(buf, 4,inDatagramPacket.getLength() - 4); //获取差错信息 System.err.println("Error: " + errorCode + " " + errorText); }}
这个是一个简单的测试方法,可以从服务器端指定的位置下载到需要的文件:
public class TftpTest { public static void main(String[] args) { String FileName ="doc1.txt"; TftpSocket s= new TftpSocket(); try { s.get(FileName); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
0 0
- java网络编程之TFTP(二)
- java网络编程之TFTP(一)
- Java之网络编程(二)UDP
- java网络编程之NIO(二)
- 【java网络编程】之二
- Java 网络编程(二)
- Java网络编程(二)
- java网络编程(二)
- 奋斗黑马程序员----Java之网络编程(二)
- Java网络编程之Socket通信(二)
- java网络socket编程(二)之Socket客户端
- java网络编程之聊天室客户端(二)
- java网络编程之缓存(二)
- 高级编程之网络编程(二)
- win7+虚拟机+开发板(网络互联设置)之二(tftp安装与设置)
- 网络编程之二
- java网络编程二
- java网络编程二
- Unity3d UGUI 自适应屏幕 代码修改Left,Top,Right,Bottom属性值
- ubuntu16.04安装ibus中文输入法
- OpenGL -- glutReshapeFunc glViewport
- raw or sparse ext4 image
- OGNL表达式 模型驱动封装数据 获取null的问题
- java网络编程之TFTP(二)
- putty 中文乱码解决方法
- Android开发之浅谈OOM
- Spark之Scala学习之路(一)
- c函数实现将一个整数转为任意进制的字符串输出
- illegal text-relocation错误解决
- jdk源码分析红黑树——插入篇
- Hadoop是什么
- 使用NGUI在两点之间作线