免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5040 | 回复: 20
打印 上一主题 下一主题

[C] 请教一个服务器程序协议设计的问题 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-27 09:47 |只看该作者 |倒序浏览
本帖最后由 csumck 于 2013-09-27 09:49 编辑

假设网络中存在机器A、B、C、D四台服务器, 它们各自只能连接最近的服务器,也就是说A只能连B,B能连A、C,C能连B、D,D只能连C。  每台服务器上也同时还有来自其他服务器的连接。
我的程序是通过TCP通信的,现在A想发一个数据请求,该数据需要依次在B、C、D四台机器上查找才能组织完全,也就是说请求包的路由顺序是 A->B->C->D,由于上面网络拓扑的原因,响应回包的路由必须是D->C->B->A。
问题是: C收到D的回包后,如何知道这个回包是要回给B的,B收到C的回包后如何知道包是要回给A的?

我现在用了个比较笨的解决办法:
      协议包头里有个请求流水号seq。B收到A的请求后,把请包头里的seq的值换成seqb(短期内不会重复)再发送给C,同时记录seqb是“来自A服务器的,原seq值是seqa”。 C收到B的请求包后,也是同样做法,包头里的seqb换成seqc再发给D,同时记录seqc是“来自C服务器,原seq值是seqb”。依此类推。
      这个方法能解决问题,但是有几个缺点:
      1. 这种记录的数据是要消耗内存的,包量越大消耗也越大(当然内存对现在服务器来讲不是大问题,但能减少消耗肯定最好了)
      2. 另外就是要判断超时,有些没有被及时回包的请求记录要删除,增加了服务器计算负担
      3. 服务一旦遭遇故障重启后,这些记录就会消失,收到回包后就找不到请求来自哪台机器了(通过共享内存等持久化的办法也可以解决,但是也会增加编码和维护的工作量)

希望大家能给指导一下,给些启发! 是不是协议还有其他的设计思路? 或者我这个笨办法有没有改进的空间?

ps. 为啥会有这种蛋疼的网络结构呢? 主要是各公司间安全通信的需要,各个机房只对某台机器开放网络连接的权限,这台机器就像一个网关一样处理所有进出这个机房的数据(主要是鉴定合法性、然后分流)。。。

论坛徽章:
6
酉鸡
日期:2013-11-04 15:30:02巳蛇
日期:2014-01-23 10:36:23双鱼座
日期:2014-01-23 13:08:332015亚冠之鹿岛鹿角
日期:2015-09-03 14:36:002015亚冠之武里南联
日期:2015-09-18 10:48:1315-16赛季CBA联赛之山西
日期:2016-05-05 00:05:33
2 [报告]
发表于 2013-09-27 09:57 |只看该作者
ID|类型(方向)|服务器标识|长度|数据|

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2013-09-27 10:00 |只看该作者
回复 2# Dannysd


    多谢, 不过我还是没明白。。方向和服务器类型具体是什么值呢? 能不能结合我那个例子说一下?

论坛徽章:
17
处女座
日期:2013-08-27 09:59:352015亚冠之柏太阳神
日期:2015-07-30 10:16:402015亚冠之萨济拖拉机
日期:2015-07-29 18:58:182015年亚洲杯之巴勒斯坦
日期:2015-03-06 17:38:17摩羯座
日期:2014-12-11 21:31:34戌狗
日期:2014-07-20 20:57:32子鼠
日期:2014-05-15 16:25:21亥猪
日期:2014-02-11 17:32:05丑牛
日期:2014-01-20 15:45:51丑牛
日期:2013-10-22 11:12:56双子座
日期:2013-10-18 16:28:17白羊座
日期:2013-10-18 10:50:45
4 [报告]
发表于 2013-09-27 10:03 |只看该作者
回复 1# csumck


    在应用层实现一个简单的路由协议,由这个路由协议决定处理节点失效和重定向等问题,通过路由协议确定目标主机。你可以参考一下消息队列(MQ)的消息路由。有很多开源实现。

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
5 [报告]
发表于 2013-09-27 10:19 |只看该作者
本帖最后由 cokeboL 于 2013-09-27 10:35 编辑

1. 这种记录的数据是要消耗内存的,包量越大消耗也越大(当然内存对现在服务器来讲不是大问题,但能减少消耗肯定最好了)

每台机器应该有自己能转发的列表,以及上游下游的区分比如

a的
transmit_map =
{
        //key  value           attr
        'b',     ip + port,    pre/behind
}

b的
transmit_map =
{
        //key  value           attr
        'a',   ip + port,    pre/behind
        'c',   ip + port,    pre/behind
}
依此推

