客户端打开

客户端打开服务器是怎么知道连接的
1.客户端调用NGP的接口
TcpLinkEx::TcpLinkEx()
{
    auto ser = GetPlug(LibEvtServer);
    if(!ser)
    {
        ser = NEW(LibEvtServer);
        SetPlug("LibEvtServer", ser);

        ser->init(&g_TcpSerEvt, 0, 5000);//主要是初始化线程,和创建base
        int port = 2000;
        while(1)
        {
            bool hr = ser->listen(&port);
            if(hr)
                break;
            port++;
        }

    }
    m_tcpServer.reset(ser);
}

2.调用ConnectServer接口
bool NGP::ConnectServer(const char* pIp, unsigned int nPort)
{
    std::shared_ptr<I_SaveOption> so = NEWSP(SaveOption);
    std::wstring path = Plug::GetCurrentPath() + L"option.xml";
    so->openFile(path.c_str());

    //连接服务器
    std::string my_ip = Plug::wcstombs(so->getStr(L"root.server.ip"));
    int port = so->getInt(L"root.server.port");

    //int i_ip = ntohl(inet_addr(my_ip.c_str()));
    int i_ip;
    if( strcmp( pIp, "127.0.0.1"))
    {
        i_ip = htonl(inet_addr(pIp));
    }
    else
    {
        i_ip = htonl(inet_addr(my_ip.c_str()));
        nPort = port;
    }
    m_nPort = nPort;
    m_nIp = i_ip;
    return _TcpLink->Connect(i_ip, nPort);
}

bool LibEvtServer::connet_to(int ip, int port)
{
    auto bev = bufferevent_socket_new(m_base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE); //创建基于SOCKET的bufferevent
    if (!bev){
        std::cout << "bufferevent_socket_new error!" << std::endl;
        return false;
    }  

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = ntohl(ip);
    sin.sin_port = htons(port);
    //连接相当于socket里面的connect,此处connect,net进程的监听器就会就会收到通知
    int hr = bufferevent_socket_connect(bev, (struct sockaddr*)&sin, sizeof(sin));
    if(0 != hr)
        return false;

    std::lock_guard<std::mutex> lock(m_offline_mtx);//跟申请释放channel id互锁
    auto c2 = CreateChannel(bev);

    bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, c2);//设置读写事件

    bufferevent_enable(bev, EV_READ | EV_WRITE);
    return true;
}
3.net进程收到通知就会把这个socketfd放到轮询线程队列中,顺便想socketpair中写入一字节的数据
此时线程的读事件会调用,从socketpair中读取这个一个字节的数据
{
    ........
    //创建基于socket的bufferevent
    auto bev = bufferevent_socket_new(plt->thread_base, item.fd, BEV_OPT_THREADSAFE);

    Channel2* c2 = CreateChannel(bev);

    //设置接收、状态改变 回调函数
    bufferevent_setcb(bev, conn_readcb, NULL, conn_eventcb, c2);
    bufferevent_enable(bev, EV_READ | EV_WRITE );
}
4.在createChannel中会产生回调
void TCPServer::on_connect(int channel_id)
{
    packet pkt;
    pkt.size = (int)link_stat::link_connected;
    pkt.channel_id = channel_id;
    pkt.is_data = false;
    from_net_push_pkt(pkt);//会将包放入TCPServer的无锁队列中
}
5.net进程中的线程取包,然后放入共享内存中
net进程在创建的时候会创建线程专门中无锁队列中取包然后放入共享内存中
std::thread thr([this]()
{
    for (;;)
    {
        fromNet2Mem();
    }
});

bool NetProcSvr::fromNet2Mem()
{
    packet pkt;
    pkt.data = m_rev_buffer;
    auto hr2 = m_spTCPServer->recv(pkt);
    if(!hr2)
    {
        boost::this_thread::interruptible_wait(1);
        return true;
    }
    shareData sd;
    sd.channel_id    = pkt.channel_id;
    sd.data            = pkt.data;
    sd.is_data        = pkt.is_data;
    sd.size            = pkt.size;
    //其实这个语句的过程
    //从共享的维护索引的队列中pop一个,然后根据其中存储的索引获取对应共享内存的地址,但这块内存没有用到,因为这只是个连接,没有数据
    //将这个从共享内存里面pop出来的东西放到push到共享的队列中,此时算是放到了共享队列里面去了
    auto hr = m_spShareMemInter->pushA(sd);
    if(hr)
        return true;
    int count = 0;
    while(1)
    {
        hr = m_spShareMemInter->pushA(sd);
        if(hr)
            break;
        if(++count > 100)
        {
            MessageBoxA(nullptr, "Net进程:fromNet2Mem,向共享内存中pushA失败超过100次!", "提示", MB_ICONWARNING);
            count = 0;
        }
        boost::this_thread::interruptible_wait(1);
    }
    return true;
}
6.GS从共享内存中去取共享内存
{
    ....
    //网络事件
    link_stat stat = (link_stat)pkt.size;
    if (stat == link_stat::link_connected)
    {
        auto gc = new GameChannel();
        m_Channels[pkt.channel_id] = gc;//有玩家连接
        gc->m_channel_id = pkt.channel_id;
        gc->m_DataLayer = m_spDataLayer.get();
        gc->m_share = this;
        gc->m_asyndb = this->m_asyndb.get();
        //gc->m_db = this->m_asyndb->getSynDBptr();//把地址复制一份给GameChannel::m_db,让其具有数据库操作权
        m_live_mgr.add(pkt.channel_id);//将其放入live_mgr中
    }
}
7.然后那个界面的应该是定时的调用
void __stdcall GameServer::get_info(GSinfo& info)
{
    info.clientNum = m_live_mgr.get_links();//这个就是现实的链接数
    m_spDataLayer->get_buffer_num(info.sendBuffNum, info.revBuffNum);
}

