网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
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 }
运行结果: