orzAsio代码研究一些笔记,感谢nous

(1) 组包发送数据

if (_ascId.cbId.clr == 0 && _ascId.cbId.id == 0)

{

return true;

}

IPacketShrPtr pk = allocPacket();

if (!ORZ_NET_DYN_ASSERT(pk != 0, __FILE__, __LINE__, 0))

{

return false;

}

 

pk->setMsg((int32)AMT_ASYNC_CALLBACK);

pk->writePtr((void*)_ascId.apId);

pk->writeUint(_ascId.cbId.clr);

pk->writeUint(_ascId.cbId.id);

pk->writeUshort((uint16)_arg.size());

pk->put(_arg.c_str(), _arg.size());

sSvcMgr(ServiceManager)->send(_ascId.snPxy, pk);

/

 

(2)OrzAsio的精华,无锁hash表

 

"这种编程思想总结为:

#1 使用某种方式(例如哈希)对数据分组;

#2 每个分组独自使用互斥锁,保证同一时间最多只有一个线程可以访问组内的数据;

#3 当有线程来访问数据的时候,根据分组方式中的分组算法选择出对应的组,来进行具

体的操作;

#4 分组算法本身最好是wait-free的;(例如key % maxGroup == groupid)。":

举例:

//

线程个数==哈希表中的桶的个数,可以做到无锁访问

 

m_threadPool->post((uint32)m_clients.hash(arc2s.nickname),  // 算出client所在的线程id

boost::bind(&ClientMgr::reg, this, arc2s.nickname, arc2s.password, arc2s.gender, _ascId));

 

void ClientMgr::reg(const std::string& _nn, const std::string& _pwd, bool _gdr, AsrpcCallId _ascId)

{

// 由于之前hash的处理,这里无需加锁

ClientPtr cln = m_clients.get(_nn, _nn, false); // 先根据_nn,算出hash值,从而得到具体的map

std::string err("ok");

if (cln)

{

err = "nickname already exist";

}

else

{

cln.reset(new Client(_nn, _pwd, _gdr));

if (m_clients.add(_nn, cln, _nn, false) != 0) // 因为一个线程对应一个hash分组,所以同一个时间只有一个线程访问这个分组故无需加锁

{

err = "internal error";

}

}

 

if (err == "ok")

{

printf("Register success!Nickname: %s/n", _nn.c_str());

}

else

{

printf("Register failed!/n");

}

 

ARegister_s2c ars2c(err);

ABase ab(MT_REG, ars2c.serialize2str());

callback(_ascId, ab.serialize2str());

}

 

 

(3) 多进程或者一些多线程经验总结

逻辑线程变成多个?这样做会给程序带来太多麻烦,从项目管理的角度来讲你不能要求每个写逻辑程序的人都精通多线程设计。而不精通,就容易写出不稳定的多线程程序。

所以最明智的做法是写成单线程多进程。

免费打工仔 发表于 2010-2-23 13:00

[i=s] 本帖最后由 免费打工仔 于 2010-2-23 13:01 编辑 [/i]

 

我不是Asio的作者,纯粹过来讨论。

多进程虽然是好的解决方案之一,但是因为在不同操作系统中进程的消耗和抢占方式不相同。在Windows类系列操作系统中创建进程和销毁进程都是比较消耗效率的。所以如果采用多进程方案的话,可能只限制在类Unix系统下比较好。

taotaotao 发表于 2010-2-23 14:27

 

我的意思是网络收发线程多个,逻辑处理线程只有一个就足够了。其实性能的瓶胫应该就是在网络收发,MMO的最大消耗资源的地方在组播和广播,只要逻辑处理没有阻塞行为,事实上只要把读写DB,读写文件等分离出来到一个线程或者一个进程,它就不会是阻塞的。

网络模块的最大瓶胫的带宽和网卡速度,其实主要还是要对广播的组播的控制,比如同一个地方1000个玩家,怎么组播移动数据?

Nous 发表于 2010-2-24 11:01

 

你完全可以设计逻辑线程是单线程的,这个取决于你怎么用OrzAsio(例如用队列从OrzAsio的多线程环境下传递网络消息到你的逻辑线程),OrzAsio中提到的多线程编程思想并没有强制使用者必须这么做。

 

