完成tcp服务器/客户端 c api

This commit is contained in:
xiongziliang 2019-12-26 21:22:19 +08:00
parent 56397628da
commit 11a7d1e6c4
10 changed files with 658 additions and 329 deletions

View File

@ -27,6 +27,7 @@
#ifndef MK_EVENT_OBJECTS_H #ifndef MK_EVENT_OBJECTS_H
#define MK_EVENT_OBJECTS_H #define MK_EVENT_OBJECTS_H
#include "common.h" #include "common.h"
#include "tcp.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -123,24 +124,6 @@ API_EXPORT void API_CALL mk_media_source_find(const char *schema,
//MediaSource::for_each_media() //MediaSource::for_each_media()
API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb); API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb);
///////////////////////////////////////////TcpSession/////////////////////////////////////////////
//TcpSession对象的C映射
typedef void* mk_tcp_session;
//TcpSession::safeShutdown()
API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int err,const char *err_msg);
//TcpSession::get_peer_ip()
API_EXPORT const char* API_CALL mk_tcp_session_peer_ip(const mk_tcp_session ctx);
//TcpSession::get_local_ip()
API_EXPORT const char* API_CALL mk_tcp_session_local_ip(const mk_tcp_session ctx);
//TcpSession::get_peer_port()
API_EXPORT uint16_t API_CALL mk_tcp_session_peer_port(const mk_tcp_session ctx);
//TcpSession::get_local_port()
API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx);
//TcpSession::send()
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len);
//切换到该对象所在线程后再TcpSession::send()
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len);
///////////////////////////////////////////HttpBody///////////////////////////////////////////// ///////////////////////////////////////////HttpBody/////////////////////////////////////////////
//HttpBody对象的C映射 //HttpBody对象的C映射
typedef void* mk_http_body; typedef void* mk_http_body;

View File

@ -35,6 +35,6 @@
#include "player.h" #include "player.h"
#include "pusher.h" #include "pusher.h"
#include "events.h" #include "events.h"
#include "websocket.h" #include "tcp.h"
#endif /* MK_API_H_ */ #endif /* MK_API_H_ */

226
api/include/tcp.h Normal file
View File

