Java聊天室功能
老徐·· 人气:0一、客户端的创建
1.我们可以用Socket来创建客户端
/** *@类名 Client *@描述 TODO 客户端 1 *@版本 1.0 *@创建人 XuKang *@创建时间 2020/9/24 16:18 **/ public class Client { public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("-----Client1-----"); BufferedReader br =new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入用户名:"); String name =br.readLine(); //1、建立连接: 使用Socket创建客户端 +服务的地址和端口 Socket client =new Socket("localhost",8888); //2、客户端发送消息 new Thread(new Send(client,name)).start(); new Thread(new Receive(client)).start(); } }
2.这时我们需要接受其他客户端发送的数据,我们需要创建一个客户端的接收方法和发送方法,我可以用阻塞式的方式进行接收和发送,考虑到多线程的安全性,可以实现Runnable
1.Send发送端:
/** *@类名 Send *@描述 TODO 使用多线程封装:发送端 *@版本 1.0 *@创建人 XuKang *@创建时间 2020/9/24 16:23 **/ 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; console =new BufferedReader(new InputStreamReader(System.in)); this.isRunning = true; this.name = name; try { dos =new DataOutputStream(client.getOutputStream()); //发送名称 send(name); } catch (IOException e) { System.out.println("==1=="); this.release(); } } @Override public void run() { while(isRunning) { String msg = getStrFromConsole(); if(!msg.equals("")) { send(msg); } } } //发送消息 private void send(String msg) { try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { System.out.println(e); System.out.println("===3=="); release(); } } /** * 从控制台获取消息 * @return */ private String getStrFromConsole() { try { return console.readLine(); } catch (IOException e) { e.printStackTrace(); } return ""; } //释放资源 private void release() { this.isRunning = false; CloseUtils.close(dos,client); } }
2.接收端
/** *@类名 Receive *@描述 TODO 使用多线程封装:接收端 *@版本 1.0 *@创建人 XuKang *@创建时间 2020/9/24 16:22 **/ public class Receive implements Runnable { private DataInputStream dis ; private Socket client; private boolean isRunning; public Receive(Socket client) { this.client = client; this.isRunning = true; try { dis =new DataInputStream(client.getInputStream()); } catch (IOException e) { System.out.println("====离开一位====="); release(); } } //接收消息 private String receive() { String msg =""; try { msg =dis.readUTF(); } catch (IOException e) { System.out.println("====接收消息异常===="); release(); } return msg; } @Override public void run() { while(isRunning) { String msg =receive(); if(!msg.equals("")) { System.out.println(msg); } } } //释放资源 private void release() { this.isRunning = false; CloseUtils.close(dis,client); } }
3.统一释放资源的方法可以提出,服务的也用得上
/** *@类名 CloseUtils *@描述 TODO 工具类,统一释放资源 *@版本 1.0 *@创建人 XuKang *@创建时间 2020/9/24 16:20 **/ public class CloseUtils { /** * 释放资源 */ public static void close(Closeable... targets ) { for(Closeable target:targets) { try { if(null!=target) { target.close(); } }catch(Exception e) { } } } }
二、客户端的创建
服务端用ServerSocket创建,如果我们吧服务的和客户端看成事一个通信通道(Channel),那么每个客户端的接入都会创建一个通信通道,那么通信通道的创建也需要实现多线程,可以实现Runnable接口,我们存放通道可以用线程容器CopyOnWriteArrayList来存放通道。
/** *@类名 Chat *@描述 TODO Socket服务端(测试类) *@版本 1.0 *@创建人 XuKang *@创建时间 2020/9/24 16:17 **/ public class Chat { private static CopyOnWriteArrayList<Channel> all =new CopyOnWriteArrayList<Channel>(); public static void main(String[] args) throws IOException { System.out.println("-----Server-----"); // 1、指定端口 使用ServerSocket创建服务器 ServerSocket server =new ServerSocket(8888); // 2、阻塞式等待连接 accept 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; //获取名称 this.name =receive();//退出出聊天室 //欢迎你的到来 this.send("欢迎你的到来"); sendOthers(this.name+"来了徐康聊天室",true);//暂时固定为私聊 } catch (IOException e) { System.out.println("---1------"); release(); } } //接收消息 private String receive() { String msg =""; try { msg =dis.readUTF(); } catch (IOException e) { System.out.println("---2------"); release(); } return msg; } //发送消息 private void send(String msg) { try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { System.out.println("---3------"); release(); } } /** * @方法名 sendOthers * @描述 TODO 群聊:获取自己的消息,发给其他人,需要设置isSys为false * TODO 私聊: 约定数据格式: @xxx:msg * @参数 msg 发送内容 * @返回值 * @创建人 XuKang * @创建时间 2020/9/24 16:28 */ private void sendOthers(String msg,boolean isSys) { boolean isPrivate = msg.startsWith("@"); if(isPrivate) { //私聊 int idx =msg.indexOf(":"); //获取目标和数据 String targetName = msg.substring(1,idx); msg = msg.substring(idx+1); for(Channel other: all) { if(other.name.equals(targetName)) {//目标 other.send(this.name +"悄悄地对您说:"+msg); break; } } }else { for(Channel other: all) { if(other==this) { //自己 continue; } if(!isSys) { other.send(this.name +"对所有人说:"+msg);//群聊消息 }else { other.send(msg); //系统消息 } } } } //释放资源 private void release() { this.isRunning = false; CloseUtils.close(dis,dos,client); //退出 all.remove(this); sendOthers(this.name+"离开大家庭...",true); } @Override public void run() { while(isRunning) { String msg = receive() ; if(!msg.equals("")) { //send(msg); sendOthers(msg,false); } } } } }
三、效果如下
1.启动服务端
2.启动客户端
3.发送消息
总结
此案例只能用来打发时间,入门网络编程可以参考一下,真正的开发不会这么弄。
加载全部内容