Socket客户端与服务端通信私聊

xiaoxiao2021-02-28  111

客户端:

/** * 将聊天室客户端内容独立完成一次. * 下面内容可以选做: * 修改代码,使聊天室可以实现用户自定义昵称, * 以及私聊功能。 * * 参考思路: * 客户端连接服务端后,要求用户输入一个昵称, * 然后将改昵称发送给服务端,服务端那边读取到 * 客户端发送的第一个字符串认为是昵称。 * * 私聊功能可以定义格式,例如: * @张三:你好 * 服务端在读取客户端发送过来的昵称时,需要进行 * 解析,分解出昵称与聊天内容,然后将该聊天内容 * 单独发送给指定昵称的用户。 * 服务端的输出流需要使用Map进行维护,而不能再 * 使用List,Map的key可以是该用户昵称,value * 为该用户输出流。 * @author Xiloer * */ public class Client { private Socket socket; public Client() throws IOException{ socket=new Socket("176.195.107.88",8088); System.out.println("已连接服务器!"); } private void inputNickName(Scanner scan) throws Exception { String nickName = null; //创建输出流 PrintWriter pw = new PrintWriter( new OutputStreamWriter(socket.getOutputStream(), "UTF-8"),true); //创建输入流 BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(),"UTF-8")); while(true) { System.out.println("请创建您的昵称:"); nickName = scan.nextLine(); if (nickName.trim().equals("")) { System.out.println("昵称不得为空"); } else { pw.println(nickName); String pass = br.readLine(); if(pass!=null&&!pass.equals("OK")) { System.out.println("昵称已经被占用,请更换!"); break; } else { System.out.println("你好!"+nickName+"可以开始聊天了"); break; } } } } public void start(){ try { System.out.println("请输入:"); Scanner scanner=new Scanner(System.in); inputNickName(scanner); ServerHandler server=new ServerHandler(); Thread t=new Thread(server); t.start(); OutputStream os = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8"); PrintWriter pw = new PrintWriter(osw,true); while(true) { pw.println(scanner.nextLine()); } } catch (Exception e) { e.printStackTrace(); }finally{ if(socket !=null) { try { socket.close(); } catch(IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { Client client=new Client(); client.start(); } private class ServerHandler implements Runnable{ public void run() { try { InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is,"UTF-8"); BufferedReader br = new BufferedReader(isr); String msgString = null; while((msgString = br.readLine())!= null) { System.out.println(msgString); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 服务端:

/** * 将聊天室服务端内容独立完成一次 * 下面内容可以选做: * 配合客户端实现支持昵称与私聊功能 * @author Xiloer * */ public class Server { private ServerSocket server; // private List<PrintWriter> allOut; private Map<String,PrintWriter> allOut; public Server(){ try { server=new ServerSocket(8088); allOut = new HashMap<String, PrintWriter>(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void addOut(String key,PrintWriter value) { synchronized(this) { allOut.put(key, value); } } private synchronized void removeOut(String key) { allOut.remove(key); System.out.println("当前在线人数为:"+ allOut.size()); } private synchronized void sendMsgToAll(String message) { for(PrintWriter out: allOut.values()) { out.println(message); System.out.println("当前在线人数为:"+ allOut.size()); } } private synchronized void sendMsgToPrivate(String nickname,String message) { PrintWriter pw = allOut.get(nickname); //将对应客户端的聊天信息取出作为私聊内容发送出去 if(pw!=null) { pw.println(message); System.out.println("1111111111111111111111111111111111111"); System.out.println("当前在线私聊人数为:"+ allOut.size()); } } public void start(){ try{ while(true){ System.out.println("等待客户端连接......."); Socket socket=server.accept(); System.out.println("客户端已连接!"); ClientHandler client=new ClientHandler(socket); Thread t=new Thread(client); t.start(); } }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { Server server=new Server(); server.start(); } private class ClientHandler implements Runnable{ private Socket socket; private String host; private String nickName; public ClientHandler(Socket socket){ this.socket=socket; InetAddress adress=socket.getInetAddress(); host=adress.getHostAddress(); } private String getNickName() throws Exception { try { //服务端的输入流读取客户端发送来的昵称输出流 InputStream in = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(in,"UTF-8"); BufferedReader bReader = new BufferedReader(isr); //服务端将昵称验证结果通过自身的输出流发送给客户端 OutputStream out = socket.getOutputStream(); OutputStreamWriter iosw = new OutputStreamWriter(out,"UTF-8"); PrintWriter ipw = new PrintWriter(iosw,true); //读取客户端发来的昵称 String nameString = bReader.readLine(); while(true) { if(nameString.trim().length()==0) { ipw.println("FAIL"); } if(allOut.containsKey(nameString)) { ipw.println("FAIL"); } else { ipw.println("OK"); return nameString; } } } catch(Exception e) { throw e; } } public void run() { PrintWriter pw = null; try { /* * 通过客户端的Socket获取客户端的输出流 * 用来将消息发送给客户端 */ OutputStream os = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8"); pw = new PrintWriter(osw,true); /* * 将客户昵称和其所说的话作为元素存入共享集合HashMap中 */ nickName = getNickName(); addOut(nickName, pw); Thread.sleep(100); /* * 服务端通知所有客户端,某用户登录 */ sendMsgToAll("[系统通知]:欢迎**"+nickName+"**登陆聊天室!"); /* * 通过客户端的Socket获取输入流 * 读取客户端发送来的信息 */ InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is,"UTF-8"); BufferedReader br = new BufferedReader(isr); String msgString = null; while((msgString = br.readLine())!=null) { //验证是否是私聊 if(msgString.startsWith("@")) { /* * 私聊格式:@昵称:内容 */ int index = msgString.indexOf(":"); if(index >=0) { //获取昵称 String name = msgString.substring(1,index); String info = msgString.substring(index+1,msgString.length()); info = nickName + "对你说:"+ info; //将私聊信息发送出去 sendMsgToPrivate(name, info); //服务端不在广播私聊的信息 continue; } System.out.println("已输出"); } /* * 遍历所有输出流,将该客户端发送的信息转发给所有客户端 */ System.out.println(nickName+"说:"+ msgString); sendMsgToAll(nickName+"说:"+ msgString); } } catch (Exception e) { /* * 因为Win系统用户的客户端断开连接后,br.readLine()方法读取 * 不到信息就会抛出异常,而Linux系统会持续发送null; * 因此这里就不在将捕获的异常抛出了。 */ } finally { /* * 当执行到此处时,说明客户端已经与服务端断开连接 * 则将该客户端存在共享集合中的输出流删除 */ removeOut(nickName); /* * 通知所有客户端,某某客户已经下线 */ sendMsgToAll("[系统通知]:"+nickName + "已经下线了。"); /* * 关闭socket,则通过Socket获取的输入输出流也一同关闭了 */ if(socket!=null) { try { socket.close(); } catch(IOException e) { e.printStackTrace(); } } } } } }

转载请注明原文地址: https://www.6miu.com/read-66712.html

最新回复(0)