@ -0,0 +1,226 @@
/*
* MIT License
*
* Copyright (c) 2019 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef MK_TCP_H
#define MK_TCP_H
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////TcpSession/////////////////////////////////////////////
//TcpSession对象的C映射
typedef void* mk_tcp_session;
//TcpSession::safeShutdown()
API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int err,const char *err_msg);
//TcpSession::get_peer_ip()
API_EXPORT const char* API_CALL mk_tcp_session_peer_ip(const mk_tcp_session ctx);
//TcpSession::get_local_ip()
API_EXPORT const char* API_CALL mk_tcp_session_local_ip(const mk_tcp_session ctx);
//TcpSession::get_peer_port()
API_EXPORT uint16_t API_CALL mk_tcp_session_peer_port(const mk_tcp_session ctx);
//TcpSession::get_local_port()
API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx);
//TcpSession::send()
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len);
//切换到该对象所在线程后再TcpSession::send()
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len);
///////////////////////////////////////////自定义tcp服务/////////////////////////////////////////////
typedef struct {
/**
* mk_tcp_session创建对象
* @param server_port
* @param session
*/
void (API_CALL *on_mk_tcp_session_create)(uint16_t server_port,mk_tcp_session session);
/**
*
* @param server_port
* @param session
* @param data
* @param len
*/
void (API_CALL *on_mk_tcp_session_data)(uint16_t server_port,mk_tcp_session session,const char *data,int len);
/**
* 2
* @param server_port
* @param session
*/
void (API_CALL *on_mk_tcp_session_manager)(uint16_t server_port,mk_tcp_session session);
/**
* tcp触发
* @param server_port
* @param session
* @param code
* @param msg
*/
void (API_CALL *on_mk_tcp_session_disconnect)(uint16_t server_port,mk_tcp_session session,int code,const char *msg);
} mk_tcp_session_events;
typedef enum {
//普通的tcp
mk_type_tcp = 0,
//ssl类型的tcp
mk_type_ssl = 1,
//基于websocket的连接
mk_type_ws = 2,
//基于ssl websocket的连接
mk_type_wss = 3
}mk_tcp_type;
/**
* tcp会话对象附着用户数据
* mk_tcp_server_server_start启动的服务类型有效
* @param session
* @param user_data
*/
API_EXPORT void API_CALL mk_tcp_session_set_user_data(mk_tcp_session session,void *user_data);
/**
* tcp会话对象上附着的用户数据
* mk_tcp_server_server_start启动的服务类型有效
* @param session tcp会话对象
* @return
*/
API_EXPORT void* API_CALL mk_tcp_session_get_user_data(mk_tcp_session session);
/**
* tcp服务器
* @param port 0
* @param type
*/
API_EXPORT uint16_t API_CALL mk_tcp_server_server_start(uint16_t port, mk_tcp_type type);
/**
* tcp服务器事件
*/
API_EXPORT void API_CALL mk_tcp_server_events_listen(const mk_tcp_session_events *events);
///////////////////////////////////////////自定义tcp客户端/////////////////////////////////////////////
typedef void* mk_tcp_client;
typedef struct {
/**
* tcp客户端连接服务器成功或失败回调
* @param client tcp客户端
* @param code 0
* @param msg
*/
void (API_CALL *on_mk_tcp_client_connect)(mk_tcp_client client,int code,const char *msg);
/**
* tcp客户端与tcp服务器之间断开回调
* eof事件导致
* @param client tcp客户端
* @param code
* @param msg
*/
void (API_CALL *on_mk_tcp_client_disconnect)(mk_tcp_client client,int code,const char *msg);
/**
* tcp服务器发来的数据
* @param client tcp客户端
* @param data
* @param len
*/
void (API_CALL *on_mk_tcp_client_data)(mk_tcp_client client,const char *data,int len);
/**
* 2
* @param client tcp客户端
*/
void (API_CALL *on_mk_tcp_client_manager)(mk_tcp_client client);
} mk_tcp_client_events;
/**
* tcp客户端
* @param events
* @param user_data
* @param type
* @return
*/
API_EXPORT mk_tcp_client API_CALL mk_tcp_client_create(mk_tcp_client_events *events, mk_tcp_type type);
/**
* tcp客户端
* @param ctx
*/
API_EXPORT void API_CALL mk_tcp_client_release(mk_tcp_client ctx);
/**
*
* @param ctx
* @param host ip或域名
* @param port
* @param time_out_sec
*/
API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *host, uint16_t port, float time_out_sec);
/**
* 线
* 线
* @param ctx
* @param data
* @param len 0strlen获取
*/
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len);
/**
* 线
* @param ctx
* @param data
* @param len 0strlen获取
*/
API_EXPORT void API_CALL mk_tcp_client_send_safe(mk_tcp_client ctx, const char *data, int len);
/**
*
* @param ctx
* @param user_data
*/
API_EXPORT void API_CALL mk_tcp_client_set_user_data(mk_tcp_client ctx,void *user_data);
/**
*
* @param ctx
* @return
*/
API_EXPORT void* API_CALL mk_tcp_client_get_user_data(mk_tcp_client ctx);
#ifdef __cplusplus
}
#endif
#endif //MK_TCP_H

View File

@ -1,105 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2019 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef MK_WEBSOCKET_H
#define MK_WEBSOCKET_H
#include "common.h"
#include "events_objects.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
/**
* websocket客户端连接服务器时触发
* @param session
*/
void (API_CALL *on_mk_websocket_session_create)(mk_tcp_session session);
/**
* session会话对象销毁时触发
*
* mk_tcp_session_send/mk_tcp_session_send_safe函数
* @param session
*/
void (API_CALL *on_mk_websocket_session_destory)(mk_tcp_session session);
/**
* websocket客户端发过来的数据
* @param session
* @param data
* @param len
*/
void (API_CALL *on_mk_websocket_session_data)(mk_tcp_session session,const char *data,int len);
/**
* 2
* @param session
*/
void (API_CALL *on_mk_websocket_session_manager)(mk_tcp_session session);
/**
* on_mk_websocket_session_destory之前触发on_mk_websocket_session_err
* tcp触发
* mk_tcp_session_send_safe函数
* @param session
* @param code
* @param msg
*/
void (API_CALL *on_mk_websocket_session_err)(mk_tcp_session session,int code,const char *msg);
} mk_websocket_events;
API_EXPORT void API_CALL mk_websocket_events_listen(const mk_websocket_events *events);
/**
* websocket会话对象附着用户数据
* @param session websocket会话对象
* @param user_data
*/
API_EXPORT void API_CALL mk_websocket_session_set_user_data(mk_tcp_session session,void *user_data);
/**
* websocket会话对象上附着的用户数据
* @param session websocket会话对象
* @return
*/
API_EXPORT void* API_CALL mk_websocket_session_get_user_data(mk_tcp_session session);
/**
* websocket服务器,websocket服务器包含了Http服务器的所有功能
* mk_websocket_server_start后不用再调用mk_http_server_start
* @param port 0
* @param ssl wss/ws
* @return 0
*/
API_EXPORT uint16_t API_CALL mk_websocket_server_start(uint16_t port, int ssl);
#ifdef __cplusplus
}
#endif
#endif //MK_WEBSOCKET_H

