windows C++ mongoose多线程服务端实例

C++ mongoose多线程实例
mongoose官网提供了多线程样例,但是没有兼容处理windows的场景,这是修改后可以兼容windows环境,并且加了消息的简单处理,可以在windows下实现多线程的http服务了。

#ifdef  _WIN32
#include 
#pragma comment(lib, "ws2_32.lib")
#endif 

#include 
#include 
#include 
using namespace std;

static sig_atomic_t s_received_signal = 0;
static const char *s_http_port = "8888";
static const int s_num_worker_threads = 5;
static unsigned long s_next_id = 0;

static void signal_handler(int sig_num) 
{
     
	signal(sig_num, signal_handler);
	s_received_signal = sig_num;
}
static struct mg_serve_http_opts s_http_server_opts;
static sock_t sock[2];

static void on_work_complete(struct mg_connection *nc, int ev, void *ev_data) 
{
     
	(void)ev;
	char s[32];
	struct mg_connection *c;
	for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) 
	{
     
		if (c->user_data != NULL) 
		{
     
			struct work_result *res = (struct work_result *)ev_data;
			if ((unsigned long)c->user_data == res->conn_id)
			{
     
				sprintf(s, "conn_id:%lu sleep:%d", res->conn_id, res->sleep_time);
				mg_send_head(c, 200, strlen(s), "Content-Type: text/plain");
				mg_printf(c, "%s", s);
			}
		}
	}
}
  
void *worker_thread_proc(void *param) 
{
     
	struct mg_mgr *mgr = (struct mg_mgr *) param;
	while (s_received_signal == 0) {
     
		struct work_request req = {
      0 };
		
		memset(&req, 0, sizeof(req));
		union socket_address sa;
		memset(&sa, 0, sizeof(sa));
		socklen_t sa_len = sizeof(sa);

		char recvBuf[4096];
		memset(recvBuf, 0, 4096);
		//if (recv(sock[1], revData,1024,0) == SOCKET_ERROR)//windows平台上使用
		//if (read(sock[1], &req, sizeof(req)) < 0)//该sock专门用于读 linux平台使用
#ifdef _WIN32
		if (recvfrom(sock[1], recvBuf, 4096, 0,&(sa.sa),(int *) sizeof(sa.sa) )< 0)
		{
     
			perror("Reading worker sock");
		}
#else
		if (read(sock[1], &req, sizeof(req)) < 0)//该sock专门用于读 linux平台使用
			perror("Reading worker sock");
#endif
		memcpy(&req, recvBuf, sizeof(work_request));
		//打印接收到的消息
		cout << req.conn_id << endl;
		string strUri = req.message.uri.p;
		strUri = strUri.substr(0, req.message.uri.len);
		cout << strUri << endl;
		string strMethod = req.message.method.p;
		strMethod = strMethod.substr(0, req.message.method.len);
		cout << strMethod << endl;
		
		int r = rand() % 10;
		sleep(r);
		struct work_result res = {
      req.conn_id, r };
		mg_broadcast(mgr, on_work_complete, (void *)&res, sizeof(res));
	}
	return NULL;
}

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) 
{
     
	(void)nc;
	(void)ev_data;

	switch (ev)
	{
     
	case MG_EV_ACCEPT:
		nc->user_data = (void *)++s_next_id;
		break;
	case MG_EV_HTTP_REQUEST: 
	{
     
		struct work_request req = {
      (unsigned long)nc->user_data };
		req.message = *(http_message* )ev_data;
		char sendBuf[4096];
		memset(sendBuf, 0, 4096);
		memcpy(sendBuf, &req, sizeof(work_request));

		union socket_address sa;
		memset(&sa, 0, sizeof(sa));
		socklen_t sa_len = sizeof(sa);
		//if (send(sock[0], sendData, 1024, 0) == SOCKET_ERROR)
		//if (write(sock[0], &req, sizeof(req)) < 0)//该sock专门用于写
		//给工作线程发消息 工作线程进行具体得消息处理
#ifdef _WIN32
		if (sendto(sock[0], sendBuf, sizeof(sendBuf), 0, &(sa.sa), sizeof(sa.sa)) < 0)
		{
     
			perror("Writing worker sock");
		}
#else
		if (write(sock[0], &req, sizeof(req)) < 0)//该sock专门用于写
			perror("Writing worker sock");
#endif
		break;
	}
	case MG_EV_CLOSE: 
	{
     
		if (nc->user_data) nc->user_data = NULL;
	}
	}
}

int main()
{
     
	struct mg_mgr mgr;
	struct mg_connection *nc;

#ifdef _WIN32
	//windows平台使用的时候 必须通过WSAStartup函数完成对Winsock服务的初始化
	WSADATA wsaDate;
	int nRet = WSAStartup(MAKEWORD(2, 1), &wsaDate);
	if (nRet != NO_ERROR)
	{
     
		perror("WSAStartup error");
		return -1;
	}
#endif

	//用于进程通信
	if (mg_socketpair(sock, SOCK_STREAM) == 0) {
     
		perror("Opening socket pair");
		return -1;
	}

	//定义信号 可用于一些特殊的处理 
	signal(SIGTERM, signal_handler);
	signal(SIGINT, signal_handler);

	mg_mgr_init(&mgr, NULL);

	//绑定端口
	nc = mg_bind(&mgr, s_http_port, ev_handler);
	if (nc == NULL) {
     
		printf("Failed to create listener\n");
		return 1;
	}

	//建立连接
	mg_set_protocol_http_websocket(nc);
	s_http_server_opts.document_root = ".";  // Serve current directory
	s_http_server_opts.enable_directory_listing = "no";

	//创建工作线程 具体的处理消息
	for (int i = 0; i < s_num_worker_threads; i++)
	{
     
		mg_start_thread(worker_thread_proc, &mgr);
	}

	printf("Started on port %s\n", s_http_port);
	while (s_received_signal == 0)
	{
     
		mg_mgr_poll(&mgr, 200);
	}

	mg_mgr_free(&mgr);

	closesocket(sock[0]);
	closesocket(sock[1]);

#ifdef _WIN32
	//解除与Socket库的绑定并且释放Socket库所占用的系统资源
	WSACleanup();
#endif 
	return 0;
}

你可能感兴趣的:(c++,c++,windows,mongoose,httpserver,多线程服务端)