TCP服务器实现-start函数启动过程-server的启动过程

版权声明:转载请注明来源 https://blog.csdn.net/u013702678/article/details/81213269

前面几篇我们分析了server的创建过程,这篇我们开始分析server的启动过程,这里的代码在E:\swoole-src-master\src\network\Server.c里面。

int swServer_start(swServer *serv)
{
    swFactory *factory = &serv->factory;//获取factory对象
    int ret;
    //server启动前的有效性检查
    ret = swServer_start_check(serv);
    if (ret < 0)
    {
        return SW_ERR;
    }
    //判断是否设置了server启动前的钩子函数设置,如果设置了则调用钩子函数
    if (SwooleG.hooks[SW_GLOBAL_HOOK_BEFORE_SERVER_START])
    {
        //调用钩子函数
        swoole_call_hook(SW_GLOBAL_HOOK_BEFORE_SERVER_START, serv);
    }
    //判断服务是否已经启动,这里通过cas操作,如果失败表示当前serv->gs_start不为0
    if (!sw_atomic_cmp_set(&serv->gs->start, 0, 1))
    {
        swoole_error_log(SW_LOG_ERROR, SW_ERROR_SERVER_ONLY_START_ONE, "must only start one server.");
        return SW_ERR;
    }
    //全局日志工具初始化
    if (SwooleG.log_file)
    {   
        //日志工具初始化,这里初始化逻辑比较简单,也就是打开日志文件而已。
        swLog_init(SwooleG.log_file);
    }
    //serv以demon方式启动
    if (serv->daemonize > 0)
    {
        if (SwooleG.log_fd > STDOUT_FILENO)//日志文件描述符大于标准输出文件描述符
        {
            swoole_redirect_stdout(SwooleG.log_fd);//文件描述符的重定向
        }
        else//日志文件描述符小于标准输出文件描述符
        {
            SwooleG.null_fd = open("/dev/null", O_WRONLY);//打开/dev/null文件
            if (SwooleG.null_fd > 0)
            {
                swoole_redirect_stdout(SwooleG.null_fd);//将标准输出重定向到/dev/null文件
            }
            else //打开文件失败
            {
                swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "open(/dev/null) failed. Error: %s[%d]", strerror(errno), errno);
            }
        }
        //将当前进程变为demon进程,这里是demon进程的标准操作,不再展开分析
        if (daemon(0, 1) < 0)
        {
            return SW_ERR;
        }
    }

    serv->gs->master_pid = getpid();//记录master进程的进程pid
    serv->gs->now = serv->stats->start_time = time(NULL);//记录serv的启动时间和当前时间
    
    //如果分发模式为unix域协议
    if (serv->dispatch_mode == SW_DISPATCH_STREAM)
    {   
        //创建unix域协议路径,最终生成的域协议路径为/tmp/swoole.%d.sock,其中%d为master进程的进程号
        serv->stream_socket = swoole_string_format(64, "/tmp/swoole.%d.sock", serv->gs->master_pid);
        if (serv->stream_socket == NULL)//创建失败
        {
            return SW_ERR;
        }

        int _reuse_port = SwooleG.reuse_port;//记录全局swooleG变量的reuse_port属性
        SwooleG.reuse_port = 0;//设置为0
        serv->stream_fd = swSocket_create_server(SW_SOCK_UNIX_STREAM, serv->stream_socket, 0, 2048);//创建socket,这里会完成create,bind,listen等操作,后续再展开分析。
        if (serv->stream_fd < 0)//socket描述符,小于0表示创建失败
        {
            return SW_ERR;
        }
        //描述符设置O_NONBLOCK和FD_CLOEXEC属性,通过fcntl操作
        swoole_fcntl_set_option(serv->stream_fd, 1, 1);
        SwooleG.reuse_port = _reuse_port;//回填reuse_port属性,没看懂为什么这里要这么操作
    }

    serv->send = swServer_tcp_send;//设置serv的send回调函数
    serv->sendwait = swServer_tcp_sendwait;//设置serv的sendwait回调函数
    serv->sendfile = swServer_tcp_sendfile;//设置serv的sendfile回调函数
    serv->close = swServer_tcp_close;//设置serv的close回调函数
    //从内存池申请worker对应的空间,这里需要申请worker_num个swWorker对象的大小
    serv->workers = SwooleG.memory_pool->alloc(SwooleG.memory_pool, serv->worker_num * sizeof(swWorker));
    if (serv->workers == NULL)//空间申请失败
    {
        swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "gmalloc[server->workers] failed.");
        return SW_ERR;
    }

    serv->gs->event_workers.workers = serv->workers;//设置属性
    serv->gs->event_workers.worker_num = serv->worker_num;//worker_num属性
    serv->gs->event_workers.use_msgqueue = 0;//是否使用msgqueue的标记

    int i;
    for (i = 0; i < serv->worker_num; i++)
    {   
        //初始化每个worker进程的swProcessPool属性
        serv->gs->event_workers.workers[i].pool = &serv->gs->event_workers;
    }

#ifdef SW_USE_RINGBUFFER
    for (i = 0; i < serv->reactor_num; i++)
    {
        //申请每个reactor线程的buffer空间
        serv->reactor_threads[i].buffer_input = swRingBuffer_new(SwooleG.serv->buffer_input_size, 1);
        if (!serv->reactor_threads[i].buffer_input)//申请空间失败
        {
            return SW_ERR;
        }
    }
#endif

    //work进程里面有task线程,则初始化task线程的属性
    if (serv->task_worker_num > 0 && serv->worker_num > 0)
    {
        serv->task_result = sw_shm_calloc(serv->worker_num, sizeof(swEventData));
        serv->task_notify = sw_calloc(serv->worker_num, sizeof(swPipe));
        for (i = 0; i < serv->worker_num; i++)
        {
            //task线程管道初始化
            if (swPipeNotify_auto(&serv->task_notify[i], 1, 0))
            {
                return SW_ERR;
            }
        }
    }

    //用户侧的worker进程列表有设置
    if (serv->user_worker_list)
    {
        swUserWorker_node *user_worker;
        i = 0;
        LL_FOREACH(serv->user_worker_list, user_worker)
        {
            //设置worker进程的worker->id属性
            user_worker->worker->id = serv->worker_num + serv->task_worker_num + i;
            i++;
        }
    }

    //启动factory对象,这里不同factory的启动不一样,后面专篇分析
    if (factory->start(factory) < 0)
    {
        return SW_ERR;
    }

    //server对应的信号的初始化
    swServer_signal_init(serv);

    //记录进程ID,这里记录的是master进程的进程ID
    if (serv->pid_file)
    {
        ret = snprintf(SwooleTG.buffer_stack->str, SwooleTG.buffer_stack->size, "%d", getpid());
        swoole_file_put_contents(serv->pid_file, SwooleTG.buffer_stack->str, ret);
    }

    if (serv->factory_mode == SW_MODE_SINGLE)//如果是单进程的模式,也就是reactor和worker是同类角色
    {
        //Reactor的启动
        ret = swReactorProcess_start(serv);
    }
    else //其他模式
    {
        //Reactor的启动
        ret = swServer_start_proxy(serv);
    }

    swServer_free(serv);//释放serv的空间,前面的启动后都是在不同的进程中
    serv->gs->start = 0;//标记start标记为0
    //删除master进程的进程文件
    if (serv->pid_file)
    {
        unlink(serv->pid_file);
    }

    return SW_OK;
}

猜你喜欢

转载自blog.csdn.net/u013702678/article/details/81213269