【Mongoose笔记】Websocket 服务器

news2024/9/23 7:22:02

【Mongoose笔记】Websocket 服务器

简介

Mongoose 笔记系列用于记录学习 Mongoose 的一些内容。

Mongoose 是一个 C/C++ 的网络库。它为 TCP、UDP、HTTP、WebSocket、MQTT 实现了事件驱动的、非阻塞的 API。

项目地址:

https://github.com/cesanta/mongoose

学习

下面通过学习 Mongoose 项目代码中的 websocket-server 示例程序 ,来学习如何使用 Mongoose 实现一个简单的 Websocket 服务器。使用树莓派平台进行开发验证。

websocket-server 的示例程序很短,代码如下:

// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
//
// Example Websocket server. See https://mongoose.ws/tutorials/websocket-server/

#include "mongoose.h"

static const char *s_listen_on = "ws://localhost:8000";
static const char *s_web_root = ".";

// This RESTful server implements the following endpoints:
//   /websocket - upgrade to Websocket, and implement websocket echo server
//   /rest - respond with JSON string {"result": 123}
//   any other URI serves static files from s_web_root
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_OPEN) {
    // c->is_hexdumping = 1;
  } else if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    if (mg_http_match_uri(hm, "/websocket")) {
      // Upgrade to websocket. From now on, a connection is a full-duplex
      // Websocket connection, which will receive MG_EV_WS_MSG events.
      mg_ws_upgrade(c, hm, NULL);
    } else if (mg_http_match_uri(hm, "/rest")) {
      // Serve REST response
      mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123);
    } else {
      // Serve static files
      struct mg_http_serve_opts opts = {.root_dir = s_web_root};
      mg_http_serve_dir(c, ev_data, &opts);
    }
  } else if (ev == MG_EV_WS_MSG) {
    // Got websocket frame. Received data is wm->data. Echo it back!
    struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
    mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
  }
  (void) fn_data;
}

int main(void) {
  struct mg_mgr mgr;  // Event manager
  mg_mgr_init(&mgr);  // Initialise event manager
  printf("Starting WS listener on %s/websocket\n", s_listen_on);
  mg_http_listen(&mgr, s_listen_on, fn, NULL);  // Create HTTP listener
  for (;;) mg_mgr_poll(&mgr, 1000);             // Infinite event loop
  mg_mgr_free(&mgr);
  return 0;
}

下面我们从main函数开始分析代码。

首先是变量定义,其中struct mg_mgr是用于保存所有活动连接的事件管理器。

  struct mg_mgr mgr;  // Event manager

初始化一个事件管理器,将上面的 struct mg_mgr变量 mgr 中的数据进行初始化。

  mg_mgr_init(&mgr);  // Initialise event manager

打印日志,将监听地址s_listen_on打印出来。

  printf("Starting WS listener on %s/websocket\n", s_listen_on);

s_listen_on是一个静态全局变量,默认值为ws://localhost:8000,监听本地主机,端口号 8000。

static const char *s_listen_on = "ws://localhost:8000";

通过 mg_http_listen 创建一个 HTTP 监听连接,监听地址s_listen_on,其中fn是事件处理函数。

  mg_http_listen(&mgr, s_listen_on, fn, NULL);  // Create HTTP listener

接下来是事件循环,mg_mgr_poll 遍历所有连接,接受新连接,发送和接收数据,关闭连接,并为各个事件调用事件处理函数。

  for (;;) mg_mgr_poll(&mgr, 1000);             // Infinite event loop

mg_mgr_free 用于关闭所有连接,释放所有资源。

  mg_mgr_free(&mgr);

分析完main函数后,我们看下事件处理函数fn的代码。

首先是判断是否接收到 MG_EV_OPEN 事件,收到MG_EV_OPEN 事件表示已创建连接。该事件在分配连接并将其添加到事件管理器之后立即发送。

  if (ev == MG_EV_OPEN) {
    // c->is_hexdumping = 1;
  }

接下来判断是否接收到的MG_EV_HTTP_MSG事件,如果是则开始 HTTP 请求的处理。

  } else if (ev == MG_EV_HTTP_MSG) {

将函数参数ev_data转换为 struct mg_http_message,其中包含已解析的 HTTP 请求。

    struct mg_http_message *hm = (struct mg_http_message *) ev_data;

使用mg_http_match_uri函数检查 HTTP 请求中 URI 是否等于/websocket,如果是的话则调用mg_ws_upgrade函数将 HTTP 连接转换为 Websocket 连接,连接变为全双工,后续收到消息时将触发的是 MG_EV_WS_MSG 事件。

    if (mg_http_match_uri(hm, "/websocket")) {
      // Upgrade to websocket. From now on, a connection is a full-duplex
      // Websocket connection, which will receive MG_EV_WS_MSG events.
      mg_ws_upgrade(c, hm, NULL);
    }

继续使用mg_http_match_uri函数,检查 HTTP 请求中 URI 是否等于/rest,如果是的话回复响应 JSON 字符串 {"result": 123}。其中mg_http_reply函数用于发送简单的 HTTP 响应,200表示返回的 HTTP 状态码,""表示额外的头信息,这里没有所以为空,"{\"result\": %d}\n", 123部分就是返回的 HTTP 报文主体。

    } else if (mg_http_match_uri(hm, "/rest")) {
      // Serve REST response
      mg_http_reply(c, 200, "", "{\"result\": %d}\n", 123);
    }

