900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Socket编程——功能类似QQ的Java聊天程序(文字聊天 传输文件)

Socket编程——功能类似QQ的Java聊天程序(文字聊天 传输文件)

时间:2019-08-26 03:31:30

相关推荐

Socket编程——功能类似QQ的Java聊天程序(文字聊天 传输文件)

实现功能

验证用户登录两个在线用户间的文字聊天多用户群聊两个在线用户之间传输二进制文件发送离线信息传输离线文件文件断点续传

框架结构

服务器框架结构

客户端框架结构

主要功能设计及实现

为方便表述,约定usr表示用户名,password为密码。srcusr为发送信息或文件的用户;dstusr为接收信息或接收文件的用户。message为文字信息;onlinefile为在线文件信息;offlinefile为离线文件信息。

服务器端主要数据结构客户端主要数据结构验证用户登录

客户端向服务器发送usr和password,服务器端验证usr和password是否合法。若成功登录,服务器向usr发送已登录用户和未登录用户名,通知已登录用户user已经成功登录。两个在线用户间的文字聊天

客户端将信息内容(srcusr+dstusr+message)发送给服务器,服务器转发信息给dstusr。多用户群聊

若dstusr为*,服务器将信息转发给所有的在线用户。

若dstusr为**,服务器将信息转发给所有的用户(在线+离线)。两在线用户间传输文件

客户端向服务器发送消息(onlinefile);服务器端work增加在线传输任务,并初始化work[onlinefile]=false;客户端向服务器传送文件,文件传送完毕时,服务器端设置work[onlinefile]=true,并通知destusr下载文件。文件断点续传

客户端上服务器上传文件前,首先获取已传输字节数量,使用RandomAccessFile.seek()方法在断点出续传。离线文件传输

与在线文件传输的区别是,当dstusr登录时,再通知dstusr下载文件。共享数据加锁

需要对服务器端logined、work、logoutinfo、logoutwork加锁。

在程序中,使用ReentrantLock()对上述4个变量加锁。

客户端和服务器间通信协议设计

因NAT穿透难以实现,本聊天程序采用CS模式,无配合P2P模式。传输协议为TCP。

所传送信息的第一个字符用于区分不同类型的信息,具体CS之间传输信息的协议如下:

服务器接收信息(客户端发送信息)协议

$<usr> <password> --用户登录

#<dstusr> <message> --向dest用户转发信息

%<dstusr> <filelength> <filename> --向dest用户转发文件客户端接收(服务器发送信息)协议

*<users> --用户列表

@<srcusr> <message> --来自source用户的信息

$<usr> --用户user已登录

!<usr> --用户user已登出

#<src> <filename> <filelength> --来自用户source的文件,是否接收

%y/n/e --服务器回复登录情况。%y成功登录;%n账号或密码错误;%e重复登录

客户端指令设计

help --show how to use commandslogin <usr> <password> --log inonlinefriendlist --show online friend listfriendlist --show friend listinfo <friendname> <message> --send message to friend. When friendname is *, send message to friends who are online; when friendname is **, send message to all friends.file <friendname> <filename> --send a file in current folder to friendexit --log out

使用示例

首先,服务器端设置登录账号和密码,程序中默认设置如下:

启动服务器后启动客户端,尝试输入以下指令:

help //get helplogin Jack 123456//登录friendlist //显示所有的用户列表onlinefriendlist //显示上线的用户列表info Mary Hello have a good day! //向Mary发送信息"Hello have a good day!"info * Hello, my online friends //向所有的在线用户发送信息"Hello, my online friends"info ** Hello, all my friends //向所有用户发送信息"Hello, all my friends"file Mary demofile.exe //向Mary发送文件demofile.exeexit //退出程序

问题记录

传输文件名和文件长度等信息时,起初使用对象流,程序出现java.io.EOFException报错。经查看此博客,发现以下两点:

a. 对象流不同于普通的字节流,当对象流中没有数据时,程序却尝试读取数据,会报EOFException;而字节流就不会出现这种情况,字节流会返回-1

