Java网络编程案例---聊天室

Posted wuyongji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java网络编程案例---聊天室相关的知识,希望对你有一定的参考价值。

  网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

  java.net包中JavaSE的API包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。

  java.net包中提供了两种常见的网络协议的支持:

  TCP:TCP是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称TCP/IP。

  UDP:UDP是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据报。

  本案例以TCP协议为例,结合多线程,实现一个多人同时聊天的聊天室。

  释放资源:

  Utils.java

 1 package com.bjwyj.chat;
 2 
 3 import java.io.Closeable;
 4 
 5 public class Utils {
 6     /**
 7      * 释放资源
 8      */
 9     public static void close(Closeable... targets) {
10         for(Closeable target:targets) {
11             try {
12                 if(target!=null) {
13                     target.close();
14                 }
15             }catch(Exception e) {
16                 e.printStackTrace();
17             }
18         }
19     }
20 }

  服务器端:

  Chat.java

  1 package com.bjwyj.chat;
  2 
  3 import java.io.DataInputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.IOException;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 import java.util.concurrent.CopyOnWriteArrayList;
  9 
 10 /**
 11  * 在线聊天室:服务端
 12  * 目标:加入容器实现群聊和私聊
 13  * 
 14  * @author 吴永吉
 15  *
 16  */
 17 public class Chat {
 18     private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>();
 19     public static void main(String[] args) throws IOException {
 20         System.out.println("------server------");
 21         //1.指定端口:使用ServerSocket创建服务器
 22         ServerSocket server = new ServerSocket(9999);
 23         //2.阻塞式等待连接accept
 24         while(true) {
 25             Socket client = server.accept();
 26             System.out.println("一个客户端建立了连接");
 27             Channel c = new Channel(client);
 28             all.add(c); //管理所有的成员
 29             new Thread(c).start();
 30         }
 31     }
 32     //一个客户代表一个Channel
 33     static class Channel implements Runnable{
 34         private DataInputStream dis;
 35         private DataOutputStream dos;
 36         private Socket client;
 37         private boolean isRunning;
 38         private String name;
 39         
 40         public Channel(Socket client) {
 41             isRunning = true;
 42             this.client = client;
 43             try {
 44                 dis = new DataInputStream(client.getInputStream());
 45                 dos = new DataOutputStream(client.getOutputStream());
 46                 //获取名称
 47                 this.name = receive();
 48                 //欢迎你的到来
 49                 this.send("欢迎上线");
 50                 this.sendOthers(this.name+"上线啦!",true);
 51             }catch(Exception e) {
 52                 release();
 53             }
 54         }
 55         
 56         //接收消息
 57         public String receive() {
 58             String msg = "";
 59             try {
 60                 msg = dis.readUTF();
 61             } catch (IOException e) {
 62                 System.out.println("-------Chat receive------");
 63                 release();
 64             }
 65             return msg;
 66         }
 67         //发送消息
 68         public void send(String msg) {
 69             try {
 70                 dos.writeUTF(msg);
 71                 dos.flush();
 72             } catch (IOException e) {
 73                 System.out.println("--------Chat send-------");
 74                 release();
 75             }
 76         }
 77         /**
 78          * 群聊:获取自己的消息,发给其他人
 79          * 私聊:约定数据格式:@xxx:msg
 80          * @param msg
 81          */
 82         public void sendOthers(String msg,boolean isSys) {
 83             boolean isPrivate = msg.startsWith("@");
 84             if(isPrivate) { //私聊
 85                 int idx = msg.indexOf(":");
 86                 //获取目标和数据
 87                 String targetName = msg.substring(1,idx);
 88                 msg = msg.substring(idx+1);
 89                 for(Channel other:all) {
 90                     if(other.name.equals(targetName)) { //目标
 91                         other.send(this.name+"悄悄的对你说:"+msg);
 92                         break;
 93                     }
 94                 }
 95             }else { //群聊
 96                 for(Channel other:all) {
 97                     if(this==other) { //自己
 98                         continue;
 99                     }
100                     if(!isSys) {
101                         other.send(this.name+"对所有人说:"+msg); //群聊消息
102                     }else {
103                         other.send(msg); //系统消息
104                     }
105                 }
106             }
107         }
108         //关闭资源
109         public void release() {
110             this.isRunning = false;
111             Utils.close(dis,dos,client);
112             //退出
113             all.remove(this);
114             sendOthers(this.name+"下线了!",true);
115         }
116 
117         @Override
118         public void run() {
119             while(isRunning) {
120                 String msg = receive();
121                 if(!msg.equals("")) {
122                     //send(msg);
123                     sendOthers(msg,false);
124                 }
125             }
126         }
127     }
128 }

  客户端:

  Send.java

 1 package com.bjwyj.chat;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.io.InputStreamReader;
 7 import java.net.Socket;
 8 
 9 /**
10  * 使用多线程封装了客户发送端:
11  * 1.发送消息
12  * 2.从控制台获取消息
13  * 3.释放资源
14  * 4.重写run
15  * @author 吴永吉
16  *
17  */
18 public class Send implements Runnable{
19     private BufferedReader console;
20     private DataOutputStream dos;
21     private Socket client;
22     private boolean isRunning;
23     private String name;
24     
25     public Send(Socket client,String name) {
26         isRunning = true;
27         this.client = client;
28         this.name = name;
29         console = new BufferedReader(new InputStreamReader(System.in));
30         try {
31             dos = new DataOutputStream(client.getOutputStream());
32             //发送名称
33             send(name);
34         } catch (IOException e) {
35             System.out.println("------Client Send------");
36             this.release();
37         }
38     }
39     
40     @Override
41     public void run() {
42         while(isRunning) {
43             String msg = this.getStringFromConsole();
44             if(!msg.equals("")) {
45                 this.send(msg);
46             }
47         }
48     }
49     
50     /**
51      * 发送消息
52      */
53     private void send(String msg) {
54         try {
55             dos.writeUTF(msg);
56             dos.flush();
57         } catch (IOException e) {
58             System.out.println("------Client send------");
59             release();
60         }
61     }
62     
63     /**
64      * 从控制台获取消息
65      */
66     private String getStringFromConsole() {
67         try {
68             return console.readLine();
69         } catch (IOException e) {
70             System.out.println("------Client console------");
71             release();
72         }
73         return "";
74     }
75     
76     //释放资源
77     private void release() {
78         this.isRunning = false;
79         Utils.close(dos,client);
80     }
81 }

  Receive.java

 1 package com.bjwyj.chat;
 2 
 3 import java.io.DataInputStream;
 4 import java.io.IOException;
 5 import java.net.Socket;
 6 
 7 /**
 8  * 使用多线程封装了客户接收端
 9  * 1.接收消息
10  * 2.释放资源
11  * 3.重写run
12  * @author 吴永吉
13  *
14  */
15 public class Receive implements Runnable{
16     private DataInputStream dis;
17     private Socket client;
18     private boolean isRunning;
19     
20     public Receive(Socket client) {
21         this.isRunning = true;
22         this.client = client;
23         try {
24             dis = new DataInputStream(client.getInputStream());
25         } catch (IOException e) {
26             System.out.println("------Client Receive------");
27             this.release();
28         }
29     }
30     
31     //接收消息
32     public String receive() {
33         String msg = "";
34         try {
35             msg = dis.readUTF();
36         } catch (IOException e) {
37             System.out.println("-------Receive receive------");
38             release();
39         }
40         return msg;
41     }
42     
43     @Override
44     public void run() {
45         while(isRunning) {
46             String msg = this.receive();
47             if(!msg.equals("")) {
48                 System.out.println(msg);
49             }
50         }
51     }
52     
53     //释放资源
54     private void release() {
55         this.isRunning = false;
56         Utils.close(dis,client);
57     }
58 }

  Client.java

 1 package com.bjwyj.chat;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.IOException;
 5 import java.io.InputStreamReader;
 6 import java.net.Socket;
 7 import java.net.UnknownHostException;
 8 
 9 /**
10  * 在线聊天室:客户端
11  * 
12  * @author 吴永吉
13  *
14  */
15 public class Client {
16     public static void main(String[] args) throws UnknownHostException, IOException {
17         System.out.println("------client------");
18         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
19         System.out.println("请输入名称:");
20         String name = br.readLine();
21         //建立连接:使用Socket创建客户端+服务器的地址和端口号
22         Socket client = new Socket("localhost",9999);
23         //客户端发送消息
24         new Thread(new Send(client,name)).start();
25         //获取消息
26         new Thread(new Receive(client)).start();
27     }
28 }

  运行结果:

技术图片技术图片

技术图片技术图片

以上是关于Java网络编程案例---聊天室的主要内容,如果未能解决你的问题,请参考以下文章

java基础——UDP实现dos聊天室案例

Java 网络编程:案例四:多个客户端群聊

小程序设计一起来聊天吧!

基于AIO的聊天室 (全future版)

P2P网络编程-3-案例实践:PubSub

Golang网络聊天室案例