package chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; /** * 聊天室服务端 * @author adminitartor * */ public class Server { /* * java.net.ServerSocket * 用于向系统申请服务端口(客户端就是通过该端口 * 与服务端应用程序建立连接的) * 监听服务端口,以接受客户端的连接。 */ private ServerSocket server; /* * 该集合存放所有客户端的输出流,以便广播消息 */ private Map<String,PrintWriter> allOut; public Server() throws Exception{ try { /* * 创建时申请服务端口,不能与系统中 * 其他应用程序已使用端口冲突 * 否则抛出: * AddressAlreadyInUser的错误 */ server = new ServerSocket(8088); allOut = new HashMap<String,PrintWriter>(); } catch (Exception e) { System.out.println("服务端初始化失败!"); throw e; } } /** * 将给定的某个客户端的输出流存入到共享集合 * @param out */ public synchronized void addOut(String nickName,PrintWriter out){ allOut.put(nickName,out); } /** * 将给定的客户端的输出流从共享集合中删除 * @param out */ public synchronized void removeOut(String nickName){ allOut.remove(nickName); } /** * 将给定的消息发送给所有客户端 * @param message */ public synchronized void sendMessage(String message){ for(PrintWriter out : allOut.values()){ out.println(message); } } /** * 将指定消息发送给指定昵称的客户端 * @param nickName * @param message */ public synchronized void sendMessage(String nickName,String message){ PrintWriter out = allOut.get(nickName); if(out != null){ out.println(message); } } public void start(){ try { /* * ServerSocket的accept方法是一个 * 阻塞方法,作用是监听申请的服务端口 * 直到一个客户端通过该端口与服务端 * 建立连接,accept方法才会执行完毕, * 并返回一个Socket实例,通过这个Socket * 可以与刚刚建立连接的客户端进行交互 */ while(true){ System.out.println("等待客户端连接..."); Socket socket = server.accept(); System.out.println("一个客户端连接了!"); //启动线程处理该客户端交互 ClientHandler handler = new ClientHandler(socket); Thread t = new Thread(handler); t.start(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { try { Server server = new Server(); server.start(); } catch (Exception e) { e.printStackTrace(); } } /** * 该线程用来处理与服务端连接的一个客户端的 * 交互工作。 * @author adminitartor * */ private class ClientHandler implements Runnable{ //当前线程通过该Socket与该客户端交互 private Socket socket; //客户端的IP地址 private String host; //用户昵称 private String nickName; public ClientHandler(Socket socket){ super(); this.socket = socket; } public void run(){ PrintWriter pw = null; try { //获取客户端IP地址 InetAddress address = socket.getInetAddress(); //获取客户端IP地址的字符串形式 host = address.getHostAddress(); /* * 想读取客户端发送过来的数据,需要通过 * Socket获取输入流。 */ InputStream in = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(in,"UTF-8"); BufferedReader br = new BufferedReader(isr); //首先读取客户端发送过来的昵称 nickName = br.readLine(); sendMessage(nickName+"上线了..."); /* * 通过Socket获取输出流,以便将消息 * 发送给给客户端 */ pw = new PrintWriter( new OutputStreamWriter( socket.getOutputStream(),"UTF-8" ),true ); //将该客户端的输出流存入共享集合 addOut(nickName,pw); /* * br.readLine方法在读取远端计算机发送过来的 * 一行字符串时,远端计算机断开连接后,其不同 * 的操作系统会影响这里readLine方法的结果。 * 当windows的客户端断开连接时: * br.readLine方法会直接抛出异常 * * 当linux的客户端断开连接时: * br.readLine方法会返回null * */ String message = null; while((message = br.readLine())!=null){ // System.out.println(host+"说:"+message); // pw.println(host+"说:"+message); //首先判断是否为私聊 if(message.startsWith("@")){ //先找到“:”的位置 int index = message.indexOf(":"); if(index<0){ //告知当前客户端格式不对 pw.println("私聊格式不对,私聊格式:@昵称:聊天内容"); }else{ //获取对方昵称 String toNick = message.substring(1,index); //检查该用户是否存在: if(allOut.containsKey(toNick)){ //获取聊天内容 message = message.substring(index+1); sendMessage(toNick,nickName+"对你说:"+message); }else{ pw.println("没有找到此用户:"+toNick); } } }else{ //广播给所有客户端 sendMessage(nickName+"说:"+message); } } } catch (Exception e) { } finally{ //客户端断开后的处理 //将该客户端的输出流从共享集合中删除 removeOut(nickName); sendMessage(nickName+"下线了..."); try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
寒江独钓 2016-02-25
凌云 2018-02-05
泡泡 2016-09-17
泡泡 2016-11-08
凌云 2018-04-26
白诗秀儿 2016-10-15
荡神戏魔 2019-01-23
沙落雁 2016-10-24
冰雪魔女 2021-02-05
白诗秀儿 2016-10-12
藏家569 2025-03-28
藏家838 2025-03-29
奇美拉 2025-03-29
许老头 2025-03-28
藏家942 2025-03-28
mei 2025-03-28
藏家113 2025-03-28
藏家518 2025-03-28
藏家372 2025-03-28
藏家372 2025-03-28