微信端口及协议分析(java、C版)
作者:supermig
有朋友公司需求如下,手机通过WIFI连接上网,而老板要求,员工使用手机只能上微信,而不能上其他网页和看在线视频。上网搜索了微信使用协议和端口。
微信通过TCP方式来进行通讯。
TCP通讯方式分析
通讯端口分析
远程通讯端口范围: 80,443,80,443,8080。
HTTP方式分析
在特征分析中,发现微信会采用HTTP协议进行通讯。
连接的主机(Host)(正则表达式)为:^short\.weixin\.qq\.com,^(mmsns|mmbiz)\.qpic\.cn。
TLS方式分析
在特征分析中,发现微信会采用TLS协议进行通讯。
连接的TLS主机(正则表达式)为:^(wx|weixin|res\.wx)\.qq\.com。
这个协议只是用来检测和屏蔽微信的,不能监控聊天记录内容。
来源:笨驴技术
安桌手机,可以用tcpdump进行抓包。。分析!!
初步分析结果:
使用80、8080,登陆和交互。
使用:tcp 14000 端口 SCOTTY High-Speed Filetransferscotty-ft 发送语音文件
TCP: 5222 5223 5228 80 8080 443
来源:http://bbs.51cto.com/thread-1031608-1.html
微信、手机QQ网络行为简析
测试环境:
智能手机一部(打开wifi关闭gprs) —-> Linux wifi 热点 —-> 公网
分析手段:
在linux 上用tcpdump抓包,用wireshark分析抓到的数据
在linux上用iptables阻断特定流量,模拟网络故障,分别模拟了拦截udp 53/tcp 80/tcp 8080/tcp 14000/tcp全拦截等各种情况以及他们的组合
通过 adb shell在手机内执行netstat了解手机网络链接情况
微信网络行为:
程序启动后,优先尝试DNS解析特定域名(support.weixin.qq.com,short.weixin.qq.com,long.weixin.qq.com,wx.qlogo.cn);
如果DNS查询不可用,程序转为使用hardcode的ip链接服务;
如果dns可用,返回的ip为根据ISP智能解析的结果,程序使用返回的ip链接服务;
程序仅在注册阶段使用https链接,内容不详;
程序使用tcp 80/8080链接服务器,其中80为http协议,8080为未知协议;
80/8080两个端口同时或任何单独一个,均可提供服务;
80端口为短链接,8080为长链接, 程序会优先使用8080端口;
没有使用udp传输数据;
当1-2次发送失败时,客户端会弹出提示“当前网络状况不好,是否提交反馈数据”,确认后客户端试图通过web提交反馈数据;
手机qq网络行为:
仅列出跟微信不同之处
尝试的域名不同: monitor.uu.qq.com,3gimg.qq.com, msfwifi.3g.qq.com, kiss.3g.qq.com;
除了80/8080外,还有tcp 14000,功能与8080相同;
程序会优先尝试80/8080,只有这两个不可用时,才尝试14000;
其余同微信;
方案设想:只开放以上端口,其他上也是全部开放了,在上网出口处加上网行为管理设备或者软件进行控制,只允许以下正则的网址通行:
^short\.weixin\.qq\.com,^(mmsns|mmbiz)\.qpic\.cn
^(wx|weixin|res\.wx)\.qq\.com
以下是软件实现方式
微信协议小结
https://www.jb51.net/article/96811.htm
发布的消息对应一个ID(只要单个方向唯一即可,服务器端可能会根ID判断重复接收),消息重传机制确保有限次的重试,重试失败给予用户提示,发送成功会反馈确认,客户端只有收到确认信息才知道发送成功。发送消息可能不会产生新SyncKey。
基于版本号(SynKey)的状态消息同步机制,增量、有序传输需求水到渠成。长连接通知/短连接获取、确认等,交互方式简单,确保了消息可靠谱、准确无误到达。
客户端/服务器端都会存储消息ID处理记录,避免被重复消费客户端获取最新消息,但未确认,服务器端不会认为该消息被消费掉。下次客户端会重新获取,会查询当前消息是否被处理过。根据一些现象猜测。
总体上看,微信协议跨平台(TCP或HTPP都可呈现,处理方式可统一),通过“握手”同步,很可靠,无论哪一个平台都可以支持的很好微信协议最小成本为16字节,大部分时间若干个消息包和在一起,批量传输。微信协议说不上最简洁,也不是最节省流量,但是非常成功的。
若服务器检测到一些不确定因素,可能会导致微启用安全套接层SSL协议进行常规的TCP长连接传输。短连接都没有发生变化
发送消息方式
发送消息走已经建立的TCP长连接通道,发送消息到服务器,然后接受确认信息等,产生一次交互。
小伙伴接收到信息阅读也都会收到服务器端通知,产生一次交互等。
可以确定,微信发送消息走TCP长连接方式,因为不对自身状态数据产生影响,应该不交换SyncKey。
在低速网络下,大概会看到消息发送中的提示,属于消息重发机制
网络不好有时客户端会出现发送失败的红色感叹号
已发送到服务器但未收到确认的消息,客户端显示红色感叹号,再次重发,服务器作为重复消息处理,反馈确认
上传图片,会根据图片大小,分割成若干部分(大概1.5K被划分为一部分),同一时间点,客户端会发起若干次POST请求,各自上传成功之后,服务器大概会合并成一个完整图片,返回一个缩略图,显示在APP聊天窗口内。APP作为常规的文字消息发送到服务器端上传音频,则单独走TCP通道,一个两秒的录制音频,客户端录制完毕,分为两块传输,一块最大1.5K左右,服务端响应一条数据通知确认收到。共三次数据传输。
音频和纯文字信息一致,都是走TCP长连接,客户端发送,服务器端确认。
微信协议简单调研笔记如下介绍:
前言
微信可调研点很多,这里仅仅从协议角度进行调研,会涉及到微信协议交换、消息收发等。所谓“弱水三千,只取一瓢”吧。
杂七杂八的,有些长,可直接拉到最后看结论好了。
一。微信协议概览
微信传输协议,官方
公布甚少,在微信技术总监所透漏PPT《微信之道—至简》文档中,有所体现。
纯个人理解:
因张小龙做邮箱Foxmail起家,继而又做了QQ Mail等,QQ Mail是国内第一个支持Exchange ActiveSync协议的免费邮箱,基于其从业背景,微信从一开始就采取基于ActiveSync的修改版状态同步协议Sync,也就再自然不过了。
一句话:增量式、按序、可靠的状态同步传输的微信协议。
大致交换简图如下:
如何获取新数据呢:
服务器端通知,客户端获取
客户端携带最新的SyncKey,发起数据请求
服务器端生成最新的SyncKey连同最新数据发送给客户端
基于版本号机制同步协议,可确保数据增量、有序传输
SyncKey,由服务器端序列号生成器生成,一旦有新消息产生,将会产生最新的SyncKey。类似于版本号
服务器端通知有状态更新,客户端主动获取自从上次更新之后有变动的状态数据,增量式,顺序式。
二。微信Web端简单调试
在线版本微信:
https://webpush.weixin.qq.com/
通过Firefox + Firebug组合调试,也能证实了微信大致通过交换SyncKey方式获取新数据的论述。
1. 发起GET长连接检测是否存在新的需要同步的数据
会携带上最新SyncKey
返回内容:
window.synccheck={retcode:"0",selector:"2"}
selector值大于0,表示有新的消息需要同步。
据目测,心跳周期为27秒左右。
2. 一旦有新数据,客户端POST请求主动获取同步的数据
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=s7c%2FsxpGRSihgZAA&r=1393208447375
携带消息体:
{"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}
会携带上最新的SyncKey,会返回复杂结构体JSON内容。
但浏览端收取到消息之后,如何通知服务器端已确认收到了?Web版本微信,没有去做。
在以往使用过程中,曾发现WEB端有丢失消息的现象,但属于偶尔现象。但Android微信客户端(只要登陆连接上来之后)貌似就没有丢失过。
3. 发送消息流程
发起一个POST提交,用于提交用户需要发送的消息
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid=lQ95vHR52DiaLVqo&r=1393988414386
发送内容:
{"BaseRequest":{"Uin":937355,"Sid":"lQ95vHR52DiaLVqo","Skey":"A6A1ECC6A7DE59DEFF6A05F226AA334DECBA457887B25BC6","DeviceID":"e937227863752975"},"Msg":{"FromUserName":"yongboy","ToUserName":"hehe057854","Type":1,"Content":"hello","ClientMsgId":1393988414380,"LocalID":1393988414380}}
相应内容:
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": 1020944348, "LocalID": "1393988414380" }
再次发起一个POST请求,用于申请最新SyncKey
https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=lQ95vHR52DiaLVqo&r=1393988414756
发送内容:
{"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}
响应的(部分)内容:
"SKey": "8F8C6A03489E85E9FDF727ACB95C93C2CDCE9FB9532FC15B"
终止GET长连接,使用最新SyncKey再次发起一个新的GET长连接
三。微信Android简单分析
Windows桌面端Android虚拟机中运行最新版微信(5.2),通过tcpdump/Wireshark组合封包分析,以下为分析结果。
0. 初始连接记录
简单记录微信启动之后请求:
11:20:35 dns查询
dns.weixin.qq.com
返回一组IP地址
11:20:35 DNS查询
long.weixin.qq.com
返回一组IP地址,本次通信中,微信使用了最后一个IP作为TCP长连接的连接地址。
11:20:35
http://dns.weixin.qq.com/cgi-bin/micromsg-bin/newgetdns?uin=0&clientversion=620888113&scene=0&net=1
用于请求服务器获得最优IP路径。服务器通过结算返回一个xml定义了域名:IP对应列表。仔细阅读,可看到微信已经开始了国际化的步伐:香港、加拿大、韩国等。
具体文本,请参考:https://gist.github.com/yongboy/9341884
11:20:35
获取到long.weixin.qq.com最优IP,然后建立到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)
返回一个名为“micromsgresp.dat”的附件,估计是未阅读的离线消息
11:21:31
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/whatsnews HTTP/1.1 (application/octet-stream)
大概是资讯、订阅更新等
中间进行一些资源请求等,类似于
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文件
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
返回chunked分块数据
11:21:49
POST http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1 (application/octet-stream)
1. 心跳频率约为5分钟
上次使用Wireshark分析有误(得出18分钟结论),再次重新分析,心跳频率在5分钟左右。
2. 登陆之后,会建立一个长连接,端口号为8080
简单目测为HTTP,初始以为是双通道HTTP,难道是自定义的用于双通道通信的HTTP协议吗,网络上可见资料都是模棱两可、语焉不详。
具体查看长连接初始数据通信,没有发现任何包含"HTTP"字样的数据,以为是微信自定义的TCP/HTTP通信格式。据分析,用于可能用于获取数据、心跳交换消息等用途吧。这个后面会详谈微信是如何做到的。
2.0 初始消息传输
个人资料、离线未阅读消息部分等通过 POST HTTP短连接单独获取。
2.1 二进制简单分析
抽取微信某次HTTP协议方式通信数据,16进制表示,每两个靠近的数字为一个byte字节:
2014-03-03_15h07_30
微信协议可能如下:
一个消息包 = 消息头 + 消息体
消息头固定16字节长度,消息包长度定义在消息头前4个字节中。
单纯摘取第0000行为例,共16个字节的头部:
00 00 00 10 00 10 00 01 00 00 00 06 00 00 00 0f
16进制表示,每两个紧挨着数字代表一个byte字节。
微信消息包格式: 1. 前4字节表示数据包长度,可变 值为16时,意味着一个仅仅包含头部的完整的数据包(可能表示着预先定义好的业务意义),后面可能还有会别的消息包 2. 2个字节表示头部长度,固定值,0x10 = 16 3. 2个字节表示谢意版本,固定值,0x01 = 1 4. 4个字节操作说明数字,可变 5. 序列号,可变 6. 头部后面紧跟着消息体,非明文,加密形式 7. 一个消息包,最小16 byte字节
通过上图(以及其它数据多次采样)分析:
0000 - 0040为单独的数据包
0050行为下一个数据包的头部,前四个字节值为0xca = 202,表示包含了从0050-0110共202个字节数据
一次数据发送,可能包含若干子数据包
换行符\n,16进制表示为0x0a,在00f0行,包含了两个换行符号
一个数据体换行符号用于更细粒度的业务数据分割 是否蒙对,需要问问做微信协议的同学
所有被标记为HTTP协议通信所发送数据都包含换行符号
2.2 动手试试猜想,模拟微信TCP长连接
开始很不解为什么会出现如此怪异的HTTP双通道长连接请求,难道基于TCP通信,然后做了一些手脚?很常规的TCP长连接,传输数据时(不是所有数据传输),被wireshark误认为HTTP长连接。这个需要做一个实验证实一下自己想法,设想如下:
写一个Ping-Pong客户端、服务器端程序,然后使用Wireshark看一下结果,是否符合判断。
Java版本的请求端,默认请求8080端口:
<span style="font-size:12px;"><pre class="line-pre" name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-size: 13px; font-style: inherit; font-variant: inherit; line-height: inherit; font-family: Consolas, 'Liberation Mono', Courier, monospace; margin-top: 0px !important; margin-bottom: 0px !important; border: none !important; padding: 0px !important; background-color: transparent !important;"><div class="line" id="file-pingclient-java-LC1"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;">/**</span></div><div class="line" id="file-pingclient-java-LC2"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * Ping Client</span></div><div class="line" id="file-pingclient-java-LC3"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * @author nieyong</span></div><div class="line" id="file-pingclient-java-LC4"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> */</span></div><div class="line" id="file-pingclient-java-LC5"><span class="kn">package</span> <span class="n">com</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">learn</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC6"> </div><div class="line" id="file-pingclient-java-LC7"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.bootstrap.Bootstrap</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC8"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.buffer.ByteBuf</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC9"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.buffer.PooledByteBufAllocator</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC10"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelFuture</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC11"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelHandlerContext</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC12"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelInboundHandlerAdapter</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC13"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelInitializer</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC14"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.ChannelOption</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC15"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.EventLoopGroup</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC16"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.nio.NioEventLoopGroup</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC17"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.socket.SocketChannel</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC18"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">io.netty.channel.socket.nio.NioSocketChannel</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC19"> </div><div class="line" id="file-pingclient-java-LC20"><span class="kn">import</span> <span class="nn" style="color: rgb(85, 85, 85);">java.util.concurrent.TimeUnit</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC21"> </div><div class="line" id="file-pingclient-java-LC22"><span class="kd" style="font-weight: bold;">class</span> <span class="nc" style="color: rgb(68, 85, 136); font-weight: bold;">PingClientHandler</span> <span class="kd" style="font-weight: bold;">extends</span> <span class="n">ChannelInboundHandlerAdapter</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC23"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">ByteBuf</span> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC24"> </div><div class="line" id="file-pingclient-java-LC25"> <span class="kd" style="font-weight: bold;">public</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClientHandler</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC26"> <span class="n">firstMessage</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">PooledByteBufAllocator</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">DEFAULT</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">buffer</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">22</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC27"> </div><div class="line" id="file-pingclient-java-LC28"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// weixin 16 byte's header</span></div><div class="line" id="file-pingclient-java-LC29"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC30"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC31"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC32"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">16</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC33"> </div><div class="line" id="file-pingclient-java-LC34"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC35"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">16</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC36"> </div><div class="line" id="file-pingclient-java-LC37"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC38"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC39"> </div><div class="line" id="file-pingclient-java-LC40"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC41"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC42"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC43"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">6</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC44"> </div><div class="line" id="file-pingclient-java-LC45"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC46"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC47"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC48"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC49"> </div><div class="line" id="file-pingclient-java-LC50"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// just for /n</span></div><div class="line" id="file-pingclient-java-LC51"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeByte</span><span class="o" style="font-weight: bold;">(</span><span class="sc" style="color: rgb(221, 17, 68);">'\n'</span><span class="o" style="font-weight: bold;">);</span> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// 1 byte</span></div><div class="line" id="file-pingclient-java-LC52"> </div><div class="line" id="file-pingclient-java-LC53"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// footer 16 byte</span></div><div class="line" id="file-pingclient-java-LC54"> <span class="n">String</span> <span class="n">welcome</span> <span class="o" style="font-weight: bold;">=</span> <span class="s" style="color: rgb(221, 17, 68);">"hello"</span><span class="o" style="font-weight: bold;">;</span> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// 5 byte</span></div><div class="line" id="file-pingclient-java-LC55"> <span class="n">firstMessage</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeBytes</span><span class="o" style="font-weight: bold;">(</span><span class="n">welcome</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">getBytes</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC56"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC57"> </div><div class="line" id="file-pingclient-java-LC58"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC59"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelActive</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC60"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">writeAndFlush</span><span class="o" style="font-weight: bold;">(</span><span class="n">firstMessage</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC61"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC62"> </div><div class="line" id="file-pingclient-java-LC63"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC64"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelRead</span><span class="o" style="font-weight: bold;">(</span><span class="kd" style="font-weight: bold;">final</span> <span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">,</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">Object</span> <span class="n">msg</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC65"> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC66"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">executor</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">schedule</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">Runnable</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC67"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC68"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">run</span><span class="o" style="font-weight: bold;">()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC69"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">writeAndFlush</span><span class="o" style="font-weight: bold;">(</span><span class="n">msg</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC70"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC71"> <span class="o" style="font-weight: bold;">},</span> <span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">,</span> <span class="n">TimeUnit</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">SECONDS</span><span class="o" style="font-weight: bold;">);</span></div><div class="line" id="file-pingclient-java-LC72"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC73"> </div><div class="line" id="file-pingclient-java-LC74"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC75"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">channelReadComplete</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">)</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC76"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">flush</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC77"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC78"> </div><div class="line" id="file-pingclient-java-LC79"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC80"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">exceptionCaught</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="o" style="font-weight: bold;">,</span> <span class="n">Throwable</span> <span class="n">cause</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC81"> <span class="n">System</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">err</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">println</span><span class="o" style="font-weight: bold;">(</span><span class="s" style="color: rgb(221, 17, 68);">"Unexpected exception from downstream :"</span></div><div class="line" id="file-pingclient-java-LC82"> <span class="o" style="font-weight: bold;">+</span> <span class="n">cause</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">getMessage</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC83"> <span class="n">ctx</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">close</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC84"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC85"><span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC86"> </div><div class="line" id="file-pingclient-java-LC87"><span class="kd" style="font-weight: bold;">public</span> <span class="kd" style="font-weight: bold;">class</span> <span class="nc" style="color: rgb(68, 85, 136); font-weight: bold;">PingClient</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC88"> </div><div class="line" id="file-pingclient-java-LC89"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="n">String</span> <span class="n">host</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC90"> <span class="kd" style="font-weight: bold;">private</span> <span class="kd" style="font-weight: bold;">final</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC91"> </div><div class="line" id="file-pingclient-java-LC92"> <span class="kd" style="font-weight: bold;">public</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClient</span><span class="o" style="font-weight: bold;">(</span><span class="n">String</span> <span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC93"> <span class="k" style="font-weight: bold;">this</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">host</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC94"> <span class="k" style="font-weight: bold;">this</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">port</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC95"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC96"> </div><div class="line" id="file-pingclient-java-LC97"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">run</span><span class="o" style="font-weight: bold;">()</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC98"> <span class="n">EventLoopGroup</span> <span class="n">group</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">NioEventLoopGroup</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC99"> <span class="k" style="font-weight: bold;">try</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC100"> <span class="n">Bootstrap</span> <span class="n">b</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">Bootstrap</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC101"> <span class="n">b</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">group</span><span class="o" style="font-weight: bold;">(</span><span class="n">group</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">(</span><span class="n">NioSocketChannel</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">class</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC102"> <span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">option</span><span class="o" style="font-weight: bold;">(</span><span class="n">ChannelOption</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">TCP_NODELAY</span><span class="o" style="font-weight: bold;">,</span> <span class="kc" style="font-weight: bold;">true</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC103"> <span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">handler</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="n">ChannelInitializer</span><span class="o" style="font-weight: bold;"><</span><span class="n">SocketChannel</span><span class="o" style="font-weight: bold;">>()</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC104"> <span class="nd">@Override</span></div><div class="line" id="file-pingclient-java-LC105"> <span class="kd" style="font-weight: bold;">public</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">initChannel</span><span class="o" style="font-weight: bold;">(</span><span class="n">SocketChannel</span> <span class="n">ch</span><span class="o" style="font-weight: bold;">)</span></div><div class="line" id="file-pingclient-java-LC106"> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC107"> <span class="n">ch</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">pipeline</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">addLast</span><span class="o" style="font-weight: bold;">(</span><span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClientHandler</span><span class="o" style="font-weight: bold;">());</span></div><div class="line" id="file-pingclient-java-LC108"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC109"> <span class="o" style="font-weight: bold;">});</span></div><div class="line" id="file-pingclient-java-LC110"> </div><div class="line" id="file-pingclient-java-LC111"> <span class="n">ChannelFuture</span> <span class="n">f</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">b</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">connect</span><span class="o" style="font-weight: bold;">(</span><span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="n">port</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">sync</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC112"> </div><div class="line" id="file-pingclient-java-LC113"> <span class="n">f</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">channel</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">closeFuture</span><span class="o" style="font-weight: bold;">().</span><span class="na" style="color: teal;">sync</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC114"> <span class="o" style="font-weight: bold;">}</span> <span class="k" style="font-weight: bold;">finally</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC115"> <span class="c1" style="color: rgb(153, 153, 136); font-style: italic;">// Shut down the event loop to terminate all threads.</span></div><div class="line" id="file-pingclient-java-LC116"> <span class="n">group</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">shutdownGracefully</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC117"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC118"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC119"> </div><div class="line" id="file-pingclient-java-LC120"> <span class="kd" style="font-weight: bold;">public</span> <span class="kd" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">main</span><span class="o" style="font-weight: bold;">(</span><span class="n">String</span><span class="o" style="font-weight: bold;">[]</span> <span class="n">args</span><span class="o" style="font-weight: bold;">)</span> <span class="kd" style="font-weight: bold;">throws</span> <span class="n">Exception</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC121"> <span class="n">String</span> <span class="n">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="s" style="color: rgb(221, 17, 68);">"127.0.0.1"</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC122"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">8080</span><span class="o" style="font-weight: bold;">;</span></div><div class="line" id="file-pingclient-java-LC123"> </div><div class="line" id="file-pingclient-java-LC124"> <span class="k" style="font-weight: bold;">if</span> <span class="o" style="font-weight: bold;">(</span><span class="n">args</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">length</span> <span class="o" style="font-weight: bold;">==</span> <span class="mi" style="color: rgb(0, 153, 153);">3</span><span class="o" style="font-weight: bold;">)</span> <span class="o" style="font-weight: bold;">{</span></div><div class="line" id="file-pingclient-java-LC125"> <span class="n">host</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">args</span><span class="o" style="font-weight: bold;">[</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="o" style="font-weight: bold;">];</span></div><div class="line" id="file-pingclient-java-LC126"> <span class="n">port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">Integer</span><span class="o" style="font-weight: bold;">.</span><span class="na" style="color: teal;">parseInt</span><span class="o" style="font-weight: bold;">(</span><span class="n">args</span><span class="o" style="font-weight: bold;">[</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="o" style="font-weight: bold;">]);</span></div><div class="line" id="file-pingclient-java-LC127"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC128"> </div><div class="line" id="file-pingclient-java-LC129"> <span class="k" style="font-weight: bold;">new</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">PingClient</span><span class="o" style="font-weight: bold;">(</span><span class="n">host</span><span class="o" style="font-weight: bold;">,</span> <span class="n">port</span><span class="o" style="font-weight: bold;">).</span><span class="na" style="color: teal;">run</span><span class="o" style="font-weight: bold;">();</span></div><div class="line" id="file-pingclient-java-LC130"> <span class="o" style="font-weight: bold;">}</span></div><div class="line" id="file-pingclient-java-LC131"><span class="o" style="font-weight: bold;">}</span></div></span>
C语言版本的服务器程序,收到什么发送什么,没有任何逻辑,默认绑定8080端口:
<span style="font-size:12px;"><pre class="line-pre" name="code" style="white-space: pre-wrap; word-wrap: break-word; color: rgb(51, 51, 51); font-size: 13px; font-style: inherit; font-variant: inherit; line-height: inherit; font-family: Consolas, 'Liberation Mono', Courier, monospace; margin-top: 0px !important; margin-bottom: 0px !important; border: none !important; padding: 0px !important; background-color: transparent !important;"><div class="line" id="file-pong_server-c-LC1"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;">/**</span></div><div class="line" id="file-pong_server-c-LC2"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * nieyong@youku.com</span></div><div class="line" id="file-pong_server-c-LC3"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * how to compile it:</span></div><div class="line" id="file-pong_server-c-LC4"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> * gcc pong_server.c -o pong_server /usr/local/lib/libev.a -lm </span></div><div class="line" id="file-pong_server-c-LC5"><span class="cm" style="color: rgb(153, 153, 136); font-style: italic;"> */</span></div><div class="line" id="file-pong_server-c-LC6"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <arpa/inet.h></span></div><div class="line" id="file-pong_server-c-LC7"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <stdlib.h></span></div><div class="line" id="file-pong_server-c-LC8"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <stdio.h></span></div><div class="line" id="file-pong_server-c-LC9"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <string.h></span></div><div class="line" id="file-pong_server-c-LC10"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <fcntl.h></span></div><div class="line" id="file-pong_server-c-LC11"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <errno.h></span></div><div class="line" id="file-pong_server-c-LC12"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <err.h></span></div><div class="line" id="file-pong_server-c-LC13"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include <unistd.h></span></div><div class="line" id="file-pong_server-c-LC14"> </div><div class="line" id="file-pong_server-c-LC15"><span class="cp" style="color: rgb(153, 153, 153); font-weight: bold;">#include "../include/ev.h"</span></div><div class="line" id="file-pong_server-c-LC16"> </div><div class="line" id="file-pong_server-c-LC17"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">server_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">8080</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC18"> </div><div class="line" id="file-pong_server-c-LC19"><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC20"><span class="k" style="font-weight: bold;">typedef</span> <span class="k" style="font-weight: bold;">struct</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC21"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">fd</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC22"> <span class="n">ev_io</span> <span class="n">ev_read</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC23"><span class="p">}</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC24"> </div><div class="line" id="file-pong_server-c-LC25"><span class="n">ev_io</span> <span class="n">ev_accept</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC26"> </div><div class="line" id="file-pong_server-c-LC27"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">free_res</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">ws</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC28"> </div><div class="line" id="file-pong_server-c-LC29"><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">setnonblock</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">fd</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC30"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">flags</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_GETFL</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC31"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC32"> <span class="k" style="font-weight: bold;">return</span> <span class="n">flags</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC33"> </div><div class="line" id="file-pong_server-c-LC34"> <span class="n">flags</span> <span class="o" style="font-weight: bold;">|=</span> <span class="n">O_NONBLOCK</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC35"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">fcntl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">F_SETFL</span><span class="p">,</span> <span class="n">flags</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC36"> <span class="k" style="font-weight: bold;">return</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC37"> </div><div class="line" id="file-pong_server-c-LC38"> <span class="k" style="font-weight: bold;">return</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC39"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC40"> </div><div class="line" id="file-pong_server-c-LC41"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">read_cb</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC42"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">data</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC43"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">r</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC44"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">char</span> <span class="n">rbuff</span><span class="p">[</span><span class="mi" style="color: rgb(0, 153, 153);">1024</span><span class="p">];</span></div><div class="line" id="file-pong_server-c-LC45"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">revents</span> <span class="o" style="font-weight: bold;">&</span> <span class="n">EV_READ</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC46"> <span class="n">r</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">read</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">rbuff</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">1024</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC47"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC48"> </div><div class="line" id="file-pong_server-c-LC49"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">EV_ERROR</span> <span class="o" style="font-weight: bold;">&</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC50"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"error event in read</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC51"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC52"> <span class="k" style="font-weight: bold;">return</span> <span class="p">;</span></div><div class="line" id="file-pong_server-c-LC53"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC54"> </div><div class="line" id="file-pong_server-c-LC55"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">r</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC56"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"read error</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC57"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">EV_A_</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC58"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC59"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC60"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC61"> </div><div class="line" id="file-pong_server-c-LC62"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">r</span> <span class="o" style="font-weight: bold;">==</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC63"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"client disconnected.</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC64"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">EV_A_</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC65"> <span class="n">free_res</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="n">w</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC66"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC67"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC68"> </div><div class="line" id="file-pong_server-c-LC69"> <span class="n">send</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="n">rbuff</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC70"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC71"> </div><div class="line" id="file-pong_server-c-LC72"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">accept_cb</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">revents</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC73"> <span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr_in</span> <span class="n">client_addr</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC74"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">socklen_t</span> <span class="n">client_len</span> <span class="o" style="font-weight: bold;">=</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">client_addr</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC75"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">client_fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr</span> <span class="o" style="font-weight: bold;">*</span><span class="p">)</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client_addr</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client_len</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC76"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">client_fd</span> <span class="o" style="font-weight: bold;">==</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC77"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"the client_fd is NULL !</span><span class="se" style="color: rgb(221, 17, 68);">\n</span><span class="s" style="color: rgb(221, 17, 68);">"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC78"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC79"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC80"> </div><div class="line" id="file-pong_server-c-LC81"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span><span class="p">));</span></div><div class="line" id="file-pong_server-c-LC82"> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">client_fd</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC83"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setnonblock</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC84"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"failed to set client socket to non-blocking"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC85"> </div><div class="line" id="file-pong_server-c-LC86"> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">.</span><span class="n">data</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">client</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC87"> </div><div class="line" id="file-pong_server-c-LC88"> <span class="n">ev_io_init</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">,</span> <span class="n">read_cb</span><span class="p">,</span> <span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">,</span> <span class="n">EV_READ</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC89"> <span class="n">ev_io_start</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC90"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC91"> </div><div class="line" id="file-pong_server-c-LC92"><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">main</span><span class="p">(</span><span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">char</span> <span class="k" style="font-weight: bold;">const</span> <span class="o" style="font-weight: bold;">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC93"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">ch</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC94"> <span class="k" style="font-weight: bold;">while</span> <span class="p">((</span><span class="n">ch</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">getopt</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"p:"</span><span class="p">))</span> <span class="o" style="font-weight: bold;">!=</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC95"> <span class="k" style="font-weight: bold;">switch</span> <span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC96"> <span class="k" style="font-weight: bold;">case</span> <span class="sc" style="color: rgb(221, 17, 68);">'p'</span><span class="o" style="font-weight: bold;">:</span></div><div class="line" id="file-pong_server-c-LC97"> <span class="n">server_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">optarg</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC98"> <span class="k" style="font-weight: bold;">break</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC99"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC100"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC101"> </div><div class="line" id="file-pong_server-c-LC102"> <span class="n">loop</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">ev_default_loop</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC103"> <span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr_in</span> <span class="n">listen_addr</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC104"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">reuseaddr_on</span> <span class="o" style="font-weight: bold;">=</span> <span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC105"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">int</span> <span class="n">listen_fd</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC106"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">listen_fd</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC107"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"listen failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC108"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setsockopt</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">SO_REUSEADDR</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">reuseaddr_on</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">reuseaddr_on</span><span class="p">))</span> <span class="o" style="font-weight: bold;">==</span> <span class="o" style="font-weight: bold;">-</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC109"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"setsockopt failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC110"> </div><div class="line" id="file-pong_server-c-LC111"> <span class="n">memset</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">listen_addr</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">listen_addr</span><span class="p">));</span></div><div class="line" id="file-pong_server-c-LC112"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">AF_INET</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC113"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">INADDR_ANY</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC114"> <span class="n">listen_addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">server_port</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC115"> </div><div class="line" id="file-pong_server-c-LC116"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">bind</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">sockaddr</span> <span class="o" style="font-weight: bold;">*</span><span class="p">)</span> <span class="o" style="font-weight: bold;">&</span><span class="n">listen_addr</span><span class="p">,</span> <span class="k" style="font-weight: bold;">sizeof</span><span class="p">(</span><span class="n">listen_addr</span><span class="p">))</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC117"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"bind failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC118"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">listen</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">5</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC119"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"listen failed"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC120"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">setnonblock</span><span class="p">(</span><span class="n">listen_fd</span><span class="p">)</span> <span class="o" style="font-weight: bold;"><</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">)</span></div><div class="line" id="file-pong_server-c-LC121"> <span class="n">err</span><span class="p">(</span><span class="mi" style="color: rgb(0, 153, 153);">1</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"failed to set server socket to non-blocking"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC122"> </div><div class="line" id="file-pong_server-c-LC123"> <span class="n">ev_io_init</span><span class="p">(</span><span class="o" style="font-weight: bold;">&</span><span class="n">ev_accept</span><span class="p">,</span> <span class="n">accept_cb</span><span class="p">,</span> <span class="n">listen_fd</span><span class="p">,</span> <span class="n">EV_READ</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC124"> <span class="n">ev_io_start</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">ev_accept</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC125"> <span class="n">ev_loop</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC126"> </div><div class="line" id="file-pong_server-c-LC127"> <span class="k" style="font-weight: bold;">return</span> <span class="mi" style="color: rgb(0, 153, 153);">0</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC128"><span class="p">}</span></div><div class="line" id="file-pong_server-c-LC129"> </div><div class="line" id="file-pong_server-c-LC130"><span class="k" style="font-weight: bold;">static</span> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">void</span> <span class="nf" style="color: rgb(153, 0, 0); font-weight: bold;">free_res</span><span class="p">(</span><span class="k" style="font-weight: bold;">struct</span> <span class="n">ev_loop</span> <span class="o" style="font-weight: bold;">*</span><span class="n">loop</span><span class="p">,</span> <span class="n">ev_io</span> <span class="o" style="font-weight: bold;">*</span><span class="n">w</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC131"> <span class="kt" style="color: rgb(68, 85, 136); font-weight: bold;">client_t</span> <span class="o" style="font-weight: bold;">*</span><span class="n">client</span> <span class="o" style="font-weight: bold;">=</span> <span class="n">w</span><span class="o" style="font-weight: bold;">-></span><span class="n">data</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC132"> <span class="k" style="font-weight: bold;">if</span> <span class="p">(</span><span class="n">client</span> <span class="o" style="font-weight: bold;">==</span> <span class="nb" style="color: rgb(0, 134, 179);">NULL</span><span class="p">)</span> <span class="p">{</span></div><div class="line" id="file-pong_server-c-LC133"> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s" style="color: rgb(221, 17, 68);">"the client is NULL !!!!!!"</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC134"> <span class="k" style="font-weight: bold;">return</span><span class="p">;</span></div><div class="line" id="file-pong_server-c-LC135"> <span class="p">}</span></div><div class="line" id="file-pong_server-c-LC136"> </div><div class="line" id="file-pong_server-c-LC137"> <span class="n">ev_io_stop</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="o" style="font-weight: bold;">&</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">ev_read</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC138"> <span class="n">close</span><span class="p">(</span><span class="n">client</span><span class="o" style="font-weight: bold;">-></span><span class="n">fd</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC139"> <span class="n">free</span><span class="p">(</span><span class="n">client</span><span class="p">);</span></div><div class="line" id="file-pong_server-c-LC140"><span class="p">}</span></div></span>
这里有一个现场图:
可以尝试稍微改变输出内容,去除换行符“\n”,把端口换成9000,试试看,就会发现Wireshark输出不同的结果来。
2.3 结论是什么呢?
若使用原始TCP进行双向通信,则需要满足以下条件,可以被类似于Wireshark协议拦截器误认为是HTTP长连接:
使用80/8080端口(81/3128/8000经测试无效) 也许8080一般被作为WEB代理服务端口,微信才会享用这个红利吧。
输出的内容中,一定要包含换行字符"\n"
因此,可以定性为微信使用了基于8080端口TCP长连接,一旦数据包中含有换行"\n"符号,就会被Wireshark误认为HTTP协议。可能微信是无心为之吧。
3. 新消息获取方式
TCP长连接接收到服务器通知有新消息需要获取
APP发起一个HTTP POST请求获取新状态消息,会带上当前SyncKey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy HTTP/1.1,看不到明文
APP获取到新的消息,会再次发起一次HTTP POST请求,告诉服务器已确认收到,同时获取最新SyncKey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/kvreport,看不到明文
接受一个消息,TCP长连接至少交互两次,客户端发起两次HTTP POST请求 具体每次交互内容是什么,有些模糊
服务器需要支持:状态消息获取标记,状态消息确认收取标记。只有被确认收到,此状态消息才算是被正确消费掉
多个不同设备同一账号同时使用微信,同一个状态消息会会被同时分发到多个设备上
此时消息请求截图如下:
4. 发送消息方式
发送消息走已经建立的TCP长连接通道,发送消息到服务器,然后接受确认信息等,产生一次交互。
小伙伴接收到信息阅读也都会收到服务器端通知,产生一次交互等。
可以确定,微信发送消息走TCP长连接方式,因为不对自身状态数据产生影响,应该不交换SyncKey。
在低速网络下,大概会看到消息发送中的提示,属于消息重发机制
网络不好有时客户端会出现发送失败的红色感叹号
已发送到服务器但未收到确认的消息,客户端显示红色感叹号,再次重发,服务器作为重复消息处理,反馈确认
上传图片,会根据图片大小,分割成若干部分(大概1.5K被划分为一部分),同一时间点,客户端会发起若干次POST请求,各自上传成功之后,服务器大概会合并成一个完整图片,返回一个缩略图,显示在APP聊天窗口内。APP作为常规的文字消息发送到服务器端上传音频,则单独走TCP通道,一个两秒的录制音频,客户端录制完毕,分为两块传输,一块最大1.5K左右,服务端响应一条数据通知确认收到。共三次数据传输。音频和纯文字信息一致,都是走TCP长连接,客户端发送,服务器端确认。
四。微信协议小结
发布的消息对应一个ID(只要单个方向唯一即可,服务器端可能会根ID判断重复接收),消息重传机制确保有限次的重试,重试失败给予用户提示,发送成功会反馈确认,客户端只有收到确认信息才知道发送成功。发送消息可能不会产生新SyncKey。
基于版本号(SynKey)的状态消息同步机制,增量、有序传输需求水到渠成。长连接通知/短连接获取、确认等,交互方式简单,确保了消息可靠谱、准确无误到达。
客户端/服务器端都会存储消息ID处理记录,避免被重复消费客户端获取最新消息,但未确认,服务器端不会认为该消息被消费掉。下次客户端会重新获取,会查询当前消息是否被处理过。根据一些现象猜测。
总体上看,微信协议跨平台(TCP或HTPP都可呈现,处理方式可统一),通过“握手”同步,很可靠,无论哪一个平台都可以支持的很好微信协议最小成本为16字节,大部分时间若干个消息包和在一起,批量传输。微信协议说不上最简洁,也不是最节省流量,但是非常成功的。
若服务器检测到一些不确定因素,可能会导致微启用安全套接层SSL协议进行常规的TCP长连接传输。短连接都没有发生变化
以上,根据有限资料和数据拦截观察总结得出,啰啰嗦嗦,勉强凑成一篇,会存在一些不正确之处,欢迎给予纠正。在多次
五。附录
Microsoft Exchange Active Sync协议,简称EAS,分为folderrsync(同步文件夹目录,即邮箱内有哪几个文件夹)和sync(每个文件夹内有哪些文档)两部分。
某网友总结的协议一次回话大致示范:
Client: synckey=0 //第一次key为0
Server: newsynckey=1235434 //第一次返回新key
Client: synckey=1235434 //使用新key查询
Server: newsynckey=1647645,data=*****//第一次查询,得到新key和数据
Client: synckey=1647645
Server: newsynckey=5637535,data=null //第二次查询,无新消息
Client: synckey=5637535
Server: newsynckey=8654542, data=****//第三次查询,增量同步
上页中的相邻请求都是隔固定时间的,如两分钟
客户端每次使用旧key标记自己的状态,服务端每次将新key和增量数据一起返回。
key是递增的,但不要求连续
请求的某个参数决定服务器是否立即返回