另外,mmo广播的确是性能的瓶颈,现在只能在设计层面去尝试解决,例如,同一个地方1000个万家的话,说明人群非常密集,那么现实生活当中的这样的情况,会发生什么情况?那就是一堆人挤在一起,乱糟糟,你一个人接收到的声音、看到的情况都是模糊不清的,因为人太多,而且肯定会漏掉很多信息,其中最能清晰完整的辨识的消息就是离你最近的那些——那么还原到mmo中,我们在这种情况下,完全没有必要对所有1000个万家进行广播,而且根据人群密度和里玩家的距离,进行分层,越远的玩家,广播消息的频率就越低,只要保证同时广播的人数在一定范围内,服务器就可以接受。

Nous 发表于 2010-2-24 11:22

 

[i=s] 本帖最后由 Nous 于 2010-2-24 11:27 编辑 [/i]

 

还有,关于多线程开发方面,我个人有两种模型,其一是顶楼的方式;

 

另外一种是异步回调,这种方式下,没有显示的锁,所有的信息传递和api等的使用,都是异步的,基于队列,一块数据唯一绑定一个线程,这个线程除了操作它专属的数据外,不可操作其他数据,尤其是其它线程得数据。你可以理解为多进程的方式;

 

第二种方式的缺点是程序编写模式有些复杂(异步,大部分函数返回都要求用回调函数),但是多线程方面是绝对安全的,不会有诸如死锁、共享数据同时写入造成的崩溃、数据不同步等传统多线程下的问题。 

 

(4) 线程锁

 

//! 线程锁类

