1
Strikeactor 2016-01-08 22:45:53 +08:00
用 HTTP 协议吧
|
2
jasontse 2016-01-08 23:01:44 +08:00 via Android
wikipedia 写的很明白了,包结构部分
https://en.wikipedia.org/wiki/Transmission_Control_Protocol |
3
cmingxu 2016-01-08 23:12:52 +08:00 1
tcp 连接是 stream , 所以没有头和尾的概念, 一种做法是传输的包前加上此包的长度信息。另外就是特殊的结束符(得注意传输内容和结束符一致的情况)。
|
4
ryd994 2016-01-08 23:16:17 +08:00 1
带长度,每个数据段的开头先声明长度
你会有这个问题说明你对 TCP 的理解不对。对应用程序, TCP 连接就是无限长的数据流,直到关闭,网络上的数据包程序是看不见的。 而且你确定建立连接的成本有那么高?比 mutiplex 这些数据所需的各种头信息还要高?有没有考虑 fastopen ?有没有考虑 udp ? |
5
easing 2016-01-08 23:37:14 +08:00 via Android 1
这是上层协议的事情,传输层不负责内容数据逻辑上的起始。你可以模拟 http 协议,要么携带长度信息,要么规定特殊字符作为起始标志。
|
6
amaranthf OP @ryd994 因为我的代理服务器是在内网,而且不能开端口映射,所以必须由服务器主动连接到客户端,为此需要使用另一方的服务器进行中转才能建立连接。
|
7
znoodl 2016-01-09 00:07:20 +08:00 via iPhone
定义协议,比如最简单的前 4 个字节做长度,后面的长度是数据
|
8
mengskysama 2016-01-09 00:12:27 +08:00
自己实现好累的,你看这样行不行,在内网代理服务器搭一个代理,然后内网代理服务器通过 ssh 连接到公网服务器,并把自己的 S5 代理端口 ssh 映射到公网服务器上,公网服务器用 iptables 做个转发,这样一行代码都不用写。
|
9
amaranthf OP @mengskysama 就是利用公网服务器做一个隧道呗,理论上是可以啦,不过我搞这个东西本来就是为了解决延迟问题,那台内网机器所在的网络非常快,我这儿 ping 过去只要 10ms ,再到外面的出口也是 10ms ,而通过公网服务器这么来回一中转……至少就 100 了……
|
10
mengskysama 2016-01-09 00:26:18 +08:00
@amaranthf 可能没明白你的要求,你意思是你(公网),那台服务器(内网),然后通过自己和那台服务器建立一个连接来访问公网资源?
|
11
amaranthf OP @mengskysama 是这样……
我的机器 A ,内网机器 B A 处于公网(实际上也是内网,不过路由这边可以做端口映射); B 处于内网,且不能与公网直接通讯。 B 可以通过代理 P1 连接“外面的网络”,另外也可以通过代理 P2 连接正常的公网。 P1 和 P2 都属于 B 所在的内网,所以延迟可以忽略。另外最最重要的一点就是, P1 是开白名单的……而且速度稳稳碾压各种国外 vps 的直连…… 就是这么个复杂的情况…… |
12
amaranthf OP @mengskysama 我的设计是这样的,需要利用公网服务器 C 。
1. B 通过 P2 与 C 建立长连接 2. A 需要连接的时候,通知 C 自己的 ip 和端口 3. C 通知 B 4. B 通过 P2 连接 A 5. A-P2-B-P1-外面 建立这样的链路 |
13
mengskysama 2016-01-09 00:43:46 +08:00
@amaranthf
A 映射一个端口 2222 在 B 上开一个代理服务器听一个端口 0.0.0.0:3333 B 通过 P1 建立 ssh 连接到 A 的 2222 ,并且映射端口 3333 到 A 的 3334 这样。 |
14
mengskysama 2016-01-09 00:45:56 +08:00
@amaranthf 不需要 C 了,你直接 A 和 B 长连不就行了有个东西叫 Autossh 。。 IP 用 DDNS ,端口固定。
|
15
amaranthf OP @mengskysama 呃,我是考虑做一个应用范围广一些的,比如我写个手机 app 就也能利用这套代理了……不过 ssh 隧道方面的东西确实没有仔细了解过,我查查相关资料,看怎么用那个简化一下吧,多谢啦
|
16
r00tt 2016-01-09 11:21:29 +08:00
tcp 流式的,没有包的概念,这种情况一般都是自定义数据包,可以设计定长,也可以设计非定长( Tag + Length + Body + CheckSum 类似这种拉~),可以用 flatbuffers ,protobuf 来实现比较好
|
17
hao123yinlong 2016-01-09 15:44:01 +08:00
/**
* 半包处理解码器 * * 两端通信单向一个完整的数据包由 Length , Type , Message 三部分组成,固定占用 4 个字节的 Length 声明了 Message * 的字节长度, Type 占用一个字节, Length 不包含 Type 所占一个字节 Message 是一个接口调用所需参数 protobuf 对象编码后的字节数组 * * 当 Lenght int 值为 0 时,表示是心跳数据包,向客户端回复心跳数据包 ,心跳数据包 5 个字节 * * | Length | Type | Message | | (4 bytes) | (1 bytes) | (n bytes) | * * @author yintengfei * */ |
18
shyling 2016-01-09 20:56:46 +08:00
固定的结束符就可以了吧。。
每次 on('data')把 chunk 插到 Buffer[]后面,然后从前面开始读到结束符,读不到就是没结束。。 |
19
MiskoLee 2016-01-12 23:04:48 +08:00 2
这个问题,我们可以提炼一下。
1. 什么叫结束? 我们举个例子,对于手机来说,并不存在结束对话这个状态。只有接通,未接通,通话中,挂断等状态。因此,此时,手机网络无法获知与处理对话结束这个状态。那么,现实中,它是怎么工作的? A : 你好! B :你好! A :.... B :..... A :先这样吧,下次再聊!( A 尝试发起结束对话) B : Bye !( B 确认结束通话) 然后 A , B 互相挂断电话。 同理, TCP 中并不存在所谓的数据接收完毕这种状态。因此,这种状态是我们人为附加上的,所以,需要我们人为的来处理这件事。 首先,我们来看看 HTTP 是怎么工作的。 在 Http 标准分为固定格式的 Header 与任意格式的 Body 构成。 在 header 中有定义 Content-Length 字段。 Http 的定义中,其实就包含了上述各位描述的:特定 chunk 符, DataLength 等技术手段。 首先是 Http Header Http Header 就是一组固定格式的文本,内部通过特定符号完成断句。 从 Header 中读取到 Content-Length 字段,读取等长的 Body ,然后关闭 TCP 连接。 当 Content-Length 未读取成功的时候,则等待服务端断开连接。 我们在使用浏览器下载稍微大型的文件的时候,通常会遇到两种情况 1. 100KB/12.3M 预计 2 分钟后下载完毕 2. 已接收 100KB 原因,我们可以思考。 现在,我们再来看一个经典的 TCP 协议。 MYSQL 协议。 MYSQL 在 TCP 层,把数据封装成一个一个的 packet 。每个 packet 的信息非常少,我们可以粗略的理解为 |DataLegnth|DataBody| 读取每个 packet 的时候,首先读取 DataLength,接着读取 DataLength 长度的 DataBody. 综上所述。 在 TCP 中,数据传输必须要有一个协议。这个协议至少要有一个信息,就是定义一个完整数据的长度。 |