a发一个请求的时候,请求包里包含一个请求序列栈
包头里包含一个请求序列栈长,request_stack_len

接收请求时,如果本机不是最后该请求所需到达的最后一台机器,就把本机id入栈,
把request_stack_len ++,并且转发给下一台机器
如果是最后一个机器,比如d,作为终结者,根据请求序列栈,把所查询的数据返回给上家

也就是请求的时候只发请求命令和请求序列,从最后一台机器开始返回数据,前面每台把自己的
数据加到其中,比如

a发请求给b:
[
  ... ,
  request_stack_len = 1,
  'a'
]

b收到继续转发给c
[
  ... ,
  request_stack_len = 2,
  'a',
  'b'
]

c收到继续转发给d
[
  ... ,
  request_stack_len = 3,
  'a',
  'b',
  'c'
]

d收到后因为自己是最后一台,就取出序列栈尾c,并返回数据给c
[
  ... ,
  return_stack_len = 2,
  'a',
  'b',
  data_len = n,
  [data]
]

c收到后把自己的数据加到里面返回给b
[
  ... ,
  return_stack_len = 1,
  'a',
  data_len = n,
  [data] //数据加到里面
]

论坛徽章:
6
酉鸡
日期:2013-11-04 15:30:02巳蛇
日期:2014-01-23 10:36:23双鱼座
日期:2014-01-23 13:08:332015亚冠之鹿岛鹿角
日期:2015-09-03 14:36:002015亚冠之武里南联
日期:2015-09-18 10:48:1315-16赛季CBA联赛之山西
日期:2016-05-05 00:05:33
6 [报告]
发表于 2013-09-27 10:28 |只看该作者
回复 3# csumck


    方向是代表由A发起的还是由D返回的,根据这个就知道应该传给上一个服务器还是下一个服务器

    服务器标识是B的话,根据方向就能判断是该传给C还是传给A

    我觉得这个结构在最前面还应该加上一个表示整个结构数据的长度字段,这样方便你TCP接收时候处理

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
7 [报告]
发表于 2013-09-27 10:28 |只看该作者
2. 另外就是要判断超时,有些没有被及时回包的请求记录要删除,增加了服务器计算负担

中转的机器不需要记录请求,始发的地方发请求的时候记录个请求标示和时间,做一个总的超时等待,超了就删掉,就可以了吧,没什么麻烦的

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
8 [报告]
发表于 2013-09-27 10:34 |只看该作者
3. 服务一旦遭遇故障重启后,这些记录就会消失,收到回包后就找不到请求来自哪台机器了(通过共享内存等持久化的办法也可以解决,但是也会增加编码和维护的工作量)

见上面的帖子,发请求和回包的时候都包含了请求和回发的序列栈,不会不知道来自哪台机器。防止服务器宕机应该在发包回包之间有确认机制,可能还是要做个超时重发,比如 b转请求给c,
计时3s,c收到转发给d后确认给b,如果3s过了b没收到确认重发请求给c。c转发给d的时候d就可以以回包作为确认。并且c回数据给b的时候给d一个确认,d超时没收到c成功转给b的确认,
就重发数据给c。直到a收到所有数据,过程over

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
9 [报告]
发表于 2013-09-27 10:34 |只看该作者
本帖最后由 yulihua49 于 2013-09-27 11:06 编辑

这是交易中间件的活。
我们的交易中间件可以做到这个。

实现方法可以说一下,没那么复杂。
首先,作为交易中间件,他有统一的数据包规范,客户端,服务器,呼叫,返回都是相同的包格式,这是数据包可以被中继的必要条件。
其次,每一个交易节点(它可以是客户端、服务器、客户端+服务器。。。。),内部对每个到达的交易都有一个context,
这个context里含有接入socket和若干接出socket。
当它需要级联接出时,就会从连接池获取一个适当的socket放在接出socket里(通过交易路由功能),并对它发送数据。
事件管理器会监听这个socket的返回,监听到了,把这个context提交给它的回调函数(也在context里),
在这个回调函数里处理其余的业务,其中,它既可以再次调用接出socket,也可以返回接入socket。不会搞错的。
在任何一个客户端连接服务器时,服务器都会给他分配一个context,并对其访问权进行认证。客户端需出示身份证、指纹等信息。
最后,这个context就是联系双方的‘ID’。直到一方logout。
其间,设置事件处理器(如epoll),一直使用这个context。

完了。


论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
10 [报告]
发表于 2013-09-27 10:49 |只看该作者
回复 5# cokeboL


    好办法,多谢你这么详细的讲解,太感谢了!
    再请教个具体点的问题,你说的这个办法里,每个服务的id是如何确定的?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP