Files
cpp-httplib/docs-src/pages/ja/tour/08-websocket.md

142 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "WebSocket"
order: 8
---
cpp-httplibはWebSocketにも対応しています。HTTPのリクエスト/レスポンスと違い、WebSocketはサーバーとクライアントが双方向にメッセージをやり取りできます。チャットやリアルタイム通知に便利です。
さっそく、エコーサーバーとクライアントを作ってみましょう。
## エコーサーバー
受け取ったメッセージをそのまま返すエコーサーバーです。
```cpp
#include "httplib.h"
#include <iostream>
int main() {
httplib::Server svr;
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg); // 受け取ったメッセージをそのまま返す
}
});
std::cout << "Listening on port 8080..." << std::endl;
svr.listen("0.0.0.0", 8080);
}
```
`svr.WebSocket()` でWebSocketハンドラーを登録します。3章の `svr.Get()` や `svr.Post()` と同じ感覚ですね。
ハンドラーの中では、`ws.read(msg)` でメッセージを待ちます。接続が閉じられると `read()` が `false` を返すので、ループを抜けます。`ws.send(msg)` でメッセージを送り返します。
## クライアントからの接続
`httplib::ws::WebSocketClient` を使ってサーバーに接続してみましょう。
```cpp
#include "httplib.h"
#include <iostream>
int main() {
httplib::ws::WebSocketClient client("ws://localhost:8080/ws");
if (!client.connect()) {
std::cout << "Connection failed" << std::endl;
return 1;
}
// メッセージを送信
client.send("Hello, WebSocket!");
// サーバーからの応答を受信
std::string msg;
if (client.read(msg)) {
std::cout << msg << std::endl; // Hello, WebSocket!
}
client.close();
}
```
コンストラクタには `ws://host:port/path` 形式のURLを渡します。`connect()` で接続を開始し、`send()` と `read()` でメッセージをやり取りします。
## テキストとバイナリ
WebSocketにはテキストとバイナリの2種類のメッセージがあります。`read()` の戻り値で区別できます。
```cpp
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
httplib::ws::ReadResult ret;
while ((ret = ws.read(msg))) {
if (ret == httplib::ws::Binary) {
ws.send(msg.data(), msg.size()); // バイナリとして送信
} else {
ws.send(msg); // テキストとして送信
}
}
});
```
- `ws.send(const std::string &)` — テキストメッセージとして送信
- `ws.send(const char *, size_t)` — バイナリメッセージとして送信
クライアント側も同じAPIです。
## リクエスト情報へのアクセス
ハンドラーの第1引数 `req` から、ハンドシェイク時のHTTPリクエスト情報を読み取れます。認証トークンの確認などに便利です。
```cpp
svr.WebSocket("/ws", [](const httplib::Request &req, httplib::ws::WebSocket &ws) {
auto token = req.get_header_value("Authorization");
if (token.empty()) {
ws.close(httplib::ws::CloseStatus::PolicyViolation, "unauthorized");
return;
}
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
});
```
ハンドラー内のチェックは、ハンドシェイクが完了した後に行われます。アップグレードする前に401などのHTTPステータスで接続を拒否したい場合は、`set_pre_request_handler()`を使ってください。WebSocketのルートでも呼ばれます。詳しくは[S11. Pre-request handlerでルート単位の認証を行う](../../cookbook/s11-pre-request)を参照してください。
## WSSで使う
HTTPS上のWebSocket(WSS)にも対応しています。サーバー側は `httplib::SSLServer` にWebSocketハンドラーを登録するだけです。
```cpp
httplib::SSLServer svr("cert.pem", "key.pem");
svr.WebSocket("/ws", [](const httplib::Request &, httplib::ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
});
svr.listen("0.0.0.0", 8443);
```
クライアント側は `wss://` スキームを使います。
```cpp
httplib::ws::WebSocketClient client("wss://localhost:8443/ws");
```
## 次のステップ
WebSocketの基本がわかりましたね。ここまでで Tourは終わりです。
次のページでは、Tourで取り上げなかった機能をまとめて紹介します。
**次:** [What's Next](../09-whats-next)