Netty With WebSocket
В прошлой статье мы говорили о том, как использоватьNettyразработатьHttpфайловый сервер, который содержит информацию о том, как использоватьNettyПредоставленный класс компонента для анализаHttpПосле протокола обрабатывается запрос, а затем кодек и передача продолжаются через существующие компоненты.
В этой статье в основном рассказывается о том, как использоватьNettyИнтегрироватьWebSocketсделай одинDEMOстатья. Фактически, какHttpТакой же,NettyВерноWebSocketИнкапсуляция предоставляет несколько удобных и простых в использовании компонентов, которые вы можете использовать, пока пишете код. В этот момент я еще раз испыталNettyвысокой масштабируемости.
Затем в этой статье будет описано содержание
- что
WebSocket. -
WebSocketа такжеHttpразница. - зачем нам нужно
WebSocket. -
Nettyа такжеWebSocketинтеграция между.
чтоWebSocket
Так большинство людей описывает это
WebSocketдаHTML5Обеспечивает связь между браузером и серверомполнодуплексная связьсетевые технологии.
Это кажется довольно непонятным.HTML5мы понимаем, но全双工通信Мы не понимаем. Итак, давайте проанализируем, что это такоеWebSocket.
Из того, что мы узнали раньше, мы знаемSocketЭто функциональный интерфейс между транспортным уровнем и приложением, через который мы можем использоватьTCP/IPСтек протоколов отправляет и получает данные на транспортном уровне. ТакWebSocketКакая связь с этим? отWebSocketБуквально, мы можем разделить называетсяWebа такжеSocket. может ты сможешьGETда, не так ли?WebSocketкак будто бежитWebвыше, ответственныйHttpВверхSocketСпецификация связи?
Конечно!WebSocketтак сказать на основеHttpпротоколSocketспецификации связи, обеспечивающие последующуюTCP SocketАналогичная функция, это может быть какTCP SocketОн также вызывает стек протоколов нижнего уровня для произвольной отправки и получения данных. Но не думайWebSocketдаHttpОбновленная версия (по причинам, которые будут описаны ниже). Фактически,WebSocketосновывается наTCPОблегченный сетевой протокол связи, статус иHttpравно.
зачем нам нужноWebSocket ?
Прежде всего, мы должны понимать, что появление новых вещей в той же области, скорее всего, не ниспровергнет прежнее, а продолжит совершенствоваться на плечах гигантов. а такжеWebSocketоказывается, на самом деле, чтобы компенсироватьHttpДефекты.
согласно сWebSocketвведение, мы знаем, что этополнодуплексная связьсетевые технологии. а такжеHttpэтополудуплексТехнология.HttpУ этой технологии есть две особенности.
- Между клиентом и сервером одновременно допускается только односторонний поток данных
- Сервер не может активно отправлять данные клиенту и может использовать толькоответ на запросспособ «пассивно» отвечать на запросы клиентов.
полудуплексКакие проблемы это принесет нам? Если вы сделали информацию в режиме реального времени, это может быть более сложным для вас. Вообще говоря, общение в реальном времени требует взаимодействия между двумя сторонами, то есть вы можете отправить его ему, а он может отправить вам. Но очевидно,полудуплексОн может быть отправлен только от клиента к серверу, и сервер не может отправить его клиенту. Может быть, вы скажете, разве мой клиент не может время от времени обращаться к серверу?
В режиме реального времени, не болееWebSocketВ случае , метод «опроса» обычно используется для достижения равномерного обмена данными, то есть для непрерывного запроса к серверу. Если частота опроса относительно высока, то ее можно аппроксимироватьобщение в реальном времениЭффект
Однако недостаток опроса также очевиден.CPUресурсов, очень неэкономично.
так,WebSocketэтополнодуплексная связь.
WebSocketспециальность
Может быть, есть еще много людей, которые сомневаются: очевидно, я вижуWebSocketосновывается наHttpвзаимодействовать, его формат протокола не совпадает сHttpЕсть ли сходство? Не совсем. мы знаемHttpПо сути, это лидер нынешних протоколов интернет-коммуникаций, и нет никого. ноWebSocketне использовал многоHttpчто-то, наоборот, имеет следующие характеристики
- первый
WebSocketиспользует структуру бинарного фрейма, сHttpструктура совсем другая. Однако, чтобы облегчить продвижение и применение, мы должны взять на себя «бесплатную поездку» и изо всех сил стараться использовать привычки, насколько это возможно.HttpПодойди поближе, вот как это называетсяWebимея в виду. (Я объясню, почему автостоп ниже) - Второй,
WebSocketНе похожSocketиспользовать такIP+端口метод, но продолжениеHttpизURIФормат. ноURLне начинается сHttp, ноwsа такжеwss, которые являются открытым текстом и зашифрованы соответственноWebSocketпротокол. - Более того,
WebSocketПорт по умолчанию по-прежнему используется80а также443. Поскольку текущий серверный брандмауэр в Интернете блокирует большинство портов, толькоHttpиз80а также443отпусти, такWebSocketмогукамуфляжсталиHttpсоглашениепроникатьБрандмауэр, установить соединение с сервером.
Процесс взаимодействия WebSocket
говорящийWebSocketКогда дело доходит до характеристик , возможно, вы знаете немного о внутренней истории:WebSocketна самом деле иHttpЭто не имеет большого значения, простоWebSocketЗависит отHttp«Слава» взлетела!
Не торопитесь, давайте посмотримWebSocketпоследовательность взаимодействия. Вот интерактивная диаграмма общей картины:
мы видим,WebSocketЕсть и похожиеTCPпроцесс рукопожатия. сначала он испускаетHttpизGetЗапрос, ниже приведены подробности сообщения
GET /HTTP/1.1
Upgrader: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Set-WebSocket-Key: sNNdMgdc2VGJEKS
Set-WebSocket-Version: 13
В сообщении стоит обратить внимание на несколько полей
| имя поля | использовать |
|---|---|
Upgrade |
Установить какWebSocket, указывая на то, что вам нужно объяснить серверуHttpобновитесь доWebSocketпротокол |
Sec-WebSocket-key |
Base64Закодированное 16-байтовое случайное число, используемое для проверки правильностиWebSocketвместоHttpпротокол |
Sec-WebSocket-Version |
указать использованиеWebSocketНомер версии протокола |
Затем, когда сервер получает сообщение от клиента, он начинает анализировать сообщение. В это время он знает из сообщения, что этоWebSocketзапрос. Итак, начните создавать специальную информацию о сообщении, содержание сообщения
HTTP/1.1 101 Switching Protocols
Upgrader: websocket
Connection: Upgrade
Set-WebSocket-Accept: fFBooB7FAkKLlXgrSz0BT3v4hq5s
Set-WebSocket-Location: ws://examples.com/
Поля сообщения все еще знакомы. но мы нашли101 Switching ProtocolsОписание, которое возвращает сервер101Код состояния, сообщающий клиенту, что он может продолжитьWebSocketПолнодуплексная двусторонняя связь. Это эквивалентно тому, что клиент и сервер согласились использоватьWebSocketПриходите пообщаться, его больше нетHttpчто случилось.
Затем выше возвращаетсяSet-WebSocket-AcceptОн используется для проверки сообщения запроса клиента, а также для предотвращения неправильного подключения. В частности, у клиентаSet-WebSocket-Keyпровести специальнуюUUID, а затем вычислитьSHA-1Резюме. Таким образом, клиент также будет использовать это вычисление для сравнения информации ответа сервера, чтобы избежать ошибки аутентификации.
После завершения рукопожатия последующая передача данных прекращается.Httpсообщение, ноWebSocketтакже отформатируйте двоичный фрейм.
NettyИнтегрироватьWebSocket
Прежде всего, мы используемNettyЧтобы реализовать класс запуска на стороне сервера
WebSocketServer.java
public class WebSocketServer {
public void run(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
// http 的解码器
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("http-codec",
new HttpServerCodec());
// 负责将 Http 的一些信息例如版本
// 和 Http 的内容继承一个 FullHttpRequesst
pipeline.addLast("aggregator",
new HttpObjectAggregator(65536));
// 大文件写入的类
ch.pipeline().addLast("http-chunked",
new ChunkedWriteHandler());
// websocket 处理类
pipeline.addLast("handler",
new WebSocketServerHandler());
}
});
// 监听端口
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new WebSocketServer().run(8080);
}
}
Далее мы являемся процессором, реализующим логику обработкиWebSocketServerHandler.java
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger logger = Logger
.getLogger(WebSocketServerHandler.class.getName());
private WebSocketServerHandshaker handshaker;
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg)
throws Exception {
// 传统的HTTP接入(握手流程是走这里的)
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
}
// WebSocket接入
else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
private void handleHttpRequest(ChannelHandlerContext ctx,
FullHttpRequest req) throws Exception {
// 如果HTTP解码失败,返回HHTP异常
if (!req.getDecoderResult().isSuccess()
|| (!"websocket".equals(req.headers().get("Upgrade")))) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
BAD_REQUEST));
return;
}
// 构造握手响应返回,目前是本机的地址
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
"ws://localhost:8080/websocket", null, false);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory
.sendUnsupportedWebSocketVersionResponse(ctx.channel());
} else {
handshaker.handshake(ctx.channel(), req);
}
}
private void handleWebSocketFrame(ChannelHandlerContext ctx,
WebSocketFrame frame) {
// 判断是否是关闭链路的指令
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(),
(CloseWebSocketFrame) frame.retain());
return;
}
// 判断是否是Ping消息
if (frame instanceof PingWebSocketFrame) {
ctx.channel().write(
new PongWebSocketFrame(frame.content().retain()));
return;
}
// 本例程仅支持文本消息,不支持二进制消息
if (!(frame instanceof TextWebSocketFrame)) {
throw new UnsupportedOperationException(String.format(
"%s frame types not supported", frame.getClass().getName()));
}
// 返回应答消息
String request = ((TextWebSocketFrame) frame).text();
if (logger.isLoggable(Level.FINE)) {
logger.fine(String.format("%s received %s", ctx.channel(), request));
}
ctx.channel().write(
new TextWebSocketFrame(request
+ " , 欢迎使用Netty WebSocket服务,现在时刻:"
+ new java.util.Date().toString()));
}
private static void sendHttpResponse(ChannelHandlerContext ctx,
FullHttpRequest req, FullHttpResponse res) {
// 返回应答给客户端
if (res.getStatus().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
setContentLength(res, res.content().readableBytes());
}
// 如果是非Keep-Alive,关闭连接
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (!isKeepAlive(req) || res.getStatus().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
На самом деле приведенный выше код относительно ясен. В основном делится на два процесса:
| метод | иллюстрировать |
|---|---|
handleHttpRequest() |
Ответственный за ответ на запрос рукопожатия клиента |
handleWebSocketFrame() |
ответственный за обработкуWebSocketНовости |
во время обработкиhandleWebSocketFrame()В основном отвечает за несколько операций:
- Это команда закрыть ссылку
- Является ли это сообщением сердцебиения
- Является ли это содержанием сообщения
Эпилог
Эта статья предназначалась дляNettyа такжеWebSocketинтегрированных. Но я узнал, чтоWebSocketРост и причины его популярности гораздо менее просты, чем предполагалось. Вот и решил копнуть глубже. Обобщить содержание статьи
-
WebSocketэквивалентноHttpПатч длительного подключения для протокола. это иHttpСуществующие общие черты (использование рукопожатия соединенияGetЗапрос), первый - это решитьHttpНе поддерживает отсутствие длинных подключений, решитьHttpХарактеристики коротких ссылок, не отвечающих спросу. - Во внутренней структуре,
WebSocketа такжеHttpЕсть много различий. Чтобы повысить эффективность,WebSocketИспользуя двоичные кадры, их легче понять и передать. - использовать
NettyПроцессор может быть реализован быстро упакованнымWebSocketПриложения
конец!