loginApp代码分析
- 查看loginApp工程的main函数
看到函数入口 KBENGINE_MAIN 这个宏,这个宏定义在server/kbemain.h 中,我们看这个定义
看到这就出来了,我们熟悉的main函数,main函数首先通过loadConfig()首先初始化环境变量加载配置kbengine_def.xml和kbengine.xml配置,然后生成componentId,解析输入的 --gid 和 --gus等参数,后面两句是在windows下设置宕机dump文件名,最后执行函数kbeMain 这个函数正好在宏最后一行,正好是KBENGINE_MAIN后面写的函数体
函数调用了模板函数kbeMain<loginapp> 函数,我们看这个函数定义
第一个关注点 Network::NetworkInterface 这个构造函数中,会调用
bool NetworkInterface::initialize(const char* pEndPointName, uint16 listeningPort_min, uint16 listeningPort_max,
const char * listeningInterface, EndPoint* pEP, ListenerReceiver* pLR, uint32 rbuffer,
uint32 wbuffer)
我们来看这个函数的代码
bool NetworkInterface::initialize(const char* pEndPointName, uint16 listeningPort_min, uint16 listeningPort_max,
const char * listeningInterface, EndPoint* pEP, ListenerReceiver* pLR, uint32 rbuffer,
uint32 wbuffer)
{
KBE_ASSERT(listeningInterface && pEP && pLR);
if (pEP->good())
{
this->dispatcher().deregisterReadFileDescriptor(*pEP);
pEP->close();
}
Address address;
address.ip = 0;
address.port = 0;
pEP->socket(SOCK_STREAM);
if (!pEP->good())
{
ERROR_MSG(fmt::format("NetworkInterface::initialize({}): couldn't create a socket\n",
pEndPointName));
return false;
}
if (listeningPort_min > 0 && listeningPort_min == listeningPort_max)
pEP->setreuseaddr(true);
this->dispatcher().registerReadFileDescriptor(*pEP, pLR);
u_int32_t ifIPAddr = INADDR_ANY;
bool listeningInterfaceEmpty =
(listeningInterface == NULL || listeningInterface[0] == 0);
// 查找指定接口名 NIP、MAC、IP是否可用
if(pEP->findIndicatedInterface(listeningInterface, ifIPAddr) == 0)
{
char szIp[MAX_IP] = {0};
Address::ip2string(ifIPAddr, szIp);
INFO_MSG(fmt::format("NetworkInterface::initialize({}): Creating on interface '{}' (= {})\n",
pEndPointName, listeningInterface, szIp));
}
// 如果不为空又找不到那么警告用户错误的设置,同时我们采用默认的方式(绑定到INADDR_ANY)
else if (!listeningInterfaceEmpty)
{
WARNING_MSG(fmt::format("NetworkInterface::initialize({}): Couldn't parse interface spec '{}' so using all interfaces\n",
pEndPointName, listeningInterface));
}
// 尝试绑定到端口,如果被占用向后递增
bool foundport = false;
uint32 listeningPort = listeningPort_min;
if(listeningPort_min != listeningPort_max)
{
for(int lpIdx=ntohs(listeningPort_min); lpIdx<=ntohs(listeningPort_max); ++lpIdx)
{
listeningPort = htons(lpIdx);
if (pEP->bind(listeningPort, ifIPAddr) != 0)
{
continue;
}
else
{
foundport = true;
break;
}
}
}
else
{
if (pEP->bind(listeningPort, ifIPAddr) == 0)
{
foundport = true;
}
}
// 如果无法绑定到合适的端口那么报错返回,进程将退出
if(!foundport)
{
ERROR_MSG(fmt::format("NetworkInterface::initialize({}): Couldn't bind the socket to {}:{} ({})\n",
pEndPointName, inet_ntoa((struct in_addr&)ifIPAddr), ntohs(listeningPort), kbe_strerror()));
pEP->close();
return false;
}
// 获得当前绑定的地址,如果是INADDR_ANY这里获得的IP是0
pEP->getlocaladdress( (u_int16_t*)&address.port,
(u_int32_t*)&address.ip );
if (0 == address.ip)
{
u_int32_t addr;
if(0 == pEP->getDefaultInterfaceAddress(addr))
{
address.ip = addr;
char szIp[MAX_IP] = {0};
Address::ip2string(address.ip, szIp);
INFO_MSG(fmt::format("NetworkInterface::initialize({}): bound to all interfaces with default route interface on {} ( {} )\n",
pEndPointName, szIp, address.c_str()));
}
else
{
ERROR_MSG(fmt::format("NetworkInterface::initialize({}): Couldn't determine ip addr of default interface\n", pEndPointName));
pEP->close();
return false;
}
}
pEP->setnonblocking(true);
pEP->setnodelay(true);
pEP->addr(address);
if(rbuffer > 0)
{
if (!pEP->setBufferSize(SO_RCVBUF, rbuffer))
{
WARNING_MSG(fmt::format("NetworkInterface::initialize({}): Operating with a receive buffer of only {} bytes (instead of {})\n",
pEndPointName, pEP->getBufferSize(SO_RCVBUF), rbuffer));
}
}
if(wbuffer > 0)
{
if (!pEP->setBufferSize(SO_SNDBUF, wbuffer))
{
WARNING_MSG(fmt::format("NetworkInterface::initialize({}): Operating with a send buffer of only {} bytes (instead of {})\n",
pEndPointName, pEP->getBufferSize(SO_SNDBUF), wbuffer));
}
}
int backlog = Network::g_SOMAXCONN;
if(backlog < 5)
backlog = 5;
if(pEP->listen(backlog) == -1)
{
ERROR_MSG(fmt::format("NetworkInterface::initialize({}): listen to {} ({})\n",
pEndPointName, address.c_str(), kbe_strerror()));
pEP->close();
return false;
}
INFO_MSG(fmt::format("NetworkInterface::initialize({}): address {}, SOMAXCONN={}.\n",
pEndPointName, address.c_str(), backlog));
return true;
}
通过这里,我们看到通过Network::NetworkInterface 的构造函数,程序将网络的socket 创建,绑定,监听操作完成,这样进程就开始监听端口,等待客户端连接
后面的分析下次继续