TeamTalk--MsgServer启动流程分析

本文详细分析了TeamTalk中消息服务器MsgServer的启动流程,包括监听端口、设置超时回调、连接FileServer、LoginServer、DBServer、PushServer和RouteServer,并深入探讨了每个步骤在系统中的作用。主要关注点在于消息服务器如何处理客户端连接及与其他服务器的交互。
摘要由CSDN通过智能技术生成

本文主要分析TeamTalk的服务器架构中MsgServer的启动流程,在TeamTalk的各个服务器中,消息服务器Msg-Server是最复杂。本文剖析了其启动流程。

1、在Msg_server.cpp的main函数是消息服务器启动的入口函数,其主要的流程包含一下几个部分:

(1)、读取配置文件中设置的各个服务器的监听IP和端口。

(2)、初始化网络库

(3)、消息服务器在监听端口监听

(4)、设置时间超时回调

(5)、连接文档服务器FileServer

(6)、连接DBServe,DB服务器

(7)、连接登录服务器loginServer

(8)、连接路由服务器RouteServer

(9)、连接推送服务器PushServer

(10)、进入主事件循环。

其中读取配置文件和初始化网络库比较简单,没有什么理解难点。下面对其他几点逐条分析。

消息服务器在监听端口监听

由于消息服务器在TeamTalk的业务流程中的占比很大,主要负责进行客户端的消息递送等服务,因此消息服务器需要监听客户端到消息服务器的连接,在消息服务器中保存每个连接的客户端类型用户ID等值,主要流程如下:

char* listen_ip = config_file.GetConfigName("ListenIP");

从配置文件中读取消息服务器的监听IP,监听IP可能有多个,因此分别在每个IP上监听客户端的连接请求,设置当前的SOCKET状态为listenning,并设置客户端发起连接时的的回调函数msg_serv_callback,

	for (uint32_t i = 0; i < listen_ip_list.GetItemCnt(); i++) {
		ret = netlib_listen(listen_ip_list.GetItem(i), listen_port, msg_serv_callback, NULL);
		if (ret == NETLIB_ERROR)
			return ret;
	}

在主事件循环中,当客户端发起连接请求时,select或者epoll调用返回,发现与数据可读,调用Onread函数,读取对应的数据,(其实这个数据是客户端发送的SYN标识)

void CBaseSocket::OnRead()
{
	if (m_state == SOCKET_STATE_LISTENING)
	{
		_AcceptNewSocket();
	}
	else
	{
		u_long avail = 0;
		if ( (ioctlsocket(m_socket, FIONREAD, &avail) == SOCKET_ERROR) || (avail == 0) )
		{
			m_callback(m_callback_data, NETLIB_MSG_CLOSE, (net_handle_t)m_socket, NULL);
		}
		else
		{
			m_callback(m_callback_data, NETLIB_MSG_READ, (net_handle_t)m_socket, NULL);
		}
	}
}
由于当前的状态时LISTENNING状态,因此接受新的Sokcet请求,并将客户端连接的socket描述符增加到select或者epoll的可读事件里, 在全局的socket map中插入一条新记录.
void CBaseSocket::_AcceptNewSocket()
{
	SOCKET fd = 0;
	sockaddr_in peer_addr;
	socklen_t addr_len = sizeof(sockaddr_in);
	char ip_str[64];
	while ( (fd = accept(m_socket, (sockaddr*)&peer_addr, &addr_len)) != INVALID_SOCKET )
	{
		CBaseSocket* pSocket = new CBaseSocket();
		uint32_t ip = ntohl(peer_addr.sin_addr.s_addr);
		uint16_t port = ntohs(peer_addr.sin_port);

		snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", ip >> 24, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);

		log("AcceptNewSocket, socket=%d from %s:%d\n", fd, ip_str, port);

		pSocket->SetSocket(fd);
		pSocket->SetCallback(m_callback);
		pSocket->SetCallbackData(m_callback_data);
		pSocket->SetState(SOCKET_STATE_CONNECTED);
		pSocket->SetRemoteIP(ip_str);
		pSocket->SetRemotePort(port);

		_SetNoDelay(fd);
		_SetNonblock(fd);
		AddBaseSocket(pSocket);
		CEventDispatch::Instance()->AddEvent(fd, SOCKET_READ | SOCKET_EXCEP);
		m_callback(m_callback_data, NETLIB_MSG_CONNECT, (net_handle_t)fd, NULL);
	}
}

 调用前面注册的客户端发起连接回调msg_server_callbakc。

void msg_serv_callback(void* callback_data, uint8_t msg, uint32_t handle, void* pParam)
{
    log("msg_server come in");

	if (msg == NETLIB_MSG_CONNECT)
	{
		CLoginConn* pConn = new CLoginConn();
		pConn->OnConnect2(handle, LOGIN_CONN_TYPE_MSG_SERV);
	}
	else
	{
		log("!!!error msg: %d ", msg);
	}
}

在回调中记录连接上msg_server,,并且设置创建一个LoginConn对象,在已连接的socket map中插入一条记录,并且修改该socket对象的回调为imconn_callback

void CLoginConn::OnConnect2(net_handle_t handle, int conn_type)
{
	m_handle = handle;
	m_conn_type = conn_type;
	ConnMap_t* conn_map = &g_msg_serv_conn_map;
	if (conn_type == LOGIN_CONN_TYPE_CLIENT) {
		conn_map = &g_client_conn_map;
	}else

	conn_map->insert(make_pair(handle, this));

	netlib_option(handle, NETLIB_OPT_SET_CALLBACK, (void*)imconn_callback);
	netlib_option(handle, NETLIB_OPT_SET_CALLBACK_DATA, (void*)conn_map);
}
至此,Msg_Server的监听已经客户端发起连接已经处理完成,主事件循环中如果有数据可读或者可写分别调用该socket最后注册的imconn_callback进行数据读写。

设置时间超时回调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值