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_USE_WOLFSSL
в C/C++ Preprocessor Definitions
как в co_tls, так и в свойстве вашего проекта.
Linux cmake
cd build
cmake ..
make
для волкаSSL
...
cmake .. -DTLS_LIB=wolfssl
...
macOS cmake (так же, как Linux)
Вебсокет-клиент
# 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);
}
больше примеров здесь