//想到客户端打开就做了这么多事情,记得刚开始过来的时候,队长叫我从上面的这个地方看是看,懵懵懂懂看了一个月还是啥也不知道。
//中途一直想把客户端服务器这个连接的过程串起来,现在终于串起来了
时间: 2024-10-13 01:53:29

客户端打开的相关文章

前端判断是否APP客户端打开触屏,实现跳转APP原生组件交互之遐想

今天做了一个html的活动页面,本来马上就要完工,准备开开心心收尾,结果~... 产品突然提出需要说,要讲html中的某些交互和APP原生组件挂钩,心里一万头xxx奔过~ 静下心来思考 以往我们是判断是否客户端打开都依赖于后端,通过app主动拼接参数的方式,传递给后端,后端告诉前端本次的加载是在app里还是app外,实现页面的特殊功能 那我们发现,这个方式环节和局限性太多,我们无法保证客户端一定能够每个触屏页面都拼接我们需要的参数,而且我们的触屏页面有很多种,有的是活动需要的,有的是动态,有的是

模拟微信接口时,提示“请在微信客户端打开链接”(转)

背景描述 相信有模拟微信页面请求的测试都有看到过这个页面,简单点说就是爬虫爬微信页面,进行回放的时候会出现这个页面.大概在1年前,专门安排了一个人去解决这个技术问题,遗憾的是当时没有找到解决方案,接下来所有微信端的接口测试和性能测试都无法进行,今天和大家分享下我们的解决方案,希望大家可以绕过微信的坑. 业务场景 我这里以JMeter来举例,我们可以通过在JMeter上开启代理,手机上设置代理来录制微信端的请求,以下为在微信端的业务对应生成的脚本: 录制完成后,我们进行回放,你会发现在查看结果树中

postgres11.2版本客户端打开column &quot;p.prolang&quot;问题处理

postgres升级到到11版本后,客户端打开会提示ERROR:column p.proisagg does not existLINE 1:...database d on d.datname=current_database() where p.proisagg..HINT: Perhaps you meant to reference the column "p.prolang" 无法打开函数功能,如下图 是数据库服务版本高,客户端版本低引起的,通过下载最新pgadmin4-4.

outlook客户端打开后报证书错误

在我们的客户端配置outlook后,打开发现提示如下报错: 这时我们单击上图的"View Cerificate--",打开后,查看到的内容如下: 解决方法为:导入根证书至客户端计算机的根证书颁发机构中即可解决此问题.

weixin://connectToFreeWifi/?apKey=协议如何跳转到微客户端打开在wifi指定任意网页?

代码如下使用:<head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0"> <meta name="apple-mobile-web-app-capable"

js判断浏览器在PC中打开还是移动设备中打开

var browser = {                            versions: function () {                                var u = navigator.userAgent, app = navigator.appVersion;                                return {         //移动终端浏览器版本信息                                  

服务器打开共享内存的初始化

服务器共享内存以及客户端打开服务器获得通知过程 打开GS就会进行共享内存的初始化,过程很复杂,看了很多次,今天看的时候终于了解了大概了 bool DataLayer::init() { int pid = GetCurrentProcessId(); auto path = Plug::GetCurrentPath(); path += L"pid.txt"; auto file = _wfopen(path.c_str(), L"wb"); char buf[10

未加域客户端使用Lync时反复弹框要求输入凭证

最近发现部分未加域客户端打开Lync 2010时反复弹框要求输入凭证,且提示与Exchange进行连接时凭证错误,此时感觉问题原因因该是发生在两端客户端信息不匹配导致的,此时在Lync客户端帐号登录处输入完整域帐号(帐号@域名)后,并记住密码后无任何报错信息,且退出重新登录也不再提示,outlook相关日历信息也得到了正常同步. 未加域客户端使用Lync时反复弹框要求输入凭证,布布扣,bubuko.com

Muduo网络库实战(二):实现服务器与客户端的连接

1. 方案的确定 1)基本需求 用户1000+, IO压力不大: 多个客户端打开网站,输入查询字符串strclient,发送给服务器=>服务器接收客户端发过来的数据并处理,将结果返回给客户端: 2)并发网络服务程序设计方案 详见:<Muduo_网络库使用手册>的1.6节-<详解Muduo多线程模型> @ muduo中TcpServer模式的选择:多线程模式 模式一:单线程,accept与TcpConnection用同一个线程做IO; 模式二:多线程,accept与EventL