通讯协议
后端实时推送
HTML5给Web浏览器带来了全双工TCP连接websocket标准服务器的能力。
1.websocket
1.1.WebSocket服务器端
@ServerEndpoint("/websocket")
public class WebSocketTest {
@OnMessage
public void onMessage(String message, Session session)
throws IOException, InterruptedException {
// Print the client message for testing purposes
System.out.println("Received: " + message);
// Send the first message to the client
session.getBasicRemote().sendText("This is the first server message");
// Send 3 messages to the client every 5 seconds
int sentMessages = 0;
while(sentMessages < 3){
Thread.sleep(5000);
session.getBasicRemote().
sendText("This is an intermediate server message. Count: "
+ sentMessages);
sentMessages++;
}
// Send a final message to the client
session.getBasicRemote().sendText("This is the last server message");
}
@OnOpen
public void onOpen() {
System.out.println("Client connected");
}
@OnClose
public void onClose() {
System.out.println("Connection closed");
}
}
- @ServerEndpoint注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址。
- onOpen 和 onClose 方法分别被@OnOpen和@OnClose所注解。这两个注解的作用不言自明:他们定义了当一个新用户连接和断开的时候所调用的方法。
- onMessage方法被@OnMessage所注解。这个注解定义了当服务器接收到客户端发送的消息时所调用的方法。
注意:这个方法可能包含一个javax.websocket.Session可选参数(在我们的例子里就是session参数)。 如果有这个参数,容器将会把当前发送消息客户端的连接Session注入进去。 本例中我们仅仅是将客户端消息内容打印出来,然后首先我们将发送一条开始消息,之后间隔5秒向客户端发送1条测试消息,共发送3次, 最后向客户端发送最后一条结束消息。
1.2.客户端
客户端API
- 客户端与服务器通信
- send() 向远程服务器发送数据
- close() 关闭该websocket链接
- 监听函数
- onopen 当网络连接建立时触发该事件
- onerror 当网络发生错误时触发该事件
- onclose 当websocket被关闭时触发该事件
- onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。msg.data
- readyState属性.这个属性可以返回websocket所处的状态。
- CONNECTING(0) websocket正尝试与服务器建立连接
- OPEN(1) websocket与服务器已经建立连接
- CLOSING(2) websocket正在关闭与服务器的连接
- CLOSED(3) websocket已经关闭了与服务器的连接
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/20160910_websocket/ws.do/${userSession.id }/${userSession.name }/${loginIp }");
} else {
alert('当前浏览器 Not support websocket')
}
//1.连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};
//2.连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}
//3.接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//4.连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}
//5.监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
//6.将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//7.关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//8.发送消息
function send() {
var friendId = document.getElementById('friend').value;
var message = document.getElementById('text').value;
websocket.send(friendId + ":" + message);
}
1.3.WebSockets 握手(升级过程)
客户端和服务器端TCP连接建立在HTTP协议握手发生之后。通过HTTP流量调试,很容易观察到握手。客户端一创建一个 WebSocket实例,就会出现如下请求和服务器端响应:
注意: 我们只录入了WebSocket握手所用到的HTTP头。
请求:
GET /byteslounge/websocket HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: wVlUJ/tu9g6EBZEh51iDvQ==
响应:
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Sec-WebSocket-Accept: 2TNh+0h5gTX019lci6mnvS66PSY=
注意:进行连接需要将通过Upgrade and Upgrade将协议升级到支持websocket HTTP头的Websocket协议。 服务器响应表明请求被接受,协议将转换到WebSocket协议(HTTP状态码101):HTTP/1.1 101 Web Socket Protocol Handshake
1.4.Spring集成
后端引入websocket支持
<!-- webSocket 秒杀通知-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
前端引入webSocket.js
2.SSE
SSE(Server-Sent Events)是一种基于HTTP协议的服务器到客户端的推送技术,主要用于在服务器和客户端之间建立持久连接, 以便服务器可以主动发送事件到客户端,而不需要客户端不断地轮询服务器。这对于实现实时更新、通知等功能非常有用。
与websocket相比,SSE 更简单易用,且为服务端向客户端的单向传输,
SSE 的基本概念
- 事件流:SSE 使用文本流(text/event-stream MIME类型)来传输数据。
- 事件:数据流被分割成一系列的事件,每个事件都有一个或多个行。
- 事件字段:每个事件由多个行组成,每行以特定的格式表示一个字段。例如:
event: message
data: Hello world!
data: Another message
id: 12345
retry: 10000
代码案例(模拟前后端交互,后端使用webflux)
async function sendMessage() {
// 前端发送信息
const messageInput = document.getElementById('messageInput');
const message = messageInput.value.trim();
if (!message) {
return;
}
appendMessage(message, true);
messageInput.value = '';
try {
// 创建 EventSource 实例,连接到后端的 SSE 接口
const eventSource = new EventSource(
'/stream/chatStream?msg=' + encodeURIComponent(message)
+ '&modelType=' + getSelectedModel());
// 监听 message 事件,当接收到服务器发送的消息时触发
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
appendMessage(data.content, false);
};
// 监听 error 事件,当连接出现错误时触发
eventSource.onerror = (error) => {
if (error.eventPhase === EventSource.CLOSED) {
console.log('Connection was closed');
} else {
console.error('EventSource failed:', error);
}
// 关闭连接
eventSource.close();
};
} catch (error) {
console.error('Error:', error);
appendMessage('发生错误,请稍后重试。', false);
}
}
@GetMapping(value = "/chatStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Map<String, Object>> chatStream(
@RequestParam(value = "msg", defaultValue = "") String msg,
@RequestParam(value = "modelType", defaultValue = ModelType.DEFAULT) String modelType
) {
return chatService.chatStream(msg, modelType).map(this::createResponse);
}
3.WebRTC
WebRTC(Web Real-Time Communication,网页实时通信)是一项浏览器原生支持的实时通信技术标准,允许浏览器之间直接建立点对点(P2P)连接, 实现音视频通话、数据传输等实时交互,无需依赖第三方插件或额外软件。
WebRTC 的核心目标是打破传统实时通信对中间服务器的强依赖,让浏览器之间能够直接传输数据(音视频、文本、文件等),其关键特性包括:
- 点对点通信:数据主要在客户端之间直接传输(仅信号协商需服务器参与),减少延迟和服务器带宽压力;
- 原生浏览器支持:无需安装插件,通过 JavaScript API 即可调用(如getUserMedia捕获音视频、RTCPeerConnection建立连接);
- 实时性强:基于 UDP 协议传输(部分场景降级为 TCP),延迟可低至 100-200 毫秒,满足实时交互需求;
- 安全性内置:所有数据强制加密传输(通过 SRTP 协议),防止窃听和篡改。
3.1.原理
WebRTC 的工作流程可分为信号协商、P2P 连接建立和媒体流传输三个核心阶段, 其中 "信号协商" 需借助服务器,而实际数据传输则在客户端之间直接进行。
第一:信号协商(Signaling):发现与连接准备。浏览器(客户端)无法直接知道对方的网络位置(IP 地址、端口), 需通过 "信号服务器" 交换连接所需的元数据(如网络信息、媒体能力):
- 交换的核心信息:
- SDP(Session Description Protocol):描述本地媒体能力(如支持的音视频编码格式、分辨率、采样率等),分为 "offer"(发起方提议)和 "answer"(接收方应答);
- ICE 候选地址(ICE Candidate):包含本地网络可被访问的 IP 地址和端口(需穿透 NAT 网络地址转换)。
流程示例:
- 客户端 A 生成 SDP offer 并通过信号服务器发送给客户端 B;
- 客户端 B 收到 offer 后,生成 SDP answer 并通过信号服务器返回给 A;
- 双方分别收集自身的 ICE 候选地址(如本地局域网地址、NAT 转换后的公网地址),并通过信号服务器互相发送;
- 双方根据收到的 SDP 和 ICE 信息,确定最优通信路径。
第二:P2P 连接建立:穿透 NAT 与防火墙。由于多数设备处于 NAT(网络地址转换)或防火墙后,直接建立 P2P 连接需解决 "地址可达性"问题, WebRTC 通过ICE(Interactive Connectivity Establishment)协议实现:
ICE 工作原理:
- 首先尝试 "主机候选地址"(本地局域网 IP),若双方在同一局域网,直接建立连接;
- 若失败,尝试 "服务器反射候选地址"(通过 STUN 服务器获取 NAT 转换后的公网地址);
- 若仍失败(如严格对称 NAT 环境),则通过 TURN 服务器中转数据(作为最后的 fallback 方案)。
关键服务器:
- STUN 服务器:帮助设备获取自身的公网 IP 和端口(用于 NAT 穿透);
- TURN 服务器:在 P2P 连接失败时,作为中继服务器转发数据(确保通信不中断,但增加延迟)。
第三:媒体流传输:实时音视频与数据交互。连接建立后,WebRTC 通过两套核心 API 实现数据传输:
媒体流传输(RTCPeerConnection):
- 客户端通过getUserMediaAPI 捕获摄像头、麦克风数据,生成MediaStream(媒体流);
- 通过RTCPeerConnection将媒体流编码(如 H.264、VP8 视频编码,OPUS 音频编码)后,通过 RTP(实时传输协议)发送给对方;
- 接收方解码后,通过
数据通道(RTCDataChannel):
- 除音视频外,WebRTC 支持通过RTCDataChannel传输任意二进制或文本数据(如聊天消息、文件、游戏控制指令);
- 数据通道支持可靠传输(类似 TCP,保证数据有序、不丢失)和非可靠传输(类似 UDP,低延迟但可能丢包),可按需配置。
3.2.应用场景
WebRTC 适用于需要低延迟、点对点实时交互的场景,尤其在音视频通信领域应用广泛:
- 实时音视频通话:如网页版视频会议(腾讯会议网页版)、在线问诊(医生与患者视频沟通)、远程面试系统等,WebRTC 可提供 100-200ms 低延迟的音视频传输。
- 屏幕共享与远程协助:如在线教育中的老师屏幕共享、远程办公中的技术支持(协助操作对方电脑),通过getDisplayMediaAPI 捕获屏幕流并实时传输。
- 实时互动直播:如直播平台的连麦功能(主播与观众实时互动)、在线课堂的师生互动,WebRTC 可支持多人间的低延迟音视频交互。
- 浏览器端 P2P 文件传输:如基于网页的文件共享工具,用户可直接向其他在线用户发送文件,无需通过服务器中转(速度取决于双方带宽)。
- 实时游戏:如多人文本冒险游戏、简单实时对战游戏,通过RTCDataChannel传输玩家操作指令,实现低延迟同步。
- 物联网设备实时监控:如通过网页实时查看家用摄像头画面、工业设备监控视频,WebRTC 可直接接收设备推送的音视频流。
4.其他
主要为框架,并非协议。
4.1.goeasy
国产实现方案,需要收费。
GoEasy实时Web推送,支持后台推送和前台推送两种:后台推送可以选择Java SDK、 Restful API支持所有开发语言;前台推送:JS推送。
无论选择哪种方式推送代码都十分简单(10分钟可搞定)。
由于它支持websocket和polling两种连接方式所以兼顾大多数主流浏览器,低版本的IE浏览器也是支持的。
4.2.Pushlets
Pushlets是通过长连接方式实现"推"消息的。推送模式分为:Poll(轮询)、Pull(拉)。 地址:http://www.pushlets.com/
4.3.Pushlet
Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。
地址:https://github.com/wjw465150/Pushlet
总结: 其实前面有提过,尽管WebSocket有诸多优点,但是,如果服务端维护很多长连接也是挺耗费资源的,服务器集群以及览器或者客户端兼容性问题, 也会带来了一些不确定性因素。大体了解了一下各大厂的做法,大多数都还是基于轮询的方式实现的,比如:腾讯PC端微信扫码登录、京东商城支付成功通知等等。 有些小伙伴可能会问了,轮询岂不是会更耗费资源?其实在我看来,有些轮询是不可能穿透到后端数据库查询服务的,比如秒杀,一个缓存标记位就可以判定是否秒杀成功。 相对于WS的长连接以及其不确定因素,在秒杀场景下,轮询还是相对比较合适的。
Jersey
1.什么是Jersey
RESTful Web服务是基于REST架构的Web服务。在REST架构一切都是一种资源。 RESTful Web服务是轻量级的,高度可扩展性和可维护性,并且非常常用于创建基于API的Web应用程序。 Jersey是JAX-RS(JSR311)开源参考实现用于构建RESTful Web service,它包含三个部分:
- 核心服务器(Core Server)通过提供JSR311中标准化的注释和API标准化,可以用直观的方式开发RESTful Web服务;
- 核心客户端(Core Client)Jersey客户端API能够帮助开发者与RESTful服务轻松通信;
- 集成(Integration)Jersey还提供可以轻松继承Spring、Guice、Apache Abdera的库。
2.常用注解
2.1.@Produces
就是发送到客户端的数据标识类型(MIME)。
- 返回xml:@Produces(MediaType.APPLICATION_XML)
- 返回json:@Produces(MediaType.APPLICATION_JSON)
- 返回自定义返回类型及编码:@Produces("application/json;charset=utf-8")
- 返回多个类型:@Produces({"application/json","application/xml"})
2.2.@Consumes
就是接受只客户端的的数据标识类型(MIME)。多用于post和put请求。用法和@Produces响应
2.3.@PathParam
可以获取URI中指定规则的参数。
2.4.@QueryParam
用于获取GET请求中的查询参数。
2.5.@DefaultValue
为参数设置默认值
2.6.@FormParam
从POST请求的表单参数中获取数据
@Path("/user/{id}")
@GET
@Produces(MediaType.APPLICATION_XML)
public User getUserById(@PathParam("id") Integer id, @DefaultValue("张三") @QueryParam("name") String name){
return this.userDao.getById(id);
}
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
}
@POST
@Consumes("application/x-www-form-urlencoded")
public void post2(@BeanParam User user) {
}
@GET
public String get(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams =
ui.getQueryParameters(); MultivaluedMap<String, String>
pathParams = ui.getPathParameters();
}
2.6.@BeanParam
将请求中的参数,保存为对象中。
2.7.@Context
因为参数的多变,参数结构的调整都会因为以上几种方式而遇到问题,这时可以考虑使用@Context 注释,并获取UriInfo实例 同样还可以通过@Context注释获取ServletConfig、ServletContext、HttpServletRequest、HttpServletResponse和HttpHeaders等
2.8.@XmlRootElement
数据为XML是,用于和Javabean绑定,
@XmlRootElement
public class User{
private String name;
@XmlElement(name = "user_name")//这个必须写在set方法上。
public void setName(String name) {
this.name = name;
}
}
DWR
- 官网:http://directwebremoting.org/dwr/index.html
- 介绍:https://www.oschina.net/p/dwr?hmsr=aladdin1e1
- 实时推送:https://blog.csdn.net/pangliang_csdn/article/details/68945872
DWR 是一个可以允许你去创建 AJAX WEB 站点的 JAVA 开源库。它可以让你在浏览器中的 Javascript 代 码调用 Web 服务器上的 Java 代码,就像在 Java 代码就在浏览器中一样。
DWR 包含 2 个主要部分:
- 一个运行在服务器端的 Java Servlet,它处理请求并且向浏览器发回响应。
- 运行在浏览器端的 JavaScript,它发送请求而且还能动态更新网页。
DWR 工作原理是通过动态把 Java 类生成为 Javascript。它的代码就像 Ajax 魔法一样,你感觉调用就像发 生在浏览器端, 但是实际上代码调用发生在服务器端,DWR 负责数据的传递和转换。这种从 Java 到 JavaScript的远程调用功能的方式使DWR用起来有种非常像RMI或者SOAP的常规RPC机制, 而且DWR 的优点在于不需要任何的网页浏览器插件就能运行在网页上。
1.邮件开发相关的概念
1.1.邮件服务器
要在Internet上提供电子邮件功能,必须有专门的电子邮件服务器(软)。例如现在Internet很多提供邮件服务的厂商: sina、sohu、163等等他们都有自己的邮件服务器。这些服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件, 并把邮件投递到邮件接收者的电子邮箱中。
1.2.电子邮箱
电子邮箱(Email地址)的获得需要在邮件服务器上进行申请,确切地说,电子邮箱其实就是用户在邮件服务器上申请的一个账户。 用户在邮件服务器上申请了一个账号后,邮件服务器就会为这个账号分配一定的空间,用户从而可以使用这个账号以及空间, 发送电子邮件和保存别人发送过来的电子邮件。
1.3.邮件开发用到的协议:SMTP、POP、RFC822、MIME
(1).SMTP:Simle Message Transfer Protocal简单消息传输协议。发送邮件时使用的协议。 描述了数据该如何表示。默认使用的端口:25
(1).POP3:Post Office Protocal邮局协议。接收邮件时使用的协议。默认使用的端口:110
2.手工发送邮件和接收邮件
itheimacloud@163.com iamsorry
itheima14@163.com iamsorry
SMTP:smtp.163.com POP3:pop.163.com
Base64编码:
用户名:itheimacloud aXRoZWltYWNsb3Vk
密码:iamsorry aWFtc29ycnk=
2.1.手工发送邮件的过程:telnet(执行命令行)
telnet smtp.163.com 25
------------------------------------------------------------以下属于SMTP协议的内容
ehlo wzt //向服务器打招呼
auth login //请求认证
//提示输入用户名和密码(Base64编码后的)
aXRoZWltYWNsb3Vk
aWFtc29ycnk=
mail from:<itheimacloud@163.com>
rcpt to:<itheima14@163.com>
data //说明邮件的开始
//邮件内容是要遵循一定格式的:RFC822规范
from:itheimacloud@163.com //fengjie@163.com
to:itheima14@163.com
subject:这是一封手工发送的邮件
aaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbb
.
------------------------------------------------------------
quit
2.2.手工收取邮件(POP协议)(执行命令行)
telnet pop.163.com 110
----------------------------------以下属于POP协议的东东
user itheima14
pass iamsorry
stat //返回邮箱的统计信息
list 邮件编号 //返回某一封的邮件统计信息
retr 邮件编号 //取出某一封邮件的内容
----------------------------------
quit
3.相关框架
- Java mail: Oracle提供的,对api进行了简单的封装
- Apache Commons email
- Spring email
4.发生失败原因
因为各种原因,总会有邮件发送失败的情况,比如:邮件发送过于频繁、网络异常等。 在出现这种情况的时候,我们一般会考虑重新重试发送邮件,会分为以下几个步骤来实现:
- 接收到发送邮件请求,首先记录请求并且入库。
- 调用邮件发送接口发送邮件,并且将发送结果记录入库。
- 启动定时系统扫描时间段内,未发送成功并且重试次数小于3次的邮件,进行再次发送
5.异步发送
很多时候邮件发送并不是我们主业务必须关注的结果,比如通知类、提醒类的业务可以允许延时或者失败。 这个时候可以采用异步的方式来发送邮件,加快主交易执行速度, 在实际项目中可以采用MQ发送邮件相关参数,监听到消息队列之后启动发送邮件。
webService
webservice,就是应用程序之间跨语言的调用,不同的语言平台对WebService都有实现,Java的WebService实现,比较流行的有Axis2、Jaxws,本文介绍的是Axis2
一、重要的组成
- xml
- wsdl:web service description language—-web服务描述语言。 也是一种xml文件,声明了调用的服务的name,URL,method以及如何调用。
- soap:simple object access protoacl—–简单对象访问协议。限定了xml的格式,是在http的基础上传输xml数据。因为有请求体,所以必须是post请求。
- operation name:服务提供的方法
- targetNamespace: 默认为倒置的包名,例如服务类在com.zx.service中,那就是service.zx.com
- JAX-WS:java api for xml - WebService
二、需要注意
- 发布的外部服务不能包含静态方法,静态变量等,这些成员是在初始化的时候,存在到内容中的,是无法被序列化, 进而数据传输的。
- 使用自动生成的webservice服务端,需要/WEB-INF/conf/axis2.xml,配置其内两个属性,以便调试
<parameter name="hotdeployment">true</parameter><!-- 开启热部署,不需要重启即可部署服务 -->
<parameter name="hotupdate">true</parameter><!-- 开启热更新,不需要重启即可更新服务 -->
- 本文作者:zhangxue
- 本文链接:https://lucksnow1989.github.io/article/9.开源/通讯协议.html
- 版权声明:本文为本人原创文章,遵循 CC 4.0 BY-NC-SA版权协议,转载请附上原文出处链接和本声明。