百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Java WebSocket编程与网页简易聊天室

toyiye 2024-08-17 00:13 7 浏览 0 评论

在webSocket还未引入前,许多开发人员通过各种非正规手段来完成更新网站的最新信息和到所有当前访问者的任务,其中一种手段就是通过浏览器向服务器轮询更新,但这种手段的网络延迟比较明显,其用户体验比较差。而webSocket协议的引入比较好的解决这种问题,webSocket是一种网络协议,它允许两个相连的端在一个TCP连接上进行全双工通讯。它主要用来作为托管在Web服务器上的Web应用和浏览器之间的通讯机制,同样,WebSocket可以在网络间的任意两端建立,而不一定要在浏览器和服务器上。Java Web Socket API 是JavaEE7平台的核心特性。端点是Java WebSocket API组件模型的中心,而创建端点的方式有注解式和编程式。下面的内容都是关于WebSocket注解式编程。

WebSocket端点的4个生命周期事件

  • 打开事件
  • 此事件发生在端点上建立新连接时并且在任何其他事件之前
  • 消息事件
  • 此事件接收WebSocket对话的另外一端发送的消息。它可以发生在WebSocket端点接收了打开事件后并且在接收关闭事件关闭连接之前的任意时刻
  • 错误事件
  • 此事件在WebSocket连接或者端点发生错误时产生
  • 关闭事件
  • 此事件表示WebSocket端点的连接目前正在部分的关闭,它可以由参与连接的任意一个端点发出

注解式端点事件处理

将Java类声明成WebSocket端点,在服务器端端点用@ServerEndpoint来注解,在客户端可以使用@ClientEndpoint来注解。对于端点的四个生命周期事件:

打开事件@OnOpen

@OnOpen
public void init(Session session,EndpointConfig config){
/*
*方法名任意,参数两个任选,可要可不要,其他事件也一样
**/
}
1
2
3
4
5
6

消息事件@OnMessage

