mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-15 02:08:08 +08:00
Merge pull request #2556 from cesanta/mt12m
add multi-threaded one to many example
This commit is contained in:
commit
b8bfa5565b
28
examples/multi-threaded-12m/Makefile
Normal file
28
examples/multi-threaded-12m/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
SOURCES = main.c mongoose.c # Source code files
|
||||
CFLAGS = -W -Wall -Wextra -g -I. # Build options
|
||||
|
||||
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
|
||||
CFLAGS_MONGOOSE +=
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD
|
||||
PROG ?= example.exe # Use .exe suffix for the binary
|
||||
CC = gcc # Use MinGW gcc compiler
|
||||
CFLAGS += -lws2_32 # Link against Winsock library
|
||||
CFLAGS += -Wno-cast-function-type # Thread functions return void instead of void *
|
||||
DELETE = cmd /C del /f /q /s # Command prompt command to delete files
|
||||
else
|
||||
# Mac, Linux
|
||||
PROG ?= example
|
||||
CFLAGS += -lpthread # Link against POSIX threads library
|
||||
DELETE = rm -rf
|
||||
endif
|
||||
|
||||
all: $(PROG)
|
||||
$(RUN) ./$(PROG) $(ARGS)
|
||||
|
||||
$(PROG): $(SOURCES)
|
||||
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) -o $@
|
||||
|
||||
clean:
|
||||
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM
|
1
examples/multi-threaded-12m/README.md
Normal file
1
examples/multi-threaded-12m/README.md
Normal file
@ -0,0 +1 @@
|
||||
See detailed tutorial at https://mongoose.ws/tutorials/multi-threaded/
|
92
examples/multi-threaded-12m/main.c
Normal file
92
examples/multi-threaded-12m/main.c
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2020-2023 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// Multithreading example.
|
||||
// On creation, we spawn a separate thread that sleeps for
|
||||
// some time to simulate some processing time, then produces an output and
|
||||
// sends that output to the parent connection.
|
||||
// That connection then broadcasts that data to all connected WebSocket
|
||||
// connections
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static void start_thread(void *(*f)(void *), void *p) {
|
||||
#ifdef _WIN32
|
||||
_beginthread((void(__cdecl *)(void *)) f, 0, p);
|
||||
#else
|
||||
#define closesocket(x) close(x)
|
||||
#include <pthread.h>
|
||||
pthread_t thread_id = (pthread_t) 0;
|
||||
pthread_attr_t attr;
|
||||
(void) pthread_attr_init(&attr);
|
||||
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&thread_id, &attr, f, p);
|
||||
pthread_attr_destroy(&attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct thread_data {
|
||||
struct mg_mgr *mgr;
|
||||
unsigned long conn_id; // Parent connection ID
|
||||
};
|
||||
|
||||
static void *thread_function(void *param) {
|
||||
struct thread_data *p = (struct thread_data *) param;
|
||||
printf("THREAD STARTED\n");
|
||||
for (;;) {
|
||||
sleep(2);
|
||||
mg_wakeup(p->mgr, p->conn_id, "hi!", 3); // Send to parent
|
||||
}
|
||||
// Free all resources that were passed to us
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// HTTP request callback
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN && c->is_listening) {
|
||||
// Start worker thread
|
||||
struct thread_data *data = calloc(1, sizeof(*data)); // Worker owns it
|
||||
data->conn_id = c->id;
|
||||
data->mgr = c->mgr;
|
||||
start_thread(thread_function, data); // Start thread and pass data
|
||||
} 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")) {
|
||||
mg_ws_upgrade(c, hm, NULL); // Upgrade HTTP to Websocket
|
||||
c->data[0] = 'W'; // Set some unique mark on a connection
|
||||
} 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);
|
||||
mg_iobuf_del(&c->recv, 0, c->recv.len);
|
||||
} else if (ev == MG_EV_WAKEUP) {
|
||||
struct mg_str *data = (struct mg_str *) ev_data;
|
||||
// Broadcast message to all connected websocket clients.
|
||||
// Traverse over all connections
|
||||
for (struct mg_connection *wc = c->mgr->conns; wc != NULL; wc = wc->next) {
|
||||
// Send only to marked connections
|
||||
if (wc->data[0] == 'W')
|
||||
mg_ws_send(wc, data->ptr, data->len, WEBSOCKET_OP_TEXT);
|
||||
}
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||
mg_http_listen(&mgr, "http://localhost:8000", fn, NULL); // Create listener
|
||||
mg_wakeup_init(&mgr); // Initialise wakeup socket pair
|
||||
for (;;) { // Event loop
|
||||
mg_mgr_poll(&mgr, 1000);
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
return 0;
|
||||
}
|
1
examples/multi-threaded-12m/mongoose.c
Symbolic link
1
examples/multi-threaded-12m/mongoose.c
Symbolic link
@ -0,0 +1 @@
|
||||
../../mongoose.c
|
1
examples/multi-threaded-12m/mongoose.h
Symbolic link
1
examples/multi-threaded-12m/mongoose.h
Symbolic link
@ -0,0 +1 @@
|
||||
../../mongoose.h
|
Loading…
x
Reference in New Issue
Block a user