初始化st协程库
state-threads协程库在使用时需要初始化IO复用类型,并初始化。
srs_error_t srs_st_init()
{
//在linux上设置为epoll()
if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) {
return srs_error_new(ERROR_ST_SET_EPOLL, "st enable st failed, current is %s", st_get_eventsys_name());
}
int r0 = 0;
//初始化
if((r0 = st_init()) != 0){
return srs_error_new(ERROR_ST_INITIALIZE, "st initialize failed, r0=%d", r0);
}
srs_trace("st_init success, use %s", st_get_eventsys_name());
return srs_success;
}
初始化signal
在使用state-threads时需要将信号转化为IO,并创建一个协程处理信号IO。
run_master
中调用svr->initialize_signal()
,初始化信号
- 调用
SrsSignalManager::initialize()
, 创建pipe
svr->register_signal()
注册信号
- 调用
SrsSignalManager::start()
:注册信号并启动信号监听的协程 - 最终执行
SrsSignalManager::cycle()
监听 - 在
SrsSignalManager::cycle()
函数中,循环执行监听操作,调用SrsServer::on_signal
SrsServer::on_signal
对每一种信号检测,如果信号发生,设置相应的bool变量为true- 在
SrsServer::do_cycle()
中检查信号,并处理
监听客户端请求
listen函数监听客户端的连接,包括rtmp, http api, http stream, stream caster,并启动连接管理的协程。
监听rtmp流
//监听rtmp流
srs_error_t SrsServer::listen_rtmp()
{
srs_error_t err = srs_success;
//读取配置文件中的端口列表
std::vector<std::string> ip_ports = _srs_config->get_listens();
srs_assert((int)ip_ports.size() > 0);
//先关闭rtmp相关的监听
close_listeners(SrsListenerRtmpStream);
//然后对每个端口都监听
for (int i = 0; i < (int)ip_ports.size(); i++) {
SrsListener* listener = new SrsBufferListener(this, SrsListenerRtmpStream);
listeners.push_back(listener);
std::string ip;
int port;
srs_parse_endpoint(ip_ports[i], ip, port);
//调用SrsBufferListener的listen
if ((err = listener->listen(ip, port)) != srs_success) {
srs_error_wrap(err, "rtmp listen %s:%d", ip.c_str(), port);
}
}
return err;
}
listern_rtmp
调用调用SrsBufferListener的listen
监听
//监听
srs_error_t SrsBufferListener::listen(string i, int p)
{
srs_error_t err = srs_success;
ip = i;
port = p;
srs_freep(listener);
//创建一个TCP监听
listener = new SrsTcpListener(this, ip, port);
//进入监听
if ((err = listener->listen()) != srs_success) {
return srs_error_wrap(err, "buffered tcp listen");
}
string v = srs_listener_type2string(type);
srs_trace("%s listen at tcp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd());
return err;
}
SrsBufferListener
是一个Listerner的缓冲类,在listern中创建了一个TCPListener,并调用其listen方法。
//监听
srs_error_t SrsBufferListener::listen(string i, int p)
{
srs_error_t err = srs_success;
ip = i;
port = p;
srs_freep(listener);
//创建一个TCP监听
listener = new SrsTcpListener(this, ip, port);
//进入监听
if ((err = listener->listen()) != srs_success) {
return srs_error_wrap(err, "buffered tcp listen");
}
string v = srs_listener_type2string(type);
srs_trace("%s listen at tcp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd());
return err;
}
SrsTcpListener类进行实际的监听,通过socket->bind->listen
创建监听的fd,并将fd注册到st库上,之后fd上的事件都有st库监听并处理。创建tcp协程,用于处理连接,协程启动,并进入cycle()函数。cycle()函数用于处理客户端连接
//rtmp tcp监听
srs_error_t SrsTcpListener::listen()
{
srs_error_t err = srs_success;
char sport[8];
snprintf(sport, sizeof(sport), "%d", port);
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "get address info");
}
//1. 创建socket
if ((_fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) {
return srs_error_new(ERROR_SOCKET_CREATE, "create socket. ip=%s, port=%d", ip.c_str(), port);
}
#ifdef SO_KEEPALIVE
int tcp_keepalive = 1;
if (setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, &tcp_keepalive, sizeof(int)) == -1) {
return srs_error_new(ERROR_SOCKET_SETKEEPALIVE, "setsockopt SO_KEEPALIVE[%d]error. port=%d", tcp_keepalive, port);
}
#endif
srs_fd_close_exec(_fd); //设置FD_CLOEXEC
srs_socket_reuse_addr(_fd); //重复使用fd
//2. 绑定服务器ip和端口
if (bind(_fd, r->ai_addr, r->ai_addrlen) == -1) {
return srs_error_new(ERROR_SOCKET_BIND, "bind socket. ep=%s:%d", ip.c_str(), port);;
}
//3. 在_fd上开启监听
if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket");
}
//将fd注册到st库上, 此后这个fd的所有请求都交由库处理
if ((_stfd = srs_netfd_open_socket(_fd)) == NULL){
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open socket");
}
srs_freep(trd);
//创建一个协程
trd = new SrsSTCoroutine("tcp", this);
//启动协程,最后进入SrsSTCoroutine::cycle()
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
}
return err;
}
监听协程接受连接请求后将执行逻辑交给BufferListener处理
//监听的循环
srs_error_t SrsTcpListener::cycle()
{
srs_error_t err = srs_success;
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "tcp listener");
}
//接受连接
srs_netfd_t cstfd = srs_accept(_stfd, NULL, NULL, SRS_UTIME_NO_TIMEOUT);
if(cstfd == NULL){
return srs_error_new(ERROR_SOCKET_CREATE, "accept failed");
}
int cfd = srs_netfd_fileno(cstfd);
srs_fd_close_exec(cfd);
//这个监听协程只是处理连接请求,具体的执行逻辑交给BufferListener处理
if ((err = handler->on_tcp_client(cstfd)) != srs_success) {
return srs_error_wrap(err, "handle fd=%d", cfd);
}
}
return err;
}
SrsBufferListener::on_tcp_client处理连接
//处理客户端的连接
srs_error_t SrsBufferListener::on_tcp_client(srs_netfd_t stfd)
{
//交给server接受连接
srs_error_t err = server->accept_client(type, stfd);
if (err != srs_success) {
srs_warn("accept client failed, err is %s", srs_error_desc(err).c_str());
srs_freep(err);
}
return srs_success;
}
最终调用sever的accept_client
//server接受连接
srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
{
srs_error_t err = srs_success;
SrsConnection* conn = NULL;
//得到连接的connection
if ((err = fd2conn(type, stfd, &conn)) != srs_success) {
return srs_error_wrap(err, "fd2conn");
}
srs_assert(conn);
//conns存放所有的连接
conns.push_back(conn);
// 每个连接都开启一个连接的协程
if ((err = conn->start()) != srs_success) {
return srs_error_wrap(err, "start conn coroutine");
}
return err;
}
//连接到来的fd转为connection, 对不同类型的连接创建
srs_error_t SrsServer::fd2conn(SrsListenerType type, srs_netfd_t stfd, SrsConnection** pconn)
{
srs_error_t err = srs_success;
int fd = srs_netfd_fileno(stfd); //fd
string ip = srs_get_peer_ip(fd); //ip
if (ip.empty()) {
return srs_error_new(ERROR_SOCKET_GET_PEER_IP, "ignore empty ip, fd=%d", fd);
}
// check connection limitation.
int max_connections = _srs_config->get_max_connections();
//此处handle为空
if (handler && (err = handler->on_accept_client(max_connections, (int)conns.size())) != srs_success) {
return srs_error_wrap(err, "drop client fd=%d, max=%d, cur=%d for err: %s",
fd, max_connections, (int)conns.size(), srs_error_desc(err).c_str());
}
//如果超过了连接限制,直接拒绝连接
if ((int)conns.size() >= max_connections) {
return srs_error_new(ERROR_EXCEED_CONNECTIONS,
"drop fd=%d, max=%d, cur=%d for exceed connection limits",
fd, max_connections, (int)conns.size());
}
if (true) {
int val;
if ((val = fcntl(fd, F_GETFD, 0)) < 0) {
return srs_error_new(ERROR_SYSTEM_PID_GET_FILE_INFO, "fnctl F_GETFD error! fd=%d", fd);
}
val |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, val) < 0) {
return srs_error_new(ERROR_SYSTEM_PID_SET_FILE_INFO, "fcntl F_SETFD error! fd=%d", fd);
}
}
if (type == SrsListenerRtmpStream) {
*pconn = new SrsRtmpConn(this, stfd, ip); //创建rtmp连接
} else if (type == SrsListenerHttpApi) {
*pconn = new SrsHttpApi(this, stfd, http_api_mux, ip);
} else if (type == SrsListenerHttpStream) {
*pconn = new SrsResponseOnlyHttpConn(this, stfd, http_server, ip);
} else {
srs_warn("close for no service handler. fd=%d, ip=%s", fd, ip.c_str());
srs_close_stfd(stfd);
return err;
}
return err;
}
SrsConnection类用于处理连接,每一个连接都有一个connnection协程处理。
//连接协程处理连接
srs_error_t SrsConnection::start()
{
srs_error_t err = srs_success;
//将整个连接抽象,初始化到skt上
if ((err = skt->initialize(stfd)) != srs_success) {
return srs_error_wrap(err, "init socket");
}
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "coroutine");
}
return err;
}
//协程调用的函数,转到do_cycle()
srs_error_t SrsConnection::cycle()
{
//SrsRtmpConn::do_cycle
srs_error_t err = do_cycle(); //连接处理
// Notify manager to remove it.
manager->remove(this); //移除通知
// success.
if (err == srs_success) {
srs_trace("client finished.");
return err;
}
if (srs_is_client_gracefully_close(srs_error_code(err))) {
srs_warn("client disconnect peer. ret=%d", srs_error_code(err));
} else {
srs_error("connect error %s", srs_error_desc(err).c_str());
}
srs_freep(err);
return srs_success;
}
根据不同的连接调用不同do_cycle(), RTMP的连接处理
// rtmp连接最终调用这个do_cycle()
srs_error_t SrsRtmpConn::do_cycle()
{
srs_error_t err = srs_success;
srs_trace("RTMP client ip=%s, fd=%d", ip.c_str(), srs_netfd_fileno(stfd));
rtmp->set_recv_timeout(SRS_CONSTS_RTMP_TMMS); //设置接收超时时间
rtmp->set_send_timeout(SRS_CONSTS_RTMP_TMMS); //设置发送超时时间
//1. rtmp握手
if ((err = rtmp->handshake()) != srs_success) {
return srs_error_wrap(err, "rtmp handshake");
}
SrsRequest* req = info->req;
//2. handshake成功后,开始接收并解析客户端发送过来的RTMP消息connect
// 该消息中指明了客户端想要连接的 app,解析信息保存在 req 中
if ((err = rtmp->connect_app(req)) != srs_success) {
return srs_error_wrap(err, "rtmp connect tcUrl");
}
// set client ip to request.
req->ip = ip;
srs_trace("connect app, tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%d, app=%s, args=%s",
req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(),
req->schema.c_str(), req->vhost.c_str(), req->port,
req->app.c_str(), (req->args? "(obj)":"null"));
// show client identity
if(req->args) {
std::string srs_version;
std::string srs_server_ip;
int srs_pid = 0;
int srs_id = 0;
SrsAmf0Any* prop = NULL;
if ((prop = req->args->ensure_property_string("srs_version")) != NULL) {
srs_version = prop->to_str();
}
if ((prop = req->args->ensure_property_string("srs_server_ip")) != NULL) {
srs_server_ip = prop->to_str();
}
if ((prop = req->args->ensure_property_number("srs_pid")) != NULL) {
srs_pid = (int)prop->to_number();
}
if ((prop = req->args->ensure_property_number("srs_id")) != NULL) {
srs_id = (int)prop->to_number();
}
if (srs_pid > 0) {
srs_trace("edge-srs ip=%s, version=%s, pid=%d, id=%d",
srs_server_ip.c_str(), srs_version.c_str(), srs_pid, srs_id);
}
}
//3. 服务循环
if ((err = service_cycle()) != srs_success) {
err = srs_error_wrap(err, "service cycle");
}
srs_error_t r0 = srs_success;
if ((r0 = on_disconnect()) != srs_success) {
err = srs_error_wrap(err, "on disconnect %s", srs_error_desc(r0).c_str());
srs_freep(r0);
}
// If client is redirect to other servers, we already logged the event.
if (srs_error_code(err) == ERROR_CONTROL_REDIRECT) {
srs_error_reset(err);
}
return err;
}