@OnMessage
public void message(String textMessage,Session session){
 //处理文本信息,Session参数可选
}
@OnMessage
public void message(byte[] messageData,Session session){
 //处理二进制信息,Session参数可选
}
@OnMessage
public void message(String textMessage,boolean isLast){
 //处理分片段的文本信息,isLast 为false表示信息没有接收完整,true则表示最后一条信息
}
//所有的@OnMessage 也可以有返回值相当于发送消息的功能
@OnMessage
public String message(String textMessage,Session session){
 //处理文本信息,Session参数可选
 return "I got it";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

错误事件@OnError

@OnError 
public void errorHandler(Throwable t){
 //log error here
}
1
2
3
4

关闭事件@OnClose

@OnClose
public void goodbye(){
 //
}
1
2
3
4

发送信息

1.发送字符串消息

RemoteEndpoint.Basic发送文本信息:public void sendText(String text) throws IOEcxeption

RemoteEndpoint.Basic发送文本信息到流:public Writer getSendStream() throws IOEcxeption

RemoteEndpoint以片段形式发送文本消息:public void sendText(String partialMessage,boolean isLast) throws IOException

以小片段序列的形式发送大的字符串消息,调用时isLast参数一般设为false,直到最后一个片段才设为true,表明消息发送完毕。

2.发送二进制消息

对于大多数应用,发送文本形式消息已经足够,对于有特殊格式例如小图像文件,以二进制形式发送消息则更合适

RemoteEndpoint发送二进制消息:

public void sendBinary(ByteBuffer data) throws IOException

public void sendBinary(ByteBuffer partialByte,boolean isLast) throws IOException 以分片的形式发送,调用时isLast参数一般设为false,直到最后一个片段才设为true,表明消息发送完毕。

RemoteEndpoint.Basic使用流发送二进制消息:

public OutputStream getSendStream() throws IOException

基于Java WebSocket 编写的简易聊天室

服务端采用注解式编写

package server;
import java.io.IOException;
import java.util.HashMap;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/echo")//注解使得此Java类声明成WebSocket的端点
public class EchoServer {
 private boolean first = true;
 private String name;//用户昵称
 //connect key为session的ID,value为此对象this
 private static final HashMap<String,Object> connect = new HashMap<String,Object>();
 //userMap key为session的ID,value为用户名
 private static final HashMap<String,String> userMap = new HashMap<String,String>();
 private Session session;
 @OnOpen
 public void start(Session session){
 this.session = session; //获取Seession,存入SashMap
 connect.put(session.getId(),this);
 }
 @OnMessage
 public void echo( String incomingMessage,Session session){
 EchoServer client = null ;
 //first 判断是否第一次传值,第一次的值是昵称,由web端的OnOpen传入
 if(first){
 this.name = incomingMessage;
 String message ="系统:欢迎"+name;
 //昵称和session的Id一一对应存储在HashMap
 userMap.put(session.getId(), name);
 //将message广播给所有用户
 for (String key : connect.keySet()) { 
 try { 
 client = (EchoServer) connect.get(key); 
 synchronized (client) { 
 //给对应的Web端发送一个文本消息
 client.session.getBasicRemote().sendText(message); 
 } 
 } catch (IOException e) { 
 connect.remove(client); 
 try { 
 client.session.close(); 
 } catch (IOException e1) { 
 } 
 } 
 } 
 //输入昵称后,往后的交互传值都不是第一次
 first = false;
 }else{
 /**
 * incomingMessage的值为xxx@xxxxx的形式xxx为要发给的用户昵称,all则表示发给所有人
 * incomingMessage.split("@",2);以@为分隔符把字符串分为xxx和xxxxx两部分
 */
 String [] list = incomingMessage.split("@",2);
 if(list[0].equalsIgnoreCase("all")){ //all广播全部人
 sendAll(list[1],session);
 }else{
 boolean you = false;//标记是否找到发送的用户
 for(String key : userMap.keySet()){
 if(list[0].equalsIgnoreCase(userMap.get(key))){
 client = (EchoServer) connect.get(key); 
 synchronized (client) { 
 try {
 //发送信息给指定的用户
 client.session.getBasicRemote().sendText(userMap.get(session.getId())+"对你说:"+list[1]);
 } catch (IOException e) {
 e.printStackTrace();
 } 
 } 
 you = true;//找到指定用户标记为true
 break;
 }
 }
 //you为true则在自己页面显示自己对xxx说xxxxx,否则显示系统:无此用户
 if(you){
 try {
 session.getBasicRemote().sendText("自己对"+ list[0]+"说:"+list[1]);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }else{
 try {
 session.getBasicRemote().sendText("系统:无此用户");
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
 }
 @OnClose
 public void close(Session session){
 //当一用户退出时,对其他用户进行广播
 String message ="系统:"+userMap.get(session.getId()) +"退出群聊";
 userMap.remove(session.getId());
 connect.remove(session.getId());
 for (String key : connect.keySet()) { 
 EchoServer client = null ; 
 try { 
 client = (EchoServer) connect.get(key); 
 synchronized (client) { 
 client.session.getBasicRemote().sendText(message); 
 } 
 } catch (IOException e) { 
 connect.remove(client); 
 try { 
 client.session.close(); 
 } catch (IOException e1) { 
 } 
 } 
 } 
 }
 //对信息进行全体广播
 public static void sendAll(String mess,Session session){ 
 String who = null;
 for (String key : connect.keySet()) { 
 EchoServer client = null ; 
 try { 
 client = (EchoServer) connect.get(key); 
 if(key.equalsIgnoreCase(session.getId())){
 who = "自己对大家说 : ";
 }else{
 who = userMap.get(session.getId())+"对大家说 : ";
 }
 synchronized (client) { 
 client.session.getBasicRemote().sendText(who+mess); 
 } 
 } catch (IOException e) { 
 connect.remove(client); 
 try { 
 client.session.close(); 
 } catch (IOException e1) { 
 } 
 } 
 } 
 } 
 public String getName(){
 return this.name;
 }
}
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

web端

<!DOCTYPE html>
<html>
 <head>
 <title>简易聊天室</title>
 <meta name="keywords" content="keyword1,keyword2,keyword3">
 <meta name="description" content="this is my page">
 <meta name="content-type" content="text/html; charset=UTF-8">
 <script type="text/javascript">
 var ws;
 var wsUri = "ws://localhost:8080/Socket/echo";
 ws = new WebSocket(wsUri);
 ws.onopen = function(){
 n=prompt('请给自己取一个昵称:');
 n=n.substr(0,16);
 ws.send(n);//在服务端必须由OnMessage接收此消息
 };
 //处理连接后的信息处理
 ws.onmessage = function(message){
 writeToScreen(message.data); 
 };
 //对发送按钮进行监听,获取发送的信息和发送对象
 function button(){
 message = document.getElementById('in').value;
 towho = document.getElementById('towho').value + "@";
 ws.send(towho+message);
 } 
 //发生错误时,处理错误
 ws.onerror = function (evt){ 
 writeToScreen('<span style="color:red;">ERROR:</span>'+evt.data);
 ws.close();
 };
 //把信息显示到当前屏幕
 function writeToScreen(message){
 var pre = document.createElement("p");
 pre.style.wordWrap = "break-word";
 pre.innerHTML = message;
 output.appendChild(pre);
 } 
 //当关闭页面时执行ws.close
 window.onbeforeunload=function (){ 
 ws.close();
 }; 
 </script>
 </head>
 <body>
 <h1>简易聊天室</h1>
<div style="width:400px;height:260px; overflow:scroll; border:3px solid; " id="output"> </div> <br> 
 <div style="text-align:left;">
 <form action="">
 <input id="in" name="message" value="" type="text" style="width:400px;height:60px; border:3px solid; " >
 <br><br>
 <input onclick="button()" value="发送" type="button"/>
 发送对象:
 <input id="towho" name="towho" value="all">
 <br>
 </form>
 </div>
 </body>
</html>
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

部署程序,Tomcat从7.0.27开始支持WebSocket,从7.0.47开始支持JSR-356,上述代码也是需要部署在Tomcat7.0.47上,JDK1.7以上才能运行。当浏览器或者Tomcat或者jdk不支持的时候会报undefined的错误


相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码