`

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
2
分享到:
评论

相关推荐

    java jdk实列宝典 光盘源代码

    自定义日志文件类; 8线程 线程的启动 和停止;线程的互斥;线程的协作;线程join;生产者、消费者问题;线程的优先级;列出虚拟机中所有的线程;守护线程Daemon;线程池;一个死锁的例子; 定时器Timer:包括在指定...

    疯狂JAVA讲义

    1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6 1.3.2 Java程序的运行机制和JVM 6 1.4 开发...

    JAVA面试题最全集

    一个“.java”原文件中是否可以包括多个类(不是内部类)? 53.掌握内部类和接口的概念 54.StringTokenizer类的使用 55.数据结构,如何遍历List中的元素? 如果要按照键值保存或者访问数据,使用什么数据结构? ...

    Java JDK实例宝典

    20 自定义日志文件类 第8章 线程 8. 1 定义和启动线程 8. 2 停止线程 8. 3 线程的互斥 8. 4 线程的协作 8. 5 线程join 8. 6 生产者. 消费者问题 8. 7 线程优先级 8. 8 列出...

    Java 实现的qq程序,头像闪动,托盘图标闪动,聊天

    用户间可以传递文件,发送消息。服务端可以向每个用户发送消息 可以直接运行bat 1、先打开目录SimpleChatServer 下的ChatServer.bat 2、然后再打开SimpleChatClient 下的ChatClient.bat 或者直接放到eclipse下面运行...

    java面试宝典

    75、socket通信(tcp/udp区别及JAVA的实现方式) 18 76、什么是java序列化,如何实现java序列化? 18 77、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 18 78、abstract class Name { private ...

    Java典型模块

    18.3.2 通过FileDir类实现列举文件和目录的功能 18.3.3 File类提供的属性和方法 18.3.4 文件访问的基本概念 18.3.5 文件的基本访问方式——字节方式 18.3.6 文件的基本访问方式——字符方式 18.3.7 文件的高级访问...

    涵盖了90%以上的面试题

    java socket java序列化 JVM加载class文件的原理 双亲委派模型 为什么要自定义类加载器 如何自定义类加载器 什么是GC 内存泄漏和内存溢出 Java的内存模型(JVM的内存划分) JVM内存模型1.7和1.8的区别 如何判断一个...

    21天学通Java-由浅入深

    33分钟) 21 1.1 Java的平台简介 21 1.2 安装工具包 22 1.2.1 下载JDK 22 1.2.2 安装JDK 24 1.2.3 查看与设置环境变量 25 1.2.4 JDK常用命令 27 1.2.5 Java各个目录含义 28 1.2.6 要善于使用JDK的帮助文件 ...

    java数据库连接方法和实现

     本地API驱动 这种类型的驱动通过客户端加载数据库厂商提供的本地代码库(C/C++等)来访问数据库,而在驱动程序中则包含了Java代码。 类型3  网络协议驱动 这种类型的驱动给客户端提供了一个网络API,客户端上的...

    java面试题

    37. 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 18 38. 比较truncate和delete 命令 18 39. 解释$ORACLE_HOME 和$ORACLE_BASE的区别? 19 40. session与cookie的区别和联系? 19 41. ...

    华为 java 安全 编码 规范 安全篇 2.0

    规则 5.5 编写自定义类加载器时应调用超类的getPermission()函数 规则 5.6 避免完全依赖URLClassLoader和java.util.jar提供的默认自动签名认证机制 规则 6.1 禁止给仅执行非特权操作的代码签名 规范 6.2 不要...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【JVM】双亲委派模型中,从顶层到底层,都是哪些类加载器,分别加载哪些类? 55 【JVM】能不能自己写个类叫java.lang.System? 57 【JVM】类的加载过程 58 【JVM】类的初始化 58 类什么时候才被初始化: 58 类的初始...

    千方百计笔试题大全

    75、socket通信(tcp/udp区别及JAVA的实现方式) 18 76、什么是java序列化,如何实现java序列化? 18 77、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 18 78、abstract class Name { private ...

    新版Android开发教程.rar

    � Google 提供了一套 Java 核心包 (J2SE 5,J2SE 6) 的有限子集,尚不承诺遵守 Java 任何 Java 规范 , 可能会造 成J ava 阵营的进一步分裂。 � 现有应用完善度不太够,需要的开发工作量较大。--------------------...

    疯狂Android讲义.part2

    2.1.4 使用XML布局文件和Java 代码混合控制UI界面 42 2.1.5 开发自定义View 43 2.2 布局管理器 46 2.2.1 线性布局 47 2.2.2 表格布局 49 2.2.3 帧布局 52 2.2.4 相对布局 55 2.2.5 绝对布局 58 2.3 基本界面组件 60 ...

    疯狂Android讲义.part1

    2.1.4 使用XML布局文件和Java 代码混合控制UI界面 42 2.1.5 开发自定义View 43 2.2 布局管理器 46 2.2.1 线性布局 47 2.2.2 表格布局 49 2.2.3 帧布局 52 2.2.4 相对布局 55 2.2.5 绝对布局 58 2.3 基本界面组件 60 ...

Global site tag (gtag.js) - Google Analytics