赞
踩
和上一篇博客差不多,只不过是在群里的基础之上增加了私聊的功能,我们约定,私聊格式为:@xxx:msg
如何实现私聊呢,加入客户端c给服务器发送消息,服务器不再是把消息转发给所以除c以外的客户端,而是解析数据格式,转发给与name(“:”之前,“@”之后的字符串)有相同名字的客户端即可。
群聊功能与之前类似,这里不再说说明。
下面是所有类的代码:
(1)Server类的代码:
package chat4; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.CopyOnWriteArrayList; /**注意:实现私聊(约定数据格式为:@xxx:msg * 在线聊天室:使用容器实现群聊 * 服务器 * @author Administrator * 需要修改和遍历数据的时候使用list会操作不方便 * 问题:为什么加了static,在主函数里面就没错啦? * */ public class Server { //CopyOnWriteArrayList和list用法一样 private static CopyOnWriteArrayList<Channel> all=new CopyOnWriteArrayList<Channel>(); public static void main(String[] args) throws IOException { System.out.println("----------server----------"); //创建服务器 ServerSocket server=new ServerSocket(8977); while(true) { //阻塞式等待客户端的连接 Socket client=server.accept(); System.out.println("一个客户端连接上。。。"); Channel c=new Channel(client); all.add(c);//容器管理所有的成员 new Thread(c).start(); } } //一个客户代表一个Channel static class Channel implements Runnable{ private DataInputStream dis ; private DataOutputStream dos; private Socket client; private boolean isRunning;//程序是否停下来的标志 private String name; public Channel(Socket client) { this.client=client; try { dis = new DataInputStream(client.getInputStream()); dos=new DataOutputStream(client.getOutputStream()); isRunning=true; //获取名称 name=receiveMsg(); this.sendMsg(name+"同学,"+"欢迎您的到来"); sendOther(this.name+"加入群聊天室",true); } catch (IOException e) { System.out.println("-----1 出问题----");//自己方便观察哪里出问题 release();//注意:这里做了修改 } } //接收消息(服务器读取客户端发过来的信息) private String receiveMsg() { String msg=""; try { msg=dis.readUTF(); } catch (IOException e) { System.out.println("-----receive 出问题----");//自己方便观察哪里出问题 release();//注意:这里做了修改 } return msg; } //发送消息(服务器反馈信息给客户端) private void sendMsg(String msg) { try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { System.out.println("-----send 出问题----");//自己方便观察哪里出问题 release();//注意:这里做了修改 } } //发送消息(服务器反馈信息(其实就是服务器读取的当前客户端的消息)给其他所有的客户端(除了当前客户端) private void sendOther(String msg,boolean isSysMsg) { boolean isPrivate=msg.startsWith("@"); if(isPrivate) {//是私聊消息 int idx=msg.indexOf(":"); //获取目标和数据 String targetName=msg.substring(1,idx); msg=msg.substring(idx+1); System.out.println("服务器收到的私聊信息为:"+targetName+"&"+msg); for(Channel other:all) { if(other.name.equals(targetName)) {//找到目标 other.sendMsg(this.name+":"+msg); } } }else { for(Channel other:all) {//服务器把收到的客户端的消息发给其余所有的客户端(除了当前客户端) if(other!=this) { if(isSysMsg) { other.sendMsg(msg);//系统消息 }else { other.sendMsg(this.name+":"+msg);//群聊消息 } } } } } //释放资源 private void release() { this.isRunning=false;//释放资源意味着该该客户端要停下来 Utils.close(dis,dos,client);//自己写的一个工具类Utils all.remove(this);//当前客户端退出 sendOther(this.name+"离开了聊天室。。。", true); } @Override public void run() { while(isRunning) { //流程:服务器读取客户端消息-服务器发送反馈消息给客户端-释放资源 String msg=receiveMsg(); //System.out.println("服务器读取到的信息为:"+msg); if(!msg.equals("")) { //sendMsg(msg); sendOther(msg,false);//群聊消息 } } //release();//老师这里没有释放 } } }
(2)Client类的代码(下面的Receive类和Send类为Client类所用):
package chat4; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; /**注意: * 在线聊天室:使用容器实现群聊 * 客户端 * @author Administrator * */ public class Client { public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("---------------client--------------"); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入用户名:"); String name=br.readLine(); //建立套接字 Socket client=new Socket("localhost", 8977); //客户端发送消息(先读取控制台的内容,再写入到客户端的输出流里) new Thread(new Send(client,name)).start(); new Thread(new Receive(client)).start(); } }
(3)Receive类的代码:
package chat4; import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; /** *作用: 被MutiClient类用到,是客户端用来接收服务器反馈的消息的 *客户端读取服务器反馈的消息,并显示输出 * @author Administrator * */ public class Receive implements Runnable { private DataInputStream dis; private Socket client; private boolean isRunning; public Receive(Socket client) { this.client=client; isRunning=true; try { dis=new DataInputStream(client.getInputStream()); } catch (IOException e) { System.out.println("客户端的Receive构造器有问题"); release(); } } @Override public void run() { while(isRunning) { String msg=receiveMsg(); if(!msg.equals("")) { System.out.println(msg); } } } private String receiveMsg() { String msg=""; try { msg=dis.readUTF(); } catch (IOException e) { System.out.println("客户端的receiveMsg有问题"); release(); } return msg; } //释放资源 private void release() {//内部类的使用 this.isRunning=false;//释放资源意味着该该客户端要停下来 Utils.close(dis,client);//自己写的一个工具类Utils } }
(4)Send类的代码:
package chat4; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; /** * 作用:被MutiClient类用到,是客户端用来发送消息的 * 具体操作是:客户端读取控制台消息--写入到client的输出流 * @author Administrator * */ public class Send implements Runnable { private BufferedReader console; private DataOutputStream dos; private Socket client; private boolean isRunning; private String name; public Send(Socket client,String name) { this.client=client; this.name=name; console=new BufferedReader(new InputStreamReader(System.in)); try { dos=new DataOutputStream(client.getOutputStream()); sendMsg(name);//发送名字 isRunning=true; } catch (IOException e) { System.out.println("客户端的send构造器有问题"); this.release(); } } @Override public void run() { while(isRunning) { //客户端读取控制台消息--写入到client的输出流 String msg=ConsoleMsg(); if(!msg.equals("")) { sendMsg(msg); } } } private String ConsoleMsg() {//先读取控制台的内容 String msg=""; try { msg=console.readLine(); } catch (IOException e) { System.out.println("客户端的ConsoleMsg有问题"); this.release(); } return msg; } private void sendMsg(String msg) {//再写入到客户端的输出流里 try { dos.writeUTF(msg); dos.flush();//这个一定不能忘记啦 } catch (IOException e) { System.out.println("客户端的sendMsg有问题"); this.release(); } } //释放资源 private void release() {//内部类的使用 this.isRunning=false;//释放资源意味着该该客户端要停下来 Utils.close(dos,client);//自己写的一个工具类Utils } }
(5)Utils类的代码(编写工具类,方便资源的释放):
package chat4; import java.io.Closeable; /** * 自己写一个释放资源的工具类 * @author Administrator * */ public class Utils { public static void close(Closeable... targets) { for(Closeable target:targets) { try { if(null!=target) { target.close(); } }catch(Exception e){ } } } }
运行结果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。