300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 网络聊天室————韩顺平版qq(有离线功能)

网络聊天室————韩顺平版qq(有离线功能)

时间:2020-06-28 01:09:57

相关推荐

网络聊天室————韩顺平版qq(有离线功能)

一、项目开发

二、需求分析

三、架构图(精华)

四、功能展现

服务端

客户端

登录

多用户

私聊

接收

群聊

文件传输

服务器推送

离线信息(登录之后把离线的时候别人发的信息发送,支持多条)

五、源码

服务端:

因为序列化和反序列化的原因,在转送user和Message类型的对象的时候,包名也要一样,不然会报错。

客户端和服务端之间的通信对象

package com.hwk.qqcommon;import java.io.Serializable;/**客户端和服务端之间的通信对象*/public class Message implements Serializable {private static final long serialVersionUID = 1L;private String sender ;private String getter;private String content;private String sendTime;private String mesType;//文件的扩展private byte[] fileByte;public byte[] getFileByte() {return fileByte;}public void setFileByte(byte[] fileByte) {this.fileByte = fileByte;}public int getFileLen() {return fileLen;}public void setFileLen(int fileLen) {this.fileLen = fileLen;}public String getDest() {return dest;}public void setDest(String dest) {this.dest = dest;}public String getSource() {return source;}public void setSource(String source) {this.source = source;}private int fileLen;private String dest;private String source;public Message(String sender, String getter, String content, String sendTime) {this.sender = sender;this.getter = getter;this.content = content;this.sendTime = sendTime;}public Message(){}public String getSender() {return sender;}public void setSender(String sender) {this.sender = sender;}public String getGetter() {return getter;}public void setGetter(String getter) {this.getter = getter;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getSendTime() {return sendTime;}public void setSendTime(String sendTime) {this.sendTime = sendTime;}public String getMesType() {return mesType;}public void setMesType(String mesType) {this.mesType = mesType;}@Overridepublic String toString() {return "Message{" +"sender='" + sender + '\'' +", getter='" + getter + '\'' +", content='" + content + '\'' +", sendTime='" + sendTime + '\'' +", mesType='" + mesType + '\'' +'}';}}

登录用到的

package com.hwk.qqcommon;public interface MessageType {String MESSAGE_LONG_SUCCESS = "1";//登陆成功的String MESSAGE_LONG_FAILE = "2";//登录失败的String MESSAGE_COMM_MES = "3";String MESSAGE_GET_ONLINE_FRIEND = "4";//要求返回在线用户String MESSAGE_RET_ONLINE_FRIEND = "5";//返回在线用户的列表String MESSAGE_CLIENT_EXIT = "6";//客户端退出String MESSAGE_T0_ALL_MES = "7";//群发的消息String MESSAGE_FILE_MES = "8";//文件的发送}

登录的类型

package com.hwk.qqcommon;import java.io.Serializable;/**@author hwk* 表示一个用户信息*/public class User implements Serializable {private String userId;private String passwd;private static final long serialVersionUID = 1L;//提高兼容性public User(String userId, String passwd) {this.userId = userId;this.passwd = passwd;}public User(){}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getPasswd() {return passwd;}public void setPasswd(String passwd) {this.passwd = passwd;}@Overridepublic String toString() {return "User{" +"userId='" + userId + '\'' +", passwd='" + passwd + '\'' +'}';}}

服务器的登录管理

package com.hwk.qqserve;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import com.hwk.qqcommon.User;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .ServerSocket;import .Socket;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.concurrent.ConcurrentHashMap;//服务器管理public class qqserver {//提升成员变量,扩大作用域private ServerSocket serverSocket;//线程安全,比hashmap安全private static ConcurrentHashMap<String ,User> validUser = new ConcurrentHashMap<>(15);private static ConcurrentHashMap<String,ArrayList<Message>> messdb = new ConcurrentHashMap<>();// 离线信息的存储public static ConcurrentHashMap<String, ArrayList<Message>> getMessdb() {return qqserver.messdb;}public static ArrayList<Message> getlxList(String key1){return qqserver.messdb.get(key1);}public static void addMessdb(String key ,Message message) {ArrayList<Message> arrayList = new ArrayList<>();if(qqserver.getlxList(key) != null){arrayList = qqserver.getlxList(key);}arrayList.add(message);qqserver.messdb.put(key,arrayList);}//初始化static {validUser.put("100",new User("100","123"));validUser.put("hwk",new User("hwk","12345"));validUser.put("200",new User("200","123"));validUser.put("300",new User("300","123"));validUser.put("舞剑",new User("舞剑","123"));validUser.put("紫霞",new User("紫霞","321"));}//构造函数里执行public qqserver() {System.out.println("服务器在9990端口监听");try {serverSocket = new ServerSocket(9990);new Thread(new sendNewstoAll()).start();Socket socket;while (true){socket = serverSocket.accept();ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());//接收客户端发的用户信息是否在服务端有记录User user1 = (User) ois.readObject();ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());Message mes = new Message();//有记录就放回MESSAGE_LONG_SUCCESS类型的mesif(checkUser(user1.getUserId(),user1.getPasswd())){mes.setMesType(MessageType.MESSAGE_LONG_SUCCESS);oos.writeObject(mes);servserConnectClinetThread servserConnectClinetThread = new servserConnectClinetThread(socket, user1.getUserId());servserConnectClinetThread.start();ManageClientConnectServe.addClentConnetServierThread(user1.getUserId(),servserConnectClinetThread);ArrayList<Message> arrayList = null;if((arrayList = qqserver.getlxList(user1.getUserId())) != null){for (Message mes1 : arrayList ) {ObjectOutputStream oos1 = new ObjectOutputStream(servserConnectClinetThread.getSocket().getOutputStream());oos1.writeObject(mes1);System.out.println(mes1.getSender()+"对"+mes1.getGetter()+"说:"+mes1.getContent());}qqserver.messdb.remove(user1.getUserId());}}//发送登录失败的记录else{mes.setMesType(MessageType.MESSAGE_LONG_FAILE);oos.writeObject(mes);}}} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {//循环最后关闭serverSockettry {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}//检测用户传的user是否在map里面public boolean checkUser(String userId,String pwd){User user = validUser.get(userId);if(user == null){return false;}if(!user.getPasswd().equals(pwd)){return false;}return true;}}

服务器的线程管理

package com.hwk.qqserve;import java.util.Iterator;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;//服务端线程管理,包括socekt的属性public class ManageClientConnectServe {private static ConcurrentHashMap<String ,servserConnectClinetThread> hm = new ConcurrentHashMap<>();//将线程加到map里面public static void addClentConnetServierThread(String userId, servserConnectClinetThread servserConnectClinetThread){hm.put(userId,servserConnectClinetThread);}//获得id线程public static servserConnectClinetThread getservserConnectClinetThread(String userId){return hm.get(userId);}//获得当前在线用户名public static String getOnlineUsers(){Set keySet = hm.keySet();Iterator<String> iterator = keySet.iterator();String onlineUserList = "";while (iterator.hasNext()){onlineUserList += iterator.next().toString()+" ";}return onlineUserList;}//public static void removeConnectClinetThread(String userid){hm.remove(userid);}public static ConcurrentHashMap<String, servserConnectClinetThread> getHm() {return hm;}}

服务器线程管理

package com.hwk.qqserve;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .Socket;import java.util.Iterator;import java.util.concurrent.ConcurrentHashMap;//自定义线程public class servserConnectClinetThread extends Thread{private Socket socket;private String userId;public servserConnectClinetThread(Socket socket, String userId) {this.socket = socket;this.userId = userId;}@Overridepublic void run() {while (true){//不断循环执行System.out.println("服务器和客服端保持通信");try {//读取用户发的信息ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());System.out.println("服务器和客户端"+userId+"保持通信,读取数据中");Message mes = (Message) ois.readObject();//判断是否是请求用户列表的if(mes.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)){System.out.println(mes.getSender()+"要在线用户的列表");//放回用户列表String onlineUser = ManageClientConnectServe.getOnlineUsers();Message mes1 = new Message();//十设置相关属性mes1.setContent(onlineUser);mes1.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);mes1.setGetter(mes.getSender());mes1.setSender(userId);//发出ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());oos.writeObject(mes1);}else if(mes.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT)){System.out.println(mes.getSender()+"退出系统了");ManageClientConnectServe.removeConnectClinetThread(mes.getSender());socket.close();break;}else if(mes.getMesType().equals(MessageType.MESSAGE_COMM_MES)){try {servserConnectClinetThread servserConnectClinetThread = ManageClientConnectServe.getservserConnectClinetThread(mes.getGetter());//看接收方是否登录if(servserConnectClinetThread != null){System.out.println(mes.getSender()+"对"+mes.getGetter()+"说:"+mes.getContent());ObjectOutputStream oos = new ObjectOutputStream(servserConnectClinetThread.getSocket().getOutputStream());oos.writeObject(mes);}//离线信息的存储else{qqserver.addMessdb(mes.getGetter(),mes);}} catch (IOException e) {}}else if(mes.getMesType().equals(MessageType.MESSAGE_T0_ALL_MES)){String onlineName = "";ConcurrentHashMap<String,servserConnectClinetThread> hm = ManageClientConnectServe.getHm();Iterator<String> iterator = hm.keySet().stream().iterator();while(iterator.hasNext()){onlineName = iterator.next().toString();if(!onlineName.equals(mes.getSender())){ObjectOutputStream oos = new ObjectOutputStream(hm.get(onlineName).getSocket().getOutputStream());oos.writeObject(mes);}}System.out.println(mes.getSender()+"对大家说:"+mes.getContent());}else if(mes.getMesType().equals(MessageType.MESSAGE_FILE_MES)){ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServe.getservserConnectClinetThread(mes.getGetter()).getSocket().getOutputStream());oos.writeObject(mes);}else{System.out.println("其他message,不做处理!");}} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {}}}public Socket getSocket() {return socket;}public void setSocket(Socket socket) {this.socket = socket;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}}

服务器实现消息推送和退出

package com.hwk.qqserve;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import com.hwk.utils.utility;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.Date;import java.util.Iterator;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;public class sendNewstoAll implements Runnable{@Overridepublic void run() {while (true) {System.out.println("请输入服务器要推送的新闻/消息 输入exit退出推送/quit退出服务器");String onlineUser = "";String str = utility.readString(50);if(str.equals("exit")){break;}if(str.equals("quit")){System.exit(0);}Message message = new Message();message.setSender("服务器");message.setContent(str);message.setSendTime(new Date().toString());message.setMesType(MessageType.MESSAGE_T0_ALL_MES);System.out.println("服务器给所有人说" + message.getContent());//遍历所有线程ConcurrentHashMap<String, servserConnectClinetThread> hm = ManageClientConnectServe.getHm();Set<String> keySet = hm.keySet();Iterator<String> iterator = keySet.iterator();while (iterator.hasNext()) {onlineUser = iterator.next();try {servserConnectClinetThread servserConnectClinetThread = hm.get(onlineUser);ObjectOutputStream oos = new ObjectOutputStream(servserConnectClinetThread.getSocket().getOutputStream());oos.writeObject(message);} catch (IOException e) {e.printStackTrace();}}}}}

入口

package com.hwk.qqframe;import com.hwk.qqserve.qqserver;//创建server,启动后台服务public class qqframe {public static void main(String[] args) {new qqserver();}}

客户端

界面的

package com.hwk.qqclient.view;import com.hwk.qqclient.service.FileClientService;import com.hwk.qqclient.service.UserClientService;import com.hwk.qqclient.service.messageClient;import com.hwk.qqclient.utils.utility;public class view {private boolean loop =true;private String key = "";//定义用户工具成员private final UserClientService userClientService = new UserClientService();//信息控制的private messageClient messageClient1 = new messageClient();//文件处理的private FileClientService fileClientService = new FileClientService();public static void main(String[] args) throws Exception{new view().mainMenu();}//菜单private void mainMenu() throws Exception{while (loop){System.out.println("-------------欢迎登录网络通信系统-------------");System.out.println("\t\t 1 登录系统");System.out.println("\t\t 9 退出系统");System.out.println("输入你的需求:");key = utility.readString(1);switch(key){case "1":System.out.println("输入用户号");String userId = utility.readString(50);System.out.println("输入密码");String pwd = utility.readString(50);//判断登陆是否成功if(userClientService.checkedUser(userId,pwd)){System.out.println("-------------欢迎"+userId+"登录网络通信系统-------------");while (loop){System.out.println("\n-------------欢迎"+userId+"进入二级菜单-------------");System.out.println("\t\t 1 显示在线用户列表");System.out.println("\t\t 2 群聊");System.out.println("\t\t 3 私聊");System.out.println("\t\t 4 发送文件");System.out.println("\t\t 9 退出系统");System.out.println("输入你的选择:");key = utility.readString(1);switch (key){case "1"://在线用户显示userClientService.onlineFreindList();break;case "2":System.out.println("输入想对大家说的话:");String str = utility.readString(100);messageClient1.sendMessagetoAll(str,userId);//群聊方法break;case "3":System.out.println("输入想私聊的用户名");String getterId = utility.readString(50);System.out.println("输入想说的话:");String content = utility.readString(100);//编写方法,发送请求给服务器,私聊messageClient1.sendMessagetoOne(content,userId,getterId);break;case "4":System.out.println("输入目标用户");String getterId1 = utility.readString(50);System.out.println("输入你的文件地址(形式 d:\\\\xx.jpg)");String src = utility.readString(50);System.out.println("输入目标用户的文件地址");String dest = utility.readString(51);// messageClient1.fileClientService.sendFiletoOne(src,dest,userId,getterId1);break;case "9":loop = false;//通知服务端退出系统userClientService.logout();break;}}}else{System.out.println("-------------登录失败-------------");}break;case "9":loop = false;break;}}}}

工具类

package com.hwk.qqclient.utils;/**工具类的作用:处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。*/import java.util.*;/***/public class utility {//静态属性。。。private static Scanner scanner = new Scanner(System.in);/*** 功能:读取键盘输入的一个菜单选项,值:1——5的范围* @return 1——5*/public static char readMenuSelection() {char c;for (; ; ) {String str = readKeyBoard(1, false);//包含一个字符的字符串c = str.charAt(0);//将字符串转换成字符char类型if (c != '1' && c != '2' &&c != '3' && c != '4' && c != '5') {System.out.print("选择错误,请重新输入:");} else break;}return c;}/*** 功能:读取键盘输入的一个字符* @return 一个字符*/public static char readChar() {String str = readKeyBoard(1, false);//就是一个字符return str.charAt(0);}/*** 功能:读取键盘输入的一个字符,如果直接按回车,则返回指定的默认值;否则返回输入的那个字符* @param defaultValue 指定的默认值* @return 默认值或输入的字符*/public static char readChar(char defaultValue) {String str = readKeyBoard(1, true);//要么是空字符串,要么是一个字符return (str.length() == 0) ? defaultValue : str.charAt(0);}/*** 功能:读取键盘输入的整型,长度小于2位* @return 整数*/public static int readInt() {int n;for (; ; ) {String str = readKeyBoard(10, false);//一个整数,长度<=10位try {n = Integer.parseInt(str);//将字符串转换成整数break;} catch (NumberFormatException e) {System.out.print("数字输入错误,请重新输入:");}}return n;}/*** 功能:读取键盘输入的 整数或默认值,如果直接回车,则返回默认值,否则返回输入的整数* @param defaultValue 指定的默认值* @return 整数或默认值*/public static int readInt(int defaultValue) {int n;for (; ; ) {String str = readKeyBoard(10, true);if (str.equals("")) {return defaultValue;}//异常处理...try {n = Integer.parseInt(str);break;} catch (NumberFormatException e) {System.out.print("数字输入错误,请重新输入:");}}return n;}/*** 功能:读取键盘输入的指定长度的字符串* @param limit 限制的长度* @return 指定长度的字符串*/public static String readString(int limit) {return readKeyBoard(limit, false);}/*** 功能:读取键盘输入的指定长度的字符串或默认值,如果直接回车,返回默认值,否则返回字符串* @param limit 限制的长度* @param defaultValue 指定的默认值* @return 指定长度的字符串*/public static String readString(int limit, String defaultValue) {String str = readKeyBoard(limit, true);return str.equals("")? defaultValue : str;}/*** 功能:读取键盘输入的确认选项,Y或N* 将小的功能,封装到一个方法中.* @return Y或N*/public static char readConfirmSelection() {System.out.println("请输入你的选择(Y/N): 请小心选择");char c;for (; ; ) {//无限循环//在这里,将接受到字符,转成了大写字母//y => Y n=>NString str = readKeyBoard(1, false).toUpperCase();c = str.charAt(0);if (c == 'Y' || c == 'N') {break;} else {System.out.print("选择错误,请重新输入:");}}return c;}/*** 功能: 读取一个字符串* @param limit 读取的长度* @param blankReturn 如果为true ,表示 可以读空字符串。* 如果为false表示 不能读空字符串。**如果输入为空,或者输入大于limit的长度,就会提示重新输入。* @return*/private static String readKeyBoard(int limit, boolean blankReturn) {//定义了字符串String line = "";//scanner.hasNextLine() 判断有没有下一行while (scanner.hasNextLine()) {line = scanner.nextLine();//读取这一行//如果line.length=0, 即用户没有输入任何内容,直接回车if (line.length() == 0) {if (blankReturn) return line;//如果blankReturn=true,可以返回空串else continue; //如果blankReturn=false,不接受空串,必须输入内容}//如果用户输入的内容大于了 limit,就提示重写输入//如果用户如的内容 >0 <= limit ,我就接受if (line.length() < 1 || line.length() > limit) {System.out.print("输入长度(不能大于" + limit + ")错误,请重新输入:");continue;}break;}return line;}}

客户端线程管理

package com.hwk.qqclient.service;import java.util.concurrent.ConcurrentHashMap;//线程管理,是一个ConcurrentHashMap,线程安全public class ManageClientConnectServe {private static ConcurrentHashMap<String ,clientContentServerThread> hm = new ConcurrentHashMap<>();public static void addClentConnetServierThread(String userId, clientContentServerThread clientContentServerThread){hm.put(userId,clientContentServerThread);}public static clientContentServerThread getclientContentServerThread(String userId){return hm.get(userId);}}

客户端的线程

package com.hwk.qqclient.service;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import .Socket;//用户线程,线程里有socket属性来联系服务public class clientContentServerThread extends Thread{private Socket socket;public clientContentServerThread(Socket socket){this.socket = socket;}public Socket getSocket() {return socket;}@Overridepublic void run() {ObjectInputStream ois = null;System.out.println("客户端线程等待,从服务器端来的数据");while (true){try {ois = new ObjectInputStream(socket.getInputStream());//如果服务器没有发送Message对象,线程会阻塞在这里Message mes = (Message) ois.readObject();if(mes.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)){String[] onlienUser = mes.getContent().split(" ");System.out.println("当前在线的用户列表");for(int i = 0;i < onlienUser.length; i++){System.out.println("用户"+onlienUser[i]);}}else if(mes.getMesType().equals(MessageType.MESSAGE_COMM_MES)){System.out.println("\n"+mes.getSender()+"对"+mes.getGetter()+"说:"+mes.getContent());}else if(mes.getMesType().equals(MessageType.MESSAGE_T0_ALL_MES)){System.out.println("\n"+mes.getSender()+"对大家说:"+mes.getContent());}else if(mes.getMesType().equals(MessageType.MESSAGE_FILE_MES)){System.out.println("\n"+mes.getSender()+"给"+mes.getGetter()+"发文件"+mes.getSource()+"到"+mes.getDest());FileOutputStream fileOutputStream = new FileOutputStream(mes.getDest());fileOutputStream.write(mes.getFileByte());fileOutputStream.close();System.out.println("保存文件成功");}else{System.out.println("其他类型,不做处理的");}} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}}

线程的登录工具类

package com.hwk.qqclient.service;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import com.hwk.qqcommon.User;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import .InetAddress;import .Socket;//登录处理的public class UserClientService {private User user1 = new User();private Socket socket;public boolean checkedUser(String name,String pwd) throws Exception{boolean b =false;user1.setUserId(name);user1.setPasswd(pwd);socket = new Socket(InetAddress.getByName("127.0.0.1"), 9990);//发送用户信息给服务器ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());oos.writeObject(user1);//读取服务器的信息ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());Message mes = (Message) ois.readObject();//判断服务器发送的信息的类型,是MESSAGE_LONG_SUCCESS就登录成功if(mes.getMesType().equals(MessageType.MESSAGE_LONG_SUCCESS)){//创建自定义线程clientContentServerThread ccst = new clientContentServerThread(socket);ccst.start();//放入线程池,为了多线程b = true;ManageClientConnectServe.addClentConnetServierThread(name,ccst);}else{//登录不成功关闭主线程的套字节socket.close();}//返回是否登录成功return b;}//向服务端获取在线用户的列表public void onlineFreindList() throws Exception{Message mes = new Message();//设置请求类型mes.setMesType(MessageType.MESSAGE_GET_ONLINE_FRIEND);//说明发送者mes.setSender(user1.getUserId());try {//客户端也可以开启多个线程,所有不能直接用socket,取得当前线程的读取流ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServe.getclientContentServerThread(user1.getUserId()).getSocket().getOutputStream());oos.writeObject(mes);//发送要用户请求} catch (IOException e) {e.printStackTrace();}}//通知服务端退出系统public void logout(){Message mes = new Message();mes.setMesType(MessageType.MESSAGE_CLIENT_EXIT);mes.setSender(user1.getUserId());try {ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServe.getclientContentServerThread(user1.getUserId()).getSocket().getOutputStream());oos.writeObject(mes);System.out.println(user1.getUserId()+"退出系统了");System.exit(0);} catch (IOException e) {e.printStackTrace();} finally {}}}

线程的私聊工具类

package com.hwk.qqclient.service;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import java.io.IOException;import java.io.ObjectOutputStream;import java.util.Date;//提供给消息相关的方法public class messageClient {public void sendMessagetoOne(String content,String senderId,String getterId){Message mes = new Message();mes.setSender(senderId);mes.setContent(content);mes.setGetter(getterId);mes.setSendTime(new Date().toString());mes.setMesType(MessageType.MESSAGE_COMM_MES);System.out.println(senderId+"对"+getterId+"说:"+content);try {ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServe.getclientContentServerThread(senderId).getSocket().getOutputStream());oos.writeObject(mes);} catch (IOException e) {e.printStackTrace();} finally {}}public void sendMessagetoAll(String content,String senderId){Message message = new Message();message.setMesType(MessageType.MESSAGE_T0_ALL_MES);message.setContent(content);message.setSender(senderId);message.setSendTime(new Date().toString());System.out.println(senderId+"对大家说:"+content);try {ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServe.getclientContentServerThread(senderId).getSocket().getOutputStream());oos.writeObject(message);} catch (IOException e) {e.printStackTrace();}}}

线程的文件传输工具类

package com.hwk.qqclient.service;import com.hwk.qqcommon.Message;import com.hwk.qqcommon.MessageType;import java.io.*;public class FileClientService {public void sendFiletoOne(String src,String dest,String senderId,String getterId) throws IOException {Message message = new Message();message.setMesType(MessageType.MESSAGE_FILE_MES);message.setSender(senderId);message.setGetter(getterId);message.setSource(src);message.setDest(dest);FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(src);byte[] bytes = new byte[(int) (new File(src).length())];fileInputStream.read(bytes);message.setFileByte(bytes);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(fileInputStream !=null){try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}}ObjectOutputStream oos =new ObjectOutputStream(ManageClientConnectServe.getclientContentServerThread(senderId).getSocket().getOutputStream());oos.writeObject(message);System.out.println(message.getSender()+"发送"+message.getGetter()+"文件"+message.getSource());}}

qqcomom包里的类和服务端的一模一样。

六、离线功能思路

之前的功能,韩老师已经讲得很透彻了,不懂的建议去b站上去看,

这个离线本质就是服务端有一个hashmap(就理解成一个特殊的数组,只是这个数组的索引不是数组,变成了别的类型,必须唯一))。

用户发送私聊信息的时候,服务器接收,在转发的时候根据getterId判断,线程的集合里面是否有这个接收者的线程,也就是接收者登录美,如果登录,就转发,如果不登录就存到准备好的消息集合里;

此外用户在登录的时候,服务器需要根据客户端发送的这个user的里面的userid来判断这个消息集合里是否为空,也就是这个用户离线的时候有没有人发私聊信息给他,如果为空,则没有,就不管;如果有,就通过服务器遍历集合里该对象的消息列表,逐条转发过去,并且在转发之后,删除在集合里关于这个客户端的离线消息。

在转发的时候,每循环一次需要建立一个输出流,否则会报错。

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