如果收到的是其他任何的 URI ,都是从s_web_root目录提供静态文件服务,s_web_root的默认值为当前目录。

    } else {
      // Serve static files
      struct mg_http_serve_opts opts = {.root_dir = s_web_root};
      mg_http_serve_dir(c, ev_data, &opts);
    }

接下来判断是否接收到的MG_EV_WS_MSG事件,表示接收到 Websocket 消息。

  } else if (ev == MG_EV_WS_MSG) {

将函数参数ev_data转换为 struct mg_ws_message,这个结构体表示 WebSocket 消息。

    struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;

将收到的消息wm->data.ptr,直接通过mg_ws_send函数原封不动的回复回去。

mg_ws_send函数用于 WebSocket 消息的发送,WEBSOCKET_OP_TEXT是 WebSocket 消息类型之一,表示要发送的有效载荷数据为文本数据。

    mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);

到这里 websocket-server 的示例程序代码就都解析完了,下面实际运行一下 websocket-server 程序。

打开示例程序,编译并运行:

pi@raspberrypi:~ $ cd Desktop/study/mongoose/examples/websocket-server/
pi@raspberrypi:~/Desktop/study/mongoose/examples/websocket-server $ make
cc ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1  -o example main.c
./example 
Starting WS listener on ws://localhost:8000/websocket

这个时候我们的服务器已经运行起来了。

接下来要测试下这个 WebSocket 服务器,我们可以使用 websocket-server 示例程序目录下的 test.html,这是一个 WebSocket 测试客户端。

在浏览器中,输入 URL http://localhost:8000/test.html:

ws1.png

然后点击 connect 按钮连接 WebSocket 服务器:

ws2.png

然后在文本输入框中输入你想发送的信息,例如输入一句Hello World!,然后点击send message按钮发送消息:

ws3.png

可以看到客户端收到了 WebSocket 服务器回复的Hello World!消息。

我们发现 WebSocket 服务器这边没有打印任何日志,如果需要查看更多的信息,例如收发的消息,可以将事件处理函数fn里的被屏蔽的代码c->is_hexdumping = 1;打开,开启Hexdump in/out traffic功能,会将接收和发送的数据以16进制的形式打印出来。

  if (ev == MG_EV_OPEN) {
    c->is_hexdumping = 1;
  }

然后重新编译运行,再将上面的连接发送等操作重新操作一遍。

