java基于DatagramSocket 的上传文件

本文章提供的只有上传的方法,没有下载且不包含服务,只有客户端。

具体的逻辑:告知服务write,然后分块发送内容,块的大小默认512字节,socket.receive(packetRE)中,对packetRE进行了解析,其中有两个参数,一个是ack 一个是当前包的序号,在for循环中做了判断,索要的块数和当前读取文件的块数相同时才会继续。

Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。

receive(DatagramPacket p):从该DatagramSocket中接收数据报。

send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。

以下是贴的代码:

Client.java

package com.hisome.ctrl.web.EMaintenance.DatagramSocketTFTP;


import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;


/**
 * Client is an incomplete implementation of the client side of TFTP specification
 * It is a command line class that takes four arguments.
 * 	1. host - ipaddress of the server
 *  2. GET or PUT - this is the operation that will be made upon the file.  
 *  	PUT will send a file to the server.
 *  	GET will retrieve a file from the server.
 *  3. fileDir - is the directory in which the file to be sent resides 
 *  	or the directory that the file will be created.
 *  4. filename - is the file name of the file to be sent or received.
 * @author David Latour
 *
 */


public class Client
{
	private static final String OCTET_STRING = "octet";
	private static final String PUT_STRING = "PUT";
	private static final int MAX_SIZE = 512;


	private final ByteBuffer receiveBuffer;
	public int maxSend=5;//块丢失时 最大从发次数
	
	public static boolean inter(String IP,String path,String filename) throws IOException{
		//对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。
		socket = new DatagramSocket();
		socket.setSoTimeout(3000);
		Client client = new Client(IP,PUT_STRING , path, filename);
		boolean success = client.doPutFile();
		if(success){
			System.out.println("成功");
		}else{
			System.out.println("失败");
		}
		return success;
	}
	public static void main(String[] args) throws IOException
	{
		//对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。
		socket = new DatagramSocket();
		socket.setSoTimeout(3000);
		Client client = new Client("192.168.156.150",PUT_STRING , "D:\\mqtt.bin", "V2.03_E");
		client.doPutFile();
	}


	private final String host;
	private final String fileDir;
	private final String fileName;
	private static DatagramSocket socket;
	
	public Client(String host, String operation, String fileDir, String fileName)
	{
		this.host = host;
		this.fileDir = fileDir;
		this.fileName = fileName;
		receiveBuffer = ByteBuffer.allocate(1024);
	}


	private boolean doPutFile() throws IOException
	{
		File fileParent = new File(fileDir);
		File fileToSend = new File(fileName);
		boolean successW = sendWriteRequest(fileToSend);
		
		boolean successC = false;
		if(successW != false){
			successC = sendFile(fileParent);
		}
		return successC;
	}


	private boolean sendWriteRequest(File file) throws IOException
	{	//kmy
//		ByteBuffer buffer = ByteBuffer.allocate(2 + file.getName().length() + 1 + OCTET_STRING.length() + 1);
		boolean success = true;
		
		ByteBuffer buffer = ByteBuffer.allocate(100);
		buffer.putShort(OpCode.WRQ.getValue());
		ByteBufferUtil.putString(buffer, file.getName());
		ByteBufferUtil.putString(buffer, OCTET_STRING);
		//kmy
		FileInputStream fileInputTftp=null;
        fileInputTftp=new  FileInputStream(fileDir);
        String fileSize =String.valueOf( fileInputTftp.available());
        ByteBufferUtil.putString(buffer, "blksize");
        String blksize = String.valueOf(MAX_SIZE);
        ByteBufferUtil.putString(buffer, blksize);
        ByteBufferUtil.putString(buffer, "tsize");
        ByteBufferUtil.putString(buffer, fileSize);
		
		buffer.flip();
		
//		channel.write(buffer);
		
		byte[] bt1 = new byte[buffer.remaining()];
		InetSocketAddress ipAddress = new InetSocketAddress(host, 69);
		DatagramPacket packet = new DatagramPacket(bt1, bt1.length, ipAddress.getAddress(), 69); 
		buffer.get(bt1, 0, bt1.length);
		socket.send(packet);
		
		byte[] by = new byte[receiveBuffer.remaining()];
		DatagramPacket packetRE=new DatagramPacket(by,by.length); 
		try {
			socket.receive(packetRE);
		} catch (Exception e) {
			success = false;
			return success;
			// TODO: handle exception
		}
		return success;
	}