View File

@ -64,7 +64,7 @@ API_EXPORT void API_CALL mk_env_init(const mk_config *cfg) {
cfg->ssl_pwd); cfg->ssl_pwd);
} }
extern void mk_websocket_server_stop(); extern void stopAllTcpServer();
API_EXPORT void API_CALL mk_stop_all_server(){ API_EXPORT void API_CALL mk_stop_all_server(){
CLEAR_ARR(rtsp_server); CLEAR_ARR(rtsp_server);
@ -72,7 +72,7 @@ API_EXPORT void API_CALL mk_stop_all_server(){
CLEAR_ARR(http_server); CLEAR_ARR(http_server);
udpRtpServer = nullptr; udpRtpServer = nullptr;
tcpRtpServer = nullptr; tcpRtpServer = nullptr;
mk_websocket_server_stop(); stopAllTcpServer();
} }
API_EXPORT void API_CALL mk_env_init1( int thread_num, API_EXPORT void API_CALL mk_env_init1( int thread_num,

View File

@ -228,60 +228,6 @@ API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_s
}); });
} }
///////////////////////////////////////////TcpSession/////////////////////////////////////////////
API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int err,const char *err_msg){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
session->safeShutdown(SockException((ErrCode)err,err_msg));
}
API_EXPORT const char* API_CALL mk_tcp_session_peer_ip(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_peer_ip().c_str();
}
API_EXPORT const char* API_CALL mk_tcp_session_local_ip(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_local_ip().c_str();
}
API_EXPORT uint16_t API_CALL mk_tcp_session_peer_port(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_peer_port();
}
API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_local_port();
}
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len){
assert(ctx && data);
if(!len){
len = strlen(data);
}
TcpSession *session = (TcpSession *)ctx;
session->send(data,len);
}
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len){
assert(ctx && data);
if(!len){
len = strlen(data);
}
try {
weak_ptr<TcpSession> weak_session = ((TcpSession *)ctx)->shared_from_this();
string str = string(data,len);
((TcpSession *)ctx)->async([weak_session,str](){
auto session_session = weak_session.lock();
if(session_session){
session_session->send(str);
}
});
}catch (std::exception &ex){
WarnL << "can not got the strong pionter of this mk_tcp_session:" << ex.what();
}
}
///////////////////////////////////////////HttpBody///////////////////////////////////////////// ///////////////////////////////////////////HttpBody/////////////////////////////////////////////
API_EXPORT mk_http_body API_CALL mk_http_body_from_string(const char *str,int len){ API_EXPORT mk_http_body API_CALL mk_http_body_from_string(const char *str,int len){
assert(str); assert(str);

299
api/source/tcp.cpp Normal file
View File

@ -0,0 +1,299 @@
/*
* MIT License
*
* Copyright (c) 2019 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tcp.h"
#include "Network/TcpSession.h"
#include "Network/TcpClient.h"
#include "Http/WebSocketClient.h"
#include "Http/WebSocketSession.h"
using namespace mediakit;
////////////////////////////////////////////////////////////////////////////////////////
API_EXPORT void API_CALL mk_tcp_session_shutdown(const mk_tcp_session ctx,int err,const char *err_msg){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
session->safeShutdown(SockException((ErrCode)err,err_msg));
}
API_EXPORT const char* API_CALL mk_tcp_session_peer_ip(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_peer_ip().c_str();
}
API_EXPORT const char* API_CALL mk_tcp_session_local_ip(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_local_ip().c_str();
}
API_EXPORT uint16_t API_CALL mk_tcp_session_peer_port(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_peer_port();
}
API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx){
assert(ctx);
TcpSession *session = (TcpSession *)ctx;
return session->get_local_port();
}
API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len){
assert(ctx && data);
if(!len){
len = strlen(data);
}
TcpSession *session = (TcpSession *)ctx;
session->send(data,len);
}
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len){
assert(ctx && data);
if(!len){
len = strlen(data);
}
try {
weak_ptr<TcpSession> weak_session = ((TcpSession *)ctx)->shared_from_this();
string str = string(data,len);
((TcpSession *)ctx)->async([weak_session,str](){
auto session_session = weak_session.lock();
if(session_session){
session_session->send(str);
}
});
}catch (std::exception &ex){
WarnL << "can not got the strong pionter of this mk_tcp_session:" << ex.what();
}
}
////////////////////////////////////////TcpSessionForC////////////////////////////////////////////////
static TcpServer::Ptr s_tcp_server[4];
static mk_tcp_session_events s_events_server = {0};
class TcpSessionForC : public TcpSession {
public:
TcpSessionForC(const Socket::Ptr &pSock) ;
~TcpSessionForC() override = default;
void onRecv(const Buffer::Ptr &buffer) override ;
void onError(const SockException &err) override;
void onManager() override;
void *_user_data;
uint16_t _local_port;
};
TcpSessionForC::TcpSessionForC(const Socket::Ptr &pSock) : TcpSession(pSock) {
_local_port = get_local_port();
if (s_events_server.on_mk_tcp_session_create) {
s_events_server.on_mk_tcp_session_create(_local_port,this);
}
}
void TcpSessionForC::onRecv(const Buffer::Ptr &buffer) {
if (s_events_server.on_mk_tcp_session_data) {
s_events_server.on_mk_tcp_session_data(_local_port,this, buffer->data(), buffer->size());
}
}
void TcpSessionForC::onError(const SockException &err) {
if (s_events_server.on_mk_tcp_session_disconnect) {
s_events_server.on_mk_tcp_session_disconnect(_local_port,this, err.getErrCode(), err.what());
}
}
void TcpSessionForC::onManager() {
if (s_events_server.on_mk_tcp_session_manager) {
s_events_server.on_mk_tcp_session_manager(_local_port,this);
}
}
void stopAllTcpServer(){
CLEAR_ARR(s_tcp_server);
}
API_EXPORT void API_CALL mk_tcp_session_set_user_data(mk_tcp_session session,void *user_data){
assert(session);
TcpSessionForC *obj = (TcpSessionForC *)session;
obj->_user_data = user_data;
}
API_EXPORT void* API_CALL mk_tcp_session_get_user_data(mk_tcp_session session){
assert(session);
TcpSessionForC *obj = (TcpSessionForC *)session;
return obj->_user_data;
}
API_EXPORT void API_CALL mk_tcp_server_events_listen(const mk_tcp_session_events *events){
if (events) {
memcpy(&s_events_server, events, sizeof(s_events_server));
} else {
memset(&s_events_server, 0, sizeof(s_events_server));
}
}
API_EXPORT uint16_t API_CALL mk_tcp_server_server_start(uint16_t port, mk_tcp_type type){
type = MAX(mk_type_tcp, MIN(type, mk_type_wss));
try {
s_tcp_server[type] = std::make_shared<TcpServer>();
switch (type) {
case mk_type_tcp:
s_tcp_server[type]->start<TcpSessionForC>(port);
break;
case mk_type_ssl:
s_tcp_server[type]->start<TcpSessionWithSSL<TcpSessionForC> >(port);
break;
case mk_type_ws:
s_tcp_server[type]->start<WebSocketSession<TcpSessionForC, HttpSession>>(port);
break;
case mk_type_wss:
s_tcp_server[type]->start<WebSocketSession<TcpSessionForC, HttpsSession>>(port);
break;
default:
return 0;
}
return s_tcp_server[type]->getPort();
} catch (std::exception &ex) {
s_tcp_server[type].reset();
WarnL << ex.what();
return 0;
}
}
///////////////////////////////////////////////////TcpClientForC/////////////////////////////////////////////////////////
class TcpClientForC : public TcpClient {
public:
typedef std::shared_ptr<TcpClientForC> Ptr;
TcpClientForC(mk_tcp_client_events *events) ;
~TcpClientForC() override ;
void onRecv(const Buffer::Ptr &pBuf) override;
void onErr(const SockException &ex) override;
void onManager() override;
void onConnect(const SockException &ex) override;
void setClient(mk_tcp_client client);
void *_user_data;
private:
mk_tcp_client_events _events;
mk_tcp_client _client;
};
TcpClientForC::TcpClientForC(mk_tcp_client_events *events){
_events = *events;
}
void TcpClientForC::onRecv(const Buffer::Ptr &pBuf) {
if(_events.on_mk_tcp_client_data){
_events.on_mk_tcp_client_data(_client,pBuf->data(),pBuf->size());
}
}
void TcpClientForC::onErr(const SockException &ex) {
if(_events.on_mk_tcp_client_disconnect){
_events.on_mk_tcp_client_disconnect(_client,ex.getErrCode(),ex.what());
}
}
void TcpClientForC::onManager() {
if(_events.on_mk_tcp_client_manager){
_events.on_mk_tcp_client_manager(_client);
}
}
void TcpClientForC::onConnect(const SockException &ex) {
if(_events.on_mk_tcp_client_connect){
_events.on_mk_tcp_client_connect(_client,ex.getErrCode(),ex.what());
}
}
TcpClientForC::~TcpClientForC() {
TraceL << "mk_tcp_client_release:" << _client;
}
void TcpClientForC::setClient(mk_tcp_client client) {
_client = client;
TraceL << "mk_tcp_client_create:" << _client;
}
TcpClientForC::Ptr *mk_tcp_client_create_l(mk_tcp_client_events *events, mk_tcp_type type){
assert(events);
type = MAX(mk_type_tcp, MIN(type, mk_type_wss));
switch (type) {
case mk_type_tcp:
return new TcpClientForC::Ptr(new TcpClientForC(events));
case mk_type_ssl:
return (TcpClientForC::Ptr *)new shared_ptr<TcpSessionWithSSL<TcpClientForC> >(new TcpSessionWithSSL<TcpClientForC>(events));
case mk_type_ws:
return (TcpClientForC::Ptr *)new shared_ptr<WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, false> >(new WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, false>(events));
case mk_type_wss:
return (TcpClientForC::Ptr *)new shared_ptr<WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, true> >(new WebSocketClient<TcpClientForC, WebSocketHeader::TEXT, true>(events));
default:
return nullptr;
}
}
API_EXPORT mk_tcp_client API_CALL mk_tcp_client_create(mk_tcp_client_events *events, mk_tcp_type type){
auto ret = mk_tcp_client_create_l(events,type);
(*ret)->setClient(ret);
return ret;
}
API_EXPORT void API_CALL mk_tcp_client_release(mk_tcp_client ctx){
assert(ctx);
TcpClient::Ptr *client = (TcpClient::Ptr *)ctx;
delete client;
}
API_EXPORT void API_CALL mk_tcp_client_connect(mk_tcp_client ctx, const char *host, uint16_t port, float time_out_sec){
assert(ctx);
TcpClient::Ptr *client = (TcpClient::Ptr *)ctx;
(*client)->startConnect(host,port);
}
API_EXPORT void API_CALL mk_tcp_client_send(mk_tcp_client ctx, const char *data, int len){
assert(ctx && data);
TcpClient::Ptr *client = (TcpClient::Ptr *)ctx;
(*client)->send(data,len);
}
API_EXPORT void API_CALL mk_tcp_client_send_safe(mk_tcp_client ctx, const char *data, int len){
assert(ctx && data);
TcpClient::Ptr *client = (TcpClient::Ptr *)ctx;
weak_ptr<TcpClient> weakClient = *client;
Buffer::Ptr buf = (*client)->obtainBuffer(data,len);
(*client)->async([weakClient,buf](){
auto strongClient = weakClient.lock();
if(strongClient){
strongClient->send(buf);
}
});
}
API_EXPORT void API_CALL mk_tcp_client_set_user_data(mk_tcp_client ctx,void *user_data){
assert(ctx);
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *)ctx;
(*client)->_user_data = user_data;
}
API_EXPORT void* API_CALL mk_tcp_client_get_user_data(mk_tcp_client ctx){
assert(ctx);
TcpClientForC::Ptr *client = (TcpClientForC::Ptr *)ctx;
return (*client)->_user_data;
}

View File

@ -1,110 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2019 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "websocket.h"
#include "Http/HttpSession.h"
#include "Http/WebSocketSession.h"
using namespace mediakit;
static TcpServer::Ptr websocket_server[2];
static mk_websocket_events s_events = {0};
class WebSocketSessionImp : public TcpSession {
public:
WebSocketSessionImp(const Socket::Ptr &pSock) : TcpSession(pSock){
if(s_events.on_mk_websocket_session_create){
s_events.on_mk_websocket_session_create(this);
}
}
virtual ~WebSocketSessionImp(){
if(s_events.on_mk_websocket_session_destory){
s_events.on_mk_websocket_session_destory(this);
}
}
void onRecv(const Buffer::Ptr &buffer) override {
if(s_events.on_mk_websocket_session_data){
s_events.on_mk_websocket_session_data(this,buffer->data(),buffer->size());
}
}
void onError(const SockException &err) override{
if(s_events.on_mk_websocket_session_err){
s_events.on_mk_websocket_session_err(this,err.getErrCode(),err.what());
}
}
void onManager() override{
if(s_events.on_mk_websocket_session_manager){
s_events.on_mk_websocket_session_manager(this);
}
}
void *_user_data;
};
API_EXPORT void API_CALL mk_websocket_events_listen(const mk_websocket_events *events){
if(events){
memcpy(&s_events,events, sizeof(s_events));
}else{
memset(&s_events,0,sizeof(s_events));
}
}
API_EXPORT void API_CALL mk_websocket_session_set_user_data(mk_tcp_session session,void *user_data){
assert(session);
WebSocketSessionImp *obj = (WebSocketSessionImp *)session;
obj->_user_data = user_data;
}
API_EXPORT void* API_CALL mk_websocket_session_get_user_data(mk_tcp_session session){
assert(session);
WebSocketSessionImp *obj = (WebSocketSessionImp *)session;
return obj->_user_data;
}
API_EXPORT uint16_t API_CALL mk_websocket_server_start(uint16_t port, int ssl){
ssl = MAX(0,MIN(ssl,1));
try {
websocket_server[ssl] = std::make_shared<TcpServer>();
if(ssl){
websocket_server[ssl]->start<WebSocketSession<WebSocketSessionImp,HttpsSession>>(port);
}else{
websocket_server[ssl]->start<WebSocketSession<WebSocketSessionImp,HttpSession>>(port);
}
return websocket_server[ssl]->getPort();
} catch (std::exception &ex) {
websocket_server[ssl].reset();
WarnL << ex.what();
return 0;
}
}
void mk_websocket_server_stop(){
CLEAR_ARR(websocket_server);
}

View File

@ -27,6 +27,7 @@
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "mediakit.h" #include "mediakit.h"
#ifdef _WIN32 #ifdef _WIN32
#include "windows.h" #include "windows.h"
@ -35,42 +36,37 @@
#endif #endif
#define LOG_LEV 4 #define LOG_LEV 4
#define TCP_TYPE mk_type_wss
static int flag = 1;
static void s_on_exit(int sig){
flag = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct { typedef struct {
mk_tcp_session _session; mk_tcp_session _session;
//下面你可以夹杂你的私货数据 //下面你可以夹杂你的私货数据
char your_some_useful_data[1024]; char your_some_useful_data[1024];
} websocket_user_data; } tcp_session_user_data;
/** /**
* websocket客户端连接服务器时触发 * tcp客户端连接服务器时触发
* @param session * @param session
*/ */
void API_CALL on_mk_websocket_session_create(mk_tcp_session session){ void API_CALL on_mk_tcp_session_create(uint16_t server_port,mk_tcp_session session){
log_printf(LOG_LEV,"%s %d",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session)); log_printf(LOG_LEV,"%s %d",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session));
websocket_user_data *user_data = malloc(sizeof(websocket_user_data)); tcp_session_user_data *user_data = malloc(sizeof(tcp_session_user_data));
user_data->_session = session; user_data->_session = session;
mk_websocket_session_set_user_data(session,user_data); mk_tcp_session_set_user_data(session,user_data);
} }
/** /**
* session会话对象销毁时触发 * tcp客户端发过来的数据
*
* mk_tcp_session_send/mk_tcp_session_send_safe函数
* @param session
*/
void API_CALL on_mk_websocket_session_destory(mk_tcp_session session){
log_printf(LOG_LEV,"%s %d",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session));
websocket_user_data *user_data = (websocket_user_data *)mk_websocket_session_get_user_data(session);
free(user_data);
}
/**
* websocket客户端发过来的数据
* @param session * @param session
* @param data * @param data
* @param len * @param len
*/ */
void API_CALL on_mk_websocket_session_data(mk_tcp_session session,const char *data,int len){ void API_CALL on_mk_tcp_session_data(uint16_t server_port,mk_tcp_session session,const char *data,int len){
log_printf(LOG_LEV,"from %s %d, data[%d]: %s",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session), len,data); log_printf(LOG_LEV,"from %s %d, data[%d]: %s",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session), len,data);
mk_tcp_session_send(session,"echo:",0); mk_tcp_session_send(session,"echo:",0);
mk_tcp_session_send(session,data,len); mk_tcp_session_send(session,data,len);
@ -80,42 +76,132 @@ void API_CALL on_mk_websocket_session_data(mk_tcp_session session,const char *da
* 2 * 2
* @param session * @param session
*/ */
void API_CALL on_mk_websocket_session_manager(mk_tcp_session session){ void API_CALL on_mk_tcp_session_manager(uint16_t server_port,mk_tcp_session session){
log_printf(LOG_LEV,"%s %d",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session)); log_printf(LOG_LEV,"%s %d",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session));
} }
/** /**
* on_mk_websocket_session_destory之前触发on_mk_websocket_session_err
* tcp触发 * tcp触发
* mk_tcp_session_send_safe函数 * mk_tcp_session_send_safe函数
* @param session * @param session
* @param code * @param code
* @param msg * @param msg
*/ */
void API_CALL on_mk_websocket_session_err(mk_tcp_session session,int code,const char *msg){ void API_CALL on_mk_tcp_session_disconnect(uint16_t server_port,mk_tcp_session session,int code,const char *msg){
log_printf(LOG_LEV,"%s %d will destory: %d %s",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session),code,msg); log_printf(LOG_LEV,"%s %d: %d %s",mk_tcp_session_peer_ip(session),(int)mk_tcp_session_peer_port(session),code,msg);
tcp_session_user_data *user_data = (tcp_session_user_data *)mk_tcp_session_get_user_data(session);
free(user_data);
} }
static int flag = 1; ////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void s_on_exit(int sig){ typedef struct {
flag = 0; mk_tcp_client client;
//下面你可以夹杂你的私货数据
char your_some_useful_data[1024];
int count;
} tcp_client_user_data;
/**
* tcp客户端连接服务器成功或失败回调
* @param client tcp客户端
* @param code 0
* @param msg
*/
void API_CALL on_mk_tcp_client_connect(mk_tcp_client client,int code,const char *msg){
log_printf(LOG_LEV,"connect result:%d %s",code,msg);
if(code == 0){
//连接上后我们发送一个hello world测试数据
mk_tcp_client_send(client,"hello world",0);
}else{
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
mk_tcp_client_release(client);
free(user_data);
} }
}
/**
* tcp客户端与tcp服务器之间断开回调
* eof事件导致
* @param client tcp客户端
* @param code
* @param msg
*/
void API_CALL on_mk_tcp_client_disconnect(mk_tcp_client client,int code,const char *msg){
log_printf(LOG_LEV,"disconnect:%d %s",code,msg);
//服务器主动断开了,我们销毁对象
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
mk_tcp_client_release(client);
free(user_data);
}
/**
* tcp服务器发来的数据
* @param client tcp客户端
* @param data
* @param len
*/
void API_CALL on_mk_tcp_client_data(mk_tcp_client client,const char *data,int len){
log_printf(LOG_LEV,"data[%d]:%s",len,data);
}
/**
* 2
* @param client tcp客户端
*/
void API_CALL on_mk_tcp_client_manager(mk_tcp_client client){
tcp_client_user_data *user_data = mk_tcp_client_get_user_data(client);
char buf[1024];
sprintf(buf,"on_mk_tcp_client_manager:%d",user_data->count);
mk_tcp_client_send(client,buf,0);
if(++user_data->count == 5){
//发送5遍后主动释放对象
mk_tcp_client_release(client);
free(user_data);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void test_server(){
mk_tcp_session_events events_server = {
.on_mk_tcp_session_create = on_mk_tcp_session_create,
.on_mk_tcp_session_data = on_mk_tcp_session_data,
.on_mk_tcp_session_manager = on_mk_tcp_session_manager,
.on_mk_tcp_session_disconnect = on_mk_tcp_session_disconnect
};
mk_tcp_server_events_listen(&events_server);
mk_tcp_server_server_start(80,TCP_TYPE);
}
void test_client(){
mk_tcp_client_events events_clent = {
.on_mk_tcp_client_connect = on_mk_tcp_client_connect,
.on_mk_tcp_client_data = on_mk_tcp_client_data,
.on_mk_tcp_client_disconnect = on_mk_tcp_client_disconnect,
.on_mk_tcp_client_manager = on_mk_tcp_client_manager,
};
mk_tcp_client client = mk_tcp_client_create(&events_clent, TCP_TYPE);
tcp_client_user_data *user_data = (tcp_client_user_data *)malloc(sizeof(tcp_client_user_data));
user_data->client = client;
user_data->count = 0;
mk_tcp_client_set_user_data(client,user_data);
mk_tcp_client_connect(client, "121.40.165.18", 8800, 3);
//你可以连接127.0.0.1 80测试
//mk_tcp_client_connect(client, "127.0.0.1", 80, 3);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char ini_path[2048] = {0}; char ini_path[2048] = {0};
strcpy(ini_path,argv[0]); strcpy(ini_path,argv[0]);
strcat(ini_path,".ini"); strcat(ini_path,".ini");
mk_env_init1(0, 0, 1, ini_path, 0, NULL, NULL); mk_env_init1(0, 0, 1, ini_path, 0, NULL, NULL);
mk_websocket_events events = {
.on_mk_websocket_session_create = on_mk_websocket_session_create,
.on_mk_websocket_session_destory = on_mk_websocket_session_destory,
.on_mk_websocket_session_data = on_mk_websocket_session_data,
.on_mk_websocket_session_manager = on_mk_websocket_session_manager,
.on_mk_websocket_session_err = on_mk_websocket_session_err
};
mk_websocket_events_listen(&events); test_server();
mk_websocket_server_start(80,0); test_client();
signal(SIGINT, s_on_exit );// 设置退出信号 signal(SIGINT, s_on_exit );// 设置退出信号
while (flag) { while (flag) {

View File

@ -348,21 +348,25 @@ public:
/** /**
* startConnect方法 * startConnect方法
* TcpClient的连接服务器行为使WebSocket握手 * TcpClient的连接服务器行为使WebSocket握手
* @param strUrl websocket服务器ip或域名 * @param host websocket服务器ip或域名
* @param iPort websocket服务器端口 * @param iPort websocket服务器端口
* @param fTimeOutSec * @param fTimeOutSec
*/ */
void startConnect(const string &strUrl, uint16_t iPort, float fTimeOutSec = 3) override { void startConnect(const string &host, uint16_t iPort, float fTimeOutSec = 3) override {
string ws_url; string ws_url;
if(useWSS){ if(useWSS){
//加密的ws //加密的ws
ws_url = StrPrinter << "wss://" + strUrl << ":" << iPort << "/" ; ws_url = StrPrinter << "wss://" + host << ":" << iPort << "/" ;
}else{ }else{
//明文ws //明文ws
ws_url = StrPrinter << "ws://" + strUrl << ":" << iPort << "/" ; ws_url = StrPrinter << "ws://" + host << ":" << iPort << "/" ;
} }
_wsClient->startWsClient(ws_url,fTimeOutSec); _wsClient->startWsClient(ws_url,fTimeOutSec);
} }
void startWebSocket(const string &ws_url,float fTimeOutSec = 3){
_wsClient->startWsClient(ws_url,fTimeOutSec);
}
private: private:
typename HttpWsClient<ClientType,DataType>::Ptr _wsClient; typename HttpWsClient<ClientType,DataType>::Ptr _wsClient;
}; };