b. ObjectInputStream写入的数据,在ObjectOutputStream上读取时,应该按照相同的数据类型依次读取,否则数据类型不等会抛出EOFException

当传送文件信息时使用对象流,因为传输时延,服务器端会检测到无对象流数据,抛出EOFException。

最终,自己使用PrintWriter传递文件信息。将文件名、长度等信息合成一个字符串,使用PrintWriter传输给服务器。当上传和下载文件使用同一个端口时,出现了死锁

当文件上传和下载使用同一个端口时,服务器不可以同时进行上传、下载文件作业,否则会出现死锁。

最终,自己将服务器文件上传和下载功能分离,两者各使用一个端口。

code

服务器:

import java.io.*;import .ServerSocket;import .Socket;import java.util.*;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Server{private ServerSocket messageServer;//收发信息服务器socketprivate ServerSocket receivefileServer;//接收文件服务器socketprivate ServerSocket sendfileServer;//发送文件服务器socketprivate Socket messageSocket;private Socket receivefileSocket;private Socket sendfileSocket;private Hashtable<String,Socket> logined=new Hashtable<String,Socket>();//存储已登录用户socketprivate Lock locklogined = new ReentrantLock();private Hashtable<String,String> user=new Hashtable<String,String>();//存储用户名及其密码,不需要加锁private Hashtable<String,Boolean> work=new Hashtable<String,Boolean>();//转发在线文件任务private Lock lockwork= new ReentrantLock();private Hashtable<String,Queue<String>> logoutinfo =new Hashtable<String,Queue<String>>();//转发离线信息private Lock locklogoutinfo= new ReentrantLock();private Hashtable<String,Boolean> logoutwork=new Hashtable<String,Boolean>();//转发离线文件任务private Lock locklogoutwork= new ReentrantLock();Server(){//初始化用户和密码user.put("Jack", "123456");user.put("Mary","123456");user.put("Wangming","123456");user.put("MRY","123456");user.put("110","123456");createSocket();}public void createSocket() {try {messageServer = new ServerSocket(1978);receivefileServer=new ServerSocket(1979);sendfileServer=new ServerSocket(1980);new Thread(new Runnable(){//收发信息服务器线程,使用线程池@Overridepublic void run() {BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);ThreadPoolExecutor tpe1 = new ThreadPoolExecutor(10, 20, 50, TimeUnit.MILLISECONDS, bq);while (true) {try {messageSocket = messageServer.accept();System.out.println("waiting for client.....");System.out.println("connected....." + messageSocket);tpe1.execute(new messageServerThread(messageSocket));} catch (IOException e) {e.printStackTrace();}// 创建套接字对象}}}).start();new Thread(new Runnable(){//接收文件服务器线程,使用线程池@Overridepublic void run() {BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);ThreadPoolExecutor tpe2 = new ThreadPoolExecutor(5, 10, 50, TimeUnit.MILLISECONDS, bq);while (true) {try {receivefileSocket=receivefileServer.accept();tpe2.execute(new receiverServerThread(receivefileSocket));} catch (IOException e) {e.printStackTrace();}}}}).start();new Thread(new Runnable(){//转发文件服务器线程,使用线程池@Overridepublic void run() {BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);ThreadPoolExecutor tpe3 = new ThreadPoolExecutor(5, 10, 50, TimeUnit.MILLISECONDS, bq);while (true) {try {sendfileSocket=sendfileServer.accept();tpe3.execute(new senderServerThread(sendfileSocket));} catch (IOException e) {e.printStackTrace();}}}}).start();while (true) {System.out.println("waiting for client.....");messageSocket = messageServer.accept();// 创建套接字对象System.out.println("connected....." + messageSocket);new messageServerThread(messageSocket).start();// 创建并启动线程对象}} catch (IOException e) {e.printStackTrace();}}class messageServerThread extends Thread{Socket socket;String usernameforThread;public messageServerThread(Socket socket){this.socket=socket;}public void run() {try {BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 创建输入流对象while (true) {String info = in.readLine().trim();// 读取信息System.out.println(info);if(info.startsWith("$")){//登录String username = "";String password="";String message[]=info.substring(1).split(" ");username=message[0];password=message[1];if(user.containsKey(username)){if(!logined.containsKey(username)){System.out.println("username exits");if(user.get(username).equals(password)){System.out.println("password correct");locklogined.lock();logined.put(username,socket);locklogined.unlock();usernameforThread=username;PrintWriter out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象out.println("%y");out.flush();//传送userSet<String> set1 = user.keySet();out = new PrintWriter(socket.getOutputStream(), true);out.println("*"+set1.toString());//传送在线userSet<String> set = logined.keySet();// 获得集合中所有键的Set视图Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器while(keyIt.hasNext()){String receiveKey = keyIt.next();// 获得表示接收信息的键Socket s = logined.get(receiveKey);// 获得与该键对应的套接字对象if(!receiveKey.equals(username)){out = new PrintWriter(socket.getOutputStream(), true);out.println("$"+receiveKey);out.flush();out = new PrintWriter(s.getOutputStream(), true);// 创建输出流对象out.println("$"+username);out.flush();}}//传送离线信息if(logoutinfo.containsKey(usernameforThread)){Queue<String> q=logoutinfo.get(usernameforThread);out = new PrintWriter(socket.getOutputStream(), true); while(!q.isEmpty()){String m=q.poll();out.println(m);out.flush();}}//传送离线文件Set<String> set3 = logoutwork.keySet();keyIt = set3.iterator();while(keyIt.hasNext()){String f=keyIt.next();String para[]=f.split(" ");if(usernameforThread.equals(para[1])&&logoutwork.get(f)){out = new PrintWriter(socket.getOutputStream(), true);out.println("#"+f);out.flush();locklogoutinfo.lock();logoutinfo.remove(f);locklogoutinfo.unlock();}}}else{//密码错误PrintWriter out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象out.println("%n");out.flush();}}else{//用户已登录PrintWriter out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象out.println("%e");out.flush(); }}else{//无此用户PrintWriter out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象out.println("%n");out.flush();}}else if(info.startsWith("#")){//转发信息String dest="";String message="";int index;for(index=0;index<info.length();index++){if(info.charAt(index)==' '){break;}}dest=info.substring(1, index);message=info.substring(index+1);if(dest.equals("*")){//在线用户Set<String> set = logined.keySet();// 获得集合中所有键的Set视图Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器while(keyIt.hasNext()){String receiveKey = keyIt.next();// 获得表示接收信息的键Socket s = logined.get(receiveKey);// 获得与该键对应的套接字对象if(!receiveKey.equals(usernameforThread)){PrintWriter out = new PrintWriter(s.getOutputStream(), true);// 创建输出流对象out.println("@"+usernameforThread+" "+message);out.flush();}}}else if(dest.equals("**")){//所有用户Set<String> set = user.keySet();// 获得集合中所有键的Set视图Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器while(keyIt.hasNext()){String receiveKey = keyIt.next();// 获得表示接收信息的键if(logined.containsKey(receiveKey)){Socket s = logined.get(receiveKey);// 获得与该键对应的套接字对象if(!receiveKey.equals(usernameforThread)){PrintWriter out = new PrintWriter(s.getOutputStream(), true);// 创建输出流对象out.println("@"+usernameforThread+" "+message);out.flush();}}else{locklogoutinfo.lock();if(!logoutinfo.containsKey(receiveKey)){logoutinfo.put(receiveKey,new LinkedList<String>());}logoutinfo.get(receiveKey).add("@"+usernameforThread+" "+message);locklogoutinfo.unlock();}}}else if(logined.containsKey(dest)){Socket s = logined.get(dest);// 获得与该键对应的套接字对象PrintWriter out = new PrintWriter(s.getOutputStream(), true);// 创建输出流对象out.println("@"+usernameforThread+" "+message);out.flush();}else{if(!logoutinfo.containsKey(dest)){logoutinfo.put(dest,new LinkedList<String>());}logoutinfo.get(dest).add("@"+usernameforThread+" "+message);}}else if(info.startsWith("%")){//转发文件String key=info.substring(1);String para[]=key.split(" ");if(logined.containsKey(para[1])){//在线传文件lockwork.lock();work.put(key, false);lockwork.unlock();System.out.println("tranfort"+" "+key);new Thread(new Runnable(){@Overridepublic void run() {while(!work.get(key)){;}try {PrintWriter out = new PrintWriter(logined.get(para[1]).getOutputStream(), true);out.println("#"+key);out.flush();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 创建输出流对象}}).start();}else{//离线传文件locklogoutwork.lock();logoutwork.put(key,false);locklogoutwork.unlock();System.out.println("tranfort"+" "+key);new Thread(new Runnable(){@Overridepublic void run() {while(!logoutwork.get(key)){;}try {if(logined.containsKey(para[1])){PrintWriter out = new PrintWriter(logined.get(para[1]).getOutputStream(), true);out.println("#"+key);out.flush();locklogoutwork.lock();logoutwork.remove(key);locklogoutwork.unlock();}} catch (IOException e) {e.printStackTrace();}// 创建输出流对象}}).start();}}else{System.out.println("unknown information!");}}} catch (IOException e) {System.out.println(socket + "has exited");Set<String> set = logined.keySet();// 获得集合中所有键的Set视图Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器while(keyIt.hasNext()){String receiveKey = keyIt.next();// 获得表示接收信息的键Socket s = logined.get(receiveKey);// 获得与该键对应的套接字对象if(!receiveKey.equals(usernameforThread)){PrintWriter out;try {out = new PrintWriter(s.getOutputStream(), true);out.println("!"+usernameforThread);out.flush();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}}locklogined.lock();logined.remove(usernameforThread);locklogined.unlock();}}}class receiverServerThread extends Thread{Socket socket;String path;String savapath;String source;String dest;String filename;long filelength;OutputStream outputStream;InputStream inputStream;FileInputStream fileInput;FileOutputStream fileoutput;int buffersize=8*1024;String key;public receiverServerThread(Socket socket){this.socket=socket;System.out.println(this.socket);}public void run(){receiveFile();}public void receiveFile() {try {inputStream=socket.getInputStream();outputStream=socket.getOutputStream();BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));String key = in.readLine().trim();String para[]=key.split(" ");source=para[0];dest=para[1];filename=para[2];filelength=Integer.valueOf(para[3]).longValue();System.out.println("*"+source+" "+dest+" "+filename+" "+filelength);File dir=new File("database/"+source);if (!dir.exists()) {dir.mkdirs();}String savePath = "database/"+source+"/"+filename; // 定义完整的存储路径File parameter = new File(savePath); // 创建文件的存储路径if (!parameter.exists()) {try {parameter.createNewFile();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}RandomAccessFile access = new RandomAccessFile(parameter,"rw");access.seek(parameter.length());PrintWriter out = new PrintWriter(outputStream, true);// 创建输出流对象out.println(parameter.length());try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}byte[] buffer = new byte[buffersize];//创建接收缓冲区int len=-1;while((len = inputStream.read(buffer))!=-1){access.write(buffer,0,len);}if(parameter.length()>=filelength){if(work.containsKey(key)){lockwork.lock();work.replace(key, true);lockwork.unlock();}if(logoutwork.containsKey(key)){locklogoutwork.lock();logoutwork.replace(key, true);locklogoutwork.unlock();}System.out.println("update file finished!");}access.close();out.close();in.close();} catch (IOException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}finally{try {inputStream.close();outputStream.close();socket.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class senderServerThread extends Thread{Socket socket;String path;OutputStream outputStream;InputStream inputStream;FileInputStream fileInput;FileOutputStream fileoutput;int buffersize=8*1024;public senderServerThread(Socket socket){this.socket=socket;}public void run(){sendfile();}void sendfile(){try {inputStream=socket.getInputStream();outputStream=socket.getOutputStream();BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));String key = in.readLine().trim();System.out.println(key);System.out.println(work.get(key));System.out.println(logoutwork.get(key));if((work.containsKey(key)&&work.get(key))||(logoutwork.containsKey(key)&&logoutwork.get(key))){String para[]=key.split(" ");String source=para[0];String dest=para[1];String filename=para[2];long filelength=Integer.valueOf(para[3]).longValue();path="database/"+source+"/"+filename;FileInputStream fileInput = new FileInputStream(path);int size = -1;byte[] buffer = new byte[buffersize];int sum=0;while ((size = fileInput.read(buffer, 0, buffersize)) !=-1) {sum+=size;System.out.println(sum/1024);outputStream.write(buffer, 0, size);outputStream.flush();}System.out.println("download finish");lockwork.lock();work.remove(key);lockwork.unlock();locklogoutwork.lock();logoutwork.remove(key);locklogoutwork.unlock();fileInput.close();}outputStream.flush();in.close();} catch (Exception e) {e.printStackTrace();}finally{try {inputStream.close();outputStream.close();socket.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public static void main(String args[]) {new Server();}}

客户端:

import java.io.*;import .*;import java.util.*;import java.text.DecimalFormat;public class Client {PrintWriter out;// 声明输出流对象private boolean loginFlag = false;// 为true时表示已经登录,为false时表示未登录private Set<String> friends=new TreeSet<String>();//在线好友列表private Set<String> users=new TreeSet<String>();//好友列表private String myself;//本机用户名private String receivefile;//当服务器询问是否接收文件时,保存文件的信息。若同意接收,则使用此信息向服务器请求发送文件private String ipv4="127.0.0.1";//服务器ip地址,我的服务器地址为47.98.153.188,需要修改成相应的服务器地址/*** author:XJTU mry* time:.04.20*/public static void main(String args[]) {new Client();}Client(){createClientSocket();}public void createClientSocket() {try {Socket socket = new Socket(ipv4, 1978);// 创建套接字对象,连接服务器//1978为服务器信息转发端口,1979为服务器接收文件端口,1980为服务器发送文件端口out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象new ClientThreadreceiveMessage(socket).start();//客户端接收信息线程new ClientThreadsendMessage(socket).start();//客户端发送信息线程} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}class ClientThreadreceiveMessage extends Thread {//客户端接收信息类。为内部类,可以访问Client类中定义的变量Socket socket;public ClientThreadreceiveMessage (Socket socket) {//构造函数,传入已经连接服务器后的socketthis.socket = socket;}public void run() {try {BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 创建输入流对象while (true) {String info = in.readLine().trim();// 读取信息//System.out.println(info);if(info.startsWith("@")){String source="";String message="";int index;for(index=0;index<info.length();index++){if(info.charAt(index)==' '){break;}}source=info.substring(1, index);message=info.substring(index+1);System.out.println("$"+source+":"+message);}else if(info.startsWith("$")){friends.add(info.substring(1));}else if(info.startsWith("!")){if(friends.contains(info.substring(1))){friends.remove(info.substring(1));}}else if(info.startsWith("#")){receivefile=info.substring(1);String para[]=receivefile.split(" ");System.out.println("#A file from"+" "+para[0]+" "+"name:"+para[2]+" "+"size:"+para[3]+"B");System.out.println("please type: y/n");}else if(info.startsWith("%")){//回复登录情况if(info.charAt(1)=='y'){loginFlag=true;System.out.println("log in successed!");}if(info.charAt(1)=='e'){System.out.println("log in failed! The user has logged in!");System.out.println("please try again");}else if(info.charAt(1)=='n'){System.out.println("log in failed! password is wrong!");System.out.println("please try again");}}else if(info.startsWith("*")){String usrs[]=info.substring(2,info.length()-1).split(",");for(int i=0;i<usrs.length;i++){users.add(usrs[i].trim());}}else{System.out.println("unknown information!");}}} catch (IOException e) {e.printStackTrace();}}}class ClientThreadsendMessage extends Thread{//客户端发送信息类。为内部类,可以访问Client类中定义的变量Socket socket;Scanner scanner = new Scanner(System.in);String command="";Socket receiveFileSocket;Socket sendFileSocket;ClientThreadsendMessage(Socket socket){this.socket=socket;}void help(){System.out.println("login <username> <password> --log in");System.out.println("onlinefriendlist --show online friend list");System.out.println("friendlist --show friend list");System.out.println("info <friendname> <message> --send message to friend");System.out.println("file <friendname> <filename> --send file to friend");System.out.println("exit--log out");}public void run(){while(!loginFlag){System.out.println("please log in first");command=scanner.nextLine().trim();if(loginFlag)break;if(command.equals("help")){help();}if(command.equals("exit")){System.exit(0);}if(command.startsWith("login")){String cmd="$";StringTokenizer oo = new StringTokenizer(command.substring(5));List<String> tmp=new ArrayList<String>();while (oo.hasMoreTokens()){tmp.add(oo.nextToken());}if(tmp.size()==2){cmd=cmd+tmp.get(0)+" "+tmp.get(1);myself=tmp.get(0);out.println(cmd.trim());out.flush();}else{System.out.println("unknown command");}}}while(true){if(command.equals("friendlist")){System.out.println(users.toString());}else if(command.equals("onlinefriendlist")){System.out.println(friends.toString());}else if(command.equals("help")){help();}else if(command.startsWith("info")){String cmd="#";StringTokenizer oo = new StringTokenizer(command.substring(4));while (oo.hasMoreTokens()){cmd+=oo.nextToken();cmd+=" ";}int index=-1;for(int i=0;i<cmd.length();i++){if(cmd.charAt(i)==' '){index=i;break;}}if(index>0){if(users.contains(cmd.substring(1, index))||cmd.substring(1,index).equals("*")||cmd.substring(1,index).equals("**")){out.println(cmd.trim());out.flush();}else{System.out.println("dest user doesn't exist!");}}else{System.out.println("unknown command!");}}else if(command.startsWith("file")){String cmd="%";List<String> tmp=new ArrayList<String>();StringTokenizer oo = new StringTokenizer(command.substring(4));while (oo.hasMoreTokens()){tmp.add(oo.nextToken());}if(tmp.size()==2){if(users.contains(tmp.get(0))){File src = new File(tmp.get(1));if(src.exists()){cmd=cmd+myself+" "+tmp.get(0)+" "+src.getName()+" "+src.length();//System.out.println(cmd);out.println(cmd.trim());out.flush();try {sleep(500);} catch (InterruptedException e1) {e1.printStackTrace();}Socket sendFilSocket;try {sendFilSocket = new Socket(ipv4, 1979);//System.out.println(myself+" "+tmp.get(0)+" "+src.getName()+" "+src.length());new senderServerThread(sendFilSocket,myself,tmp.get(0),src.getName(),src.length()).start();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}else{System.out.println("file doesn't exit!");}}else{System.out.println("dest user doesn't exist!");}}else{System.out.println("unkown command!");}}else if(command.equals("y")){try {Socket socket = new Socket(ipv4, 1980);new receiverServerThread(socket,receivefile).start();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}// 创建套接字对象}else if(command.equals("n")){;}else if(command.equals("exit")){System.exit(0);}else{System.out.println("unkown command!");}command=scanner.nextLine().trim();}}}class senderServerThread extends Thread{//客户端向服务器上传文件类,先传递文件名字、长度等基本信息,再传送文件内容Socket socket;String path;String source;String dest;String filename;long filelength;OutputStream outputStream;InputStream inputStream;FileInputStream fileInput;FileOutputStream fileoutput;int buffersize=8*1024;public senderServerThread(Socket socket,String source,String dest,String filename,long filelength){this.socket=socket;this.source=source;this.dest=dest;this.filename=filename;this.filelength=filelength;this.path=filename;}public void run(){sendfile();}void sendfile(){try {inputStream=socket.getInputStream();outputStream=socket.getOutputStream();PrintWriter out = new PrintWriter(outputStream, true);// 创建输出流对象out.println(source+" "+dest+" "+filename+ " "+filelength);BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));String Stringlen = in.readLine().trim();long len=Integer.valueOf(Stringlen).longValue();//System.out.println("断点续传:"+len);File file = new File(path);RandomAccessFile access = new RandomAccessFile(file,"r");access.seek(len);int size = -1;byte[] buffer = new byte[buffersize];long sum=0;sum+=len;System.out.println("file upload start");ConsoleProgressBarDemo cpb = new ConsoleProgressBarDemo(50, '#');while ((size = access.read(buffer, 0, buffersize)) !=-1) {sum+=size;cpb.show((int)(sum*100/filelength));outputStream.write(buffer, 0, size);outputStream.flush();}System.out.println("upload ended");outputStream.flush();access.close();in.close();out.close();} catch (Exception e) {e.printStackTrace();}finally{try {inputStream.close();outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}}class receiverServerThread extends Thread{//客户端下载文件类,先向服务器传递文件名字、长度等基本信息(Client类变量receivefile),然后接收文件具体内容Socket socket;String path;String savapath;String source;String dest;String filename;long filelength;OutputStream outputStream;InputStream inputStream;FileInputStream fileInput;FileOutputStream fileoutput;int buffersize=8*1024;String receivefile;public receiverServerThread(Socket socket,String receivefile){this.socket=socket;String para[]=receivefile.split(" ");source=para[0];dest=para[1];filename=para[2];filelength=Integer.valueOf(para[3]).longValue();this.receivefile=receivefile.trim();}public void run(){receiveFile();}public void receiveFile() {try {inputStream=socket.getInputStream();outputStream=socket.getOutputStream();PrintWriter out = new PrintWriter(outputStream, true);// 创建输出流对象out.println(receivefile);File dir = new File("database/"+source); // 创建文件的存储路径if (!dir.exists()) {dir.mkdirs();}String savePath = "database/"+source+"/"+filename; // 定义完整的存储路径File parameter = new File(savePath); // 创建文件的存储路径if (!parameter.exists()) {try {parameter.createNewFile();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}FileWriter fileWriter;fileWriter = new FileWriter(parameter);fileWriter.write("");fileWriter.flush();fileWriter.close();FileOutputStream file = new FileOutputStream(parameter, false);byte[] buffer = new byte[buffersize];//创建接收缓冲区int len=-1;long sum=0;ConsoleProgressBarDemo cpb = new ConsoleProgressBarDemo(50, '#');while((len = inputStream.read(buffer))!=-1){file.write(buffer, 0, len);sum+=len;cpb.show((int)(sum*100/filelength));if(sum>=filelength){break;}}System.out.println("download ended");file.close();out.close();} catch (IOException e2) {e2.printStackTrace();}finally{try {inputStream.close();outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}}public class ConsoleProgressBarDemo {//进度条类,显示进度条private int barLen;private char showChar;private DecimalFormat formater = new DecimalFormat("#.##%");public ConsoleProgressBarDemo(int barLen, char showChar) {this.barLen = barLen;this.showChar = showChar;}public void show(int value) {if (value < 0 || value > 100) {return;}reset();// 比例float rate = (float) (value*1.0 / 100);// 比例*进度条总长度=当前长度draw(barLen, rate);if (value == 100L) {afterComplete();}}private void draw(int barLen, float rate) {int len = (int) (rate * barLen);System.out.print("Progress: ");for (int i = 0; i < len; i++) {System.out.print(showChar);}for (int i = 0; i < barLen-len; i++) {System.out.print(" ");}System.out.print(" |" + format(rate));}private void reset() {System.out.print('\r');}private void afterComplete() {System.out.print('\n');}private String format(float num) {return formater.format(num);}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。