	private boolean sendFile(File fileToSend) throws IOException
	{
		boolean success = true;
		byte[] buffer = new byte[MAX_SIZE];
		DataInputStream inputStream = new DataInputStream(new FileInputStream(fileToSend));
		maxSend = 1;
		
		int reNum = 0;
		DatagramPacket packet=null;
		for (short i = 1; inputStream.available() > 0; i++)
		{	
			
			int length = MAX_SIZE;
			//判断发送的文件块和内容的是否一致
			if(reNum == (i-1)){
				if (inputStream.available() < MAX_SIZE)
				{
					length = inputStream.available();
				}
				inputStream.readFully(buffer, 0, length);
				ByteBuffer byteBuffer = ByteBuffer.allocate(length + 4); // opCode and block #
				byteBuffer.putShort(OpCode.DATA.getValue());
				byteBuffer.putShort(i);
				byteBuffer.put(buffer, 0, length);
				byteBuffer.flip();
				
				byte[] bt1 = new byte[byteBuffer.remaining()];
				InetSocketAddress ipAddress = new InetSocketAddress(host, 69);
				packet = new DatagramPacket(bt1, bt1.length, ipAddress.getAddress(), 69); 
				byteBuffer.get(bt1, 0, bt1.length);
			}else{// 如果不一致 就发送上一条文件内容
				i = (short) (i-1);
			}
			socket.send(packet);
			
			// 创建接受类型的数据报 
			byte[] by = new byte[receiveBuffer.remaining()];
			DatagramPacket packetRE=new DatagramPacket(by,by.length);  
			
			try {
				
				socket.receive(packetRE);
				
				byte[] getBuf = new byte[1024];  
				getBuf = packetRE.getData();
		        StringBuffer sb = new StringBuffer(getBuf.length);
		        String sTemp;
		        for (int a = 0; a < getBuf.length; a++) {
		        sTemp = Integer.toHexString(0xFF & getBuf[a]);
		        if (sTemp.length() < 2)
		        	sb.append(0);
		          	sb.append(sTemp.toUpperCase());
		        }
		        reNum = Integer.parseInt(sb.toString().substring(4, 8),16);
				
			} catch (Exception e) {
//				tryS(packet,packetRE);
				// TODO: handle exception
			}
		}
		socket.close();
		inputStream.close();
		return success;
	}
	private void tryS(DatagramPacket packet, DatagramPacket packetRE) throws IOException{
		maxSend = maxSend+1;
		if(maxSend>10){
			return;
		}
		socket.send(packet);
		try {
			socket.receive(packetRE);
		} catch (Exception e2) {
			tryS(packet,packetRE);
		}
	}


}

ByteBufferUtil.java

package com.latour.tftp;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;

/**
 * ByteBufferUtil handles null terminated strings
 * @author David Latour
 *
 */
public class ByteBufferUtil
{
	private static final Charset asciCharset = Charset.forName("US-ASCII");
	public static String readString(ByteBuffer receiveBuffer)
	{
		int startPos = receiveBuffer.position();
		byte[] array = receiveBuffer.array();
		int stringLen = 0;
		for (int i = startPos; i < array.length && array[i] != 0; stringLen++, i++)
		{
		}
		String str = new String(array, startPos, stringLen, asciCharset);
		for (int i = 0; i <= stringLen; i++)
		{
			receiveBuffer.get();
		}
		return str;
	}

	public static void putString(ByteBuffer buffer, String inString)
	{
		byte[] stringBytes = inString.getBytes(asciCharset);
		buffer.put(stringBytes);
		buffer.put((byte)0);
	}
}

OpCode.java

package com.latour.tftp;

/** 
 * OpCode is an enum to identify the different types of messages that can be sent.
 * 
 * @author David Latour
 *
 */
public enum OpCode
{
	RRQ((short)1), // Read request
	WRQ((short)2), // Write request
	DATA((short)3), // Data
	ACK((short)4), // Acknowledge
	ERROR((short)5); // Error

	private final short opCode;

	private OpCode(short opCode)
	{
		this.opCode = opCode;
	}

	public short getValue()
	{
		return opCode;
	}

	public static OpCode valueOf(short inValue)
	{
		OpCode returnValue = ERROR;
		for (OpCode code : OpCode.values())
		{
			if (code.opCode == inValue)
			{
				returnValue = code;
				break;
			}
		}
		return returnValue;
	}
}

了解DatagramSocket内容的可参考该链接 https://www.cnblogs.com/blog-yuesheng521/p/6230441.html

下面有测试压缩包,亲测有效。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值