利用sorket实现聊天功能-服务端实现
工具包
package loaderman.im.util; public class Constants { public static final String SERVER_IP = "192.168.0.195"; public static final int SERVER_PORT = 8080; public static final int CLIENT_SERVER_PORT = 8081; public static final int CLIENT_FILE_TRANSPORT_PORT = 8082; public static final String REGISTER_FAIL = 0+""; }
package loaderman.im.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * 数据库工具类 * * */ public class DButil { /** * 连接数据库 * * @return 数据库连接对象 */ public static Connection connect() { try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/qq?useUnicode=true&characterEncoding=utf-8", "root", "root"); return conn; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } /** * 关闭数据库 * * @param conn * 传入数据库连接对象 */ public static void close(Connection con) { if (con != null) { try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
package loaderman.im.util; import java.text.SimpleDateFormat; import java.util.Date; public class MyDate { public static String getDateCN() { SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String date = format.format(new Date(System.currentTimeMillis())); return date;// 2018年10月03日 23:41:31 } public static String getDateEN() { SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date1 = format1.format(new Date(System.currentTimeMillis())); return date1;// 2018-10-03 23:41:31 } }
传输对象建立
packageloaderman.im.tran; import java.io.Serializable; /** * 传输的对象,直接通过Socket传输的最大对象 * * @author xjyt */ public class TranObject<T> implements Serializable { /** * */ private static final long serialVersionUID = 1L; private TranObjectType type;// 发送的消息类型 private String fromUser;// 来自哪个用户 private String toUser;// 发往哪个用户 private T object;// 传输的对象 public TranObject(TranObjectType type) { this.type = type; } public String getFromUser() { return fromUser; } public void setFromUser(String fromUser) { this.fromUser = fromUser; } public String getToUser() { return toUser; } public void setToUser(String toUser) { this.toUser = toUser; } public T getObject() { return object; } public void setObject(T object) { this.object = object; } public TranObjectType getType() { return type; } @Override public String toString() { return "TranObject [type=" + type + ", fromUser=" + fromUser + ", toUser=" + toUser + ", object=" + object + "]"; } }
packageloaderman.im.tran; /** * 传输对象类型 * * */ public enum TranObjectType { REGISTER, // 注册 LOGIN, // 用户登录 LOGOUT, // 用户退出登录 FRIENDLOGIN, // 好友上线 FRIENDLOGOUT, // 好友下线 MESSAGE, // 用户发送消息 UNCONNECTED, // 无法连接 FILE, // 传输文件 REFRESH,//刷新好友列表 OFFLINEMESSAGE//离线消息 }
实体类
package loaderman.im.bean; import java.io.Serializable; //离线消息实体类 public class OffLineMessage implements Serializable { private String fromUser; private String toUser; private String textMsg; private int msgType; private String msgTime; public OffLineMessage() { } public OffLineMessage(String fromUser, String toUser, String textMsg, int msgType, String msgTime) { this.fromUser = fromUser; this.toUser = toUser; this.textMsg = textMsg; this.msgType = msgType; this.msgTime = msgTime; } public String getFromUser() { return fromUser; } public void setFromUser(String fromUser) { this.fromUser = fromUser; } public String getToUser() { return toUser; } public void setToUser(String toUser) { this.toUser = toUser; } public String getTextMsg() { return textMsg; } public void setTextMsg(String textMsg) { this.textMsg = textMsg; } public int getMsgType() { return msgType; } public void setMsgType(int msgType) { this.msgType = msgType; } public String getMsgTime() { return msgTime; } public void setMsgTime(String msgTime) { this.msgTime = msgTime; } }
package loaderman.im.bean; import java.io.Serializable; /** * 文本消息 */ public class TextMessage implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String message; public TextMessage() { } public TextMessage(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
package loaderman.im.bean; import java.io.Serializable; /** * 用户对象 * */ public class User implements Serializable { private String userId; private String userName; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private String userHeadPhoto; private String password; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserHeadPhoto() { return userHeadPhoto; } public void setUserHeadPhoto(String userHeadPhoto) { this.userHeadPhoto = userHeadPhoto; } @Override public String toString() { return "User{" + "userId='" + userId + '\'' + ", userName='" + userName + '\'' + ", userHeadPhoto='" + userHeadPhoto + '\'' + ", password='" + password + '\'' + '}'; } }
数据库建立
packageloaderman.dao; import java.util.ArrayList; import loaderman.im.bean.OffLineMessage; import loaderman.im.bean.User; public interface UserDao { //注册成功返回用户id public String register(User u); public boolean login(User u); public ArrayList<User> refresh(String id); public ArrayList<OffLineMessage> getOffLineMessage(String id); public void logout(String id); boolean isHasUser(String userId); public boolean saveOffLineMessage(OffLineMessage offLineMessage); }
package loaderman.dao.impl; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.lang.String; import loaderman.im.bean.OffLineMessage; import loaderman.im.bean.User; import loaderman.im.util.Constants; import loaderman.im.util.DButil; import loaderman.im.util.MyDate; import loaderman.dao.UserDao; public class UserDaoImpl implements UserDao { @Override public String register(User u) { String userID; Connection con = DButil.connect(); String sql1 = "insert into user(userID,userName,password,userHeadPhoto,time) values(?,?,?,?,?)"; String sql2 = "select userID from user"; UserDao dao = UserDaoFactory.getInstance(); boolean hasUser = dao.isHasUser(u.getUserId()); if (!hasUser) { try { PreparedStatement ps = con.prepareStatement(sql1); ps.setString(1, u.getUserId()); ps.setString(2, u.getUserName()); ps.setString(3, u.getPassword()); ps.setString(4, u.getUserHeadPhoto()); ps.setString(5, MyDate.getDateCN()); int res = ps.executeUpdate(); if (res > 0) { PreparedStatement ps2 = con.prepareStatement(sql2); ResultSet rs = ps2.executeQuery(); if (rs.last()) { userID = rs.getString("userID"); createFriendtable(userID);// 注册成功后,创建一个已用户id为表名的表,用于存放好友信息 return userID; } } } catch (SQLException e) { e.printStackTrace(); } finally { DButil.close(con); } } return Constants.REGISTER_FAIL; } @Override public boolean login(User u) { Connection con = DButil.connect(); String sql = "select * from user where userID=? and password=?"; try { PreparedStatement ps = con.prepareStatement(sql); ps.setString(1, u.getUserId()); ps.setString(2, u.getPassword()); ResultSet rs = ps.executeQuery(); if (rs.first()) { return true; } } catch (SQLException e) { return false; } finally { DButil.close(con); } return false; } /** * 查找自己 */ public User findMe(String UserId) { User me = new User(); Connection con = DButil.connect(); String sql = "select * from user where userID=?"; PreparedStatement ps; try { ps = con.prepareStatement(sql); ps.setString(1, UserId); ResultSet rs = ps.executeQuery(); if (rs.first()) { me.setUserId(rs.getString("userID")); me.setUserName(rs.getString("userName")); me.setUserHeadPhoto(rs.getString("userHeadPhoto")); } return me; } catch (SQLException e) { // e.printStackTrace(); } finally { DButil.close(con); } return null; } public boolean isHasUser(String userId) { Connection con = DButil.connect(); String sql = "select * from user where userID=?"; PreparedStatement ps; try { ps = con.prepareStatement(sql); ps.setString(1, userId); ResultSet rs = ps.executeQuery(); if (rs.first()) { return true; } else { return false; } } catch (SQLException e) { // e.printStackTrace(); } finally { DButil.close(con); return false; } } //保存离线消息 @Override public boolean saveOffLineMessage(OffLineMessage offLineMessage) { Connection con = DButil.connect(); String sql = "insert into offlinemessage(fromUser,toUser,textMsg,msgType,msgTime) values(?,?,?,?,?)"; PreparedStatement ps = null; try { ps = con.prepareStatement(sql); ps.setString(1, offLineMessage.getFromUser()); ps.setString(2, offLineMessage.getToUser()); ps.setString(3, offLineMessage.getTextMsg()); ps.setInt(4, offLineMessage.getMsgType()); ps.setString(5, offLineMessage.getMsgTime()); int res = ps.executeUpdate(); if (res > 0) { return true; } else { return false; } } catch (SQLException e) { e.printStackTrace(); } return false; } @Override public ArrayList<OffLineMessage> getOffLineMessage(String toUser) { ArrayList<OffLineMessage> list = new ArrayList<OffLineMessage>(); Connection con = DButil.connect(); String sql = "select * from offlinemessage where toUser= ?" ; String sql2 = "delete from offlinemessage where toUser= ?" ; PreparedStatement ps; try { ps = con.prepareStatement(sql); ps.setString(1, toUser); ResultSet rs = ps.executeQuery(); if (rs.first()) { System.out.println("离线消息获取"); do { OffLineMessage offLineMessage = new OffLineMessage(); offLineMessage.setFromUser(rs.getString("fromUser")); offLineMessage.setMsgType(rs.getInt("msgType")); offLineMessage.setTextMsg(rs.getString("textMsg")); offLineMessage.setToUser(rs.getString("toUser")); offLineMessage.setMsgTime(rs.getString("msgTime")); list.add(offLineMessage); } while (rs.next()); } ps = con.prepareStatement(sql2); ps.setString(1, toUser); ps.executeUpdate(); return list; } catch (SQLException e) { e.printStackTrace(); System.out.println("异常" + e.toString()); } finally { DButil.close(con); } return null; } /** * 刷新好友列表 */ @Override public ArrayList<User> refresh(String userId) { ArrayList<User> list = new ArrayList<User>(); User me = findMe(userId); System.out.println("me -- > " + me); list.add(me);// 先添加自己 Connection con = DButil.connect(); String sql = "select * from " + userId; PreparedStatement ps; try { ps = con.prepareStatement(sql); // ps.setString(1, userId); ResultSet rs = ps.executeQuery(); if (rs.first()) { System.out.println("好友消息获取"); do { User friend = new User(); friend.setUserId(rs.getString("userID")); friend.setUserName(rs.getString("userName")); friend.setUserHeadPhoto(rs.getString("userHeadPhoto")); list.add(friend); } while (rs.next()); } return list; } catch (SQLException e) { e.printStackTrace(); System.out.println("异常" + e.toString()); } finally { DButil.close(con); } return null; } /** * 注册成功后,创建一个用户表,保存该用户好友 * * @param userID */ public void createFriendtable(String userID) { Connection con = DButil.connect(); try { String sql = "create table _" + userID + " (id int auto_increment not null primary key," + " userID varchar(20) not null," + " userName varchar(20) not null," + "userHeadPhoto varchar(50) )"; PreparedStatement ps = con.prepareStatement(sql); int res = ps.executeUpdate(); System.out.println(res); } catch (SQLException e) { e.printStackTrace(); } finally { DButil.close(con); } } /** * 下线更新状态为离线 */ @Override public void logout(String userID) { Connection con = DButil.connect(); try { String sql = "update user set _isOnline=0 where userID=?"; PreparedStatement ps = con.prepareStatement(sql); ps.setString(1, userID); ps.executeUpdate(); // updateAllOff(userID); // System.out.println(res); } catch (SQLException e) { // e.printStackTrace(); } finally { DButil.close(con); } } public List<String> getAllId() { Connection con = DButil.connect(); List<String> list = new ArrayList<String>(); try { String sql = "select _id from user"; PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery(); if (rs.first()) { do { String id = rs.getString("_id"); list.add(id); } while (rs.next()); } // System.out.println(list); return list; } catch (SQLException e) { // e.printStackTrace(); } finally { DButil.close(con); } return null; } public static void main(String[] args) { // User u = new User(); UserDaoImpl dao = new UserDaoImpl(); ArrayList<OffLineMessage> test = dao.getOffLineMessage("test"); System.out.println(test.size()); // // // System.out.println(list); } }
package loaderman.dao.impl; import petrochina.xjyt.fcydyy.dao.UserDao; public class UserDaoFactory { private static UserDao dao; public static UserDao getInstance() { if (dao == null) { dao = new UserDaoImpl(); } return dao; } }
服务器实现
package loaderman.server; import java.io.*; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.List; import loaderman.im.bean.OffLineMessage; import loaderman.im.tran.TranObjectType; import loaderman.dao.UserDao; import loaderman.im.bean.TextMessage; import loaderman.im.bean.User; import loaderman.im.tran.TranObject; import loaderman.im.util.MyDate; import loaderman.dao.impl.UserDaoFactory; /** * 读消息线程和处理方法 * */ public class InputThread extends Thread { private Socket socket;// socket对象 private OutputThread out;// 传递进来的写消息线程,因为我们要给用户回复消息啊 private OutputThreadMap map;// 写消息线程缓存器 private ObjectInputStream ois;// 对象输入流 private boolean isStart = true;// 是否循环读消息 public InputThread(Socket socket, OutputThread out, OutputThreadMap map) { this.socket = socket; this.out = out; this.map = map; try { ois = new ObjectInputStream(socket.getInputStream());// 实例化对象输入流 } catch (IOException e) { e.printStackTrace(); } } public void setStart(boolean isStart) {// 提供接口给外部关闭读消息线程 this.isStart = isStart; } @Override public void run() { try { while (isStart) { // 读取消息 System.out.println("InputThread读消息开始"); readMessage(); System.out.println("InputThread读消息完成"); } if (ois != null) ois.close(); if (socket != null) socket.close(); } catch (ClassNotFoundException e) { System.out.println("异常信息1"); isStart = false;// 结束自己的读循环 e.printStackTrace(); } catch (SocketException e){ System.out.println("InputThread1"+e.toString()); }catch (IOException e) { System.out.println("InputThread2"+e.toString()); isStart = false;// 结束自己的读循环 e.printStackTrace(); }catch (Exception e){ System.out.println("InputThread3"+e.toString()); e.printStackTrace(); } } /** * 读消息以及处理消息,抛出异常 * * @throws IOException * @throws ClassNotFoundException */ public void readMessage() throws IOException, ClassNotFoundException { System.out.println("readMessage 1 "); Object readObject = ois.readObject();// 从流中读取对象 System.out.println("readMessage 2 "); UserDao dao = UserDaoFactory.getInstance();// 通过dao模式管理后台 if (readObject != null && readObject instanceof TranObject) { TranObject read_tranObject = (TranObject) readObject;// 转换成传输对象 switch (read_tranObject.getType()) { case REGISTER:// 如果用户是注册 System.out.println("REGISTER"); User registerUser = (User) read_tranObject.getObject(); String registerResult = dao.register(registerUser); System.out.println(MyDate.getDateCN() + " 新用户注册:" + registerResult); // 给用户回复消息 TranObject<User> register2TranObject = new TranObject<User>( TranObjectType.REGISTER); User register2user = new User(); register2user.setUserId(registerResult); register2TranObject.setObject(register2user); out.setMessage(register2TranObject); break; case LOGIN: System.out.println("LOGIN"); User loginUser = (User) read_tranObject.getObject(); System.out.println("登录用户 " + loginUser.toString()); boolean login = dao.login(loginUser); TranObject<Boolean> login2Object = new TranObject<Boolean>( TranObjectType.LOGIN); User login2User = new User(); login2User.setUserId(loginUser.getUserId()); if (login) {// 如果登录成功 System.out.println("登录成功"); TranObject<User> onObject = new TranObject<User>( TranObjectType.LOGIN); onObject.setObject(login2User); for (OutputThread onOut : map.getAll()) { onOut.setMessage(onObject);// 广播一下用户上线 } map.add(loginUser.getUserId(), out);// 先广播,再把对应用户id的写线程存入map中,以便转发消息时调用 login2Object.setObject(true);// 把好友列表加入回复的对象中 System.out.println(MyDate.getDateCN() + " 用户:" + loginUser.getUserId() + " 上线了"); } else { login2Object.setObject(false);// 把好友列表加入回复的对象中 } out.setMessage(login2Object);// 同时把登录信息回复给用户 System.out.println(MyDate.getDateCN() + " 用户:" + loginUser.getUserId() + " 上线了"); break; case LOGOUT:// 如果是退出,更新数据库在线状态,同时群发告诉所有在线用户 System.out.println("LOGOUT"); User logoutUser = (User) read_tranObject.getObject(); String offId = logoutUser.getUserId(); System.out .println(MyDate.getDateCN() + " 用户:" + offId + " 下线了"); dao.logout(offId); isStart = false;// 结束自己的读循环 map.remove(offId);// 从缓存的线程中移除 out.setMessage(null);// 先要设置一个空消息去唤醒写线程 out.setStart(false);// 再结束写线程循环 TranObject<User> offObject = new TranObject<User>( TranObjectType.LOGOUT); User logout2User = new User(); logout2User.setUserId(logoutUser.getUserId()); offObject.setObject(logout2User); for (OutputThread offOut : map.getAll()) {// 广播用户下线消息 offOut.setMessage(offObject); } break; case MESSAGE:// 如果是转发消息(可添加群发) System.out.println("MESSAGE"); // 获取消息中要转发的对象id,然后获取缓存的该对象的写线程 String id2 = read_tranObject.getToUser(); System.out.println("给谁发" + id2); OutputThread toOut = map.getById(id2); if (toOut != null) {// 如果用户在线 System.out.println("用户在线"); TextMessage tm = (TextMessage) read_tranObject.getObject(); System.out.println("消息内容 " + tm.getMessage()); toOut.setMessage(read_tranObject); } else {// 如果为空,说明用户已经下线,回复用户 TextMessage text = new TextMessage(); System.out.println("用户不在线"); TranObject<TextMessage> offText = new TranObject<TextMessage>( TranObjectType.MESSAGE); offText.setObject(text); offText.setFromUser(id2); String fromUser = read_tranObject.getFromUser(); String toUser = read_tranObject.getToUser(); TextMessage tm = (TextMessage) read_tranObject.getObject(); //保存离线消息 OffLineMessage offLineMessage = new OffLineMessage(fromUser, toUser, tm.getMessage(), 0, MyDate.getDateEN()); boolean saveOffLineMessage = dao.saveOffLineMessage(offLineMessage); if (saveOffLineMessage) { text.setMessage("亲!对方不在线哦,您的消息将暂时保存在服务器"); } else { text.setMessage("亲!无法发送,请稍后重试"); } out.setMessage(offText); } break; case REFRESH: System.out.println("REFRESH"); System.out.println("当前用户REFRESH" + read_tranObject .getFromUser()); List<User> refreshList = dao.refresh(read_tranObject.getFromUser()); System.out.println(refreshList.size()); TranObject<List<User>> refreshO = new TranObject<List<User>>( TranObjectType.REFRESH); refreshO.setObject(refreshList); out.setMessage(refreshO); break; case OFFLINEMESSAGE: System.out.println("客户端要获取离线消息了"); ArrayList<OffLineMessage> offLineMessage = dao.getOffLineMessage(read_tranObject.getFromUser()); TranObject<List<OffLineMessage>> offMsgObject = new TranObject<List<OffLineMessage>>( TranObjectType.OFFLINEMESSAGE); offMsgObject.setObject(offLineMessage); offMsgObject.setFromUser(read_tranObject.getFromUser()); out.setMessage(offMsgObject); break; default: break; } } } /** * 判断是否断开连接,连接返回true,断开返回false * @return */ public Boolean isServerConnetion( Socket socket){ try{ socket.sendUrgentData(0xFF);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信 return true; }catch(Exception se){ return false; } } }
package loaderman.server; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.Socket; import java.net.SocketException; import loaderman.im.tran.TranObject; /** * 写消息线程 * */ public class OutputThread extends Thread { private OutputThreadMap map; private ObjectOutputStream oos; private TranObject object; private boolean isStart = true;// 循环标志位 private Socket socket; public OutputThread(Socket socket, OutputThreadMap map) { try { this.socket = socket; this.map = map; oos = new ObjectOutputStream(socket.getOutputStream());// 在构造器里面实例化对象输出流 } catch (IOException e) { e.printStackTrace(); } } public Socket getSocket() { return socket; } public void setStart(boolean isStart) { this.isStart = isStart; } // 调用写消息线程,设置了消息之后,唤醒run方法,可以节约资源 public void setMessage(TranObject object) { this.object = object; synchronized (this) { System.out.println("OutputThread唤醒"); notify(); } } @Override public void run() { try { while (isStart) { if (object != null) { System.out.println("OutputThread写出开始"); oos.writeObject(object); System.out.println("OutputThread写出中"); oos.flush(); System.out.println("OutputThread写出结束"); } // 没有消息写出的时候,线程等待 synchronized (this) { System.out.println("OutputThread等待"); wait(); } } if (oos != null){// 循环结束后,关闭流,释放资源 oos.close(); } if (socket != null) { socket.close(); } } catch (InterruptedException e) { System.out.println("OutputThread1" + e.toString()); e.printStackTrace(); } catch (SocketException e) { System.out.println("OutputThread2" + e.toString()); } catch (IOException e) { System.out.println("OutputThread3" + e.toString()); e.printStackTrace(); } } }
package loaderman.server; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 存放写线程的缓存器 */ public class OutputThreadMap { private HashMap<String, OutputThread> map; private static OutputThreadMap instance; // 私有构造器,防止被外面实例化改对像 private OutputThreadMap() { map = new HashMap<String, OutputThread>(); } // 单例模式像外面提供该对象 public synchronized static OutputThreadMap getInstance() { if (instance == null) { instance = new OutputThreadMap(); } return instance; } // 添加写线程的方法 public synchronized void add(String id, OutputThread out) { OutputThread outputThread = map.get(id); System.out.println(id + "之前线程 --> " + outputThread); System.out.println(id + "新线程 --> " + out); if (outputThread!=null){ outputThread.setMessage(null); outputThread.setStart(false); } map.put(id, out); OutputThread outputThread2 = map.get(id); System.out.println(id + "现在运行新线程 --> " + outputThread2); } // 移除写线程的方法 public synchronized void remove(String id) { map.remove(id); } // 取出写线程的方法,群聊的话,可以遍历取出对应写线程 public synchronized OutputThread getById(String id) { return map.get(id); } // 得到所有写线程方法,用于向所有在线用户发送广播 public synchronized List<OutputThread> getAll() { List<OutputThread> list = new ArrayList<OutputThread>(); for (Map.Entry<String, OutputThread> entry : map.entrySet()) { list.add(entry.getValue()); } return list; } }
package loaderman.server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import loaderman.im.util.Constants; import loaderman.im.util.MyDate; /** * 服务器,接受用户登录、离线、转发消息 * */ public class Server { private ExecutorService executorService;// 线程池 private ServerSocket serverSocket = null; private Socket socket = null; private boolean isStarted = true; public Server() { try { // 创建线程池,池中具有(cpu个数*50)条线程 executorService = Executors.newFixedThreadPool(Runtime.getRuntime() .availableProcessors() * 50); serverSocket = new ServerSocket(Constants.SERVER_PORT); } catch (IOException e) { e.printStackTrace(); quit(); } } public void start() { try { while (isStarted) { System.out.println(MyDate.getDateCN() + " 服务器已启动..."); socket = serverSocket.accept(); System.out.println("客户端已经连接"); String ip = socket.getInetAddress().toString(); System.out.println(MyDate.getDateCN() + " 用户:" + ip + " 已建立连接"); // 为支持多用户并发访问,采用线程池管理每一个用户的连接请求 if (socket.isConnected()) executorService.execute(new SocketTask(socket));// 添加到线程池 } if (socket != null) socket.close(); if (serverSocket != null) serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } private final class SocketTask implements Runnable { private Socket socket = null; private InputThread in; private OutputThread out; private OutputThreadMap map; public SocketTask(Socket socket) { this.socket = socket; map = OutputThreadMap.getInstance(); } @Override public void run() { out = new OutputThread(socket, map);// // 先实例化写消息线程,(把对应用户的写线程存入map缓存器中) in = new InputThread(socket, out, map);// 再实例化读消息线程 out.setStart(true); in.setStart(true); in.start(); out.start(); } } /** * 退出 */ public void quit() { System.out.println("退出"); try { this.isStarted = false; serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Server().start(); } }
完成
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!