楔子
- Java-WebSocket and the example in this
WebSocket 的主要优点和缺点
-
全双工通信
- WebSocket 支持双向通信,客户端和服务器可以同时发送和接收数据,而不需要像 HTTP 那样依赖请求-响应模式。
-
低延迟
- WebSocket 建立连接后,数据传输的延迟非常低,适合实时应用(如聊天、游戏、实时数据推送等)。
-
减少带宽消耗
- WebSocket 的连接是持久的,不需要像 HTTP 那样频繁地建立和关闭连接,减少了握手和头信息的开销。
-
高效的数据传输
- WebSocket 的数据帧较小,传输效率高,特别适合频繁的小数据包传输。
-
支持二进制和文本数据
- WebSocket 可以传输二进制数据和文本数据,灵活性高。
-
跨域支持
- WebSocket 支持跨域通信,可以通过
wss://
实现安全的跨域数据传输。
- WebSocket 支持跨域通信,可以通过
-
心跳机制
- WebSocket 支持 Ping/Pong 帧,可以用于检测连接是否存活,避免连接因超时被关闭。
-
易于扩展
- WebSocket 协议支持扩展,可以通过扩展实现压缩、加密等功能。
-
兼容性好
- 现代浏览器和主流编程语言都支持 WebSocket,易于集成到现有系统中。
-
减少服务器压力
- 相比 HTTP 轮询,WebSocket 的持久连接减少了服务器的并发压力。
WebSocket 是基于什么协议实现的
WebSocket 是基于 TCP 协议 实现的。具体来说,WebSocket 是一个应用层协议,它依赖于传输层的 TCP 协议来提供可靠的双向通信。
WebSocket 和 TCP 的关系
-
传输层协议:TCP
- WebSocket 使用 TCP 作为底层传输协议,确保数据的可靠传输(无丢失、无重复、按序到达)。
- TCP 提供了面向连接、可靠的字节流服务,适合 WebSocket 的实时通信需求。
-
应用层协议:WebSocket
- WebSocket 是一个独立的应用层协议,定义了自己的握手过程、数据帧格式和通信规则。
- 它在 TCP 之上运行,利用 TCP 提供的可靠传输能力,实现了全双工通信。
WebSocket 的数据帧
WebSocket 定义了自己的数据帧格式,用于传输文本或二进制数据。数据帧包括以下部分:
- FIN :指示是否是消息的最后一帧。
- Opcode:指示帧的类型(如文本帧、二进制帧、关闭帧等)。
- Mask :指示是否使用掩码(客户端到服务器的帧必须掩码)。
- Payload length:指示数据的长度。
- Payload data:实际传输的数据。
WebSocket 连接的建立分为两个阶段:
- HTTP 握手阶段:客户端和服务器通过 HTTP 协议进行握手,协商升级到 WebSocket 协议。
- WebSocket 通信阶段:握手成功后,客户端和服务器使用 WebSocket 协议进行双向通信。
WebSocket 连接建立的详细过程
step 1 :客户端发起握手请求
客户端发送一个 HTTP GET 请求,请求头中包含以下关键字段:
Upgrade: websocket
:表示客户端希望升级到 WebSocket 协议。Connection: Upgrade
:表示客户端希望升级连接。Sec-WebSocket-Key
:一个随机生成的 Base64 编码字符串,用于握手验证。Sec-WebSocket-Version
:指定 WebSocket 协议版本(通常是 13)。
示例:
http
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
step 2 服务器响应握手
服务器收到客户端的握手请求后,如果同意升级到 WebSocket 协议,会返回一个 HTTP 101 状态码(Switching Protocols),并在响应头中包含以下关键字段:
Upgrade: websocket
:表示服务器同意升级到 WebSocket 协议。Connection: Upgrade
:表示服务器同意升级连接。Sec-WebSocket-Accept
:服务器根据客户端的Sec-WebSocket-Key
计算出的验证字符串。
Sec-WebSocket-Accept
的计算方法:
- 将客户端的
Sec-WebSocket-Key
与固定的 GUID(258EAFA5-E914-47DA-95CA-C5AB0DC85B11
)拼接。 - 对拼接后的字符串进行 SHA-1 哈希计算。
- 将哈希结果进行 Base64 编码。
示例:
http
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
step3 升级到 WebSocket 协议
diff
- 握手完成后,客户端和服务器之间的通信将使用 WebSocket 协议,不再使用 HTTP。
WebSocket 的数据帧
WebSocket 定义了自己的数据帧格式,用于传输文本或二进制数据。数据帧包括以下部分:
- FIN:1 位,表示是否是消息的最后一帧。
- RSV1, RSV2, RSV3:各 1 位,保留字段,通常为 0。
- Opcode:4 位,表示帧的类型(如文本帧、二进制帧、关闭帧等)。
- Mask:1 位,指示是否使用掩码。
- Payload length:7 位、7+16 位或 7+64 位,表示数据的长度。
- Masking key:4 字节(如果 Mask 为 1),用于掩码计算。
- Payload data:实际的数据。
C
// WebSocket 数据帧结构体
typedef struct {
uint8_t fin : 1; // FIN 标志位
uint8_t rsv1 : 1; // RSV1 标志位
uint8_t rsv2 : 1; // RSV2 标志位
uint8_t rsv3 : 1; // RSV3 标志位
uint8_t opcode : 4; // 操作码(Opcode)
uint8_t mask : 1; // 掩码标志位
uint8_t payload_len : 7; // 数据长度(7 位或扩展)
uint32_t masking_key; // 掩码键(4 字节)
uint8_t* payload_data; // 数据内容
} WebSocketFrame;
WebSocket 是全双工还是半双工
WebSocket 是 全双工(Full-Duplex) 的通信协议。
全双工 vs 半双工
-
全双工(Full-Duplex)
- 通信双方可以同时发送和接收数据。
- 例如:电话通话,双方可以同时说话和听对方说话。
-
半双工(Half-Duplex)
- 通信双方可以发送和接收数据,但不能同时进行。
- 例如:对讲机,同一时间只能有一方说话,另一方听。
WebSocket 的握手请求头中有哪些关键字段
WebSocket 握手请求头中的关键字段包括:
Upgrade
Connection
Sec-WebSocket-Key
Sec-WebSocket-Version
Host
Origin
(可选)Sec-WebSocket-Protocol
(可选)Sec-WebSocket-Extensions
(可选)
解释
1. Upgrade
-
作用:表示客户端希望将连接升级到 WebSocket 协议。
-
值 :必须为
websocket
。 -
示例:
httpUpgrade: websocket
2. Connection
-
作用:表示客户端希望升级连接。
-
值 :必须为
Upgrade
。 -
示例:
httpConnection: Upgrade
3. Sec-WebSocket-Key
-
作用:客户端随机生成的一个 Base64 编码的字符串,用于握手验证。
-
值:16 字节随机数的 Base64 编码。
-
示例:
httpSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
4. Sec-WebSocket-Version
-
作用:指定客户端支持的 WebSocket 协议版本。
-
值 :当前标准版本为
13
。 -
示例:
httpSec-WebSocket-Version: 13
5. Host
-
作用:指定服务器的域名或 IP 地址。
-
值:服务器的地址。
-
示例:
httpHost: example.com
6. Origin
(可选)
-
作用:表示请求的来源,用于跨域验证。
-
值:客户端的源地址(协议 + 域名 + 端口)。
-
示例:
httpOrigin: http://example.com
7. Sec-WebSocket-Protocol
(可选)
-
作用 :指定客户端支持的子协议(如
chat
、superchat
等)。 -
值:子协议名称。
-
示例:
httpSec-WebSocket-Protocol: chat, superchat
8. Sec-WebSocket-Extensions
(可选)
-
作用:指定客户端支持的扩展(如压缩、加密等)。
-
值:扩展名称。
-
示例:
httpSec-WebSocket-Extensions: permessage-deflate
完整的 WebSocket 握手请求示例
http
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Extensions: permessage-deflate
WebSocket 的最大帧大小是多少
-
协议设计:
- WebSocket 数据帧的
Payload length
字段可以表示的最大长度为 2^63 - 1 字节(约 9.22 EB,Exabytes)。 - 这是一个理论值,实际应用中不会达到这个大小。
- WebSocket 数据帧的
-
实现限制:
- 客户端和服务器的实现可能会对帧大小设置限制。
- 例如,某些 WebSocket 库可能默认限制帧大小为 16 MB 或更小。
-
网络和硬件限制:
- 网络带宽、内存和硬件资源也会影响帧大小的实际限制。
- Java 的
Java-WebSocket
库
java
import org.java_websocket.server.WebSocketServer;
WebSocketServer server = new WebSocketServer(new InetSocketAddress(8765)) {
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {}
@Override
public void onMessage(WebSocket conn, String message) {}
@Override
public void onError(WebSocket conn, Exception ex) {}
@Override
public void onStart() {}
};
server.setMaxFrameSize(100 * 1024 * 1024); // 设置最大帧大小为 100 MB
server.start();
- WebSocket 协议本身没有明确规定最大帧大小,理论最大长度为 2^63 - 1 字节。
- 实际应用中,浏览器和服务器通常会对帧大小设置限制(如 16 MB)。
- 如果需要传输大文件或大数据,可以将数据分片传输,或通过配置调整帧大小限制
WebSocket 的连接状态有哪些
WebSocket 的连接状态包括:
- CONNECTING:连接中。
- OPEN:连接已打开,可以通信。
- CLOSING:连接关闭中。
- CLOSED:连接已关闭。
通过监听 onopen
、onclose
和 onerror
事件,可以实时获取连接状态的变化。
WebSocket 的连接是如何关闭的?
1. 发送关闭帧(Close Frame)
-
关闭帧的格式:
- Opcode :
0x8
(表示关闭帧)。 - Payload:可选的关闭原因(状态码和原因短语)。
- Opcode :
-
状态码:
- 2 字节的无符号整数,表示关闭原因。
- 例如:
1000
(正常关闭)、1001
(端点离开)等。
-
原因短语:
- 可选的 UTF-8 编码字符串,描述关闭原因。
2. 接收关闭帧
- 当一端收到关闭帧后,必须发送一个关闭帧作为响应。
- 收到关闭帧后,连接进入 CLOSING 状态。
3. 关闭 TCP 连接
- 在双方都发送和接收了关闭帧后,连接进入 CLOSED 状态。
- 底层 TCP 连接被关闭。
WebSocket 关闭连接的示例
1. 客户端主动关闭连接
javascript
Copy
javascript
const socket = new WebSocket('ws://example.com');
// 监听连接打开事件
socket.onopen = () => {
console.log('WebSocket 连接已打开');
// 主动关闭连接
socket.close(1000, 'Normal Closure');
};
// 监听连接关闭事件
socket.onclose = (event) => {
console.log('WebSocket 连接已关闭');
console.log('状态码:', event.code);
console.log('原因:', event.reason);
};
2. 服务器主动关闭连接(Node.js + ws 库)
js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('客户端已连接');
// 服务器主动关闭连接
ws.close(1000, 'Normal Closure');
ws.on('close', (code, reason) => {
console.log('客户端已断开连接');
console.log('状态码:', code);
console.log('原因:', reason.toString());
});
});
WebSocket 关闭连接的生命周期
-
OPEN → CLOSING:
- 当一端发送关闭帧后,连接进入 CLOSING 状态。
-
CLOSING → CLOSED:
- 当另一端也发送关闭帧后,连接进入 CLOSED 状态。
-
异常关闭:
- 如果未收到关闭帧(如网络中断),连接直接进入 CLOSED 状态。
WebSocket 的关闭帧是什么 (opcode = 0x8)
WebSocket 连接的关闭是通过 关闭握手 实现的:
- 发送关闭帧(包含状态码和原因短语)。
- 接收关闭帧并响应。
- 关闭底层 TCP 连接。
通过监听 onclose
事件,可以获取关闭的状态码和原因,便于调试和处理异常情况。
WebSocket 的关闭帧是什么
WebSocket 的 关闭帧(Close Frame) 是 WebSocket 协议中用于关闭连接的一种特殊数据帧。 关闭帧的作用是通知对方连接即将关闭,并可以携带关闭原因(状态码和原因短语)。
关闭帧的结构
关闭帧是 WebSocket 数据帧的一种,其结构如下:
字段 | 长度 | 描述 |
---|---|---|
FIN | 1 位 | 表示是否是消息的最后一帧(关闭帧必须为 1 )。 |
RSV1, RSV2, RSV3 | 各 1 位 | 保留字段,必须为 0 。 |
Opcode | 4 位 | 操作码,关闭帧的值为 0x8 。 |
Mask | 1 位 | 指示是否使用掩码(客户端到服务器的帧必须掩码)。 |
Payload length | 7/7+16/7+64 位 | 数据长度(关闭帧的 Payload 长度可以为 0 或 2 字节以上)。 |
Masking key | 4 字节(如果 Mask 为 1) | 掩码键(客户端到服务器的帧必须掩码)。 |
Payload data | 可变长度 | 关闭帧的有效载荷,包含状态码和原因短语(可选)。 |
关闭帧的有效载荷(Payload Data)
关闭帧的有效载荷可以包含以下内容:
-
状态码(Status Code) :
- 2 字节的无符号整数,表示关闭原因。
- 例如:
1000
(正常关闭)、1001
(端点离开)等。
-
原因短语(Reason Phrase) :
- 可选的 UTF-8 编码字符串,描述关闭原因。
- 最大长度为 123 字节(因为 WebSocket 帧的最大 Payload 长度为 125 字节,状态码占 2 字节)。
关闭帧的示例
以下是一个关闭帧的示例:
- 状态码 :
1000
(正常关闭)。 - 原因短语 :
"Normal Closure"
。
关闭帧的字节流
字节位置 | 值(十六进制) | 描述 |
---|---|---|
0 | 0x88 |
FIN=1, RSV1=0, RSV2=0, RSV3=0, Opcode=0x8(关闭帧)。 |
1 | 0x82 |
Mask=1, Payload length=2(状态码占 2 字节)。 |
2-5 | 0x37 0xFA 0x21 0x3D |
掩码键(随机生成的 4 字节)。 |
6-7 | 0x03 0xE8 |
状态码 1000 (0x03E8 是 1000 的十六进制表示)。 |
8-15 | 0x34 0x9F 0x45 0x6E 0x6F 0x72 0x6D 0x61 |
原因短语 "Normal Closure" 的掩码数据。 |
关闭帧的发送与接收
1. 发送关闭帧
-
客户端或服务器可以调用
close()
方法发送关闭帧。 -
示例(JavaScript):
javascriptconst socket = new WebSocket('ws://example.com'); socket.close(1000, 'Normal Closure');
2. 接收关闭帧
-
当一端收到关闭帧后,必须发送一个关闭帧作为响应。
-
示例(JavaScript):
javascriptsocket.onclose = (event) => { console.log('状态码:', event.code); console.log('原因:', event.reason); };
关闭帧的状态码
WebSocket 协议定义了一些标准的状态码,用于表示关闭原因:
状态码 | 名称 | 描述 |
---|---|---|
1000 | Normal Closure | 正常关闭 |
1001 | Going Away | 端点离开(如服务器关闭或浏览器导航离开) |
1002 | Protocol Error | 协议错误 |
1003 | Unsupported Data | 接收到不支持的数据(如文本帧接收二进制数据) |
1004 | Reserved | 保留 |
1005 | No Status Rcvd | 未收到状态码(用于占位) |
1006 | Abnormal Closure | 异常关闭(如未发送关闭帧) |
1007 | Invalid Frame Payload Data | 接收到无效的数据(如非 UTF-8 文本数据) |
1008 | Policy Violation | 策略违规 |
1009 | Message Too Big | 消息过大 |
1010 | Mandatory Extension | 需要扩展 |
1011 | Internal Server Error | 服务器内部错误 |
1015 | TLS Handshake | TLS 握手失败 |
总结
WebSocket 的关闭帧是用于关闭连接的特殊数据帧,其结构包括:
- Opcode :
0x8
。 - Payload:可选的关闭原因(状态码和原因短语)。
通过发送和接收关闭帧,WebSocket 连接可以优雅地关闭,并传递关闭原因
WebSocket 的心跳机制是什么
WebSocket 的 心跳机制(Heartbeat Mechanism) 是一种用于检测连接是否存活的机制。通过定期发送和接收 Ping/Pong 帧,客户端和服务器可以确认对方是否仍然在线,从而避免因长时间无通信而导致的连接超时或断开。
心跳机制的作用
-
检测连接状态:
- 通过定期发送 Ping 帧,检测对方是否仍然在线。
-
防止连接超时:
- 如果连接长时间无通信,可能会被防火墙、代理服务器或操作系统关闭。心跳机制可以保持连接活跃。
-
快速发现断线:
- 如果未收到 Pong 帧响应,可以快速发现连接已断开。
Ping/Pong 帧
WebSocket 协议定义了两种控制帧用于心跳机制:
-
Ping 帧:
- Opcode:
0x9
。 - 用于发送心跳检测。
- 可以携带少量数据(如时间戳)。
- Opcode:
-
Pong 帧:
- Opcode:
0xA
。 - 用于响应 Ping 帧。
- 必须携带与对应 Ping 帧相同的数据。
- Opcode:
心跳机制的实现
1. 客户端发送 Ping 帧
客户端可以定期向服务器发送 Ping 帧,检测服务器是否在线。
2. 服务器响应 Pong 帧
服务器收到 Ping 帧后,必须发送一个 Pong 帧作为响应。
3. 超时处理
如果客户端在指定时间内未收到 Pong 帧,可以认为连接已断开,并进行重连或其他处理。
心跳机制的示例
以下是一个简单的心跳机制实现示例:
1. 客户端实现(JavaScript)
javascript
const socket = new WebSocket('ws://example.com');
// 定时发送 Ping 帧
const heartbeatInterval = 30000; // 30 秒
let heartbeatTimer;
socket.onopen = () => {
console.log('WebSocket 连接已打开');
// 启动心跳机制
heartbeatTimer = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send('Ping'); // 发送 Ping 帧
}
}, heartbeatInterval);
};
// 监听 Pong 帧
socket.onmessage = (event) => {
if (event.data === 'Pong') {
console.log('收到 Pong 帧');
}
};
// 监听连接关闭事件
socket.onclose = () => {
console.log('WebSocket 连接已关闭');
// 清除心跳定时器
clearInterval(heartbeatTimer);
};
2. 服务器实现(Node.js + ws 库)
javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('客户端已连接');
// 监听 Ping 帧
ws.on('ping', (data) => {
console.log('收到 Ping 帧');
// 发送 Pong 帧
ws.pong(data);
});
// 监听连接关闭事件
ws.on('close', () => {
console.log('客户端已断开连接');
});
});
心跳机制的优化
-
动态调整心跳间隔:
- 根据网络状况动态调整心跳间隔,避免频繁发送 Ping 帧。
-
超时重连:
- 如果未收到 Pong 帧,可以尝试重连。
-
携带数据:
- 在 Ping 帧中携带时间戳或其他数据,用于计算延迟或诊断问题。
总结
WebSocket 的心跳机制通过 Ping/Pong 帧 实现,用于检测连接是否存活。客户端定期发送 Ping 帧,服务器响应 Pong 帧。如果未收到 Pong 帧,可以认为连接已断开,并进行相应处理。心跳机制是保持 WebSocket 连接稳定的重要手段。
如何实现 WebSocket 的加密传输(wss)
实现 WebSocket 的加密传输(wss)的步骤如下:
- 获取 SSL/TLS 证书。
- 配置服务器支持
wss
。 - 客户端通过
wss://
协议连接服务器。
通过 wss
,可以确保 WebSocket 通信的安全性,防止数据被窃听或篡改。
如何处理 WebSocket 跨域问题
览器跨域问题是指在Web开发中,由于浏览器的同源策略(Same-Origin Policy)限制,导致在一个域下的网页无法与其他域(协议、域名、端口有任何一个不同即为不同域)的资源进行交互或通信的情况
使用websocket解决跨域,首先也是需要服务端支持websocket相关的协议,可以用于两个页面之间的通信,A页面和A服务器正常通信,B页面通过websocket和A服务器通信,从而达到A页面和B页面的通信。这其实也是一个比较彻底的方案,绕过了浏览器的限制,如果有两个页面的通信,可以使用这个方案。不过我的经验,在日常中,websocket主要还是做服务端向前端推送的工作,做跨域的比较少。
- 当浏览器从一个域名下的页面向另一个域名服务器发起WebSocket连接时,就会涉及到跨域问题,
- WebSocket 是一种在客户端和服务器之间建立持久连接的通信协议,它可以用于实时通信和数据传输。由于 WebSocket 是一种独立的协议,不受同源策略的限制,因此它可以轻松解决跨域问题。下面是 WebSocket 如何解决跨域问题的简要说明:
- 不受同源策略限制:WebSocket 协议不受同源策略的限制,允许在不同域之间建立连接。
- 独立的协议:WebSocket 使用自己的协议,与 HTTP/HTTPS 不同,因此不受同源策略的限制。在初始握手期间,服务器可以使用适当的响应头来允许跨域连接。
- 服务器设置 :要允许跨域 WebSocket 连接,服务器端需要设置适当的响应头。通常,服务器会设置
Access-Control-Allow-Origin
头来指定允许的来源域。例如,可以将其设置为*
表示允许来自任何域的连接。
服务器端如何设置允许跨域 WebSocket 连接:
javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
// 设置允许跨域连接
wss.on('headers', (headers, req) => {
headers['Access-Control-Allow-Origin'] = '*';
});
通过上述设置,WebSocket 可以轻松解决跨域问题,实现不同域之间的实时通信和数据传输。
如何在 WebSocket 中实现身份认证
-
建立连接时验证身份 :在客户端发起 WebSocket 连接时,可以在握手阶段进行身份验证。这可以通过在连接 URL 中传递身份信息(如 token)或在连接的 HTTP 头部中包含身份验证信息来实现。
-
验证身份信息:在服务端接收到 WebSocket 连接请求后,可以解析连接 URL 或读取 HTTP 头部中的身份验证信息,并进行验证。这可能涉及检查 token 的有效性、检查用户权限等操作。
-
认证成功后建立连接:如果身份验证成功,服务端可以接受连接并与客户端建立 WebSocket 连接。否则,可以拒绝连接或断开连接。
-
维护身份信息:一旦身份验证成功,服务端可以在连接建立后维护用户的身份信息,以便在后续通信中使用。
c
#include <libwebsockets.h>
#include <string.h>
static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
return 0;
}
static int callback_websocket(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_ESTABLISHED: {
// 在连接建立时进行身份验证
const char *token = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
if (strcmp(token, "valid_token") == 0) {
// 身份验证成功,向客户端发送消息
char msg[] = "Authentication successful. You are now connected.";
lws_write(wsi, (unsigned char *)msg, strlen(msg), LWS_WRITE_TEXT);
} else {
// 身份验证失败,关闭连接
char msg[] = "Authentication failed. Connection refused.";
lws_write(wsi, (unsigned char *)msg, strlen(msg), LWS_WRITE_TEXT);
lws_close_reason(wsi, LWS_CLOSE_STATUS_POLICY_VIOLATION, NULL, 0);
}
break;
}
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{
"http-only",
callback_http,
0,
},
{
"websocket",
callback_websocket,
0,
},
{ NULL, NULL, 0, 0 }
};
int main() {
struct lws_context_creation_info info;
memset(&info, 0, sizeof(info));
struct lws_context *context = lws_create_context(&info);
if (!context) {
return -1;
}
int port = 8080;
const char *iface = NULL;
struct lws_vhost *vhost = lws_create_vhost(context, &port, iface, NULL, NULL, NULL, NULL);
if (!vhost) {
lws_context_destroy(context);
return -1;
}
while (1) {
lws_service(context, 50);
}
lws_context_destroy(context);
return 0;
}