<肆>kbengine源码剖析之kcp

kbengine中使用了udp跟tcp两种传输方式,udp使用的是可靠udp,也就是kcp,这里我们分析一下kcp是怎么植入到引擎中

1.channel初始化kcp接口

bool Channel::init_kcp()
{
	static IUINT32 convID = 1;

	// 防止溢出,理论上正常使用不会用完
	KBE_ASSERT(convID != 0);

	if(id_ == 0)
		id_ = convID++;

	pKCP_ = ikcp_create((IUINT32)id_, (void*)this);
	pKCP_->output = &Channel::kcp_output;

	// 配置窗口大小:平均延迟200ms,每20ms发送一个包,
	// 而考虑到丢包重发,设置最大收发窗口为128
	int sndwnd = this->isExternal() ? Network::g_rudp_extWritePacketsQueueSize : Network::g_rudp_intWritePacketsQueueSize;
	int rcvwnd = this->isExternal() ? Network::g_rudp_extReadPacketsQueueSize : Network::g_rudp_intReadPacketsQueueSize;

	// nodelay-启用以后若干常规加速将启动
	// interval为内部处理时钟,默认设置为 10ms
	// resend为快速重传指标,设置为2
	// nc为是否禁用常规流控,这里禁止
	int nodelay = Network::g_rudp_nodelay ? 1 : 0;
	int interval = Network::g_rudp_tickInterval;
	int resend = Network::g_rudp_missAcksResend;
	int disableNC = (!Network::g_rudp_congestionControl) ? 1 : 0;
	int minrto = Network::g_rudp_minRTO;

	if (this->isExternal() && Network::g_rudp_mtu > 0 && Network::g_rudp_mtu < (PACKET_MAX_SIZE_UDP * 4))
	{
		ikcp_setmtu(pKCP_, Network::g_rudp_mtu);
	}
	else
	{
		uint32 mtu = PACKET_MAX_SIZE_UDP - 72;
		if(pKCP_->mtu != mtu)
			ikcp_setmtu(pKCP_, mtu);
	}
		
	ikcp_wndsize(pKCP_, sndwnd, rcvwnd);
	ikcp_nodelay(pKCP_, nodelay, interval, resend, disableNC);
	pKCP_->rx_minrto = minrto;

	pKCP_->writelog = &Channel::kcp_writeLog;
	
	/*
	pKCP_->logmask |= (IKCP_LOG_OUTPUT | IKCP_LOG_INPUT | IKCP_LOG_SEND | IKCP_LOG_RECV | IKCP_LOG_IN_DATA | IKCP_LOG_IN_ACK | 
		IKCP_LOG_IN_PROBE | IKCP_LOG_IN_WINS | IKCP_LOG_OUT_DATA | IKCP_LOG_OUT_ACK | IKCP_LOG_OUT_PROBE | IKCP_LOG_OUT_WINS);
	*/

	hasSetNextKcpUpdate_ = false;
	addKcpUpdate();
	return true;
}

2.channel中sendto进行发数据

void Channel::sendto(bool reliable, Bundle* pBundle)
{
	//..........
	if (pPacketSender_ == NULL)
	{
        //KCP
		pPacketSender_ = KCPPacketSender::createPoolObject(OBJECTPOOL_POINT);
		pPacketSender_->pEndPoint(pEndPoint_);
		pPacketSender_->pNetworkInterface(pNetworkInterface_);
	}
	else
	{
        //TCP
		if (pPacketSender_->type() != PacketSender::UDP_PACKET_SENDER)
		{
			TCPPacketSender::reclaimPoolObject((TCPPacketSender*)pPacketSender_);
			pPacketSender_ = KCPPacketSender::createPoolObject(OBJECTPOOL_POINT);
			pPacketSender_->pEndPoint(pEndPoint_);
			pPacketSender_->pNetworkInterface(pNetworkInterface_);
		}
	}

	pPacketSender_->processSend(this, reliable ? 1 : 0);
	sendCheck(bundleSize);
}

3.kcp发送数据

bool UDPPacketSender::processSend(Channel* pChannel, int userarg)
{
    //..........
	Packet* pPacket = (*iter1);
	reason = processPacket(pChannel, pPacket, userarg);
    //..........

	return true;
}

//
Reason KCPPacketSender::processFilterPacket(Channel* pChannel, Packet * pPacket, int userarg)
{
	//......
	if (ikcp_waitsnd(pChannel->pKCP()) > (int)(pChannel->pKCP()->snd_wnd * 2)/* 发送队列超出发送窗口2倍则提示资源不足 */ || 
			ikcp_send(pChannel->pKCP(), (const char*)pPacket->data(), pPacket->length()) < 0)
		{
			ERROR_MSG(fmt::format("KCPPacketSender::ikcp_send: send error! currPacketSize={}, ikcp_waitsnd={}, snd_wndsize={}\n", 
				pPacket->length(), ikcp_waitsnd(pChannel->pKCP()), pChannel->pKCP()->snd_wnd));

			return REASON_RESOURCE_UNAVAILABLE;
		}
	//......
}

4.kcp接收数据

Reason KCPPacketReceiver::processPacket(Channel* pChannel, Packet * pPacket)
{
	if (pChannel != NULL && pChannel->hasHandshake())
	{
		pChannel->addKcpUpdate();

		if (ikcp_input(pChannel->pKCP(), (const char*)pPacket->data(), pPacket->length()) < 0)
		{
			RECLAIM_PACKET(pPacket->isTCPPacket(), pPacket);
			return REASON_CHANNEL_LOST;
		}

		RECLAIM_PACKET(pPacket->isTCPPacket(), pPacket);

		while (true)
		{
			Packet* pRcvdUDPPacket = UDPPacket::createPoolObject(OBJECTPOOL_POINT);
			int bytes_recvd = ikcp_recv(pChannel->pKCP(), (char*)pRcvdUDPPacket->data(), pRcvdUDPPacket->size());
			if (bytes_recvd < 0)
			{
				//WARNING_MSG(fmt::format("KCPPacketReceiver::processPacket(): recvd_bytes({}) <= 0! addr={}\n", bytes_recvd, pChannel->c_str()));
				RECLAIM_PACKET(pRcvdUDPPacket->isTCPPacket(), pRcvdUDPPacket);
				return REASON_SUCCESS;
			}
			else
			{
				if (bytes_recvd >= (int)pRcvdUDPPacket->size())
				{
					ERROR_MSG(fmt::format("KCPPacketReceiver::processPacket(): recvd_bytes({}) >= maxBuf({})! addr={}\n", bytes_recvd, pRcvdUDPPacket->size(), pChannel->c_str()));
				}

				pRcvdUDPPacket->wpos(bytes_recvd);

				Reason r = PacketReceiver::processPacket(pChannel, pRcvdUDPPacket);
				if (r != REASON_SUCCESS)
				{
					RECLAIM_PACKET(pRcvdUDPPacket->isTCPPacket(), pRcvdUDPPacket);
					return r;
				}
			}
		}
	}
	else
	{
		return PacketReceiver::processPacket(pChannel, pPacket);
	}

	return REASON_SUCCESS;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无痕Miss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值