前言
哈,这又是一个socket.io服务端实现,本意是,拿C练练手,加强对C和linux系统的理解,写着写着,就写成了一个socket.io服务器端实现了。以为半成品,那就正式托管在github站点上吧,以便记录一下,可让大家批评与指正,加强内功的修炼等。
项目地址为:yongboy/c_socket.io_server
以下部分文字,偷懒,摘录自项目的README.md文件
说明
这是一个纯C语言版本的socket.io服务器端实现,目前仅支持linux系统,严重依赖libev and glib等基础库。
在运行socket.io_server之前,需要安装以下依赖:
- sudo apt-get install uuid-dev
- sudo apt-get install libglib2.0-dev
如何运行
- 编写实现代码(eg:chatroom.c),需要包含头文件 endpoint_impl.h
- 把实现代码(eg:chatroom.c)放入examples目录
- 编写对应的html文件,放入static目录
- 编辑Makefile文件
- 终端下运行make命令
- 然后敲入 ./socket.io_server 接口运行
- 打开浏览器即可访问 (eg:http://localhost:8000/chatroom.html)
API说明
对外的API,可以在头文件 endpoint_impl.h 看到其定义,其继承了另外一个公用的头文件 endpoint.h, 其完整定义为:
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- typedef struct {
- char *message_type;
- char *message_id;
- char *endpoint;
- char *message_data;
- char *ori_data;
- } message_fields;
- typedef struct {
- char *endpoint;
- void (*on_init)(const char *endpoint);
- void (*on_connect)(const char *sessionid);
- void (*on_message)(const char *sessionid, const message_fields *msg_fields);
- void (*on_json_message)(const char *sessionid, const message_fields *msg_fields);
- void (*on_event)(const char *sessionid, const message_fields *msg_fields);
- void (*on_other)(const char *sessionid, const message_fields *msg_fields);
- void (*on_disconnect)(const char *sessionid, const message_fields *msg_fields);
- void (*on_destroy)(const char *endpoint);
- } endpoint_implement;
- extern void send_msg(char *sessionid, char *message);
- extern void broadcast_clients(char *except_sessionid, char *message);
- static void on_init(const char *endpoint);
- static void on_connect(const char *sessionid);
- static void on_message(const char *sessionid, const message_fields *msg_fields) {
- printf("on_message recevie ori msg is %s\n", msg_fields->ori_data);
- }
- static void on_json_message(const char *sessionid, const message_fields *msg_fields) {
- printf("on_json_message recevie ori msg is %s\n", msg_fields->ori_data);
- }
- static void on_other(const char *sessionid, const message_fields *msg_fields) {
- printf("on_other recevie ori msg is %s\n", msg_fields->ori_data);
- }
- static void on_event(const char *sessionid, const message_fields *msg_fields);
- static void on_disconnect(const char *sessionid, const message_fields *msg_fields);
- static void on_destroy(const char *endpoint);
- static endpoint_implement *init_default_endpoint_implement(char *endpoint_name) {
- endpoint_implement *impl_point = (endpoint_implement *)malloc(sizeof(endpoint_implement));
- impl_point->endpoint = strdup(endpoint_name);
- impl_point->on_init = on_init;
- impl_point->on_connect = on_connect;
- impl_point->on_message = on_message;
- impl_point->on_json_message = on_json_message;
- impl_point->on_event = on_event;
- impl_point->on_other = on_other;
- impl_point->on_disconnect = on_disconnect;
- impl_point->on_destroy = on_destroy;
- return impl_point;
- }
完整定义.
在example目录中,你可以看到聊天室演示chatroom 和在线白板示范whiteboard .
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <glib.h>
- #include "../endpoint_impl.h"
- typedef struct {
- char *event_name;
- char *event_args;
- } event_message;
- static char *event_message_reg = "{\"name\":\"(.*?)\",\"args\":\\[([^\\]]*?)\\]}";
- static gchar *get_match_result(GMatchInfo *match_info, gint index) {
- gchar *match = g_match_info_fetch(match_info, index);
- gchar *result = g_strdup(match);
- g_free(match);
- return result;
- }
- static void *message_2_struct(gchar *post_string, event_message *event_msg) {
- GError *error = NULL;
- GRegex *regex;
- GMatchInfo *match_info;
- regex = g_regex_new(event_message_reg, 0, 0, &error );
- g_regex_match( regex, post_string, 0, &match_info );
- if (g_match_info_matches(match_info)) {
- event_msg->event_name = get_match_result(match_info, 1);
- event_msg->event_args = get_match_result(match_info, 2);
- } else {
- event_msg = NULL;
- }
- g_match_info_free( match_info );
- g_regex_unref( regex );
- return event_msg;
- }
- static GHashTable *hashtable;
- static void hashtable_init(void) {
- hashtable = g_hash_table_new(g_str_hash, g_str_equal);
- }
- static void hashtable_add(const char *key, void *value) {
- if (key) {
- g_hash_table_insert(hashtable, g_strdup(key), value);
- }
- }
- static gboolean hashtable_remove(const char *key) {
- if (key)
- return g_hash_table_remove(hashtable, key);
- return 0;
- }
- static void *hashtable_lookup(const char *key) {
- if (key == NULL)
- return NULL;
- return g_hash_table_lookup(hashtable, key);
- }
- /*static gint hashtable_size(void) {
- return g_hash_table_size(hashtable);
- }*/
- static void hashtable_destroy(void) {
- g_hash_table_destroy(hashtable);
- }
- /**
- ** use the struct to warpper the demo implment
- **/
- static char *endpoint_name;
- static void on_init(const char *endpoint) {
- hashtable_init();
- printf("%s has been inited now\n", endpoint);
- endpoint_name = g_strdup(endpoint);
- }
- static void on_connect(const char *sessionid) {
- char messages[strlen(sessionid) + 50];
- sprintf(messages, "5::%s:{\"name\":\"clientId\",\"args\":[{\"id\":\"%s\"}]}", endpoint_name, sessionid);
- send_msg(sessionid, messages);
- }
- static void send_it(char *session_id, char *messaage) {
- send_msg(session_id, messaage);
- }
- static void free_event_msg(event_message *event_msg) {
- free(event_msg->event_name);
- free(event_msg->event_args);
- }
- static void on_event(const char *sessionid, const message_fields *msg_fields) {
- event_message event_msg;
- if (!message_2_struct(msg_fields->message_data, &event_msg)) {
- fprintf(stderr, "%s Parse Message Error !\n", msg_fields->ori_data);
- return;
- }
- if (!strcmp(event_msg.event_name, "roomNotice")) {
- /*5::/whiteboard:{"name":"roomNotice","args":[{"room":"myRoom"}]}*/
- char target_room_id[strlen(event_msg.event_args) - 10];// = event_msg.event_args + 9;
- strncpy(target_room_id, event_msg.event_args + 9, strlen(event_msg.event_args) - 11);
- GPtrArray *list = (GPtrArray *)hashtable_lookup(target_room_id);
- if (list == NULL) {
- list = g_ptr_array_new();
- hashtable_add(target_room_id, list);
- }
- g_ptr_array_add(list, g_strdup(sessionid));
- int room_count = list->len;
- char messages[strlen(sessionid) + 200];
- sprintf(messages, "5::%s:{\"name\":\"roomCount\",\"args\":[{\"room\":\"%s\",\"num\":%d}]}", endpoint_name, target_room_id, room_count);
- hashtable_add(g_strdup(sessionid), g_strdup(target_room_id));
- g_ptr_array_foreach(list, (GFunc)send_it, messages);
- free_event_msg(&event_msg);
- return;
- }
- char messages[strlen(msg_fields->ori_data) + 200];
- sprintf(messages, "5::%s:{\"name\":\"%s\",\"args\":[%s]}", endpoint_name, event_msg.event_name, event_msg.event_args);
- free_event_msg(&event_msg);
- char *target_room_id = (char *)hashtable_lookup(sessionid);
- GPtrArray *list = (GPtrArray *)hashtable_lookup(target_room_id);
- if(list == NULL){
- return;
- }
- int i;
- for (i = 0; i < list->len; i++) {
- char *session_id = g_ptr_array_index(list, i);
- if (strcmp(session_id, sessionid) == 0)
- continue;
- send_msg(session_id, messages);
- }
- }
- static void on_disconnect(const char *sessionid, const message_fields *msg_fields) {
- char *room_id = (char *)hashtable_lookup(sessionid);
- if (room_id == NULL) {
- fprintf(stderr, "the room_id is NULL\n");
- return;
- }
- char notice_msg[strlen(endpoint_name) + strlen(room_id) + 70];
- GPtrArray *list = (GPtrArray *)hashtable_lookup(room_id);
- sprintf(notice_msg, "5::%s:{\"name\":\"roomCount\",\"args\":[{\"room\":\"%s\",\"num\":%d}]}", endpoint_name, room_id, list->len - 1);
- int i, remove_index;
- for (i = 0; i < list->len; i++) {
- char *session_id = g_ptr_array_index(list, i);
- if (strcmp(session_id, sessionid) == 0) {
- remove_index = i;
- continue;
- }
- send_msg(session_id, notice_msg);
- }
- g_ptr_array_remove_index(list, remove_index);
- hashtable_remove(sessionid);
- free(room_id);
- }
- static void on_destroy(const char *endpoint) {
- printf("%s has been destroy now\n", endpoint);
- hashtable_destroy();
- free(endpoint_name);
- }
- extern endpoint_implement *init_whiteboard_endpoint_implement(char *endpoint_name) {
- return init_default_endpoint_implement(endpoint_name);
- }
因为C语言中没有散列表,只好借助于成熟的glib库实现。
其它
项目不太成熟,期待大家的参与,您的建议、批评和指正,都是一种激励,再次表示感谢。
原文链接:http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html