服务器启动时调用rtmp端口的监听过程如下:
run_master()-->SrsServer::listen()--->SrsServer::listen_rtmp()
listen_rtmp服务端口监听流程如下:
1).获取配置文件中设定的端口列表 _srs_config->get_listens()
2).释放掉已经监听rtmp端口 close_listeners(SrsListenerRtmpStream)
3).根据端口列表创建SrsListener实例,并启动监听listener->listen(ip, port))
srs_error_t SrsServer::listen_rtmp()
{
srs_error_t err = srs_success;
// stream service port.
std::vector<std::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 SrsBufferListener(this, SrsListenerRtmpStream);
listeners.push_back(listener);
std::string ip;
int port;
srs_parse_endpoint(ip_ports[i], ip, port);
if ((err = listener->listen(ip, port)) != srs_success) {
srs_error_wrap(err, "rtmp listen %s:%d", ip.c_str(), port);
}
}
return err;
}
4).
SrsBufferListener::listen()中创建SrsTcpListener的实例并启动监听listener->listen()
srs_error_t SrsBufferListener::listen(string i, int p)
{
srs_error_t err = srs_success;
ip = i;
port = p;
srs_freep(listener);
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;
}
5).SrsTcpListener::listen()中绑定监听的端口,开启监听,创建SrsSTCoroutine协程实例,开启协程。
srs_error_t SrsTcpListener::listen()
{
srs_error_t err = srs_success;
if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
return srs_error_new(ERROR_SOCKET_CREATE, "create socket");
}
srs_fd_close_exec(_fd);
srs_socket_reuse_addr(_fd);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
return srs_error_new(ERROR_SOCKET_BIND, "bind socket");
}
if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket");
}
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);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
}
return err;
}
6).SrsSTCoroutine::start()中调用st_thread_create来创建协程
srs_error_t SrsSTCoroutine::start()
{
......
if((trd = (srs_thread_t)st_thread_create(pfn, this, 1, 0)) == NULL){
err = srs_error_new(ERROR_ST_CREATE_CYCLE_THREAD, "create failed");
srs_freep(trd_err);
trd_err = srs_error_copy(err);
return err;
}
started = true;
return err;
}
其中pfn定义如下,pfn传入的参数this 是SrsSTCoroutine的实例
void* SrsSTCoroutine::pfn(void* arg)
{
SrsSTCoroutine* p = (SrsSTCoroutine*)arg;
void* res = (void*)p->cycle();
return res;
}
pfn中会调用SrsSTCoroutine的cycle函数,函数定义如下:
srs_error_t SrsSTCoroutine::cycle()
{
......
srs_error_t err = handler->cycle();
if (err != srs_success) {
return srs_error_wrap(err, "coroutine cycle");
}
return err;
}
SrsSTCoroutine::cycle()函数中会调用handler->cycle(),handler是在构造函数中赋初值的。
SrsSTCoroutine::SrsSTCoroutine(const string& n, ISrsCoroutineHandler* h, int cid)
{
name = n;
handler = h;
context = cid;
trd = NULL;
trd_err = srs_success;
started = interrupted = disposed = false;
}
SrsSTCoroutine对象是在SrsTcpListener::listen()进行创建的,并把SrsTcpListener对象传递给handler(SrsTcpListener是ISrsCoroutineHandler的子类)
srs_error_t SrsTcpListener::listen()
{
......
trd = new SrsSTCoroutine("tcp", this);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
}
}
因此,SrsSTCoroutine::cycle()->handler->cycle()最终调用SrsTcpListener::cycle(),SrsTcpListener::cycle()在while循环中调用srs_accept()阻塞等待连接请求的到来,当有连接到来时将获取连接的fd,接着调用handler->on_tcp_client().
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);
if ((err = handler->on_tcp_client(cstfd)) != srs_success) {
return srs_error_wrap(err, "handle fd=%d", cfd);
}
}
return err;
}
SrsTcpListener中的handler是在构造函数中赋值的,代码如下
SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
{
handler = h;
ip = i;
port = p;
_fd = -1;
_stfd = NULL;
trd = new SrsDummyCoroutine();
}
SrsTcpListener是在SrsBufferListener::listen()中创建的,并把SrsBufferListener对象作为参数传给handler(SrsBufferListener是ISrsTcpHandler的子类)
srs_error_t SrsBufferListener::listen(string i, int p)
{
......
listener = new SrsTcpListener(this, ip, port);
if ((err = listener->listen()) != srs_success) {
return srs_error_wrap(err, "buffered tcp listen");
}
}
因此,handler->on_tcp_client()最终调用SrsBufferListener::on_tcp_client(),代码如下:
srs_error_t SrsBufferListener::on_tcp_client(srs_netfd_t stfd)
{
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;
}
SrsBufferListener::on_tcp_client调用server->accept_client来处理客户端连接请求,server成员变量是SrsServer的实例,最终调用SrsServer::accept_client,代码如下:
srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
{
srs_error_t err = srs_success;
SrsConnection* conn = NULL;
if ((err = fd2conn(type, stfd, &conn)) != srs_success) {
return srs_error_wrap(err, "fd2conn");
}
srs_assert(conn);
// directly enqueue, the cycle thread will remove the client.
conns.push_back(conn);
// cycle will start process thread and when finished remove the client.
// @remark never use the conn, for it maybe destroyed.
if ((err = conn->start()) != srs_success) {
return srs_error_wrap(err, "start conn coroutine");
}
return err;
}
SrsServer::accept_client调用fd2conn(type, stfd, &conn)创建一个连接对象SrsRtmpConn(SrsRtmpConn是SrsConnection的子类),
SrsConnection中有个协程类型SrsSTCoroutine成员变量trd,调用过程如下:
SrsServer::accept_client--->SrsConnection::start--->SrsSTCoroutine::start-->SrsConnection::cycle--->SrsRtmpConn::do_cycle
由于SrsConnection中do_cycle是纯虚函数,实际调用的是SrsRtmpConn::do_cycle,
该函数完成rtmp握手,连接以及一些检查,最终进入到service_cycle,至此rtmp连接已经建立。具体代码如下:
srs_error_t SrsRtmpConn::do_cycle()
{
int ret = ERROR_SUCCESS;
srs_error_t err = srs_success;
srs_trace("RTMP client ip=%s, fd=%d", ip.c_str(), srs_netfd_fileno(stfd));
// notify kafka cluster.
#ifdef SRS_AUTO_KAFKA
if ((ret = _srs_kafka->on_client(srs_id(), SrsListenerRtmpStream, ip)) != ERROR_SUCCESS) {
return srs_error_new(ret, "kafka on client");
}
#endif
rtmp->set_recv_timeout(SRS_CONSTS_RTMP_TMMS);
rtmp->set_send_timeout(SRS_CONSTS_RTMP_TMMS);
if ((ret = rtmp->handshake()) != ERROR_SUCCESS) {
return srs_error_new(ret, "rtmp handshake");
}
SrsRequest* req = info->req;
if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) {
return srs_error_new(ret, "rtmp connect tcUrl");
}
// set client ip to request.
req->ip = ip;
// discovery vhost, resolve the vhost from config
SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
if (parsed_vhost) {
req->vhost = parsed_vhost->arg0();
}
srs_info("discovery app success. schema=%s, vhost=%s, port=%d, app=%s",
req->schema.c_str(), req->vhost.c_str(), req->port, req->app.c_str());
if (req->schema.empty() || req->vhost.empty() || req->port == 0 || req->app.empty()) {
return srs_error_new(ERROR_RTMP_REQ_TCURL, "discovery tcUrl failed, tcUrl=%s, schema=%s, vhost=%s, port=%d, app=%s",
req->tcUrl.c_str(), req->schema.c_str(), req->vhost.c_str(), req->port, req->app.c_str());
}
// check vhost, allow default vhost.
if ((ret = check_vhost(true)) != ERROR_SUCCESS) {
return srs_error_new(ret, "check vhost");
}
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();
}
srs_info("edge-srs ip=%s, version=%s, pid=%d, id=%d",
srs_server_ip.c_str(), srs_version.c_str(), srs_pid, srs_id);
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);
}
}
if ((ret = service_cycle()) != ERROR_SUCCESS) {
err = srs_error_new(ret, "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);
}
return err;
}