基于HTTP高性能零拷贝zerocopy文件传输

package com.zyp.net;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.List;

import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicException;
import net.sf.jmimemagic.MagicMatch;
import net.sf.jmimemagic.MagicMatchNotFoundException;
import net.sf.jmimemagic.MagicParseException;

/**
 * 
 * @author zyping
 * 处理文件流传输
 *
 */
public class HttpTemplate implements Template {
	final String BOUNDARY = "---------------------------123821742118716";

	private HttpURLConnection createConnection(NetRequest request) throws IOException {
		HttpURLConnection conn = (HttpURLConnection) request.getUrl().openConnection();
		conn.setConnectTimeout(5000);
		conn.setReadTimeout(30000);
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setUseCaches(false);
		conn.setRequestMethod(request.getMethod());
		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
		conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
		return conn;
	}

	@Override
	public NetResponse execute(NetRequest request) throws IOException {
		HttpURLConnection conn = createConnection(request);

		try (OutputStream out = new DataOutputStream(conn.getOutputStream())) {
			// 提交文本数据
			if (request.getParams() != null) {
				writeText(out, request);
			}
			// 传输流数据
			if (request.getStreams() != null) {
				writeStream(out, request);
			}
			byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
			out.write(endData);
			out.flush();
			// 读取返回数据
			return read(conn);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();
				conn = null;
			}
		}
		return null;
	}

	private void writeText(OutputStream out, NetRequest request) throws IOException {
		StringBuffer strBuf = new StringBuffer();
		request.getParams().forEach(param -> {
			strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
			strBuf.append("Content-Disposition: form-data; name=\"" + param.getName() + "\"\r\n\r\n");
			strBuf.append(param.getValue());
		});
		out.write(strBuf.toString().getBytes());
	}

	private void writeStream(OutputStream out, NetRequest request) throws IOException {
		WritableByteChannel writableByteChannel = Channels.newChannel(out);
		ByteBuffer dst = null;// 可以根据增加情况定义
		for (StreamData stream : request.getStreams()) {
			String contentType = stream.getMimeType();

			StringBuffer strBuf = new StringBuffer();
			strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
			strBuf.append("Content-Disposition: form-data; name=\"" + stream.getParamName() + "\"; filename=\""
					+ stream.getFileName() + "\"\r\n");
			strBuf.append("Content-Type:" + contentType + "\r\n\r\n");

			out.write(strBuf.toString().getBytes());

			if (stream.getFile() != null) {
				try (RandomAccessFile raf = new RandomAccessFile(stream.getFile(), "rw");
						FileChannel fileChannel = raf.getChannel();) {
					fileChannel.transferTo(0, fileChannel.size(), writableByteChannel);
				}
			}
			if (stream.getInputStream() != null) {
				try (ReadableByteChannel inChannel = Channels.newChannel(stream.getInputStream());) {
					if(dst==null)
						ByteBuffer.allocate(2048);
					copyChannel(inChannel, writableByteChannel, dst);
				}
			}
		}
	}

	private static void copyChannel(ReadableByteChannel inChannel, WritableByteChannel outChannel, ByteBuffer dst)
			throws IOException {
		while (inChannel.read(dst) != -1) {
			dst.flip();
			outChannel.write(dst);
			dst.clear();
		}
	}

	private NetResponse read(HttpURLConnection connection) throws IOException {
		StringBuffer strBuf = new StringBuffer();
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
			String line = null;
			while ((line = reader.readLine()) != null) {
				strBuf.append(line).append("\n");
			}
			String res = strBuf.toString();
			NetResponse netResponse = new NetResponse();
			netResponse.setData(res);
			netResponse.setHttpCode(connection.getResponseCode());
			return netResponse;
		}
	}
	
	public static void main(String args[]) throws MagicParseException, MagicMatchNotFoundException, MagicException, IOException {
		HttpTemplate template = new HttpTemplate();
		
		String filepath = "C:\\workdoc\\test\\1.jpg";
		String url = "http://127.0.0.1:8080/uploadtest";
		
		NetRequest request = new NetRequest();
		request.setUrl(new URL(url));
		request.setMethod(NetRequest.METHOD_POST);
		
		//定义请求参数
		List<FieldData> params = new ArrayList<>();
		FieldData mainIndex = new FieldData();
		mainIndex.setName("mainIndex");
		mainIndex.setValue("050081909566572");
		params.add(mainIndex);
		
		FieldData docTypeId = new FieldData();
		docTypeId.setName("docTypeId");
		docTypeId.setValue("137");
		params.add(docTypeId);
		
		FieldData netId = new FieldData();
		netId.setName("netId");
		netId.setValue("B040102");
		params.add(netId);
		
		request.setParams(params);
		
		//定义传输文件流
		List<StreamData> streams = new ArrayList<>();
		StreamData stream = new StreamData();
		stream.setFile(new File(filepath));
		stream.setFileName("2790776276");
		
		MagicMatch match = Magic.getMagicMatch(stream.getFile(), false, true);
		String mimeType = match.getMimeType();
		stream.setMimeType(mimeType);
		stream.setParamName("imgs");
		streams.add(stream);
		
		StreamData stream2 = new StreamData();
		stream2.setFile(new File(filepath));
		stream2.setFileName("2790776277");
		stream2.setMimeType(mimeType);
		stream2.setParamName("imgs");
		streams.add(stream2);
		
		request.setStreams(streams);
		
		System.out.println(template.execute(request).getData());
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值