gdb运行一个最简单的raknet程序,断点以后,敲入 info threads,可以看到有三个线程在跑
除了线程1的主线程外,还有其他两个线程,干什么的呢?由于只调用了一个startup函数,进入startup函数发现如下代码
#if !defined(__native_client__) && !defined(WINDOWS_STORE_RT)
for (i=0; i<socketDescriptorCount; i++)
{
if (socketList[i]->IsBerkleySocket())
((RNS2_Berkley*) socketList[i])->CreateRecvPollingThread(threadPriority);
}
#endif
errorCode = RakNet::RakThread::Create(UpdateNetworkLoop, this, threadPriority);
这两处创建了线程。但是有一堆的现在条件,打调试信息,看看是否走到这里
在以上的语句中分别打入pritf语句后,在起程序,发现如下
可以看到.两个线程都被穿件,而且,如果监听多个端口的话,会起n+1个线程。下面来看看这些线程都干什么。
第一个线程的循环体
unsigned RNS2_Berkley::RecvFromLoopInt(void)
{
isRecvFromLoopThreadActive.Increment();
while ( endThreads == false )
{
RNS2RecvStruct *recvFromStruct;
recvFromStruct=binding.eventHandler->AllocRNS2RecvStruct(_FILE_AND_LINE_);
if (recvFromStruct != NULL)
{
recvFromStruct->socket=this;
RecvFromBlocking(recvFromStruct);
if (recvFromStruct->bytesRead>0)
{
RakAssert(recvFromStruct->systemAddress.GetPort());
binding.eventHandler->OnRNS2Recv(recvFromStruct);
}
else
{
RakSleep(0);
binding.eventHandler->DeallocRNS2RecvStruct(recvFromStruct, _FILE_AND_LINE_);
}
}
}
isRecvFromLoopThreadActive.Decrement();
return 0;
}
核心函数是RecvFromBlocking(recvFromStruct),看实现
void RNS2_Berkley::RecvFromBlockingIPV4(RNS2RecvStruct *recvFromStruct)
{
sockaddr* sockAddrPtr;
socklen_t sockLen;
socklen_t* socketlenPtr=(socklen_t*) &sockLen;
sockaddr_in sa;
memset(&sa,0,sizeof(sockaddr_in));
const int flag=0;
{
sockLen=sizeof(sa);
sa.sin_family = AF_INET;
sa.sin_port=0;
sockAddrPtr=(sockaddr*) &sa;
}
recvFromStruct->bytesRead = recvfrom__( GetSocket(), recvFromStruct->data, sizeof(recvFromStruct->data), flag, sockAddrPtr, socketlenPtr );
if (recvFromStruct->bytesRead<=0)
{
return;
}
recvFromStruct->timeRead=RakNet::GetTimeUS();
{
recvFromStruct->systemAddress.SetPortNetworkOrder( sa.sin_port );
recvFromStruct->systemAddress.address.addr4.sin_addr.s_addr=sa.sin_addr.s_addr;
}
// printf("--- Got %i bytes from %s\n", recvFromStruct->bytesRead, recvFromStruct->systemAddress.ToString());
}
recvfrom__,阻塞函数。
可以猜测,这个线程是用来接收数据的,接收到以后放入一个队列中,然后通过一个事件,通知处理线程处理数据。
看看下一个线程的作用
RAK_THREAD_DECLARATION(RakNet::UpdateNetworkLoop)
{
RakPeer * rakPeer = ( RakPeer * ) arguments;
BitStream updateBitStream( MAXIMUM_MTU_SIZE
#if LIBCAT_SECURITY==1
+ cat::AuthenticatedEncryption::OVERHEAD_BYTES
#endif
);
//
rakPeer->isMainLoopThreadActive = true;
while ( rakPeer->endThreads == false )
{
if (rakPeer->userUpdateThreadPtr)
rakPeer->userUpdateThreadPtr(rakPeer, rakPeer->userUpdateThreadData);
rakPeer->RunUpdateCycle(updateBitStream);
// Pending sends go out this often, unless quitAndDataEvents is set
rakPeer->quitAndDataEvents.WaitOnEvent(10);
}
rakPeer->isMainLoopThreadActive = false;
return 0;
}
核心函数 RunUpdateCycle(updateBitStream),看其实现
实现函数太负责,下篇分析