pi@raspberrypi:~/Desktop/study/mongoose/examples/websocket-server $ make clean all
rm -rf example *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
cc ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1  -o example main.c
./example 
Starting WS listener on ws://localhost:8000/websocket
1bf531 2 sock.c:112:iolog               
-- 2 127.0.0.1:8000 <- 127.0.0.1:59652  519
0000   47 45 54 20 2f 74 65 73 74 2e 68 74 6d 6c 20 48   GET /test.html H
0010   54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 6c   TTP/1.1..Host: l
0020   6f 63 61 6c 68 6f 73 74 3a 38 30 30 30 0d 0a 43   ocalhost:8000..C
0030   6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 70 2d   onnection: keep-
0040   61 6c 69 76 65 0d 0a 55 70 67 72 61 64 65 2d 49   alive..Upgrade-I
0050   6e 73 65 63 75 72 65 2d 52 65 71 75 65 73 74 73   nsecure-Requests
0060   3a 20 31 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a   : 1..User-Agent:
0070   20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 58 31    Mozilla/5.0 (X1
0080   31 3b 20 4c 69 6e 75 78 20 61 72 6d 76 37 6c 29   1; Linux armv7l)
0090   20 41 70 70 6c 65 57 65 62 4b 69 74 2f 35 33 37    AppleWebKit/537
00a0   2e 33 36 20 28 4b 48 54 4d 4c 2c 20 6c 69 6b 65   .36 (KHTML, like
00b0   20 47 65 63 6b 6f 29 20 52 61 73 70 62 69 61 6e    Gecko) Raspbian
00c0   20 43 68 72 6f 6d 69 75 6d 2f 37 38 2e 30 2e 33    Chromium/78.0.3
00d0   39 30 34 2e 31 30 38 20 43 68 72 6f 6d 65 2f 37   904.108 Chrome/7
00e0   38 2e 30 2e 33 39 30 34 2e 31 30 38 20 53 61 66   8.0.3904.108 Saf
00f0   61 72 69 2f 35 33 37 2e 33 36 0d 0a 53 65 63 2d   ari/537.36..Sec-
0100   46 65 74 63 68 2d 55 73 65 72 3a 20 3f 31 0d 0a   Fetch-User: ?1..
0110   41 63 63 65 70 74 3a 20 74 65 78 74 2f 68 74 6d   Accept: text/htm
0120   6c 2c 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 68   l,application/xh
0130   74 6d 6c 2b 78 6d 6c 2c 61 70 70 6c 69 63 61 74   tml+xml,applicat
0140   69 6f 6e 2f 78 6d 6c 3b 71 3d 30 2e 39 2c 69 6d   ion/xml;q=0.9,im
0150   61 67 65 2f 77 65 62 70 2c 69 6d 61 67 65 2f 61   age/webp,image/a
0160   70 6e 67 2c 2a 2f 2a 3b 71 3d 30 2e 38 2c 61 70   png,*/*;q=0.8,ap
0170   70 6c 69 63 61 74 69 6f 6e 2f 73 69 67 6e 65 64   plication/signed
0180   2d 65 78 63 68 61 6e 67 65 3b 76 3d 62 33 0d 0a   -exchange;v=b3..
0190   53 65 63 2d 46 65 74 63 68 2d 53 69 74 65 3a 20   Sec-Fetch-Site: 
01a0   6e 6f 6e 65 0d 0a 53 65 63 2d 46 65 74 63 68 2d   none..Sec-Fetch-
01b0   4d 6f 64 65 3a 20 6e 61 76 69 67 61 74 65 0d 0a   Mode: navigate..
01c0   41 63 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 3a   Accept-Encoding:
01d0   20 67 7a 69 70 2c 20 64 65 66 6c 61 74 65 2c 20    gzip, deflate, 
01e0   62 72 0d 0a 41 63 63 65 70 74 2d 4c 61 6e 67 75   br..Accept-Langu
01f0   61 67 65 3a 20 7a 68 2d 43 4e 2c 7a 68 3b 71 3d   age: zh-CN,zh;q=
0200   30 2e 39 0d 0a 0d 0a                              0.9....         
1bf533 2 sock.c:112:iolog               
-- 2 127.0.0.1:8000 -> 127.0.0.1:59652  1687
0000   48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d   HTTP/1.1 200 OK.
0010   0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74   .Content-Type: t
0020   65 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65   ext/html; charse
0030   74 3d 75 74 66 2d 38 0d 0a 45 74 61 67 3a 20 22   t=utf-8..Etag: "
0040   31 36 36 37 37 32 38 37 31 39 2e 31 35 38 31 22   1667728719.1581"
0050   0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 68   ..Content-Length
0060   3a 20 31 35 38 31 0d 0a 0d 0a 3c 21 44 4f 43 54   : 1581....<!DOCT
0070   59 50 45 20 68 74 6d 6c 3e 0a 3c 68 74 6d 6c 20   YPE html>.<html 
0080   6c 61 6e 67 3d 22 65 6e 22 3e 0a 20 20 3c 62 6f   lang="en">.  <bo
0090   64 79 3e 0a 20 20 20 20 3c 68 31 3e 57 65 62 73   dy>.    <h1>Webs
00a0   6f 63 6b 65 74 20 74 65 73 74 20 63 6c 69 65 6e   ocket test clien
00b0   74 3c 2f 68 31 3e 0a 20 20 20 20 3c 69 6e 70 75   t</h1>.    <inpu
00c0   74 20 69 64 3d 22 75 72 6c 22 20 74 79 70 65 3d   t id="url" type=
00d0   22 74 65 78 74 22 20 70 6c 61 63 65 68 6f 6c 64   "text" placehold
00e0   65 72 3d 22 54 79 70 65 20 55 52 4c 22 20 76 61   er="Type URL" va
00f0   6c 75 65 3d 22 77 73 3a 2f 2f 6c 6f 63 61 6c 68   lue="ws://localh
0100   6f 73 74 3a 38 30 30 30 2f 77 65 62 73 6f 63 6b   ost:8000/websock
0110   65 74 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68   et" style="width
0120   3a 32 30 65 6d 3b 22 20 2f 3e 20 0a 20 20 20 20   :20em;" /> .    
0130   3c 62 75 74 74 6f 6e 20 69 64 3d 22 63 6f 6e 6e   <button id="conn
0140   65 63 74 22 3e 63 6f 6e 6e 65 63 74 3c 2f 62 75   ect">connect</bu
0150   74 74 6f 6e 3e 0a 20 20 20 20 3c 64 69 76 20 73   tton>.    <div s
0160   74 79 6c 65 3d 22 68 65 69 67 68 74 3a 20 30 2e   tyle="height: 0.
0170   33 65 6d 3b 22 3e 26 6e 62 73 70 3b 3c 2f 64 69   3em;">&nbsp;</di
0180   76 3e 0a 20 20 20 20 3c 69 6e 70 75 74 20 69 64   v>.    <input id
0190   3d 22 6d 65 73 73 61 67 65 22 20 74 79 70 65 3d   ="message" type=
01a0   22 74 65 78 74 22 20 70 6c 61 63 65 68 6f 6c 64   "text" placehold
01b0   65 72 3d 22 54 79 70 65 20 6d 65 73 73 61 67 65   er="Type message
01c0   22 20 73 74 79 6c 65 3d 22 77 69 64 74 68 3a 20   " style="width: 
01d0   32 30 65 6d 3b 22 20 2f 3e 20 0a 20 20 20 20 3c   20em;" /> .    <
01e0   62 75 74 74 6f 6e 20 69 64 3d 22 73 65 6e 64 22   button id="send"
01f0   3e 73 65 6e 64 20 6d 65 73 73 61 67 65 3c 2f 62   >send message</b
0200   75 74 74 6f 6e 3e 0a 20 20 20 20 3c 64 69 76 20   utton>.    <div 
0210   73 74 79 6c 65 3d 22 6d 61 72 67 69 6e 2d 74 6f   style="margin-to
0220   70 3a 20 31 65 6d 3b 22 3e 45 76 65 6e 74 20 6c   p: 1em;">Event l
0230   6f 67 3a 3c 2f 64 69 76 3e 0a 20 20 20 20 3c 64   og:</div>.    <d
0240   69 76 20 69 64 3d 22 6c 6f 67 22 20 73 74 79 6c   iv id="log" styl
0250   65 3d 22 62 61 63 6b 67 72 6f 75 6e 64 3a 20 23   e="background: #
0260   65 65 65 3b 20 68 65 69 67 68 74 3a 20 31 30 65   eee; height: 10e
0270   6d 3b 20 70 61 64 64 69 6e 67 3a 20 30 2e 35 65   m; padding: 0.5e
0280   6d 3b 22 3e 3c 64 69 76 3e 0a 20 20 3c 2f 62 6f   m;"><div>.  </bo
0290   64 79 3e 0a 20 20 3c 73 63 72 69 70 74 3e 0a 20   dy>.  <script>. 
02a0   20 20 20 76 61 72 20 77 73 2c 20 45 20 3d 20 66      var ws, E = f
02b0   75 6e 63 74 69 6f 6e 28 69 64 29 20 7b 20 72 65   unction(id) { re
02c0   74 75 72 6e 20 64 6f 63 75 6d 65 6e 74 2e 67 65   turn document.ge
02d0   74 45 6c 65 6d 65 6e 74 42 79 49 64 28 69 64 29   tElementById(id)
02e0   3b 20 7d 3b 0a 20 20 20 20 76 61 72 20 75 72 6c   ; };.    var url
02f0   20 3d 20 45 28 27 75 72 6c 27 29 2c 20 63 6f 6e    = E('url'), con
0300   6e 65 63 74 20 3d 20 45 28 27 63 6f 6e 6e 65 63   nect = E('connec
0310   74 27 29 2c 20 6d 65 73 73 61 67 65 20 3d 20 45   t'), message = E
0320   28 27 6d 65 73 73 61 67 65 27 29 2c 20 73 65 6e   ('message'), sen
0330   64 20 3d 20 45 28 27 73 65 6e 64 27 29 2c 20 6c   d = E('send'), l
0340   6f 67 20 3d 20 45 28 27 6c 6f 67 27 29 3b 0a 20   og = E('log');. 
0350   20 20 20 76 61 72 20 65 6e 61 62 6c 65 20 3d 20      var enable = 
0360   66 75 6e 63 74 69 6f 6e 28 65 6e 29 20 7b 20 6d   function(en) { m
0370   65 73 73 61 67 65 2e 64 69 73 61 62 6c 65 64 20   essage.disabled 
0380   3d 20 73 65 6e 64 2e 64 69 73 61 62 6c 65 64 20   = send.disabled 
0390   3d 20 21 65 6e 3b 20 75 72 6c 2e 64 69 73 61 62   = !en; url.disab
03a0   6c 65 64 20 3d 20 65 6e 3b 20 63 6f 6e 6e 65 63   led = en; connec
03b0   74 2e 69 6e 6e 65 72 48 54 4d 4c 20 3d 20 65 6e   t.innerHTML = en
03c0   20 3f 20 27 64 69 73 63 6f 6e 6e 65 63 74 27 20    ? 'disconnect' 
03d0   3a 20 27 63 6f 6e 6e 65 63 74 27 3b 20 7d 3b 0a   : 'connect'; };.
03e0   20 20 20 20 65 6e 61 62 6c 65 28 66 61 6c 73 65       enable(false
03f0   29 0a 20 20 20 20 63 6f 6e 6e 65 63 74 2e 6f 6e   ).    connect.on
0400   63 6c 69 63 6b 20 3d 20 66 75 6e 63 74 69 6f 6e   click = function
0410   28 29 20 7b 0a 20 20 20 20 20 20 69 66 20 28 77   () {.      if (w
0420   73 29 20 7b 20 77 73 2e 63 6c 6f 73 65 28 29 3b   s) { ws.close();
0430   20 72 65 74 75 72 6e 3b 20 7d 0a 20 20 20 20 20    return; }.     
0440   20 77 73 20 3d 20 6e 65 77 20 57 65 62 53 6f 63    ws = new WebSoc
0450   6b 65 74 28 75 72 6c 2e 76 61 6c 75 65 29 3b 0a   ket(url.value);.
0460   20 20 20 20 20 20 69 66 20 28 21 77 73 29 20 72         if (!ws) r
0470   65 74 75 72 6e 3b 0a 20 20 20 20 20 20 77 73 2e   eturn;.      ws.
0480   6f 6e 6f 70 65 6e 20 3d 20 66 75 6e 63 74 69 6f   onopen = functio
0490   6e 28 29 20 7b 20 6c 6f 67 2e 69 6e 6e 65 72 48   n() { log.innerH
04a0   54 4d 4c 20 2b 3d 20 27 43 4f 4e 4e 45 43 54 49   TML += 'CONNECTI
04b0   4f 4e 20 4f 50 45 4e 45 44 3c 62 72 2f 3e 27 3b   ON OPENED<br/>';
04c0   20 7d 0a 20 20 20 20 20 20 77 73 2e 6f 6e 6d 65    }.      ws.onme
04d0   73 73 61 67 65 20 3d 20 66 75 6e 63 74 69 6f 6e   ssage = function
04e0   28 65 76 29 20 7b 20 6c 6f 67 2e 69 6e 6e 65 72   (ev) { log.inner
04f0   48 54 4d 4c 20 2b 3d 20 27 52 45 43 45 49 56 45   HTML += 'RECEIVE
0500   44 3a 20 27 20 2b 20 65 76 2e 64 61 74 61 20 2b   D: ' + ev.data +
0510   20 27 3c 62 72 2f 3e 27 3b 20 7d 0a 20 20 20 20    '<br/>'; }.    
0520   20 20 77 73 2e 6f 6e 65 72 72 6f 72 20 3d 20 66     ws.onerror = f
0530   75 6e 63 74 69 6f 6e 28 65 76 29 20 7b 20 6c 6f   unction(ev) { lo
0540   67 2e 69 6e 6e 65 72 48 54 4d 4c 20 2b 3d 20 27   g.innerHTML += '
0550   45 52 52 4f 52 3a 20 27 20 2b 20 65 76 20 2b 20   ERROR: ' + ev + 
0560   27 3c 62 72 2f 3e 27 3b 20 7d 0a 20 20 20 20 20   '<br/>'; }.     
0570   20 77 73 2e 6f 6e 63 6c 6f 73 65 20 3d 20 66 75    ws.onclose = fu
0580   6e 63 74 69 6f 6e 28 29 20 7b 20 6c 6f 67 2e 69   nction() { log.i
0590   6e 6e 65 72 48 54 4d 4c 20 2b 3d 20 27 43 4f 4e   nnerHTML += 'CON
05a0   4e 45 43 54 49 4f 4e 20 43 4c 4f 53 45 44 3c 62   NECTION CLOSED<b
05b0   72 2f 3e 27 3b 20 65 6e 61 62 6c 65 28 66 61 6c   r/>'; enable(fal
05c0   73 65 29 3b 20 77 73 20 3d 20 6e 75 6c 6c 3b 20   se); ws = null; 
05d0   7d 0a 20 20 20 20 20 20 65 6e 61 62 6c 65 28 74   }.      enable(t
05e0   72 75 65 29 3b 0a 20 20 20 20 7d 3b 0a 20 20 20   rue);.    };.   
05f0   20 73 65 6e 64 2e 6f 6e 63 6c 69 63 6b 20 3d 20    send.onclick = 
0600   66 75 6e 63 74 69 6f 6e 28 29 20 7b 0a 20 20 20   function() {.   
0610   20 20 20 69 66 20 28 21 77 73 29 20 72 65 74 75      if (!ws) retu
0620   72 6e 3b 0a 20 20 20 20 20 20 6c 6f 67 2e 69 6e   rn;.      log.in
0630   6e 65 72 48 54 4d 4c 20 2b 3d 20 27 53 45 4e 54   nerHTML += 'SENT
0640   3a 20 27 20 2b 20 6d 65 73 73 61 67 65 2e 76 61   : ' + message.va
0650   6c 75 65 20 2b 20 27 3c 62 72 2f 3e 27 3b 0a 20   lue + '<br/>';. 
0660   20 20 20 20 20 77 73 2e 73 65 6e 64 28 6d 65 73        ws.send(mes
0670   73 61 67 65 2e 76 61 6c 75 65 29 3b 0a 20 20 20   sage.value);.   
0680   20 7d 0a 20 20 3c 2f 73 63 72 69 70 74 3e 0a 3c    }.  </script>.<
0690   2f 68 74 6d 6c 3e 0a                              /html>.         
1c2bb5 2 sock.c:112:iolog               
-- 4 127.0.0.1:8000 <- 127.0.0.1:59668  526
0000   47 45 54 20 2f 77 65 62 73 6f 63 6b 65 74 20 48   GET /websocket H
0010   54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 6c   TTP/1.1..Host: l
0020   6f 63 61 6c 68 6f 73 74 3a 38 30 30 30 0d 0a 43   ocalhost:8000..C
0030   6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 61   onnection: Upgra
0040   64 65 0d 0a 50 72 61 67 6d 61 3a 20 6e 6f 2d 63   de..Pragma: no-c
0050   61 63 68 65 0d 0a 43 61 63 68 65 2d 43 6f 6e 74   ache..Cache-Cont
0060   72 6f 6c 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 55   rol: no-cache..U
0070   73 65 72 2d 41 67 65 6e 74 3a 20 4d 6f 7a 69 6c   ser-Agent: Mozil
0080   6c 61 2f 35 2e 30 20 28 58 31 31 3b 20 4c 69 6e   la/5.0 (X11; Lin
0090   75 78 20 61 72 6d 76 37 6c 29 20 41 70 70 6c 65   ux armv7l) Apple
00a0   57 65 62 4b 69 74 2f 35 33 37 2e 33 36 20 28 4b   WebKit/537.36 (K
00b0   48 54 4d 4c 2c 20 6c 69 6b 65 20 47 65 63 6b 6f   HTML, like Gecko
00c0   29 20 52 61 73 70 62 69 61 6e 20 43 68 72 6f 6d   ) Raspbian Chrom
00d0   69 75 6d 2f 37 38 2e 30 2e 33 39 30 34 2e 31 30   ium/78.0.3904.10
00e0   38 20 43 68 72 6f 6d 65 2f 37 38 2e 30 2e 33 39   8 Chrome/78.0.39
00f0   30 34 2e 31 30 38 20 53 61 66 61 72 69 2f 35 33   04.108 Safari/53
0100   37 2e 33 36 0d 0a 55 70 67 72 61 64 65 3a 20 77   7.36..Upgrade: w
0110   65 62 73 6f 63 6b 65 74 0d 0a 4f 72 69 67 69 6e   ebsocket..Origin
0120   3a 20 68 74 74 70 3a 2f 2f 6c 6f 63 61 6c 68 6f   : http://localho
0130   73 74 3a 38 30 30 30 0d 0a 53 65 63 2d 57 65 62   st:8000..Sec-Web
0140   53 6f 63 6b 65 74 2d 56 65 72 73 69 6f 6e 3a 20   Socket-Version: 
0150   31 33 0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f 64   13..Accept-Encod
0160   69 6e 67 3a 20 67 7a 69 70 2c 20 64 65 66 6c 61   ing: gzip, defla
0170   74 65 2c 20 62 72 0d 0a 41 63 63 65 70 74 2d 4c   te, br..Accept-L
0180   61 6e 67 75 61 67 65 3a 20 7a 68 2d 43 4e 2c 7a   anguage: zh-CN,z
0190   68 3b 71 3d 30 2e 39 0d 0a 53 65 63 2d 57 65 62   h;q=0.9..Sec-Web
01a0   53 6f 63 6b 65 74 2d 4b 65 79 3a 20 61 69 6a 63   Socket-Key: aijc
01b0   35 31 35 71 66 7a 79 56 5a 78 64 45 79 76 31 63   515qfzyVZxdEyv1c
01c0   44 77 3d 3d 0d 0a 53 65 63 2d 57 65 62 53 6f 63   Dw==..Sec-WebSoc
01d0   6b 65 74 2d 45 78 74 65 6e 73 69 6f 6e 73 3a 20   ket-Extensions: 
01e0   70 65 72 6d 65 73 73 61 67 65 2d 64 65 66 6c 61   permessage-defla
01f0   74 65 3b 20 63 6c 69 65 6e 74 5f 6d 61 78 5f 77   te; client_max_w
0200   69 6e 64 6f 77 5f 62 69 74 73 0d 0a 0d 0a         indow_bits....  
1c2bb6 2 sock.c:112:iolog               
-- 4 127.0.0.1:8000 -> 127.0.0.1:59668  129
0000   48 54 54 50 2f 31 2e 31 20 31 30 31 20 53 77 69   HTTP/1.1 101 Swi
0010   74 63 68 69 6e 67 20 50 72 6f 74 6f 63 6f 6c 73   tching Protocols
0020   0d 0a 55 70 67 72 61 64 65 3a 20 77 65 62 73 6f   ..Upgrade: webso
0030   63 6b 65 74 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e   cket..Connection
0040   3a 20 55 70 67 72 61 64 65 0d 0a 53 65 63 2d 57   : Upgrade..Sec-W
0050   65 62 53 6f 63 6b 65 74 2d 41 63 63 65 70 74 3a   ebSocket-Accept:
0060   20 4d 75 47 51 2f 53 4b 56 35 58 6d 34 77 76 4e    MuGQ/SKV5Xm4wvN
0070   4c 69 34 71 55 68 52 77 37 6c 6b 63 3d 0d 0a 0d   Li4qUhRw7lkc=...
0080   0a                                                .               
1c5be6 2 sock.c:112:iolog               
-- 4 127.0.0.1:8000 <- 127.0.0.1:59668  18
0000   81 8c ed 7f 06 db a5 1a 6a b7 82 5f 51 b4 9f 13   ........j.._Q...
0010   62 fa                                             b.              
1c5be7 2 sock.c:112:iolog               
-- 4 127.0.0.1:8000 -> 127.0.0.1:59668  14
0000   81 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21         ..Hello World!  

可以看到整个操作过程的收发消息都打印了出来。

另外我们也可以使用 Mongoose 的 websocket-client 示例程序来访问我们的 WebSocket 服务器。

【参考资料】

examples/websocket-server

Documentation

rfc6455


本文链接:https://blog.csdn.net/u012028275/article/details/128513876

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chromium Embedded Framework(CEF)源码编译基于windows

1.打开维基百科CEF主页: Chromium Embedded Framework - Wikipedia 2.找到CEF仓库地址:chromiumembedded / cef — Bitbucket 打开CEF源码仓库: 点击 Wiki,然后在 Getting Started节,点击cef-project 向下拉浏览滚动条,可看到Setup章节

第三十二讲:神州交换机和路由器上分别实现QoS

QoS&#xff08;Quality of Service&#xff0c;服务品质保证&#xff09;是指一个网络能够利用各种各样的技术向选定的网络通信提供更好的服务的能力。QoS是服务品质保证&#xff0c;提供稳定、可预测的数据传送服务&#xff0c;来满足使用程序的要求&#xff0c;QoS不能产生新…

深入浅出闭包

目录 一、闭包概念 二、重载operator() 三、lambda表达式 3.1 lambda表达式介绍 3.2 lambda表达式语法 3.2.1 [capture-list]捕捉列表 3.2.2(parameters)&#xff1a;参数列表 3.2.3 mutable关键字 3.2.4 ->returntype&#xff1a;返回值类型 3.2.5 {statement}&a…

基于OpenSSL的安全Web Server实现

目录 一、实验目的 二、实验软硬件要求 三、实验预习 四、实验内容&#xff08;实验步骤、测试数据等&#xff09; 实验步骤 1编辑代码 2解决报错 3准备网页 五、实验体会&#xff08;遇到的问题及解决方法&#xff09; 六、服务器代码 七、测试网页代码 一、实验目…

(02)Cartographer源码无死角解析-(43) 2D栅格地图→

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

利用Python构建Wiki中文语料词向量模型

利用Python构建Wiki中文语料词向量模型试验 完整代码下载地址&#xff1a;利用Python构建Wiki中文语料词向量模型 本实例主要介绍的是选取wiki中文语料&#xff0c;并使用python完成Word2vec模型构建的实践过程&#xff0c;不包含原理部分&#xff0c;旨在一步一步的了解自然语…

CH450/TM1637 驱动调试

CH450&#xff1a;支持带有中断的扫描键盘、数码显示&#xff1b; TM1637&#xff1a;键盘扫描/数码显示&#xff1b; CH450/TM1637 I2C的时序调试有问题&#xff0c;总体上注意以下几点 MSB还是LSB&#xff0c;这两个不一样&#xff1b;&#xff08;TM1637从低到高传输&…

PhpStorm 使用全局搜索得不到结果

一、前言二、解决一、前言 全文搜索快捷键&#xff1a;ctrl shift f&#xff0c;如果 没有弹出搜索框。看下快捷键是不是被其他软件占用了&#xff1a;比如搜狗输入法现在的问题是&#xff1a;输入想要搜索的关键字&#xff0c;但是没用搜出来结果&#xff08;实际上关键字在…

BurpSuite与Xray联动进行被动扫描实战

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是BurpSuite与Xray联动进行被动扫描实战。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xf…

Linux权限及其理解

文章目录&#xff1a;Linux权限的概念Linux权限管理文件访问者的分类&#xff08;人&#xff09;文件类型和访问权限&#xff08;事物属性&#xff09;文件权限值的表示方法文件访问权限的设置方法权限掩码目录的权限粘滞位总结Linux权限的概念 与其它系统相比&#xff0c;Lin…

文件包含漏洞渗透与攻防(一)

目录 前言 什么是文件包含漏洞 文件包含漏洞类型 本地文件包含 远程文件包含 PHP相关函数和伪协议 函数 PHP伪协议 CTF题目案例 文件包含漏洞挖掘与利用 URL关键字 代码审计 利用流程 文件包含漏洞修复方案 前言 随着网站业务的需求&#xff0c;程序开发人员一…

【ACWING】【图的广度遍历】【848有向图的拓扑顺序】

给定一个 n个点 m条边的有向图&#xff0c;点的编号是 1到 n&#xff0c;图中可能存在重边和自环。 请输出任意一个该有向图的拓扑序列&#xff0c;如果拓扑序列不存在&#xff0c;则输出 −1。 若一个由图中所有点构成的序列 A满足&#xff1a;对于图中的每条边 (x,y)&#…

STM32MP157驱动开发——Linux CAN驱动

STM32MP157驱动开发——Linux CAN驱动一、简介1.电气属性2.CAN协议3.CAN速率4.CAN FD 简介二、驱动开发1.修改设备树2.FDCAN1控制器节点3.修复 m_can_platform.c4.使能 CAN 总线5.使能FDCAN外设驱动三、运行测试1.移植 iproute2 和 can-utils 工具2.测试1&#xff09;收发测试&…

数据结构排序

文章目录直接插入排序直接插入排序 核心代码 void InsertSort(int arr[], int n) {for (int i 2; i < n; i) ///直接从第二个元素开始遍历{if (arr[i - 1] > arr[i]) //判断前一个元素和当前元素的大小&#xff0c;若前一个元素小于当前元素才需要插入{arr[0] …

Markdown之折叠语法以及表格内父子折叠

背景 在编写接口文档的时候发现一些特别扭的问题&#xff0c;就是一个表格来说明入参和出参的时候&#xff0c;怎么去表达嵌套的父子关系呢&#xff1f;查看了大厂的接口文档&#xff0c;比如微信支付&#xff0c;他们是有完善的接口文档页面&#xff0c;也都全部标记出了表格…

pycharm-qt5-基础篇1

pycharm-qt5-基础篇1一: QT5介绍1> 主要的特性2> pycharm 外部工具及功能1. Qt Designer2. PyUic3> PyUrcc二: pycharm QT5 环境搭建1> 虚拟环境搭建2> 安装 pyqt5、pyqt5-tools3> 将QT工具添加到环境变量4> 配置PyCharm三: QT5 demo四: pyinstaller 打包…

Java 并发编程知识总结【三】

4. CompletableFuture 4.1 Future 和 Callable 接口 Future 接口定义了操作异步任务执行一些方法&#xff0c;如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。 Callable 接口中定义了需要有返回的任务需要实现的方法。 使用途径&am…

详解Spring面试AOP

文章目录什么是 AOP&#xff1f;AOP作用AOP核心概念&#xff08;来自黑马程序课程&#xff09;AOP 解决了什么问题&#xff1f;AOP 为什么叫做切面编程&#xff1f;总结1 AOP的核心概念2 切入点表达式3 五种通知类型4 通知中获取参数AOP是面向切面编程&#xff0c;是一个设计思…

Java同学录系统同学录网站

简介 用户注册可以创建班级&#xff08;创建者即为群主&#xff09;&#xff0c;用户也可以查找班级申请加入&#xff0c;群主添加同学的联系方式等&#xff0c;可以在班级里留言&#xff0c;管理相册等&#xff0c;还可以指定其他人为群主或者解散班级群&#xff0c;群里的用…

【ROS】—— ROS快速上手(一)

文章目录前言1. ROS-melodic 安装2. ROS基本操作2.1 创建工作空间2.2 创建功能包2.3 HelloWorld(C版)2.4 HelloWorld(Python版)3. Vscode ROS 插件4. vscode 使用基本配置4.1 启动 vscode4.2 vscode 中编译 ros5. launch文件演示6. ROS文件系统7. ROS文件系统相关命令前言 &…