java群聊_Java Socket通信实现私聊、群聊

前言

闲言少叙,上代码!

代码编写

server服务端

/*** 服务端*/

public classServer {private static ServerSocket server = null;private static Socket ss = null;/*** 客户端集合*/

private static Map serverThreadMap = new HashMap();public static voidmain(String[] args) {

server();

}/*** 普通服务器连接*/

private static voidserver() {try{//建立服务端

server = new ServerSocket(10010);

System.out.println("server端已启动!");while (true) {//创建接收接口

ss =server.accept();//启动新客户监听线程

newServerThread(server, ss).start();

}

}catch(IOException e) {

e.printStackTrace();

}finally{try{

ss.close();

server.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}/*** 内部类线程,每连接一个新的客户端就启动一个对应的监听线程*/@SuppressWarnings("Duplicates")private static class ServerThread extendsThread {

ServerSocket server= null;

Socket socket= null;

InputStream is= null;

OutputStream os= null;

String clientName= null;boolean alive = true;publicServerThread() {

}

ServerThread(ServerSocket server, Socket socket) {this.socket =socket;this.server =server;

}

@Overridepublic voidrun() {//接收数据

try{

is=socket.getInputStream();//发送

os =socket.getOutputStream();//缓存区

byte[] b = new byte[1024];int length = 0;while(alive) {//接收从客户端发送的消息

length =is.read(b);if (length != -1) {//文本消息

String message = new String(b, 0, length);//JSON字符串转 HashMap

HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);//消息类型

String type = (String) hashMap.get("type");//新连接

if ("OPEN".equals(type)) {

clientName= (String) hashMap.get("clientName");//添加客户端到集合容器中

serverThreadMap.put(clientName, this);

System.out.println(clientName+ "连接成功!");

System.out.println("当前客户端数量:" +serverThreadMap.size());

}//关闭

if ("CLOSE".equals(type)) {

alive= false;

System.err.println(clientName+ "退出连接,关闭监听线程!");

}//文本消息

if ("MESSAGE".equals(type)) {

String msg= (String) hashMap.get("message");

String chat= (String) hashMap.get("chat");//群聊(广播)

if ("GROUP".equals(chat)) {//遍历容器,给容器中的每个对象转发消息

for(ServerThread st : serverThreadMap.values()) {//向其他客户端发送数据

if (st != this) {

st.os.write(new String(b, 0, length).getBytes());

}

}//后台打印

System.out.println(clientName + "向所有人说:" +msg);

}//私聊

if ("PRIVATE".equals(chat)) {

String to= (String) hashMap.get("to");

serverThreadMap.get(to).os.write(new String(b, 0, length).getBytes());//后台打印

System.out.println(clientName + "向" + to + "说:" +msg);

}

}

}

}

}catch(IOException e) {

e.printStackTrace();

System.err.println("与" + clientName + "连接中断,被迫关闭监听线程!");

}finally{try{

serverThreadMap.remove(clientName);

System.out.println("当前客户端数量:" +serverThreadMap.size());

os.close();

is.close();

socket.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}

}

}

client客户端

/*** 客户端*/@SuppressWarnings("Duplicates")public classClient {private static String serverInetAddress = "127.0.0.1";private static int serverPort = 10010;private static Socket client = null;private static OutputStream os = null;private static InputStream is = null;private staticString thisName;private static boolean alive = true;/*** 客户端连接服务器*/@SuppressWarnings("unused")public static voidopen(String name) {try{

thisName=name;

InetAddress inetAddress=InetAddress.getLocalHost();//建立连接

client = newSocket(serverInetAddress, serverPort);//数据流发送数据

os =client.getOutputStream();

sendMsg("{\"type\":\"OPEN\",\"clientName\":\"" + name + "\"}");//数据流接收数据

is =client.getInputStream();byte[] b = new byte[1024];int length = 0;while(alive) {//接收从服务器发送回来的消息

length =is.read(b);if (length != -1) {

onMsg(new String(b, 0, length));

}

}

}catch(IOException e) {

e.printStackTrace();

}finally{try{//关流

os.close();

client.close();

is.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}/*** 关闭客户端*/

public static voidclose() {

sendMsg("{\"type\":\"CLOSE\"}");

alive= false;

}/*** 发送消息*/

public static voidsendMsg(String msg) {try{//调用发送

os.write(msg.getBytes());

}catch(IOException e) {

e.printStackTrace();

}

}/*** 收到消息的回调*/

private static voidonMsg(String message) {//JSON字符串转 HashMap

HashMap hashMap = null;try{

hashMap= new ObjectMapper().readValue(message, HashMap.class);

}catch(IOException e) {

e.printStackTrace();

}

String msg= (String) hashMap.get("message");

String chat= (String) hashMap.get("chat");

String from= (String) hashMap.get("from");

String to= (String) hashMap.get("to");//群聊

if ("GROUP".equals(chat)) {//后台打印

System.out.println(thisName + "收到(" + to + ")群聊消息:" +msg);

}//私聊

if ("PRIVATE".equals(chat)) {//后台打印

System.out.println(thisName + "收到(" + from + ")私聊消息:" +msg);

}

}/*** 获取thisName*/

public staticString getThisName() {returnthisName;

}

}

controller模拟调用客户端

@RequestMapping("/sendMsg/{chat}/{msg}")public void sendMsg(@PathVariable("chat") String chat, @PathVariable("msg") String msg) {if ("group".equals(chat.toLowerCase())) {//群聊

Client.sendMsg("{\"type\":\"MESSAGE\",\"chat\":\"GROUP\",\"from\":\""+Client.getThisName()+"\",\"to\":\"群号:xxxx\",\"message\":\"" + msg + "\"}");

}else{//私聊

Client.sendMsg("{\"type\":\"MESSAGE\",\"chat\":\"PRIVATE\",\"from\":\""+Client.getThisName()+"\",\"to\":\"" + chat + "\",\"message\":\"" + msg + "\"}");

}

}

@RequestMapping("/starClient/{name}")public void starClient(@PathVariable("name") String name) {

Client.open(name);

}

@RequestMapping("/closeClient")public voidcloseClient() {

Client.close();

}

效果展示

一个服务端、两个客户端(两个不同的工程、模拟两个客户端),注意,要先启动服务端,再启动客户端!

使用controller模拟启动两个客户端:

http://localhost:10086/springboot/user/starClient/张三

http://localhost:10087/starClient/李四

f0168330b2b46e3d8fd01ff11003b708.png

张三发送群聊

http://localhost:10086/springboot/user/sendMsg/group/大家好啊

3302fd173f0fdfb9e5afc3ac8e679fa1.png

张三是发送者,server不再转发此消息给张三

a17671579a5502cc07b3be96ef018081.png

张三向李四发送私聊信息

http://localhost:10086/springboot/user/sendMsg/李四/老表,你好啊

65ed2998d4f2853c967fbc0767284635.png

张三是发送者,server不再转发此消息给张三

485f1556f26cd32438681c954f152f01.png

李四回复张三私聊信息

4c630ade0bde67f81b2b2bf95bbcde52.png

a44ba4d208732035b0ce8dcacc2896cf.png

李四是发送者,server不再转发此消息给李四

下线、掉线

张三:http://localhost:10086/springboot/user/closeClient

李四:直接终止客户端进程

6125fd5b31fa4639a5804cc729d06c56.png

后记

这个例子服务端每次有新的客户端连接进来,就启动一个线程去监听与此客户端的通信,当有大量客户端时就不适用了,而且涉及界面时,java socket不能主动给浏览器发送消息,界面聊天只能用轮询的方式实现,不好;多客户端、涉及有界面的聊天建议使用websocket(猛戳这里 -->WebSocket+Java 私聊、群聊实例)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值