java Socket实现多人群聊与私聊功能

时间:2022-04-20 15:33:17

本文实例为大家分享了java socket实现多人群聊私聊的具体代码,供大家参考,具体内容如下

关于socket套接字的一些基本知识与认识可以参见上一篇或自行查阅。

serversocket和socket实现群聊与私聊涉及到多线程编程,实现过程的重点是利用socket通信的原理,即不断的在服务端和客户端创建输入输出流来相互传递、交换数据等以达到通信的目的。具体实现如下:

服务端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import java.io.*;
import java.net.*;
import java.util.hashmap;
import java.util.map;
import java.util.concurrent.executorservice;
import java.util.concurrent.executors;
import java.util.concurrent.threadpoolexecutor;
 
 
public class tcpserver {
 
 private serversocket serversocket;
 
 /**
 * 创建线程池来管理客户端的连接线程
 * 避免系统资源过度浪费
 */
 private executorservice exec;
 
 // 存放客户端之间私聊的信息
 private map<string,printwriter> storeinfo;
 
 public tcpserver() {
 try {
 
 serversocket = new serversocket(6789);
 storeinfo = new hashmap<string, printwriter>();
 exec = executors.newcachedthreadpool();
 
 } catch (exception e) {
 e.printstacktrace();
 }
 }
 
 // 将客户端的信息以map形式存入集合中
 private void putin(string key,printwriter value) {
 synchronized(this) {
 storeinfo.put(key, value);
 }
 }
 
 // 将给定的输出流从共享集合中删除
 private synchronized void remove(string key) {
 storeinfo.remove(key);
 system.out.println("当前在线人数为:"+ storeinfo.size());
 }
 
 // 将给定的消息转发给所有客户端
 private synchronized void sendtoall(string message) {
 for(printwriter out: storeinfo.values()) {
 out.println(message);
 }
 }
 
 // 将给定的消息转发给私聊的客户端
 private synchronized void sendtosomeone(string name,string message) {
 printwriter pw = storeinfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去
 if(pw != null) pw.println(message);
 }
 
 public void start() {
 try {
 while(true) {
 system.out.println("等待客户端连接... ... ");
 socket socket = serversocket.accept();
 
 // 获取客户端的ip地址
 inetaddress address = socket.getinetaddress();
 system.out.println("客户端:“" + address.gethostaddress() + "”连接成功! ");
 /**
 * 启动一个线程,由线程来处理客户端的请求,这样可以再次监听
 * 下一个客户端的连接
 */
 exec.execute(new listenrclient(socket)); //通过线程池来分配线程
 }
 } catch(exception e) {
 e.printstacktrace();
 }
 }
 
 /**
 * 该线程体用来处理给定的某一个客户端的消息,循环接收客户端发送
 * 的每一个字符串,并输出到控制台
 */
 class listenrclient implements runnable {
 
 private socket socket;
 private string name;
 
 public listenrclient(socket socket) {
 this.socket = socket;
 }
 
 // 创建内部类来获取昵称
 private string getname() throws exception {
 try {
 //服务端的输入流读取客户端发送来的昵称输出流
 bufferedreader breader = new bufferedreader(
 new inputstreamreader(socket.getinputstream(), "utf-8"));
 //服务端将昵称验证结果通过自身的输出流发送给客户端
 printwriter ipw = new printwriter(
 new outputstreamwriter(socket.getoutputstream(), "utf-8"),true);
 
 //读取客户端发来的昵称
 while(true) {
 string namestring = breader.readline();
 if ((namestring.trim().length() == 0) || storeinfo.containskey(namestring)) {
 ipw.println("fail");
 } else {
 ipw.println("ok");
 return namestring;
 }
 }
 } catch(exception e) {
 throw e;
 }
 }
 
