zoukankan      html  css  js  c++  java
  • 9、Khala实现0.01版QQ

      这次来个有界面的。

      登录界面:

    QQ图片20160101200957

    QQ图片20160101201510

      主界面:

    QQ图片20160101202605

    QQ图片20160101203009

    1、服务端开发:

      只需创建一个类ChatType(./examples/HelloKhala/src/ChatType.cpp),在该类型中,核心为创建的两个消息事件,一个为onCurrFriends,用于获取当前在线用户;一个为onSendMsg,用于向具体用户发送消息。

      客户端请求当前的在线用户的信息,发送请求消息。该请求消息由onCurrFriends解析。onCurrFriends首先获取所有类型为ChatType的在线用户的id,然后再遍历这些id,根据id获取具体的用户信息,并将这些信息以json形式进行处理,设置类型为CHAT_TYPE,并最终将该json消息发送给请求的客户端。

    bool ChatType::onCurrFriends(khala::InfoNodePtr& infoNodePtr, Json::Value& msg,
            khala::Timestamp time) {
        Json::Value res;
        //返回给请求用户的消息类型
        res[MSG_TYPE] = CHAT_FRIENDS;
        res["result"] = "true";
        khala::NodeManager* nodeManager = getNodeManager();
        //获取类型为ChatType的在线用户的id
        std::vector<uint> currIds = nodeManager->getNodeIDs(
                infoNodePtr->getNodeType());
        for (std::vector<uint>::iterator it = currIds.begin(); it != currIds.end();
                ++it) {
            khala::InfoNodePtr usrInfoNode;
            //根据id获取具体用户的信息
            if (nodeManager->find(*it, usrInfoNode)) {
                Json::Value usrJs;
                usrJs[KEY_ID] = *it;
                UsrInfo* usrInfo = boost::any_cast<UsrInfo*>(
                        usrInfoNode->getExtraContext());
                usrJs["name"] = usrInfo->getName();
                res["data"].append(usrJs);
            }
        }
        //发送json消息
        Json::FastWriter jwriter;
        std::string sendStr = jwriter.write(res);
        infoNodePtr->send(sendStr);
        return true;
    }

      客户端用户A请求发送消息msg给用户B,该请求消息由onSendMsg解析。onSendMsg获取消息msg,根据用户B的id获取用户B的对象,并将msg以json进行消息处理后设置消息类型为CHAT_REV,并发送给用户B。同时记录发送结果,并将结果以json形式进行处理,最后设置消息类型为CHAT_SEND将该结果返回给用户A。

    bool ChatType::onSendMsg(khala::InfoNodePtr& infoNodePtr, Json::Value& msg,
            khala::Timestamp time) {
        Json::Value res;
        //返回给请求发送用户的消息类型
        res[MSG_TYPE] = CHAT_SEND;
        //获取目的用户的id
        uint friendId = msg[KEY_FRIEND_ID].asUInt();
        //得到待发送消息
        std::string sendMsg = msg[CHAT_MSG].asString();
        res[FRIEND_NAME] = msg[FRIEND_NAME].asString();
        res[CHAT_MSG] = sendMsg;
        khala::InfoNodePtr friendNodePtr;
        //根据目的用户的id获取目的用户的对象
        if (this->getNodeManager()->find(friendId, friendNodePtr)) {
            Json::Value sendJs;
            //发送给目的用户的消息类型
            sendJs[MSG_TYPE] = CHAT_REV;
            //发送给目的用户的消息
            sendJs[CHAT_MSG] = sendMsg;
            UsrInfo* usrInfo = boost::any_cast<UsrInfo*>(
                    infoNodePtr->getExtraContext());
            if (usrInfo == 0) {
                return false;
            }
            //发送用户的姓名和id
            sendJs[SEND_NAME] = usrInfo->getName();
            sendJs[KEY_FRIEND_ID] = infoNodePtr->getId();
            //将该json消息发送给目的用户
            Json::FastWriter jwriter;
            std::string sendStr = jwriter.write(sendJs);
            friendNodePtr->send(sendStr);
            //向请求用户标示结果为成功
            res["result"] = "true";
        } else {
            //向请求用户标示结果为失败
            res["result"] = "false";
        }
        //将发送结果返回给请求用户
        Json::FastWriter jwriter;
        std::string sendStr = jwriter.write(res);
        infoNodePtr->send(sendStr);
        return true;
    }

    2、客户端开发:

      主要工作,拖界面,写控件响应事件!(废话)

      主要创建2个线程,一个为消息发送线程,一个为消息接收线程。

      消息发送线程:建立一个多生产者单消费者模型,每个窗口作为一个生产者,消息发送线程作为单独的消费者,选择System.Collections.Queue作为中间缓存。窗口将待发送json消息通过生产者接口发送给缓存容器。一旦缓存容器中存在待发送的消息,发送线程便被唤醒,从缓存中读取消息,对消息进行处理(选择utf8对字符进行处理,并添加长度头解决粘包问题),最终通过套接字发送给服务端。

      消息接收线程:以阻塞方式通过套接字循环接收消息,并将消息以字节形式保存在接收缓存中,通过长度头从接收缓存中获取每条完整的消息。再对该消息进行字符处理,解析为json形式,并根据消息类型将完整的消息通过SendMessage()发送给相应的窗口句柄进行处理。

      在每个具体窗口中,通过重写DefWndProc()来获取接收线程获取到的具体消息,并根据接收到的json消息编写窗口响应函数。

      具体客户端的代码就不贴了,不会C#,代码写得丑…

      最近应该会重写设备生命周期部分的代码,之前生命周期的超时检测部分设计实现得太丑陋,自己都看不下去了。争取少改动主要接口吧,阿门...

  • 相关阅读:
    滴水穿石Pydoop 架构和模块包介绍
    滴水穿石SSH Secure Shell Client安装和使用
    安装memcache到CentOS(另附yum法)
    php文件锁(转)
    MySQL中distinct和group by性能比较
    php中的自动加载
    php注释标准
    新浪API40310错误解决方法
    CentOS 5.5使用yum来安装LAMP(php运行环境)(转)
    MySQL优化之COUNT()效率
  • 原文地址:https://www.cnblogs.com/moyangvip/p/5093823.html
Copyright © 2011-2022 走看看