??xml version="1.0" encoding="utf-8" standalone="yes"?>久久男人天堂,国产在线一区二区综合免费视频,久久亚洲精品成人http://www.aygfsteel.com/yongboy/category/54840.html记录工作/学习的点Ҏ滴?/description>zh-cnThu, 25 Feb 2021 04:44:55 GMTThu, 25 Feb 2021 04:44:55 GMT60Apisix 1.5 升?2.2 t坑备忘http://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.htmlnieyongnieyongTue, 23 Feb 2021 06:57:00 GMThttp://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.htmlhttp://www.aygfsteel.com/yongboy/comments/435806.htmlhttp://www.aygfsteel.com/yongboy/archive/2021/02/23/435806.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/435806.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/435806.html零、前a

U上q行?APISIX ?1.5 版本Q而社区已l发布了 Apisix 2.2Q是时候需要升U到最新版了,能够享受最版本带来的大量的BugFixQ性能增强Q以及新增特性的支持{~

从Apisix 1.5升到Apisix 2.2q程中,不是一帆风的Q中间踩了不坑Q所谓前车之鉴后事之师,q里l大家简单梳理一下我们团队所在具体业务环境下Q升U过E中t的若干坑,以及一些需要避免的若干注意事项{?/p>

下文所说原先版本,皆指Apisix 1.5Q新版则是Apisix 2.2版本?/p>

一、已有服务发现机制无法正常工?/h2>

针对上游Upstream没有使用服务发现的\由来Ԍ本次升没有遇到什么问题?/p>

公司内部U上业务大都ZConsul KV方式实现服务注册和服务发玎ͼ因此我们自行实现了一?consul_kv.lua 模块实现服务发现程?/p>

q在Apisix 1.5下面一切工作正常?/p>

但在Apisix 2.2下面Q就无法直接工作了,原因如下Q?/p>

  • 服务发现配置指o变了
  • 上游对象包含服务发现旉增加字段 discovery_type q行索引

2.1 服务发现配置指o变了

原先q行中仅支持一U服务发现机Ӟ需要配|在 apisix层下面Q?/p>

apisix:
    ......
    discover: consul_kv
    ......    

新版需要直接在config*.yaml文g中顶层层U下q行配置Q可支持多种不同的\由发现机Ӟ如下Q?/p>

discovery:                      # service discovery center
  eureka:
    host:                       # it's possible to define multiple eureka hosts addresses of the same eureka cluster.
      - "http://127.0.0.1:8761"
    prefix: "/eureka/"
    fetch_interval: 30          # default 30s
    weight: 100                 # default weight for node
    timeout:
      connect: 2000             # default 2000ms
      send: 2000                # default 2000ms
      read: 5000

我们有所变通,直接在配|文仉层配|consul_kv多个集群相关参数Q避?discovery 层q深?/p>

 discovery:
    consul_kv: 1
consul_kv:
  servers:
    -
      host: "172.19.5.30"
      port: 8500
    -
      host: "172.19.5.31"
      port: 8500
  prefix: "upstreams"
  timeout:
    connect: 6000
    read: 6000
    wait: 60
  weight: 1
  delay: 5
  connect_type: "long" # long connect
  ......

当然Q这仅仅保证了服务发现模块能够在启动时被正常加蝲?/p>

推荐阅读Q?/p>

2.2 upstream对象新增字段discovery_type

Apisix当前同时支持多种服务发现机制Q这个很赞。对应的代hQ就是需要额外引?discovery_type 字段Q用于烦引可能同时存在的多个服务发现机制?/p>

?Cousul KV方式服务发现ZQ那么需要在已有?upstream 对象中需要添加该字段Q?/p>

"discovery_type" : "consul_kv"

原先的一?code>upstream对象Q仅仅需?service_name 字段属性指定服务发现相兛_址卛_Q?/p>

{
    "id": "d6c1d325-9003-4217-808d-249aaf52168e",
    "name": "grpc_upstream_hello",
    ......
    "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
    "create_time": 1610437522,
    "desc": "demo grpc service",
    "type": "roundrobin"
}

而新版的则需要添?code>discovery_type字段Q表明该service_name 字段对应的具体模块名Uͼ效果如下Q?/p>

{
    "id": "d6c1d325-9003-4217-808d-249aaf52168e",
    "name": "grpc_upstream_hello",
    ......
    "service_name": "http://172.19.5.30:8500/v1/kv/upstreams/grpc/grpc_hello",
    "create_time": 1610437522,
    "desc": "demo grpc service",
    "type": "roundrobin",
    "discovery_type":"consul_kv"
}

后面我们若支持Consul Service或ETCD KV方式服务发现机制Q则会非常弹性和清晰?/p>

调整了配|指令,d上述字段之后Q后端服务发现其实就已经起作用了?/p>

但gRPC代理路由q不会生?#8230;…

二、gRPC当前不支持upstream_id

在我们的pȝ中,上游和\由是需要单独分开理的,因此创徏的HTTP或GRPC路由需要处理支?code>upstream_id的烦引?/p>

q在1.5版本中,grpc路由是没问题的,但到了apisix 2.2版本中,l护?@spacewander 暂时没做支持Q原因是规划grpc路由和dubbo路由处理逻辑于一_更ؓ紧凑。从l护角度我是认可的,但作Z用者来Ԍq就有些不合理了Q直接丢弃了针对以往数据的支持?/p>

作ؓ当前Geek一些方式,?apisix/init.lua 中,最成?Q优雅和成本成反比)修改如下Q找到如下代码:

    -- todo: support upstream id
    api_ctx.matched_upstream = (route.dns_value and
                                route.dns_value.upstream)
                               or route.value.upstream 

直接替换Z面代码即可解决燃眉之急:

    local up_id = route.value.upstream_id
    if up_id then
        local upstreams = core.config.fetch_created_obj("/upstreams")
        if upstreams then
            local upstream = upstreams:get(tostring(up_id))
            if not upstream then
                core.log.error("failed to find upstream by id: " .. up_id)
                return core.response.exit(502)
            end
            if upstream.has_domain then
                local err
                upstream, err = lru_resolved_domain(upstream,
                                                    upstream.modifiedIndex,
                                                    parse_domain_in_up,
                                                    upstream)
                if err then
                    core.log.error("failed to get resolved upstream: ", err)
                    return core.response.exit(500)
                end
            end
            if upstream.value.pass_host then
                api_ctx.pass_host = upstream.value.pass_host
                api_ctx.upstream_host = upstream.value.upstream_host
            end
            core.log.info("parsed upstream: ", core.json.delay_encode(upstream))
            api_ctx.matched_upstream = upstream.dns_value or upstream.value
        end
    else
        api_ctx.matched_upstream = (route.dns_value and
                                route.dns_value.upstream)
                               or route.value.upstream  
    end

三、自定义auth插g需要微?/h2>

新版的apisix auth授权插g支持多个授权插g串行执行Q这个功能也很赞Q但此DD了先前ؓ具体业务定制的授权插件无法正常工作,q时需要微调一下?/p>

原先调用方式Q?/p>

    local consumers = core.lrucache.plugin(plugin_name, "consumers_key",
            consumer_conf.conf_version,
            create_consume_cache, consumer_conf)

因ؓ新版?code>lrucache不再提供 plugin 函数Q需要微调一下:

local lrucache = core.lrucache.new({
  type = "plugin",
})
......
    local consumers = lrucache("consumers_key", consumer_conf.conf_version,
        create_consume_cache, consumer_conf)

另一处是Q顺利授权之后,需要赋?code>consumer相关信息Q?/p>

    ctx.consumer = consumer
    ctx.consumer_id = consumer.consumer_id

此时需要替换成如下方式QؓQ可能存在的Q后l的授权插gl箋作用?/p>

consumer_mod.attach_consumer(ctx, consumer, consumer_conf)

更多请参考:apisix/plugins/key-auth.lua 源码?/p>

四、ETCD V2数据q移到V3

q移分ؓ三步Q?/p>

  1. 升U上已有ETCD 3.3.*版本?.4.*Q满x版Apisix的要求,q时ETCD实例同时支持了V2和V3格式数据
  2. q移V2数据到V3
    • 因ؓ数据量不是非常多Q我采取了一个非常简单和原始的方?/li>
    • 使用 etcdctl 完成V2数据到导?/li>
    • 然后使用文本~辑器vim{完成数据的替换Q生成etcdctl v3格式的数据导入命令脚?/li>
    • q行之后V3数据导入脚本Q完成V2到V3的数据导?/li>
  3. 修改V3 /apisix/upstreams 中包含服务注册的数据Q一一d "discovery_type" : "consul_kv"属?/li>

Z以上操作之后Q从而完成了ETCD V2到V3的数据迁UR?/p>

五、启动apisix后发现ETCD V3已有数据无法加蝲

我们在运l层面,使用 /usr/local/openresty/bin/openresty -p /usr/local/apisix -g daemon off; 方式q行|关E序?/p>

q也导_自动忽略了官Ҏ倡的Q?code>apisix start 命o自动提前为ETCD V3初始化的一些键值对内容?/p>

因此Q需要提前ؓETCD V3建立以下键值对内容Q?/p>

Key                         Value
/apisix/routes          :   init_dir
/apisix/upstreams       :   init_dir
/apisix/services        :   init_dir
/apisix/plugins         :   init_dir
/apisix/consumers       :   init_dir
/apisix/node_status     :   init_dir
/apisix/ssl             :   init_dir
/apisix/global_rules    :   init_dir
/apisix/stream_routes   :   init_dir
/apisix/proto           :   init_dir
/apisix/plugin_metadata :   init_dir

不提前徏立的话,׃Dapisix重启后,无法正常加蝲ETCD中已有数据?/p>

其实有一个补救措施,需要修?apisix/init.lua 内容Q找到如下代码:

            if not dir_res.nodes then
                dir_res.nodes = {}
            end

比较geek的行为,使用下面代码替换一下即可完成兼容:

                if dir_res.key then
                    dir_res.nodes = { clone_tab(dir_res) }
                else
                    dir_res.nodes = {}
                end

六、apisix-dashboard的支?/h2>

我们Zapisix-dashboard定制开发了大量的针对公司实际业务非常实用的企业U特性,但也D了无法直接升U到最新版的apisix-dashboard?/p>

因ؓ非常基础的上游和路由没有发生多大改变Q因此这部分升的需求可以忽略?/p>

实际上,只是在提交上游表单时Q包含服务注册信息JSON字符串中需要增?discovery_type 字段和对应值即可完成支持?/p>

七、小l?/h2>

p了一些时间完成了从Apisix 1.5升到Apisix 2.2的行为,虽然有些坑,但整体来Ԍq算利。目前已l上Uƈ全量部vq行Q目前运行良好?/p>

针对q停留在Apisix 1.5的用P新版增加了Control API以及多种服务发现{新Ҏ支持,q是非常值得升的?/p>

升之前Q不妨仔l阅L一个版本的升日志Q地址Q?a >https://github.com/apache/apisix/blob/2.2/CHANGELOG.md Q,然后需要根据具体业务做好兼Ҏ试准备和准备升步骤Q这些都是非常有必要的?/p>

针对我们团队来讲Q升U到最新版Q一斚w降低了版本升U的压力Q另一斚w也能够辅助我们能参与到开源社Z去,挺好~



nieyong 2021-02-23 14:57 发表评论
]]>HTTP API设计W记http://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.htmlnieyongnieyongTue, 02 Jan 2018 12:53:00 GMThttp://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.htmlhttp://www.aygfsteel.com/yongboy/comments/433000.htmlhttp://www.aygfsteel.com/yongboy/archive/2018/01/02/433000.html#Feedback0http://www.aygfsteel.com/yongboy/comments/commentRss/433000.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/433000.html前言

最q一D|_要ؓ一个手机终端APPE序从零开始设计一整套HTTP APIQ因为面向的用户很固定,一个新的移动端APP。目前还是项目初期,自然要求一切快速、从Q实用性ؓ丅R?/p>

下面逐一我们是如何设计HTTP APIQ虽然相对大部分言Q没有什么新意,但对我来说很新鲜的。避免忘_着I闲快记录下来?/p>

技术堆栈的选择

PHP嘛?团队内也没几个h熟悉?/p>

JavaQ好几年没有过了,那么复杂的解x案,再加上团队内也没什么h?……

团队使用qLuaQ基于OpenResty构徏qTCP、HTTP|关{,对Lua + Nginxl合非常熟悉Q能够快速的应用在线上环境。再说Lua语法y、简单,一个新手半天就可以基本熟悉Q马上开工?/p>

看来QNginx + Lua是目前最为适合我们的了?/p>

HTTP APIQ需要充分利用HTTP具体操作语义Q来应对具体的业务操作方法。基于此Q没有闭门造RQ我们选择?http://lor.sumory.com/ q么一个小巧的框架Q用于辅助HTTP API的开发开发?/p>

嗯,OpenResty + Lua + LorQ就构成了我们简单技术堆栈?/p>

HTTP API要设?/h2>

HTTP API路径和语?/h3>

每一具体业务逻辑Q直接在URL Path中体现出来。我们要的是单快速,数据l构之间的连接关p,可能的LE化。egQ?/p>

/resource/video/ID

比如用户反馈q一模块Q将使用下面比较固定的\径:

/user/feedback
  • GETQ以用户l度查询反馈的历史列表,可分?
    • curl -X GET http://localhost/user/feedback?page=1
  • POSTQ提交一个反?
    • curl -X POST http://localhost/user/feedback -d "content=hello"
  • DELETEQ删除一个或多个反馈Q参数附加在URL路径中?
    • curl -X DELETE http://localhost/user/feedback?id=1001
  • PUTQ更新评论内?
    • curl -X PUT http://localhost/user/feedback/1234 -d "content=hello2"

用户属性很多,用户늧只是其中一个部分,因此更新늧q一行ؓQHTTP?PATCH Ҏ可更_և的描q部分数据更新的业务需求:

/user/nickname
  • PATCHQ更新用hUͼ늧是用户属性之一Q可以用更轻量U的 PATCH 语义
    • curl -X PATCH http://localhost/user/nickname -d "nickname=hello2"

嗯,同一cȝ资源URL虽然固定了,但HTTP Method呈现了不同的业务逻辑需求?/p>

HTTP API的访问授?/h3>

实际业务HTTP API的访问是需要授权的?/p>

传统的Access Token解决ҎQ有session回话机制Q一般需要结合Web览器,需要写入到Cookie中,或生产一个JSessionID用于标识{。这针对单纯面向Udl端的HTTP API后端来讲Qƈ没有义务dq一的兼容,略显冗余?/p>

另外是 OAUTH 认证了,有整套的认证Ҏq已工业化,很是成熟了,但对我们而言q是太重Q不太适合轻量U的HTTP APIQ不太可能花费太多的_֊d它的q维工作?/p>

最l选择了轻量?Json Web TokenQ非常紧凑,开即用?/p>

最佛_法是把JWT Token攑֜HTTPh头部中,不至于和其它参数hQ?/p>

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI2NyIsInV0eXBlIjoxfQ.LjkZYriurTqIpHSMvojNZZ60J0SZHpqN3TNQeEMSPO8" -X GET http://localhost/user/info

下面是一副浏览器D늚一般认证流E,q与HTTP API认证大体一_

JWT的Lua实现Q推? https://github.com/SkyLothar/lua-resty-jwt.gitQ简单够用?/p>

JWT和Lor的结?/h3>

jwt需要和业务q行l定Q结?lor q个API开发框架提供的中间件机Ӟ可在业务处理之前Q在合适位|进行权限拦截?/p>

  • 用户需要请求进行授权接口,比如登陆{?/li>
  • 服务器端会把用户标识W,比如用户id{,存入JWT的payload负荷中,然后生成Token字符Ԍ发给客户?/li>
  • 客户端收到JWT生成的Token字符Ԍ在后l的h中需要附加在HTTPh的Header?/li>
  • 完成认证q程

不同于OAUTHQJWT协议?strong>自包?/strong>Ҏ,军_了后端可以将很多属性信息存攑֜payload负荷中,其token生成之后后端可以不用存储Q下ơ客L发送请求时会发送给服务器端Q后端获取之后,直接验证卛_Q验证通过Q可以直接读取原先保存其中的所有属性?/p>

下面梳理一下Jwt认证和Lor的结合?/p>

  • 全局拦截Q针Ҏ有PATHQ所有HTTP MethodQ这里处理JWT认证Q若认证成功Q会直接把用户id注入到当前业务处理上下文中,后面的业务可以直接读取当前用Lid?/li>
app:use(function(req, res, next)
    local token = ngx.req.get_headers()["Authorization"]
    -- 校验p|Qerr为错误代码,比如 400
    local payload, err = verify_jwt(token)
    if err then
        res:status(err):send("bad access token reqeust")
        return
    end

    -- 注入q当前上下文中,避免每次从token中获?    req.params.uid = payload.uid

    next()
end)
  • 针对具体路径q行讑֮权限拦截Q较_粒度;比如 /user 只允许已登陆授权用户讉K
app:use("/user", function(req, res, next)
    if not req.params.uid then
        -- 注意Q这里没有调用next()ҎQ请求到q里截止了Q不在匹配后面的路由
        res:status(403):send("not allowed reqeust")
    else
        next() -- 满以上条gQ那么l匹配下一个\?    end
end)
  • 一U是较细_度Q具体到每一个API接口Q因然URL一_但不同的HTTP Method有时h权限q是有区别的
local function check_token(req, res, next)
    if not req.params.uid then
        res:status(403):send("not allowed reqeust")
    else
        next()
    end
end

local function check_master(req, res, next)
    if not req.params.uid ~= master_uid then
        res:status(403):send("not allowed reqeust")
    else
        next()
    end
end

local lor = require("lor.index")
local app = lor()

-- 声明一个group router
local user_router = lor:Router()

-- 假设查看是不需要用h限的
user_router:get("/feedback", function(req, res, next)
end)

user_router:put("/feedback", check_token, function(req, res, next)
end)

user_router:post("/feedback", check_token, function(req, res, next)
end)

-- 只有理员才有权限删?user_router:delete("/feedback", check_master, function(req, res, next)
end)

-- 以middleware的Ş式将该group router加蝲q来
app:use("/user", user_router())

......

app:run()

Z么没有选择GraphQL API Q?/h2>

我们在上一个项目中对外提供了GraphQL APIQ其Q在试环境下)自n提供文档输出自托机Ӟ再结合方便的调试客户端,实让后端开发和前端APP开发大大降低了频繁交流的频率,节省了若q流量,但前期还是需要较多的培训投入?/p>

但在新项目中Q一度想提供GraphQL APIQ遇到的问题如下Q?/p>

  • 全新的项目数据结构属性变动太频繁
  • 普遍求快Q业务模型快速开发、调?/li>
  • 大家普遍对GraphQL API有些抵触Q用JSON输出格式的HTTP API是约定俗成的习惯选择

毫无疑问Q以最低成本快速构为完整的APP功能QHTTP API + JSON格式是最服的选择?/p>

虽然有些担心服务器端的输出,很多时候还是会费掉一些流量,客户端ƈ不能够有效的利用q回数据的所有字D属性。但和进度以及h们已l习惯的HTTP API调用方式相比Q又微乎其微了?/p>

当前q一套HTTP API技术堆栈运行的q不错,希望能给有同样需要的同学提供一点点的参考h? :))

当然没有一成不变的架构模型Q随着业务的逐渐发展Q后面相信会有很多的变动。但q是以后的事情了Q谁知道呢,后面有空再次记录吧~



nieyong 2018-01-02 20:53 发表评论
]]>
《环信支持千万ƈ发即佉K讯的技术要炏V阅L?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/10/30/419289.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 30 Oct 2014 08:15:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/10/30/419289.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/419289.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/10/30/419289.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/419289.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/419289.html</trackback:ping><description><![CDATA[<h3><font style="font-weight: bold">零。前a</font></h3> <p>一天早上v来,偶然Z看到《环信支持千万ƈ发即佉K讯的技术要炏V演C文档,单翻阅之后,感觉q货很多Q于是快速记下以下笔记? </p><h3><font style="font-weight: bold">一。IM协议和IM Server </font></h3> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/870671719_2.png"><img title="870671719" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="870671719" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/870671719_thumb.png" border="0" height="665" width="860" /></a> </p><p>XMPP实很传l,WhatsApp选用了,同时l过压羃、精Q比如说user字符串用u字符替代Q处理,让XMPP轻量不少? </p><p>MQTTQ如何实现群l、好友呢Q这个是业务层面上事情,大家都订阅某一个主题Topic好了Q属于业务拓展? </p><p>SIPQ接触少? </p><p>微信U有协议ActivitySyncQ以前在博客上分享过? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881148668_2.png"><img title="881148668" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="881148668" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881148668_thumb.png" border="0" height="664" width="873" /></a> </p><p>正确拼写是WhatsAppQ呵c? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881243517_2.png"><img title="881243517" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="881243517" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881243517_thumb.png" border="0" height="606" width="836" /></a> </p><p>针对XMPP协议的改q,很有参考h倹{? </p><p>心蟩单向四个字节Q在XMPP协议下,估计应该是极限了吧。在U有协议协议下,一来一往两个字节_? </p><p>文g传输方式Q这是业界通用方式? </p><p>Ud互联|环境下Q用hq在U,大家的共识。可是取决于手机有没有连接到服务器端Q这是无法逾越的障? </p><p>Muc聊天室,业务层面改进? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881482479_2.png"><img title="881482479" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="881482479" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/881482479_thumb.png" border="0" height="615" width="846" /></a> </p><p>q个针对使用OpenFire的同学,很有参考意义? </p><p>话说Q我以前也安装过OpenFireQ定制过在线聊天/咨询的代码? </p><h3><font style="font-weight: bold">二。移动网l环境下的网l、电量等客户端优?/font></h3> <p><strong></strong><br /><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868742751_2.png"><img title="868742751" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="868742751" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868742751_thumb.png" border="0" height="379" width="685" /></a> </p><p>IM或推送,建立长连接是必须的,可以节省TCP来回创徏的开销Q但断线之后Q是否需要即刻重q,其是处于地铁、WIFI边缘地带Q可能会造成重连风暴Q需要添加稍加gq连接机制? </p><p>针对发送的消息的回执,客户端一定要发送回执反馈,否则不知道是否发送成功与否? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868780347_2.png"><img title="868780347" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="868780347" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868780347_thumb.png" border="0" height="512" width="691" /></a> </p><p>量跑马速,心蟩Q压~传输? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868832358_2.png"><img title="868832358" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="868832358" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868832358_thumb.png" border="0" height="515" width="684" /></a> </p><p>Android手机端优化措施,q货、细节很实用Q可以直接拿来用Q分享很l力Q呵呵! </p><p>扚w、合q数据请?发送,增量更新Q这是一个大安应该使用的常规节省流量手D,应牢讎ͼ </p><p>隑־的是Q分享了Q? </p><p>2G 文g上传最佳buffer size 1024个字节,3G/4G下直接设|ؓ10K </p><p>2G 文g下蝲最佳buffer size 2048个字节,3G/4G?30K </p><p>l对l验的ȝQ赞Q? </p><p>心很l,l出了频J的属性访问直接声明protected/publish了,不创建新的Java对象只能staticcd了。记得很久以前写J2MEE序Ӟqq这L方式? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868936208_2.png"><img title="868936208" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="868936208" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868936208_thumb.png" border="0" height="432" width="657" /></a> </p><p>实践中走q多弯路才ȝ出来的同步、绘图、渲染页面惊艻I其是支持离U方式的数据同步机制Q很受用? </p><h3><strong>三。百万架构l验分n</strong> </h3> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868995894_2.png"><img title="868995894" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="868995894" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/868995894_thumb.png" border="0" height="364" width="671" /></a> </p><p>虽然很简单,熟悉TCP/IP协议Q这是毫无疑问? </p><p>无状态协议交互,才能够很Ҏ水^横向扩展Q也是当今共识? </p><p>让所有操作都要尽可能的异? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/869119306_2.png"><img title="869119306" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="869119306" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/869119306_thumb.png" border="0" height="966" width="1192" /></a> </p><p>典型的按照机房进行完整部|Ԍ若不能够在DNS层面做到按照用户IDq行指派QHTTP DNSq行接入IP分配Q,那么必d理用户ؕ入机房的问题Q必然要做到一些数据的跨机房的同步Q大安会采用增量式同步方式Q跨机房一般常?0毫秒的gq,扚w形式增量同步Q那都不叫事? </p><p>可以看到业务垂直切分Q各个业务之间水qx展? </p><p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/869214857_2.png"><img title="869214857" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="869214857" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/a80247aad248_DCBB/869214857_thumb.png" border="0" height="901" width="1205" /></a> </p><p>貌似可以看到单元化CELL/SET架构的媄子,但这只是自己的瞎猜而已? </p><p>PPT上架构图文字l节不甚清晰Q再加上自己q视Q分辨不太老好的,可以看到消息存储使用了KafkaQ和数据库集之间存定时拉取关系Q,分布式锁ZZookeeperQ前端LVS做负载均衡,业务非常垂直? </p><p>在PPT上只看到了两个机房,若用户量U上亿,可能需要扩展到W三个、第三机房,可能跨机房同步的压力就凸显出来了? </p><h3><font style="font-weight: bold">四。小l?</font></h3> <p>MQ干货不,很给力,再次对刘壮大牛表示感谢Q? </p><p>原PPT下蝲地址Q?a >http://vdisk.weibo.com/s/A0GI9rXObFMd</a> </p><p>PS: 若有侉|Q请及时告知?</p><img src ="http://www.aygfsteel.com/yongboy/aggbug/419289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-10-30 16:15 <a href="http://www.aygfsteel.com/yongboy/archive/2014/10/30/419289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>微信协议单调研笔?/title><link>http://www.aygfsteel.com/yongboy/archive/2014/03/05/410636.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 05 Mar 2014 06:15:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2014/03/05/410636.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/410636.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2014/03/05/410636.html#Feedback</comments><slash:comments>22</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/410636.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/410636.html</trackback:ping><description><![CDATA[<h3>前言</h3> <p>微信可调研点很多Q这里仅仅从协议角度q行调研Q会涉及到微信协议交换、消息收发等。所?#8220;弱水三千Q只取一?#8221;吧?/p> <p>杂七杂八的,有些长,可直接拉到最后看l论好了?/p> <h3>一。微信协议概?/h3> <p>微信传输协议Q官方公布甚,在微信技术ȝ所透漏PPT《微信之?#8212;至简》文档中Q有所体现?/p> <p>U个人理解:</p><pre><code>因张龙做邮Foxmail起家Q而又做了QQ Mail{,QQ Mail是国内第一个支持Exchange ActiveSync协议的免贚w,Z其从业背景,微信从一开始就采取ZActiveSync的修改版状态同步协议SyncQ也再自然不过了? </code></pre> <p>一句话Q增量式、按序、可靠的状态同步传输的微信协议?/p> <p>大致交换囑֦下:</p> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/Image(9)_2.png"><img title="Image(9)" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" alt="Image(9)" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/Image(9)_thumb.png" border="0" height="772" width="690" /></a></p> <p>如何获取新数据呢Q?/p> <ol> <li>服务器端通知Q客L获取 </li><li>客户端携带最新的SyncKeyQ发h据请? </li><li>服务器端生成最新的SyncKeyq同最新数据发送给客户? </li><li>Z版本h制同步协议,可确保数据增量、有序传? </li><li>SyncKeyQ由服务器端序列L成器生成Q一旦有新消息生,会产生最新的SyncKey。类g版本?</li></ol> <p>服务器端通知有状态更斎ͼ客户端主动获取自从上ơ更C后有变动的状态数据,增量式,序式?/p> <h3>二。微信Web端简单调?/h3> <p>在线版本微信Q?/p> <p><a >https://webpush.weixin.qq.com/</a></p> <p>通过Firefox + Firebugl合调试Q也能证实了微信大致通过交换SyncKey方式获取新数据的?/p> <h4>1. 发vGET长连接检是否存在新的需要同步的数据</h4> <p>会携带上最新SyncKey</p><pre><code>https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?callback=jQuery18306073923335455973_1393208247730&r=1393209241862&sid=s7c%2FsxpGRSihgZAA&uin=937355&deviceid=e542565508353877&synckey=1_620943725%7C2_620943769%7C3_620943770%7C11_620942796%7C201_1393208420%7C202_1393209127%7C1000_1393203219&_=1393209241865 </code></pre> <p>q回内容Q?/p><pre><code> window.synccheck={retcode:"0",selector:"2"} </code></pre> <p>selector值大?Q表C有新的消息需要同步?/p> <p>据目,心蟩周期?7U左叟?/p> <h4>2. 一旦有新数据,客户端POSThd获取同步的数?/h4><pre><code>https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=s7c%2FsxpGRSihgZAA&r=1393208447375 </code></pre> <p>携带消息体:</p><pre><code>{"BaseRequest":{"Uin":937355,"Sid":"s7c/sxpGRSihgZAA"},"SyncKey":{"Count":6,"List":[{"Key":1,"Val":620943725},{"Key":2,"Val":620943767},{"Key":3,"Val":620943760},{"Key":11,"Val":620942796},{"Key":201,"Val":1393208365},{"Key":1000,"Val":1393203219}]},"rr":1393208447374} </code></pre> <p>会携带上最新的SyncKeyQ会q回复杂l构体JSON内容?/p> <p>但浏览端收取到消息之后,如何通知服务器端已确认收CQWeb版本微信Q没有去做?/p> <p>在以往使用q程中,曑֏现WEB端有丢失消息的现象,但属于偶现象。但Android微信客户端(只要登陆q接上来之后Q貌似就没有丢失q?/p> <h4>3. 发送消息流E?/h4> <ol> <li> <p>发v一个POST提交Q用于提交用户需要发送的消息</p> <p>https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid=lQ95vHR52DiaLVqo&r=1393988414386</p></li></ol> <p>发送内容:</p><pre><code>{"BaseRequest":{"Uin":937355,"Sid":"lQ95vHR52DiaLVqo","Skey":"A6A1ECC6A7DE59DEFF6A05F226AA334DECBA457887B25BC6","DeviceID":"e937227863752975"},"Msg":{"FromUserName":"yongboy","ToUserName":"hehe057854","Type":1,"Content":"hello","ClientMsgId":1393988414380,"LocalID":1393988414380}} </code></pre> <p>相应内容Q?/p><pre><code>{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": 1020944348, "LocalID": "1393988414380" } </code></pre> <ol> <li> <p>再次发v一个POSThQ用于申h新SyncKey</p> <p>https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=lQ95vHR52DiaLVqo&r=1393988414756</p></li></ol> <p>发送内容:</p><pre><code>{"BaseRequest":{"Uin":937355,"Sid":"lQ95vHR52DiaLVqo"},"SyncKey":{"Count":6,"List":[{"Key":1,"Val":620944310},{"Key":2,"Val":620944346},{"Key":3,"Val":620944344},{"Key":11,"Val":620942796},{"Key":201,"Val":1393988357},{"Key":1000,"Val":1393930108}]},"rr":1393988414756} </code></pre> <p>响应的(部分Q内容:</p><pre><code>"SKey": "8F8C6A03489E85E9FDF727ACB95C93C2CDCE9FB9532FC15B" </code></pre> <ol> <li> <p>l止GET长连接,使用最新SyncKey再次发v一个新的GET长连?/p> <p>https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?callback=jQuery183024581008965208218<em>1393988305564&r=1393988415015&sid=lQ95vHR52DiaLVqo&uin=937355&deviceid=e937227863752975&synckey=1</em>620944310%7C2<em>620944348%7C3<em>620944344%7C11</em>620942796%7C201</em>1393988357%7C1000<em>1393930108&</em>=1393988415016</p></li></ol> <h3>三。微信Android单分?/h3> <p>Windows桌面端Android虚拟Zq行最新版微信(5.2)Q通过tcpdump/Wiresharkl合包分析Q以下ؓ分析l果?/p> <h4>0. 初始q接记录</h4> <p>单记录微信启动之后请求:</p><pre><code>11:20:35 dns查询 dns.weixin.qq.com q回一lIP地址 11:20:35 DNS查询 long.weixin.qq.com q回一lIP地址Q本ơ通信中,微信使用了最后一个IP作ؓTCP长连接的q接地址? 11:20:35 http://dns.weixin.qq.com/cgi-bin/micromsg-bin/newgetdns?uin=0&clientversion=620888113&scene=0&net=1 用于h服务器获得最优IP路径。服务器通过l算q回一个xml定义了域?IP对应列表。仔l阅读,可看到微信已l开始了国际化的步伐Q香港、加拿大、韩国等? 具体文本Q请参考:https://gist.github.com/yongboy/9341884 11:20:35 获取到long.weixin.qq.com最优IPQ然后徏立到101.227.131.105的TCP长连? 11:21:25 POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/getprofile HTTP/1.1 (application/octet-stream) q回一个名?#8220;micromsgresp.dat”的附Ӟ估计是未阅读的离U消? 11:21:31 POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/whatsnews HTTP/1.1 (application/octet-stream) 大概是资讯、订阅更新等 中间q行一些资源请求等Q类g GET http://wx.qlogo.cn/mmhead/Q3auHgzwzM7NR4TYFcoNjbxZpfO9aiaE7RU5lXGUw13SMicL6iacWIf2A/96 囄{一些静态资源都会被分配到wx.qlogo.cn域名下面 不明白做什么用? POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/downloadpackage HTTP/1.1 (application/octet-stream) 输出为micromsgresp.dat文g 11:21:47 GET http://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportdevice?channel=34&deviceid=A952001f7a840c2a&clientversion=620888113&platform=0&lang=zh_CN&installtype=0 HTTP/1.1 q回chunked分块数据 11:21:49 POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1 (application/octet-stream) </code></pre> <h4>1. 心蟩频率Uؓ5分钟</h4> <p>上次使用Wireshark分析有误Q得?8分钟l论Q,再次重新分析Q心跳频率在5分钟左右?/p> <h4>2. 登陆之后Q会建立一个长q接Q端口号?080</h4> <p>单目ؓHTTPQ初始以为是双通道HTTPQ难道是自定义的用于双通道通信的HTTP协议吗,|络上可见资料都是模׃可、语焉不详?/p> <p>具体查看长连接初始数据通信Q没有发CQ何包?HTTP"字样的数据,以ؓ是微信自定义的TCP/HTTP通信格式。据分析Q用于可能用于获取数据、心跳交换消息等用途吧。这个后面会详谈微信是如何做到的?/p> <h5>2.0 初始消息传输</h5> <p>个h资料、离U未阅读消息部分{通过 POST HTTP短连接单独获取?/p> <h5>2.1 二进制简单分?/h5> <p>抽取微信某次HTTP协议方式通信数据Q?6q制表示Q每两个靠近的数字ؓ一个byte字节Q?/p> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_15h07_30_2.png"><img title="2014-03-03_15h07_30" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" alt="2014-03-03_15h07_30" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_15h07_30_thumb.png" border="0" height="342" width="625" /></a></p> <p>微信协议可能如下Q?/p><pre><code>一个消息包 = 消息?+ 消息? </code></pre> <p>消息头固?6字节长度Q消息包长度定义在消息头?个字节中?/p> <p>单纯摘取W?000行ؓ例,?6个字节的头部:</p><pre><code>00 00 00 10 00 10 00 01 00 00 00 06 00 00 00 0f </code></pre> <p>16q制表示Q每两个紧挨着数字代表一个byte字节?/p> <p>微信消息包格式: 1. ?字节表示数据包长度,可变 gؓ16Ӟ意味着一个仅仅包含头部的完整的数据包Q可能表C着预先定义好的业务意义Q,后面可能q有会别的消息包 2. 2个字节表C头部长度,固定|0x10 = 16 3. 2个字节表C意版本,固定|0x01 = 1 4. 4个字节操作说明数字,可变 5. 序列P可变 6. 头部后面紧跟着消息体,非明文,加密形式 7. 一个消息包Q最?6 byte字节</p> <p>通过上图Q以及其它数据多ơ采P分析Q?/p> <ol> <li>0000 - 0040为单独的数据? </li><li>0050行ؓ下一个数据包的头部,前四个字节gؓ0xca = 202Q表C包含了?050-0110?02个字节数? </li><li>一ơ数据发送,可能包含若干子数据包 </li><li>换行W\nQ?6q制表示?x0aQ在00f0行,包含了两个换行符? </li><li>一个数据体换行W号用于更细_度的业务数据分?是否蒙对Q需要问问做微信协议的同? </li><li>所有被标记为HTTP协议通信所发送数据都包含换行W号 </li></ol> <h5>2.2 动手试试猜想Q模拟微信TCP长连?/h5> <p>开始很不解Z么会出现如此怪异的HTTP双通道长连接请求,NZTCP通信Q然后做了一些手脚?很常规的TCP长连接,传输数据?不是所有数据传?Q被wireshark误认为HTTP长连接。这个需要做一个实验证实一下自己想法,设想如下Q?/p> <p>写一个Ping-Pong客户端、服务器端程序,然后使用Wireshark看一下结果,是否W合判断?/p> <p>Java版本的请求端Q默认请?080端口Q?<script src="https://gist.github.com/yongboy/9319660.js"></script></p> <p>C语言版本的服务器E序Q收C么发送什么,没有M逻辑Q默认绑?080端口Q?<script src="https://gist.github.com/yongboy/9341037.js"></script></p> <p>q里有一个现场图Q?/p> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_14h53_19_2.png"><img title="2014-03-03_14h53_19" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" alt="2014-03-03_14h53_19" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_14h53_19_thumb.png" border="0" height="702" width="1052" /></a></p> <p>可以试E微改变输出内容Q去除换行符“\n”Q把端口换成9000Q试试看Q就会发现Wireshark输出不同的结果来?/p> <h5>2.3 l论是什么呢Q?/h5> <p>若用原始TCPq行双向通信Q则需要满以下条Ӟ可以被类gWireshark协议拦截器误认ؓ是HTTP长连接:</p> <ol> <li>使用80/8080端口Q?1/3128/8000l测试无效) 也许8080一般被作ؓWEB代理服务端口Q微信才会n用这个红利吧? </li><li>输出的内容中Q一定要包含换行字符"\n" </li></ol> <p>因此Q可以定性ؓ微信使用了基?080端口TCP长连接,一旦数据包中含有换?\n"W号Q就会被Wireshark误认为HTTP协议。可能微信是无心Z吧?/p> <h4>3. 新消息获取方?/h4> <ol> <li>TCP长连接接收到服务器通知有新消息需要获? </li><li>APP发v一个HTTP POSTh获取新状态消息,会带上当前SyncKey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1Q看不到明文 </li><li>APP获取到新的消息,会再ơ发起一ơHTTP POSThQ告诉服务器已确认收刎ͼ同时获取最新SyncKey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/kvreportQ看不到明文 </li><li>接受一个消息,TCP长连接至交互两ơ,客户端发起两ơHTTP POSTh <br />具体每次交互内容是什么,有些模糊<br /></li><li>服务器需要支持:状态消息获取标讎ͼ状态消息确认收取标记。只有被认收到Q此状态消息才是被正消Ҏ </li><li>多个不同讑֤同一账号同时使用微信Q同一个状态消息会会被同时分发到多个设备上 </li></ol> <p>此时消息h截图如下Q?/p> <p><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_15h58_15_2.png"><img title="2014-03-03_15h58_15" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" alt="2014-03-03_15h58_15" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/215cc736c7b0_A31F/2014-03-03_15h58_15_thumb.png" border="0" height="371" width="1422" /></a></p> <h4>4. 发送消息方?/h4> <p>发送消息走已经建立的TCP长连接通道Q发送消息到服务器,然后接受认信息{,产生一ơ交互?/p> <p>伙伴接收到信息阅读也都会收到服务器端通知Q生一ơ交互等?/p><!--![](wg/2014-03-03_16h19_14.png)--> <p>可以定Q微信发送消息走TCP长连接方式,因ؓ不对自n状态数据生媄响,应该不交换SyncKey?/p> <ul> <li>在低速网l下Q大概会看到消息发送中的提C,属于消息重发机制 </li><li>|络不好有时客户端会出现发送失败的U色感叹? </li><li>已发送到服务器但未收到确认的消息Q客L昄U色感叹P再次重发Q服务器作ؓ重复消息处理Q反馈确?/li><li>上传囄Q会Ҏ囄大小Q分割成若干部分Q大?.5K被划分ؓ一部分Q,同一旉点,客户端会发v若干ơPOSThQ各自上传成功之后,服务器大概会合ƈ成一个完整图片,q回一个羃略图Q显C在APP聊天H口内。APP作ؓ常规的文字消息发送到服务器端</li><li>上传音频Q则单独走TCP通道Q一个两U的录制音频Q客L录制完毕Q分Z块传输,一块最?.5K左右Q服务端响应一条数据通知认收到。共三次数据传输?br />音频和纯文字信息一_都是走TCP长连接,客户端发送,服务器端认?/li></ul> <h3>四。微信协议小l?/h3> <ol> <li>发布的消息对应一个IDQ只要单个方向唯一卛_Q服务器端可能会根ID判断重复接收Q,消息重传机制保有限ơ的重试Q重试失败给予用hC,发送成功会反馈认Q客L只有收到认信息才知道发送成功。发送消息可能不会生新SyncKey? </li><li>Z版本PSynKeyQ的状态消息同步机Ӟ增量、有序传输需求水到渠成。长q接通知/短连接获取、确认等Q交互方式简单,保了消息可靠谱、准无误到达? </li><li>客户?服务器端都会存储消息ID处理记录Q避免被重复消费客户端获取最新消息,但未认Q服务器端不会认消息被消Ҏ。下ơ客L会重新获取,会查询当前消息是否被处理q。根据一些现象猜? </li><li>M上看Q微信协议跨q_QTCP或HTPP都可呈现Q处理方式可l一Q,通过“握手”同步Q很可靠Q无论哪一个^台都可以支持的很? </li><li>微信协议最成本ؓ16字节Q大部分旉若干个消息包和在一P扚w传输。微信协议说不上最z,也不是最节省量Q但是非常成功的?</li><li><div>若服务器到一些不定因素Q可能会D微启用安全套接层SSL协议q行常规的TCP长连接传输。短q接都没有发生变?/div><br /></li></ol> <p>以上Q根据有限资料和数据拦截观察ȝ得出Q啰啰嗦嗦,勉强凑成一,会存在一些不正确之处Q欢q给予纠正。在多次</p> <h3>五。附?/h3> <p>Microsoft Exchange Active Sync协议Q简UEASQ分为folderrsync(同步文g夹目录,即邮内有哪几个文g?和syncQ每个文件夹内有哪些文档Q两部分?/p> <p>某网友ȝ的协议一ơ回话大致示范:</p><pre><code>Client: synckey=0 //W一ơkey? Server: newsynckey=1235434 //W一ơ返回新key Client: synckey=1235434 //使用新key查询 Server: newsynckey=1647645,data=*****//W一ơ查询,得到新key和数? Client: synckey=1647645 Server: newsynckey=5637535,data=null //W二ơ查询,无新消息 Client: synckey=5637535 Server: newsynckey=8654542, data=****//W三ơ查询,增量同步 </code></pre> <ul> <li>上页中的盔Rh都是隔固定时间的Q如两分? </li><li>客户端每ơ用旧key标记自己的状态,服务端每ơ将新key和增量数据一赯回? </li><li>key是递增的,但不要求q箋 </li><li>h的某个参数决定服务器是否立即q回 </li></ul><img src ="http://www.aygfsteel.com/yongboy/aggbug/410636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2014-03-05 14:15 <a href="http://www.aygfsteel.com/yongboy/archive/2014/03/05/410636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ϳ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̩</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ȫ</a>| <a href="http://" target="_blank">ó</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¹</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Է</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ȷ</a>| <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ϳ</a>| <a href="http://" target="_blank">Ϫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ϰ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">봨</a>| <a href="http://" target="_blank">Ž</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¡</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʲ</a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>