java一对一网络聊天室,websocket网络编程实战 - 用原生SOCKET协议实现在线群聊聊天室和一对一单聊天室...

前言

上篇文章我们用STOMP子协议实现了在线群聊和一对一聊天室等功能,本篇我们继续WebSocket这个话题,这次我们换个实现维度:用原生的WebSocket来实现,看看这两者在实现上的差别有多大。

575c9bfb05d109c6acf652c999cf5960.png

实战WebSocket的要点

一、WebSocket重要属性属性备注

Socket.readyState只读属性 readyState 表示连接状态,可以是以下值:

0 -表示连接尚未建立。

1 -表示连接已建立,可以进行通信。

2 -表示连接正在进行关闭。

3 -表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

二、WebSocket核心事件事件事件处理程序备注

openSocket.onopen连接建立时触发

messageSocket.onmessage客户端接收服务端数据时触发

errorSocket.onerror通信发生错误时触发

closeSocket.onclose连接关闭时触发

三、WebSocket核心方法方法备注

Socket.send()使用连接发送数据

Socket.close()连接关闭

代码设计实现

一、服务端部分/**

*@authorandychen https://blog.51cto.com/14815984

*@description:WebSocket配置*/@Configurationpublic classWebSocketConfig {

/**

* 注册并开启WebSocket

*@return*/@BeanpublicServerEndpointExporter serverEndpointExporter(){

return newServerEndpointExporter();}

}/**

*@authorandychen https://blog.51cto.com/14815984

*@description:WebSocket通信业务类*/@ServerEndpoint("/ws/server")

@Componentpublic classWebSocketController {

private static finalLogger log= LoggerFactory.getLogger(WebSocketController.class);/**

* 服务端连接计数器

*/private static finalAtomicInteger counter= newAtomicInteger(0);/**

* 定义客户端会话安全容器

* 缓存客户端会话对象(正式环境,这里可以直接做分布式缓存)

*/private static finalCopyOnWriteArraySet sessionContainer= newCopyOnWriteArraySet<>();/**

* 定义客户端会话和用户身份映射安全容器

*/private static finalMap sessionMap= newConcurrentHashMap<>();/**

* 消息分隔字符窜

*/private static finalString MSG_SPLIT_STR= "@#@";/**

* 消息角色

*/private static finalString[] MSG_ROLES= {"sender","recevier"};/**

* WebSocket连接打开事件

*@paramsession客户端连接会话

*/@OnOpenpublic voidopen(Session session){

//缓存会话sessionContainer.add(session);//会话IdString sessionId = session.getId();

if(!sessionMap.containsKey(sessionId)){

String receiver = this.getRecevier(session);

booleanisMass = (null== receiver);//消息用户:群聊为发送者,单聊时为发送者和接收者String usrInfo = parseMsgParameter(session,MSG_ROLES[0]);

if(isMass){

sessionMap.put(sessionId,usrInfo);}else{

usrInfo += MSG_SPLIT_STR+receiver;sessionMap.put(usrInfo,sessionId);}

//发送新用户加入消息if(isMass){

sendMass("系统消息"+MSG_SPLIT_STR+"用户["+usrInfo+"]加入群聊");}

log.info("会话[{}]加入,当前连接数为:{}",sessionId,counter.incrementAndGet());}

}

/**

* 接收客户端消息事件

*@parammessage文本消息(也支持对象、二进制Buffer)

*@paramsession客户端连接会话

*/@OnMessagepublic voidaccept(String message,Session session){

String sender = null;String sessionId = session.getId();String sessionId2 = null;String msg =null;String recevier = getRecevier(session);

if(null== recevier){

msg = sessionMap.get(sessionId)+MSG_SPLIT_STR+message;sendMass(msg);}else{

sender = parseMsgParameter(session,MSG_ROLES[0]);msg = sender+MSG_SPLIT_STR+message;//发送者sessionIdsessionId = sender+MSG_SPLIT_STR+recevier;sessionId = sessionMap.get(sessionId);//接收者sessionIdsessionId2 = recevier+MSG_SPLIT_STR+sender;sessionId2 = sessionMap.get(sessionId2);sendSingle(sessionId,sessionId2,msg);}

log.info("已接收客户端[{}]消息:{},请求地址:{}",sessionId,message,session.getRequestURI().toString());}

/**

* 连接关闭事件

*@paramsession客户端连接会话

*/@OnClosepublic voidclose(Session session){

String sessionId = session.getId();sessionContainer.remove(session);String recevier =getRecevier(session);

if(null== recevier){

//群聊发送退群消息String sender = sessionMap.get(sessionId);sessionMap.remove(sessionId);sendMass("系统消息"+MSG_SPLIT_STR+"用户["+sender+"]退出群聊");}else{

sessionId = parseMsgParameter(session,MSG_ROLES[0])+MSG_SPLIT_STR+recevier;sessionId = sessionMap.get(sessionId);sessionMap.remove(sessionId);}

log.info("会话[{}]关闭连接,当前连接数为:{}",sessionId,counter.decrementAndGet());}

/**

* 连接发生错误事件

*@paramsession客户端连接会话

*@paramerror错误对象

*/@OnErrorpublic voiderror(Session session,Throwable error){

log.error("连接发生错误:{},\n\n客户端会话ID[{}],请求地址:{}",error.getMessage(),session.getId(),session.getRequestURI().toString());error.printStackTrace();}

/**

* 是否单聊

*@paramsession客户会话id

*@return*/privateString getRecevier(Session session){

returnparseMsgParameter(session,MSG_ROLES[1]);}

/**

* 解析消息参数

*@paramsession客户端会话

*@paramname参数名称

*@return*/private staticString parseMsgParameter(Session session,String name){

//获取会话中包含的参数信息Map> params = session.getRequestParameterMap();

if(params.containsKey(name)){

returnparams.get(name).get(0);}

return null;}

/**

* 发送消息

*@paramsession客户端会话

*@parammsg消息内容

*/private static booleansend(Session session,String msg){

try{

//异步转发文本消息(也可发送消息对象,二进制流等)session.getAsyncRemote().sendText(msg);

return true;} catch(Exception e) {

log.error("消息发送失败:{}",e.getMessage());e.printStackTrace();}

return false;}

/**

* 群发消息

*@parammsg消息内容

*/private static voidsendMass(String msg){

for(Session session : sessionContainer){

if(session.isOpen()){

//发送send(session,msg);}

}

}

/**

* 发送聊消息

*@paramsenderSid发送者会话id

*@paramrecevSid接收者会话id

*@parammsg消息内容

*/private static voidsendSingle(String senderSid,String recevSid,String msg){

String id = null;

intcount = 0;

for(Session s : sessionContainer) {

id = s.getId();

if(senderSid.equals(id)) {

count++;send(s,msg);}

if(recevSid.equals(id)) {

count++;send(s,msg);}

if(2== count){break;}

}

if(2> count){

log.warn("未找到指定会话[ID: {}或{}]",senderSid,recevSid);}

}

}

二、客户端部分

WebSocket在线聊天室

选择你的网名:

请选择..

zhangsan

lisi

wangwu

zhaoliu

chenqi

qianba

群聊:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值