 @override
 public void run() {
 try {
 /*
 * 通过客户端的socket获取客户端的输出流
 * 用来将消息发送给客户端
 */
 printwriter pw = new printwriter(
 new outputstreamwriter(socket.getoutputstream(), "utf-8"), true);
 
 /*
 * 将客户昵称和其所说的内容存入共享集合hashmap中
 */
 name = getname();
 putin(name, pw);
 thread.sleep(100);
 
 // 服务端通知所有客户端,某用户上线
 sendtoall("[系统通知] “" + name + "”已上线");
 
 /*
 * 通过客户端的socket获取输入流
 * 读取客户端发送来的信息
 */
 bufferedreader breader = new bufferedreader(
 new inputstreamreader(socket.getinputstream(), "utf-8"));
 string msgstring = null;
 
 
 while((msgstring = breader.readline()) != null) {
 // 检验是否为私聊(格式:@昵称:内容)
 if(msgstring.startswith("@")) {
 int index = msgstring.indexof(":");
 if(index >= 0) {
 //获取昵称
 string thename = msgstring.substring(1, index);
 string info = msgstring.substring(index+1, msgstring.length());
 info = name + ":"+ info;
 //将私聊信息发送出去
 sendtosomeone(thename, info);
 continue;
 }
 }
 // 遍历所有输出流,将该客户端发送的信息转发给所有客户端
 system.out.println(name+":"+ msgstring);
 sendtoall(name+":"+ msgstring);
 }
 } catch (exception e) {
 // e.printstacktrace();
 } finally {
 remove(name);
 // 通知所有客户端,某某客户已经下线
 sendtoall("[系统通知] "+name + "已经下线了。");
 
 if(socket!=null) {
 try {
 socket.close();
 } catch(ioexception e) {
 e.printstacktrace();
 }
 }
 }
 }
 }
 
 public static void main(string[] args) {
 tcpserver server = new tcpserver();
 server.start();
 }
}

客户端:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.io.*;
import java.net.*;
import java.util.scanner;
import java.util.concurrent.executorservice;
import java.util.concurrent.executors;
import java.util.concurrent.threadpoolexecutor;
 
public class tcpclient {
 
 static private socket clientsocket;
 
 public tcpclient() {}
 
 public static void main(string[] args) throws exception {
 scanner scanner = new scanner(system.in);
 string serverip;
 
 system.out.println("请设置服务器ip:");
 serverip = scanner.next();
 clientsocket = new socket(serverip, 6789);
 tcpclient client = new tcpclient();
 client.start();
 }
 
 public void start() {
 try {
 scanner scanner = new scanner(system.in);
 setname(scanner);
 
 // 接收服务器端发送过来的信息的线程启动
 executorservice exec = executors.newcachedthreadpool();
  exec.execute(new listenrservser());
 
 // 建立输出流,给服务端发信息
 printwriter pw = new printwriter(
 new outputstreamwriter(clientsocket.getoutputstream(), "utf-8"), true);
 
 while(true) {
 pw.println(scanner.nextline());
 }
 } catch(exception e) {
 e.printstacktrace();
 } finally {
 if (clientsocket !=null) {
 try {
 clientsocket.close();
 } catch(ioexception e) {
 e.printstacktrace();
 }
 }
 }
 }
 
 private void setname(scanner scan) throws exception {
 string name;
 //创建输出流
 printwriter pw = new printwriter(
 new outputstreamwriter(clientsocket.getoutputstream(), "utf-8"),true);
 //创建输入流
 bufferedreader br = new bufferedreader(
 new inputstreamreader(clientsocket.getinputstream(),"utf-8"));
 
 while(true) {
 system.out.println("请创建您的昵称:");
 name = scan.nextline();
 if (name.trim().equals("")) {
 system.out.println("昵称不得为空");
 } else {
 pw.println(name);
 string pass = br.readline();
 if (pass != null && (!pass.equals("ok"))) {
 system.out.println("昵称已经被占用,请重新输入:");
 } else {
 system.out.println("昵称“"+name+"”已设置成功,可以开始聊天了");
 break;
 }
 }
 }
 }
 
 // 循环读取服务端发送过来的信息并输出到客户端的控制台
 class listenrservser implements runnable {
 
 @override
 public void run() {
 try {
 bufferedreader br = new bufferedreader(
 new inputstreamreader(clientsocket.getinputstream(), "utf-8"));
 string msgstring;
 while((msgstring = br.readline())!= null) {
 system.out.println(msgstring);
 }
 } catch(exception e) {
 e.printstacktrace();
 }
 }
 }
 
}

运行结果:

java Socket实现多人群聊与私聊功能

开始自己的实现也不是很完整,后来也是借鉴别人比较好的思想后完善的,权当分享。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/zhaokx3/article/details/52513019