/*!

 * /note 线程安全

 * /note 可以自由的选择何种锁定方式(构造函数锁定、析构函数解锁,还是用成员函数加锁和解锁)

 example:

 /code

#1 情况1

boost::shared_mutex mutex;

{

DynShrLock lock(mutex); // 默认情况下,这里已经加锁,而且这种情况下选择的方式就是构造函数锁定、析构函数解锁;

// 用户只有在lock被销毁和手动调用lock.unlock()来解锁

lock.unlock(); // 手动调用解锁,但是这种情况下lock.lock();无效(即无法手动加锁)

}

// lock被销毁,同时执行解锁,但由于之前手动调用了解锁,所以这里"will nothing happen"

 

#2 情况2

boost::shared_mutex mutex;

{

DynShrLock lock(mutex, DynShrLock::LT_DELAY); // 这里并没有加锁,这种情况下选择的方式是用户需要用成员函数来手动加锁和解锁;

lock.lock(); // 手动加锁

}

// lock被销毁,但是由于模式为"DynShrLock::LT_DELAY",所以并不会自动解锁!

 

 

 

(4) 获取客户端ip地址

 

这个地址就是客户端的ip地址

 

ISession有一个方法,ISession::getSocket

 

取得ISocket指针,请将其根据ISocket::type来(TCP、UDP、SSL等)用dynamic_cast<>转换为对应的 Socket(TcpSocket,UdpSocket等)。

 

下面用TcpSocket举例:

 

使用TcpSocket::socket()取得boost::asio::ip::tcp::socket指针,然后用

 

boost::asio::ip::tcp::socket::remote_endpoint 方法取得远端endpoint:

 

boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();

 

然后用boost::asio::ip::tcp::endpoint::address()方法取得ip地址类,

 

最后用boost::asio::ip::address::to_string()方法取得std::string类型的ip地址

 

 

 

这些步骤中涉及的boost::asio的api在这里查阅:

 

http://www.boost.org/doc/libs/1_ … asio/reference.html

 

ISession* session = _snPxy.getSession();

std::string ip;

int port = 0;

if( SKTP_TCP == _snPxy.getSocketType() )

{

        TcpSocket* sock = dynamic_cast<TcpSocket*>(session->getSocket());

        boost::asio::ip::tcp::socket* sc = sock->socket();

        boost::asio::ip::tcp::endpoint endpoint = sc->remote_endpoint();

        boost::asio::ip::address addr;

        addr = endpoint.address();

        ip = addr.to_string();

        port = endpoint.port();

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据来源:中经数据库 主要指标110多个(全部都是纯粹的 市辖区 指标),大致是: GDP GDP增速 第一产业增加值占GDP比重 第二产业增加值占GDP比重 第三产业增加值占GDP比重 人均GDP 社会消费品零售总额 固定资产投资(不含农户) 新设外商投资企业数_外商直接投资 实际利用外资金额(美元) 一般公共预算收入 一般公共预算支出 一般公共预算支出_教育 一般公共预算支出_科学技术 金融机构人民币各项存款余额_个人储蓄存款 金融机构人民币各项存款余额 金融机构人民币各项贷款余额 规模以上工业企业单位数 规模以上工业企业单位数_内资企业 规模以上工业企业单位数_港澳台商投资企业 规模以上工业企业单位数_外商投资企业 规模以上工业总产值 规模以上工业总产值_内资企业 规模以上工业总产值_港澳台商投资企业 规模以上工业总产值_外商投资企业 规模以上工业企业流动资产合计 规模以上工业企业固定资产合计 规模以上工业企业利润总额 规模以上工业企业应交增值税 规模以上工业企业主营业务税金及附加 户籍人口数 年均户籍人口数 户籍人口自然增长率 第一产业就业人员占全部城镇单位就业人员比重 第二产业就业人员占全部城镇单位就业人员比重 第三产业就业人员占全部城镇单位就业人员比重 城镇非私营单位就业人员数 城镇非私营单位就业人员数_第一产业 城镇非私营单位就业人员数_第二产业 城镇非私营单位就业人员数_第三产业 城镇非私营单位就业人员数_农、林、牧、渔业 城镇非私营单位就业人员数_采矿业 城镇非私营单位就业人员数_制造业 城镇非私营单位就业人员数_电力、热力、燃气及水生产和供应业 城镇非私营单位就业人员数_建筑业 城镇非私营单位就业人员数_批发和零售业 城镇非私营单位就业人员数_交通运输、仓储和邮政业 城镇非私营单位就业人员数_住宿和餐饮业 城镇非私营单位就业人员数_信息传输、软件和信息技术服务业 城镇非私营单位就业人员数_金融业 城镇非私营单位就业人员数_房地产业 城镇非私营单位就业人员数_租赁和商务服务业 城镇非私营单位就业人员数_科学研究和技术服务业 城镇非私营单位就业人员数_水利、环境和公共设施管理业 城镇非私营单位就业人员数_居民服务、修理和其他服务业 城镇非私营单位就业人员数_教育 城镇非私营单位就业人员数_卫生和社会工作 城镇非私营单位就业人员数_文化、体育和娱乐业 城镇非私营单位就业人员数_公共管理、社会保障和社会组织 城镇非私营单位在岗职工平均人数 城镇就业人员数_私营企业和个体 城镇非私营单位在岗职工工资总额 城镇非私营单位在岗职工平均工资 城镇登记失业人员数 建成区面积 建设用地面积 建设用地面积_居住用地 液化石油气供气总量 液化石油气供气总量_居民家庭 人工煤气、天然气供气总量 人工煤气、天然气供气总量_居民家庭 液化石油气用气人口 人工煤气、天然气用气人口 城市公共汽电车运营车辆数 城市出租汽车运营车辆数 城市公共汽电车客运总量 道路面积 排水管道长度 建成区绿化覆盖面积 建成区绿化覆盖率 绿地面积 公园绿地面积 维护建设资金支出 土地面积 生活用水供水量 供水总量 全社会用电量 城乡居民生活用电量 工业生产用电量 房地产开发投资 房地产开发投资_住宅 限额以上批发和零售业法人单位数 限额以上批发和零售业商品销售总额 普通中学学校数 中等职业教育学校数 普通小学学校数 普通高等学校专任教师数 普通中学专任教师数 中等职业教育专任教师数 普通小学专任教师数 普通高等学校在校生数 普通中学在校生数 中等职业教育在校生数 普通小学在校生数 电视节目综合人口覆盖率 公共图书馆总藏量_图书 医疗卫生机构数_医院和卫生院 卫生人员数_执业(助理)医师 医疗卫生机构床位数_医院和卫生院 城镇职工基本养老保险参保人数 职工基本医疗保险参保人数 失业保险参保人数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值