天天看點

c語言 socket.io,純C語言版本的socket.io伺服器端實作

前言

哈,這又是一個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

本文來源:聶永的部落格