前言
哈,這又是一個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
#include
#include
typedefstruct{
char*message_type;
char*message_id;
char*endpoint;
char*message_data;
char*ori_data;
} message_fields;
typedefstruct{
char*endpoint;
void(*on_init)(constchar*endpoint);
void(*on_connect)(constchar*sessionid);
void(*on_message)(constchar*sessionid,constmessage_fields *msg_fields);
void(*on_json_message)(constchar*sessionid,constmessage_fields *msg_fields);
void(*on_event)(constchar*sessionid,constmessage_fields *msg_fields);
void(*on_other)(constchar*sessionid,constmessage_fields *msg_fields);
void(*on_disconnect)(constchar*sessionid,constmessage_fields *msg_fields);
void(*on_destroy)(constchar*endpoint);
} endpoint_implement;
externvoidsend_msg(char*sessionid,char*message);
externvoidbroadcast_clients(char*except_sessionid,char*message);
staticvoidon_init(constchar*endpoint);
staticvoidon_connect(constchar*sessionid);
staticvoidon_message(constchar*sessionid,constmessage_fields *msg_fields) {
printf("on_message recevie ori msg is %s\n", msg_fields->ori_data);
}
staticvoidon_json_message(constchar*sessionid,constmessage_fields *msg_fields) {
printf("on_json_message recevie ori msg is %s\n", msg_fields->ori_data);
}
staticvoidon_other(constchar*sessionid,constmessage_fields *msg_fields) {
printf("on_other recevie ori msg is %s\n", msg_fields->ori_data);
}
staticvoidon_event(constchar*sessionid,constmessage_fields *msg_fields);
staticvoidon_disconnect(constchar*sessionid,constmessage_fields *msg_fields);
staticvoidon_destroy(constchar*endpoint);
staticendpoint_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;
returnimpl_point;
}
完整定義.
在example目錄中,你可以看到聊天室示範chatroom 和線上白闆示範whiteboard .
#include
#include
#include
#include
#include "../endpoint_impl.h"
typedefstruct{
char*event_name;
char*event_args;
} event_message;
staticchar*event_message_reg ="{\"name\":\"(.*?)\",\"args\":\\[([^\\]]*?)\\]}";
staticgchar *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);
returnresult;
}
staticvoid*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 );
returnevent_msg;
}
staticGHashTable *hashtable;
staticvoidhashtable_init(void) {
hashtable = g_hash_table_new(g_str_hash, g_str_equal);
}
staticvoidhashtable_add(constchar*key,void*value) {
if(key) {
g_hash_table_insert(hashtable, g_strdup(key), value);
}
}
staticgboolean hashtable_remove(constchar*key) {
if(key)
returng_hash_table_remove(hashtable, key);
return0;
}
staticvoid*hashtable_lookup(constchar*key) {
if(key == NULL)
returnNULL;
returng_hash_table_lookup(hashtable, key);
}
staticvoidhashtable_destroy(void) {
g_hash_table_destroy(hashtable);
}
staticchar*endpoint_name;
staticvoidon_init(constchar*endpoint) {
hashtable_init();
printf("%s has been inited now\n", endpoint);
endpoint_name = g_strdup(endpoint);
}
staticvoidon_connect(constchar*sessionid) {
charmessages[strlen(sessionid) + 50];
sprintf(messages,"5::%s:{\"name\":\"clientId\",\"args\":[{\"id\":\"%s\"}]}", endpoint_name, sessionid);
send_msg(sessionid, messages);
}
staticvoidsend_it(char*session_id,char*messaage) {
send_msg(session_id, messaage);
}
staticvoidfree_event_msg(event_message *event_msg) {
free(event_msg->event_name);
free(event_msg->event_args);
}
staticvoidon_event(constchar*sessionid,constmessage_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")) {
chartarget_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));
introom_count = list->len;
charmessages[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;
}
charmessages[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;
}
inti;
for(i = 0; i len; i++) {
char*session_id = g_ptr_array_index(list, i);
if(strcmp(session_id, sessionid) == 0)
continue;
send_msg(session_id, messages);
}
}
staticvoidon_disconnect(constchar*sessionid,constmessage_fields *msg_fields) {
char*room_id = (char*)hashtable_lookup(sessionid);
if(room_id == NULL) {
fprintf(stderr,"the room_id is NULL\n");
return;
}
charnotice_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);
inti, remove_index;
for(i = 0; i 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);
}
staticvoidon_destroy(constchar*endpoint) {
printf("%s has been destroy now\n", endpoint);
hashtable_destroy();
free(endpoint_name);
}
externendpoint_implement *init_whiteboard_endpoint_implement(char*endpoint_name) {
returninit_default_endpoint_implement(endpoint_name);
}
因為C語言中沒有散清單,隻好借助于成熟的glib庫實作。
其它
項目不太成熟,期待大家的參與,您的建議、批評和指正,都是一種激勵,再次表示感謝。
原文連結:http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html
本文來源:聶永的部落格