coldforce
1.0.0
Coldforce は、さまざまなネットワーク プロトコルをサポートする C で書かれたライブラリです。このライブラリの非同期 API を使用すると、イベント駆動型のネットワーク アプリケーションを簡単に開発できます。現在サポートされているプロトコルは以下のとおりです。これらはすべて、クライアントとサーバー (マルチクライアント、C10K) をサポートします。
C99以降
-pthread
-lm
を使用します
OpenSSL または wolfSSL (TLS、https、および wss を使用する場合のみ)
wolfSSL ビルド オプション
IDE
#define OPENSSL_EXTRA
#define OPENSSL_ALL
#define HAVE_ALPN
#define HAVE_SNI
#define WOLFSSL_SYS_CA_CERTS
#define WOLFSSL_DTLS
#define WOLFSSL_DTLS13
mkdir inc/wolfssl
copy your user_settings.h to inc/wolfssl/.
configure
--enable-opensslextra --enable-opensslall --enable-alpn --enable-sni --enable-sys-ca-certs --enable-dtls --enable-dtls13
co_core.dll
/ libco_core.a
co_net.dll
/ libco_net.a
co_tls.dll
/ libco_tls.a
co_http.dll
/ libco_http.a
co_http2.dll
/ libco_http2.a
co_ws.dll
、 co_ws_http2.dll
/ libco_ws.a
、 libco_ws_http2.a
Windows Visual Studio (prj/msvc/coldforce.sln)
wolfSSL の場合 co_tls とプロジェクト プロパティの両方のC/C++ Preprocessor Definitions
にCO_USE_WOLFSSL
を追加します。
Linux cmake
cd build
cmake ..
make
wolfSSL用
...
cmake .. -DTLS_LIB=wolfssl
...
macOS cmake (Linux と同じ方法)
WebSocketクライアント
# include < coldforce.h >
# include < stdio.h >
# include < stdlib.h >
# include < string.h >
typedef struct {
co_app_t base_app;
co_ws_client_t * ws_client;
co_url_st* url;
} app_st;
void
app_on_ws_receive_frame (
app_st* self,
co_ws_client_t * ws_client,
const co_ws_frame_t * frame,
int error_code
)
{
if (error_code == 0 )
{
bool fin = co_ws_frame_get_fin (frame);
uint8_t opcode = co_ws_frame_get_opcode (frame);
size_t data_size = ( size_t ) co_ws_frame_get_payload_size (frame);
const uint8_t * data = co_ws_frame_get_payload_data (frame);
switch (opcode)
{
case CO_WS_OPCODE_TEXT:
{
printf ( " receive text(%d): %*.*s n " , fin,
( int )data_size, ( int )data_size, ( char *)data);
break ;
}
case CO_WS_OPCODE_BINARY:
{
printf ( " receive binary(%d): %zu bytes n " ,
fin, data_size);
break ;
}
case CO_WS_OPCODE_CONTINUATION:
{
printf ( " receive continuation(%d): %zu bytes n " ,
fin, data_size);
break ;
}
default :
{
co_ws_default_handler (ws_client, frame);
break ;
}
}
}
else
{
co_ws_client_destroy (ws_client);
self-> ws_client = NULL ;
}
}
void
app_on_ws_close (
app_st* self,
co_ws_client_t * ws_client
)
{
co_ws_client_destroy (ws_client);
self-> ws_client = NULL ;
co_app_stop ();
}
void
app_on_ws_upgrade (
app_st* self,
co_ws_client_t * ws_client,
const co_http_response_t * response,
int error_code
)
{
if (error_code == 0 )
{
co_ws_send_text (ws_client, " hello " );
}
else
{
co_ws_client_destroy (ws_client);
self-> ws_client = NULL ;
co_app_stop ();
}
}
void
app_on_ws_connect (
app_st* self,
co_ws_client_t * ws_client,
int error_code
)
{
if (error_code == 0 )
{
co_http_request_t * request =
co_http_request_create_ws_upgrade (self-> url -> path_and_query , NULL , NULL );
co_ws_send_upgrade_request (self-> ws_client , request);
}
else
{
co_ws_client_destroy (ws_client);
self-> ws_client = NULL ;
co_app_stop ();
}
}
bool
app_on_create (
app_st* self
)
{
self-> url = co_url_create ( " ws://127.0.0.1:8080/ " );
co_net_addr_t local_net_addr = { 0 };
co_net_addr_set_family (&local_net_addr, CO_NET_ADDR_FAMILY_IPV4);
self-> ws_client = co_ws_client_create (self-> url -> origin , &local_net_addr, NULL );
if (self-> ws_client == NULL )
{
return false ;
}
co_ws_callbacks_st* callbacks = co_ws_get_callbacks (self-> ws_client );
callbacks-> on_connect = (co_ws_connect_fn)app_on_ws_connect;
callbacks-> on_upgrade = (co_ws_upgrade_fn)app_on_ws_upgrade;
callbacks-> on_receive_frame = (co_ws_receive_frame_fn)app_on_ws_receive_frame;
callbacks-> on_close = (co_ws_close_fn)app_on_ws_close;
co_ws_start_connect (self-> ws_client );
return true ;
}
void
app_on_destroy (
app_st* self
)
{
co_ws_client_destroy (self-> ws_client );
co_url_destroy (self-> url );
}
int
main (
int argc,
char * argv[]
)
{
app_st self = { 0 };
return co_net_app_start (
( co_app_t *)&self, " ws-client-app " ,
(co_app_create_fn)app_on_create,
(co_app_destroy_fn)app_on_destroy,
argc, argv);
}
WebSocket エコーサーバー -> ws://127.0.0.1:8080
# include < coldforce.h >
typedef struct {
co_app_t base_app;
co_tcp_server_t * tcp_server;
co_list_t * ws_clients;
} app_st;
void
app_on_ws_receive_frame (
app_st* self,
co_ws_client_t * ws_client,
const co_ws_frame_t * frame,
int error_code
)
{
if (error_code == 0 )
{
bool fin = co_ws_frame_get_fin (frame);
uint8_t opcode = co_ws_frame_get_opcode (frame);
size_t data_size = ( size_t ) co_ws_frame_get_payload_size (frame);
const uint8_t * data = co_ws_frame_get_payload_data (frame);
switch (opcode)
{
case CO_WS_OPCODE_TEXT:
case CO_WS_OPCODE_BINARY:
case CO_WS_OPCODE_CONTINUATION:
{
co_ws_send (ws_client, fin, opcode, data, data_size);
break ;
}
default :
{
co_ws_default_handler (ws_client, frame);
break ;
}
}
}
else
{
co_list_remove (self-> ws_clients , ws_client);
}
}
void
app_on_ws_close (
app_st* self,
co_ws_client_t * ws_client
)
{
co_list_remove (self-> ws_clients , ws_client);
}
void
app_on_ws_upgrade (
app_st* self,
co_ws_client_t * ws_client,
const co_http_request_t * http_request,
int error_code
)
{
if (error_code == 0 )
{
co_http_response_t * http_response =
co_http_response_create_ws_upgrade (http_request, NULL , NULL );
co_http_connection_send_response (
( co_http_connection_t *)ws_client, http_response);
co_http_response_destroy (http_response);
}
else
{
co_list_remove (self-> ws_clients , ws_client);
}
}
void
app_on_tcp_accept (
app_st* self,
co_tcp_server_t * tcp_server,
co_tcp_client_t * tcp_client
)
{
co_tcp_accept (( co_thread_t *)self, tcp_client);
co_ws_client_t * ws_client = co_tcp_upgrade_to_ws (tcp_client, NULL );
co_ws_callbacks_st* callbacks = co_ws_get_callbacks (ws_client);
callbacks-> on_upgrade = (co_ws_upgrade_fn)app_on_ws_upgrade;
callbacks-> on_receive_frame = (co_ws_receive_frame_fn)app_on_ws_receive_frame;
callbacks-> on_close = (co_ws_close_fn)app_on_ws_close;
co_list_add_tail (self-> ws_clients , ws_client);
}
bool
app_on_create (
app_st* self
)
{
uint16_t port = 8080 ;
co_list_ctx_st list_ctx = { 0 };
list_ctx. destroy_value = (co_item_destroy_fn)co_ws_client_destroy;
self-> ws_clients = co_list_create (&list_ctx);
co_net_addr_t local_net_addr = { 0 };
co_net_addr_set_family (&local_net_addr, CO_NET_ADDR_FAMILY_IPV4);
co_net_addr_set_port (&local_net_addr, port);
self-> tcp_server = co_tcp_server_create (&local_net_addr);
co_socket_option_set_reuse_addr (
co_tcp_server_get_socket (self-> tcp_server ), true );
co_tcp_server_callbacks_st* callbacks =
co_tcp_server_get_callbacks (self-> tcp_server );
callbacks-> on_accept = (co_tcp_accept_fn)app_on_tcp_accept;
return co_tcp_server_start (self-> tcp_server , SOMAXCONN);
}
void
app_on_destroy (
app_st* self
)
{
co_tcp_server_destroy (self-> tcp_server );
co_list_destroy (self-> ws_clients );
}
int
main (
int argc,
char * argv[]
)
{
app_st self = { 0 };
return co_net_app_start (
( co_app_t *)&self, " ws-server-app " ,
(co_app_create_fn)app_on_create,
(co_app_destroy_fn)app_on_destroy,
argc, argv);
}
その他の例はこちら