mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-02 03:27:52 +08:00
Update websocket_chat, add websocket_chat_client
A number of people asked for a WebSocket client example, websocket_chat_client is one. PUBLISHED_FROM=c33e758c0a36a0aa919bdb6ef37ed1478d6b29e2
This commit is contained in:
parent
21665e367c
commit
5714056f9f
@ -18,42 +18,42 @@ static int is_websocket(const struct mg_connection *nc) {
|
|||||||
return nc->flags & MG_F_IS_WEBSOCKET;
|
return nc->flags & MG_F_IS_WEBSOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void broadcast(struct mg_connection *nc, const char *msg, size_t len) {
|
static void broadcast(struct mg_connection *nc, const struct mg_str msg) {
|
||||||
struct mg_connection *c;
|
struct mg_connection *c;
|
||||||
char buf[500];
|
char buf[500];
|
||||||
|
char addr[32];
|
||||||
|
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr),
|
||||||
|
MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT);
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%p %.*s", nc, (int) len, msg);
|
snprintf(buf, sizeof(buf), "%s %.*s", addr, (int) msg.len, msg.p);
|
||||||
|
printf("%s\n", buf); /* Local echo. */
|
||||||
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
||||||
|
if (c == nc) continue; /* Don't send to the sender. */
|
||||||
mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
|
mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||||
struct http_message *hm = (struct http_message *) ev_data;
|
|
||||||
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
|
||||||
|
|
||||||
switch (ev) {
|
switch (ev) {
|
||||||
case MG_EV_HTTP_REQUEST:
|
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
||||||
/* Usual HTTP request - serve static files */
|
|
||||||
mg_serve_http(nc, hm, s_http_server_opts);
|
|
||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
|
||||||
break;
|
|
||||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
|
|
||||||
/* New websocket connection. Tell everybody. */
|
/* New websocket connection. Tell everybody. */
|
||||||
broadcast(nc, "joined", 6);
|
broadcast(nc, mg_mk_str("++ joined"));
|
||||||
break;
|
break;
|
||||||
case MG_EV_WEBSOCKET_FRAME:
|
}
|
||||||
|
case MG_EV_WEBSOCKET_FRAME: {
|
||||||
|
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
||||||
/* New websocket message. Tell everybody. */
|
/* New websocket message. Tell everybody. */
|
||||||
broadcast(nc, (char *) wm->data, wm->size);
|
struct mg_str d = {(char *) wm->data, wm->size};
|
||||||
|
broadcast(nc, d);
|
||||||
break;
|
break;
|
||||||
case MG_EV_CLOSE:
|
}
|
||||||
|
case MG_EV_CLOSE: {
|
||||||
/* Disconnect. Tell everybody. */
|
/* Disconnect. Tell everybody. */
|
||||||
if (is_websocket(nc)) {
|
if (is_websocket(nc)) {
|
||||||
broadcast(nc, "left", 4);
|
broadcast(nc, mg_mk_str("-- left"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +63,8 @@ int main(void) {
|
|||||||
|
|
||||||
signal(SIGTERM, signal_handler);
|
signal(SIGTERM, signal_handler);
|
||||||
signal(SIGINT, signal_handler);
|
signal(SIGINT, signal_handler);
|
||||||
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
mg_mgr_init(&mgr, NULL);
|
mg_mgr_init(&mgr, NULL);
|
||||||
|
|
||||||
|
2
examples/websocket_chat_client/Makefile
Normal file
2
examples/websocket_chat_client/Makefile
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
PROG = websocket_chat_client
|
||||||
|
include ../examples.mk
|
99
examples/websocket_chat_client/websocket_chat_client.c
Normal file
99
examples/websocket_chat_client/websocket_chat_client.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Cesanta Software Limited
|
||||||
|
* All rights reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a WebSocket client example.
|
||||||
|
* Prints WS frames to stdout and forwards stdin to server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static int s_done = 0;
|
||||||
|
static int s_is_connected = 0;
|
||||||
|
|
||||||
|
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||||
|
struct websocket_message *wm = (struct websocket_message *) ev_data;
|
||||||
|
(void) nc;
|
||||||
|
|
||||||
|
switch (ev) {
|
||||||
|
case MG_EV_CONNECT: {
|
||||||
|
int status = *((int *) ev_data);
|
||||||
|
if (status != 0) {
|
||||||
|
printf("-- Connection error: %d\n", status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
||||||
|
printf("-- Connected\n");
|
||||||
|
s_is_connected = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MG_EV_POLL: {
|
||||||
|
char msg[500];
|
||||||
|
int n = 0;
|
||||||
|
#ifdef _WIN32 /* Windows console input is special. */
|
||||||
|
INPUT_RECORD inp[100];
|
||||||
|
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
DWORD i, num;
|
||||||
|
if (!PeekConsoleInput(h, inp, sizeof(inp) / sizeof(*inp), &num)) break;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
if (inp[i].EventType == KEY_EVENT &&
|
||||||
|
inp[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == num) break;
|
||||||
|
if (!ReadConsole(h, msg, sizeof(msg), &num, NULL)) break;
|
||||||
|
/* Un-unicode. This is totally not the right way to do it. */
|
||||||
|
for (i = 0; i < num * 2; i += 2) msg[i / 2] = msg[i];
|
||||||
|
n = (int) num;
|
||||||
|
#else /* For everybody else, we just read() stdin. */
|
||||||
|
fd_set read_set, write_set, err_set;
|
||||||
|
struct timeval timeout = {0, 0};
|
||||||
|
FD_ZERO(&read_set);
|
||||||
|
FD_ZERO(&write_set);
|
||||||
|
FD_ZERO(&err_set);
|
||||||
|
FD_SET(0 /* stdin */, &read_set);
|
||||||
|
if (select(1, &read_set, &write_set, &err_set, &timeout) == 1) {
|
||||||
|
n = read(0, msg, sizeof(msg));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (n <= 0) break;
|
||||||
|
while (msg[n - 1] == '\r' || msg[n - 1] == '\n') n--;
|
||||||
|
mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MG_EV_WEBSOCKET_FRAME: {
|
||||||
|
printf("%.*s\n", (int) wm->size, wm->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MG_EV_CLOSE: {
|
||||||
|
if (s_is_connected) printf("-- Disconnected\n");
|
||||||
|
s_done = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
struct mg_mgr mgr;
|
||||||
|
struct mg_connection *nc;
|
||||||
|
const char *chat_server_url = argc > 1 ? argv[1] : "ws://127.0.0.1:8000";
|
||||||
|
|
||||||
|
mg_mgr_init(&mgr, NULL);
|
||||||
|
|
||||||
|
nc = mg_connect_ws(&mgr, ev_handler, chat_server_url, "ws_chat", NULL);
|
||||||
|
if (nc == NULL) {
|
||||||
|
fprintf(stderr, "Invalid address\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!s_done) {
|
||||||
|
mg_mgr_poll(&mgr, 100);
|
||||||
|
}
|
||||||
|
mg_mgr_free(&mgr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -315,7 +315,10 @@ typedef struct stat cs_stat_t;
|
|||||||
#define to64(x) strtoll(x, NULL, 10)
|
#define to64(x) strtoll(x, NULL, 10)
|
||||||
#define INT64_FMT PRId64
|
#define INT64_FMT PRId64
|
||||||
#define INT64_X_FMT PRIx64
|
#define INT64_X_FMT PRIx64
|
||||||
|
|
||||||
|
#ifndef __cdecl
|
||||||
#define __cdecl
|
#define __cdecl
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#ifdef __va_copy
|
#ifdef __va_copy
|
||||||
|
Loading…
x
Reference in New Issue
Block a user