服务器端采用多线程方式并行处理传输请求以提高效率。
因为我想用JavaServiceWrapper将 程序作为windows服务运行,所以main方法中需接收一些参数,比如端口、密钥文件位置、文件存放路径等。
1.从main方法接受配置参数
- for(String arg : args){
- String argName = arg.substring(0,arg.indexOf(":")).trim();
- String argValue = arg.substring(arg.indexOf(":")+1).trim();
- if(argName.equals("rsa_private")){
- privateKey = argValue;
- }else if(argName.equals("rsa_public")){
- publicKey = argValue;
- }else if(argName.equals("port")){
- port = Integer.parseInt(argValue);
- }else if(argName.equals("file_dir")){
- file_dir = argValue;
- }
- }
2.初始化解密、签名类实例
- RSASecurityCoder coder = new RSASecurityCoder(privateKey);
- RSASecuritySignature sign = new RSASecuritySignature(publicKey);
3.建立服务器
- private static void runServer(String[] args){
- long start = System.currentTimeMillis();
- //获取配置参数
- for(String arg : args){
- String argName = arg.substring(0,arg.indexOf(":")).trim();
- String argValue = arg.substring(arg.indexOf(":")+1).trim();
- if(argName.equals("rsa_private")){
- privateKey = argValue;
- }else if(argName.equals("rsa_public")){
- publicKey = argValue;
- }else if(argName.equals("port")){
- port = Integer.parseInt(argValue);
- }else if(argName.equals("file_dir")){
- file_dir = argValue;
- }
- }
- //配置
- coder = new RSASecurityCoder(privateKey);
- sign = new RSASecuritySignature(publicKey);
- //启动服务器
- System.out.println("服务器启动中...");
- try {
- ss = new ServerSocket(port);
- clientCount = 0;
- } catch (NumberFormatException e) {
- System.err.println("端口配置错误");
- } catch (IOException e) {
- System.err.println("服务器在端口"+port+"启动失败");
- }
- //文件存放目录
- dir = new File(file_dir);
- if(!dir.exists()){
- dir.mkdir();
- }
- System.out.println("服务器已启动,端口: "+port);
- //计算启动时间
- long end = System.currentTimeMillis();
- System.out.println("共消耗 "+(end-start)+" ms.");
- //接收数据
- while(true){
- try {
- if(ss == null){
- ss = new ServerSocket(port);
- clientCount = 0;
- }
- Socket socket = ss.accept();
- clientCount += 1;
- System.out.println("有新的连接,当前总连接数:"+clientCount);
- Thread th = new Thread(new ServerProcessor(socket));
- th.start();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
3.建立线程类ServerProcessor处理每个文件
- static class ServerProcessor extends Thread{
- private Socket socket;
- private InputStream in;
- private String filename;
- private long totalBytes;
- private File file;
- private FileOutputStream fos;
- public ServerProcessor(Socket socket){
- this.socket = socket;
- }
- @Override
- public void run(){
- try {
- in = socket.getInputStream();
- DataInputStream dis = new DataInputStream(in);
- filename = dis.readUTF(); //读取文件名
- totalBytes = dis.readLong(); //读取文件大小
- file = new File(dir,filename);
- fos = new FileOutputStream(file);
- //FileOutputStream fos = new FileOutputStream(File.createTempFile(filename, null, dir));
- //输出日志
- //RSA加密以128 bytes位单位,一次最多加密117bytes.
- byte[] buf = new byte[128];
- int available;
- while((available = in.read(buf)) != -1){
- //读取签名
- byte[] signature = buf;
- //读取数据
- buf = new byte[128];
- available = in.read(buf);
- byte[] availableBytes = null;
- if(available == buf.length){
- availableBytes = buf;
- }else{
- availableBytes = new byte[available];
- for (int i = 0; i < available; i++) {
- availableBytes[i] = (Byte) buf[i];
- }
- }
- //验证数据签名
- boolean flag = sign.verifySignature(availableBytes, signature);
- //写入数据
- if(flag){
- //count += availableBytes.length;
- fos.write(coder.decrypt(availableBytes));
- //System.out.println(""+count+" bytes received");
- }
- }
- fos.close();
- socket.shutdownInput();
- clientCount -= 1;
- System.out.println("有连接断开,当前总连接数:"+clientCount);
- System.out.println(new SimpleDateFormat("[yyyy-MM-DD HH:mm:ss ]").format(new Date())
- +filename+" 接收完毕. 大小 "+(totalBytes/1024)+" kb,保存路径:"+dir.getAbsolutePath());
- } catch (NumberFormatException e) {
- System.err.println("端口配置错误");
- e.printStackTrace();
- } catch (FileNotFoundException e) {
- System.err.println("文件没找到,文件名:"+filename+",可能是因为读取socket数据失败");
- e.printStackTrace();
- } catch (IOException e) {
- System.err.println("文件读/写错误");
- try {
- fos.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- file.delete();
- e.printStackTrace();
- }
- }
- }
main方法
- public static void main(String[] args) {
- runServer(args);
- }