java socket类文件传递及加载

最近遇到一个java socket问题,具体业务场景不做描述,只谈谈具体的技术需求,如下所述:

1.client端从server端下载java class文件.

2.完成后动态加载该类,并调用该类的某个方法。

 

关键点:

1.利用java socket传递java class文件。

2.如何将某path下的java class文件加载到JVM。

 

测试实现:

需求很明确,没有特别的地方,如下是我写的测试代码。

DataClient:        传递类名等信息到server,从服务端下载指定的java类文件。

DataServer:      根据client端参数传递指定的类文件到client端。

MyClassLoader:以byte格式读取class文件,并加载到JVM。

SocketTool:       java socket工具类。

TestClass:         被传递的java class。

 

 

package org.socket;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Supply for class file download
 * 
 * @author chares
 * @date	2013-5-9
 * 
 */
public class DataServer {
	int port = 8821;
	
	void start() {
		Socket socket = null;
		try {
			ServerSocket serverSocket = new ServerSocket(port);
			
			while (true) {
				// 选择进行传输的文件
				String filePath = "c:\\TestClass.class";
				File fi = new File(filePath);
				System.out.println("~~~~ [server] 文件长度:" + (int) fi.length());
				
				socket = serverSocket.accept();
				System.out.println("~~~~ [server] : 建立socket链接");
				DataInputStream dis = new DataInputStream(
						new BufferedInputStream(socket.getInputStream()));
				dis.readByte();
				
				DataInputStream fis = new DataInputStream(
						new BufferedInputStream(new FileInputStream(filePath)));
				DataOutputStream ps = new DataOutputStream(socket.getOutputStream());
				
				// 将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java
				// 4th里有现成的代码
				ps.writeUTF(fi.getName());
				ps.flush();
				ps.writeLong((long) fi.length());
				ps.flush();
				
				int bufferSize = 8192;
				byte[] buf = new byte[bufferSize];

				while (true) {
					int read = 0;
					if (fis != null) {
						read = fis.read(buf);
						// 从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b
						// 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾 (end of file)
						// 或抛出异常之前,此方法将一直阻塞。
					}

					if (read == -1) {
						break;
					}
					ps.write(buf, 0, read);
				}
				ps.flush();
				// 注意关闭socket链接哦,不然客户端会等待server的数据过来,
				// 直到socket超时,导致数据不完整。
				fis.close();
				socket.close();
				System.out.println("~~~~ [server] 文件传输完成");
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String arg[]) {
		new DataServer().start();
	}
}


 

package org.socket;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;

/**
 * Get class file from DataServer.
 * 
 * @author	chares
 * @date	2013-5-9
 * 
 */
public class DataClient {
	private SocketTool cs = null;
	private String ip = "localhost";// 设置成服务器IP
	private int port = 8821;
	private String sendMessage = "Windows";
	
	public DataClient() {
		try {
			if (createConnection()) {
				sendMessage();
				getMessage();
			}
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	private boolean createConnection() {
		cs = new SocketTool(ip, port);
		try {
			cs.crtConnection();
			System.out.print("~~~~ [client] : 连接服务器成功!" + "\n");
			return true;
		} catch (Exception e) {
			System.out.print("~~~~ [client] : 连接服务器失败!" + "\n");
			return false;
		}

	}

	private void sendMessage() {
		if (cs == null)
			return;
		try {
			cs.sendMessage(sendMessage);
		} catch (Exception e) {
			System.out.print("~~~~ [client] : 发送消息失败!" + "\n");
		}
	}

	private void getMessage() {
		if (cs == null)
			return;
		
		DataInputStream inputStream = null;
		try {
			inputStream = cs.getMessageStream();
		} catch (Exception e) {
			System.out.print("~~~~ [client] : 接收消息缓存错误\n");
			return;
		}

		try {
			// 本地保存路径,文件名会自动从服务器端继承而来
			String savePath = "d:\\test_java\\";
			int bufferSize = 8192;
			byte[] buf = new byte[bufferSize];
			int passedlen = 0;
			long len = 0;

			savePath += inputStream.readUTF();
			DataOutputStream fileOut = new DataOutputStream(
					new BufferedOutputStream(new BufferedOutputStream(
							new FileOutputStream(savePath))));
			len = inputStream.readLong();

			System.out.println("~~~~ [client] : 文件的长度为:" + len + "\n");
			System.out.println("~~~~ [client] : 开始接收文件!" + "\n");

			while (true) {
				int read = 0;
				if (inputStream != null) {
					read = inputStream.read(buf);
				}
				passedlen += read;
				if (read == -1) {
					break;
				}
				// 下面进度条本为图形界面的prograssBar做的,这里如果是打文件,可能会重复打印出一些相同的百分比
				System.out.println("~~~~ [client] : 文件接收了" + (passedlen * 100 / len) + "%\n");
				fileOut.write(buf, 0, read);
			}
			System.out.println("~~~~ [client] : 接收完成,文件存为" + savePath + "\n");

			fileOut.close();
		} catch (Exception e) {
			System.out.println("~~~~ [client] : 接收消息错误" + "\n");
			e.printStackTrace();
		}
	}
	
	public static void main(String arg[]) {
		new DataClient();//download class File
		new MyClassLoader().load("org.socket.TestClass","getName","");// load class
	}
}



 

 

package org.socket;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

public class SocketTool {
	private String ip;
	private int port;
	private Socket socket = null;
	DataOutputStream out = null;
	DataInputStream getMessageStream = null;

	public SocketTool(String ip, int port) {
		this.ip = ip;
		this.port = port;
	}

	/**
	 * 创建socket连接
	 * @throws Exception
	 */
	public void crtConnection() throws Exception {
		try {
			socket = new Socket(ip, port);
		} catch (Exception e) {
			e.printStackTrace();
			if (socket != null)
				socket.close();
			throw e;
		} finally {
		}
	}

	public void sendMessage(String sendMessage) throws Exception {
		try {
			out = new DataOutputStream(socket.getOutputStream());
			if (sendMessage.equals("Windows")) {
				out.writeByte(0x1);
				out.flush();
				return;
			}
			if (sendMessage.equals("Unix")) {
				out.writeByte(0x2);
				out.flush();
				return;
			}
			if (sendMessage.equals("Linux")) {
				out.writeByte(0x3);
				out.flush();
			} else {
				out.writeUTF(sendMessage);
				out.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
			if (out != null)
				out.close();
			throw e;
		} finally {
		}
	}

	public DataInputStream getMessageStream() throws Exception {
		try {
			getMessageStream = new DataInputStream(new BufferedInputStream(
					socket.getInputStream()));
			return getMessageStream;
		} catch (Exception e) {
			e.printStackTrace();
			if (getMessageStream != null)
				getMessageStream.close();
			throw e;
		} finally {
		}
	}

	public void shutDownConnection() {
		try {
			if (out != null)
				out.close();
			if (getMessageStream != null)
				getMessageStream.close();
			if (socket != null)
				socket.close();
		} catch (Exception e) {

		}
	}
}

 

package org.socket;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * Custom class loader
 * 
 * @author	chares
 * @date	2013-5-9
 * 
 */
public class MyClassLoader extends ClassLoader {
	public static final String DIR_PATH = "file:d:\\test_java\\";
	public static final String DONET_CLASS = ".class";
	
	/**
	 * Load java class and invoke the method 
	 * 
	 * @param methodName
	 * @param params		String:param1|String:param2
	 * 
	 */
	public void load(String fullClassName, String methodName, String params) {
		try {
			Class clazz = loadClass(fullClassName, this.getClassPathAbsolute(fullClassName));
			System.out.println("~~~~ clazz's classloader : "+ clazz.getClassLoader());
			
			// Class clazz = Class.forName(CLASS_NAME);
			Method[] methods = clazz.getDeclaredMethods();
			if (methods != null && methods.length > 0) {
				for (int i = 0; i < methods.length; i++) {
					if (methods[i].getName().equals(methodName)) {
						Object object = clazz.newInstance();
						System.out.println("~~~~ object : "+ object);
						
						Object rtnObj = methods[i].invoke(object, new Object[]{});
						System.out.println("~~~~ rtnObj : "+ rtnObj);
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	

	/**
	 * Get java.lang.Class from a XX.class file
	 * @param name
	 * @param classUrl
	 * @return
	 * @throws ClassNotFoundException
	 */
	public Class loadClass(String name, String classUrl)
			throws ClassNotFoundException {
		if (!"org.socket.TestClass".equals(name))
			return super.loadClass(name);
		
		try {
			/*
			 * String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
			 * "classes/reflection/MyObject.class";
			 */
			URL myUrl = new URL(classUrl);
			URLConnection connection = myUrl.openConnection();
			InputStream input = connection.getInputStream();
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
			int data = input.read();

			while (data != -1) {
				buffer.write(data);
				data = input.read();
			}

			input.close();

			byte[] classData = buffer.toByteArray();

			return defineClass(name, classData, 0, classData.length);

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return null;
	}
	
	/**
	 * Get absolute path from the java full class name(org.socket.TestClass)
	 * @param fullClassName
	 * @return
	 */
	private String getClassPathAbsolute(String fullClassName){
		String[] parts = fullClassName.split("\\.");
		if(parts != null && fullClassName.length() > 0){
			return DIR_PATH + parts[parts.length - 1] + DONET_CLASS;
		}
		return "";
	}
	
	public static void main(String[] args) {
		//ClassLoader parentCl = MyClassLoader.class.getClassLoader();
		//System.out.println("~~~~ parentCl classloader : "+ parentCl);
		new MyClassLoader().load("org.socket.TestClass","getName","");// load class
	}
}

 

 

package org.socket;

/**
 * @author chares
 *
 */
public class TestClass {
	public String name = "init";
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值