【Mongoose笔记】Websocket 服务器

【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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值