go srs 流媒体服务器_SRS流媒体服务器源码分析(一)

线程模型

srs使用了state-threads协程库,是单线程多协程模型。

这个协程的概念类似于 lua 的协程,都是单线程中可以创建多个协程。而golang中的goroutine协程是多线程并发的,goroutine有可能运行在同一个线程也可能在不同线程,这样就有了线程安全问题,所以需要chan通信或者mutex加锁共享资源。

而srs因为是单线程多协程所以不用考虑线程安全,数据不用加锁。

主流程分析

撇掉程序启动的一些初始化和设置,直接进入:

int SrsServer::listen()

{

int ret = ERROR_SUCCESS;

if ((ret = listen_rtmp()) != ERROR_SUCCESS) {

return ret;

}

if ((ret = listen_http_api()) != ERROR_SUCCESS) {

return ret;

}

if ((ret = listen_http_stream()) != ERROR_SUCCESS) {

return ret;

}

if ((ret = listen_stream_caster()) != ERROR_SUCCESS) {

return ret;

}

return ret;

}

先看看 listen_rtmp()

:

int SrsServer::listen_rtmp()

{

int ret = ERROR_SUCCESS;

// stream service port.

std::vector<:string> ip_ports = _srs_config->get_listens();

srs_assert((int)ip_ports.size() > 0);

close_listeners(SrsListenerRtmpStream);

for (int i = 0; i < (int)ip_ports.size(); i++) {

SrsListener* listener = new SrsStreamListener(this, SrsListenerRtmpStream);

listeners.push_back(listener);

std::string ip;

int port;

srs_parse_endpoint(ip_ports[i], ip, port);

if ((ret = listener->listen(ip, port)) != ERROR_SUCCESS) {

srs_error("RTMP stream listen at %s:%d failed. ret=%d", ip.c_str(), port, ret);

return ret;

}

}

return ret;

}

创建了 SrsStreamListener

,在 SrsStreamListener::listen

中又创建了 SrsTcpListener

进行 listen

SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)

{

handler = h;

ip = i;

port = p;

_fd = -1;

_stfd = NULL;

pthread = new SrsReusableThread("tcp", this);

}

在 SrsTcpListener

中创建了 pthread: SrsReusableThread

在 int SrsTcpListener::listen()

中调用了 pthread->start()

,协程会回调到 int SrsTcpListener::cycle()

int SrsTcpListener::cycle()

{

int ret = ERROR_SUCCESS;

st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);

if(client_stfd == NULL){

// ignore error.

if (errno != EINTR) {

srs_error("ignore accept thread stoppped for accept client error");

}

return ret;

}

srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));

if ((ret = handler->on_tcp_client(client_stfd)) != ERROR_SUCCESS) {

srs_warn("accept client error. ret=%d", ret);

return ret;

}

return ret;

}

accept

连接后,回调到 on_tcp_client

也就是 SrsStreamListener::on_tcp_client

int SrsStreamListener::on_tcp_client(st_netfd_t stfd)

{

int ret = ERROR_SUCCESS;

if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) {

srs_warn("accept client error. ret=%d", ret);

return ret;

}

return ret;

}

int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)

{

...

SrsConnection* conn = NULL;

if (type == SrsListenerRtmpStream) {

conn = new SrsRtmpConn(this, client_stfd);

} else if (type == SrsListenerHttpApi) {

#ifdef SRS_AUTO_HTTP_API

conn = new SrsHttpApi(this, client_stfd, http_api_mux);

#else

srs_warn("close http client for server not support http-api");

srs_close_stfd(client_stfd);

return ret;

#endif

} else if (type == SrsListenerHttpStream) {

#ifdef SRS_AUTO_HTTP_SERVER

conn = new SrsResponseOnlyHttpConn(this, client_stfd, http_server);

#else

srs_warn("close http client for server not support http-server");

srs_close_stfd(client_stfd);

return ret;

#endif

} else {

// TODO: FIXME: handler others

}

srs_assert(conn);

// directly enqueue, the cycle thread will remove the client.

conns.push_back(conn);

srs_verbose("add conn to vector.");

// cycle will start process thread and when finished remove the client.

// @remark never use the conn, for it maybe destroyed.

if ((ret = conn->start()) != ERROR_SUCCESS) {

return ret;

}

srs_verbose("conn started success.");

srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);

return ret;

}

在上面根据type创建不同的 SrsConnection

, Rtmp

创建了 SrsRtmpConn

,并且加入到 std::vector conns;

中,然后执行 conn->start()

SrsConnection

基类创建了一个协程 pthread: SrsOneCycleThread

,上面的 conn->start()

。实际上是 pthread->start()

SrsConnection::SrsConnection(IConnectionManager* cm, st_netfd_t c)

{

id = 0;

manager = cm;

stfd = c;

disposed = false;

expired = false;

// the client thread should reap itself,

// so we never use joinable.

// TODO: FIX

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值