6月 152016
 

 

  1. tcp序号是两个方向的,每个方向有自己的序列号
  2. 依次发出的两个tcp数据包的序号可能相同、可能加1、也可能加更多,规则:
    1. 如果上个数据包不需要确认,则下个数据包的序号不增加
    2. 如果上个数据包没有数据,但是也需要确认,如SYN,则下个数据包的序号加1
    3. 如果上个数据包有n个数据,则下个数据包的序号加n
  3. 确认号比较简单,就是要确认的数据包的序号加1
  4. 确认包可以是包含在响应的数据包中的
  5. 不是每个数据包都要对应一个确认包的,一个确认包可以确认好几个数据包的,如:
    1. 由于接收方buffer比较大(就是tcp的win比较大),发送方连续发送了3个数据包,这时候,接收方可以只确认最后一个数据包就足以说明前两个数据包都已经收到了
 Posted by at 下午 6:08
6月 152016
 

问题包如下图:

138 数据包问题: 其实 138、139、140 三个包是在某个设备上因超过mtu值而被拆分的一个包; 138是首先被收到的一个子包,所以有此标识

140数据包问题: 其实从ip的标识头(序号自增)来看,140应该出现在139前面,所以说:Out-Of-Order (就是所谓的乱序)

139数据包问题: 从ip的标识头来看,139前面应该有一个数据包没被抓到(其实就是140),实际是迟到了那么几微妙; 也就是说,如果140数据包能赶到139前面,那么139和140的问题就都没有了

142数据包问题: 从tcp协议的seq来看,141和142是重复了; 从ip数据包来看,这不是同一个数据包的重传,至于为啥会重复ack,不知道啊!

 

问题: ip分包标识是在ip协议上的,这里的重组为什么是reassembled TCP Segments

 Posted by at 下午 5:56
4月 252014
 

缘起

我的IE上访问 www.google.com.hk 是正常的;但是我的chrome上访问 www.google.com.hk 却报证书错误;

查看证书: 在IE上确实是正确的,在chrome上确实是错误的。

另: 由于www.google.com.hk 被解析到一个内网IP 192.168.xx.xx ;

问题:同是被解析到192.168.xx.xx ,为什么IE可以,而chrome不可以?

分析

抓包看看

chrome抓包结果:

IE访问时的抓包结果:

 

从抓包信息不难发现:

内网IP 192.168.xx.xx 提供了两种代理模式:

1.  7层代理模式:  chrome走的是这种模式

2.  HTTP隧道模式: IE走的是这种模式

通过nslookup查看www.google.com.hk解析到的IP地址为: 192.168.xx.xx ,如下

 

说明

该dns: 10.xx.xx.xx 提供了wpad.dat 文件(wpad参考资料:http://yuelei.blog.51cto.com/202879/83841/ );

似乎是:

IE参考该文件,通过HTTP隧道模式完成请求

chrome没有参考该文件,直接发起了请求

为什么会这样?

原本chrome的代理等设置是和IE相同的,如此看来,有可能不同了,去chrome的设置中看看,发现如下可以地方:

有没有发现,这里无法“更改代理服务器设置”,原因是: 您的网络代理设置有扩展程序管理  正常情况为:

 

去扩展程序中看看,我安装并启用了如下两个插件:

Proxy SwitchySharp

Unblock Youku

这两个插件都有此功能,全部禁用后,恢复正常:

最后

那么哪些域名会走隧道呢? 访问如下地址:

http://10.xx.xx.xx/wpad.dat

其中 10.xx.xx.xx 为你的dns服务器的IP地址;当然,也可能是dns告诉你的某个其他的IP地址,详情参考( http://yuelei.blog.51cto.com/202879/83841/ ),如下:

 

到此为止,浪费了1个小时

 Posted by at 上午 11:32
1月 052014
 

1. 一般来讲,在我们写一个server的时候,会用到SO_REUSEADDR,因为,当server正在工作的时候,需要重启,这时候,可能server的一些子进程还在工作,也或者一些连接还处于time_wait状态,而且time_wait状态的时间一般比较长,如果没有SO_REUSEADDR,则会因为端口被占用而bind失败,无法启动server,实例如下:

 

注意:

端口被占用后,不是listen是否能够成功,主要是bind能否成功。

 

2. 对于一个client来讲,如果总是疯狂地连接某个IP的同一个端口,并且连接完之后主动关闭连接,会导致大量的time_wait状态的连接,如果系统没有设置 net.ipv4.tcp_tw_reuse = 1 , 则会导致bind失败(虽然该bind的是隐式的)

 Posted by at 下午 11:45
11月 152013
 

一、 http代理服务器代理https请求(这个就是http隧道吧)

1) 打开连接

CONNECT passport.sina.cn:443 HTTP/1.1
Host: passport.sina.cn
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Linux; Android 4.1.1; MI 2 Build/JRO03L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.92 Mobile Safari/537.36

HTTP/1.1 200 Connection Established
FiddlerGateway: Direct
StartTime: 20:01:27.916
Connection: close

2) 开始ssl握手(其实下面可以是任何的其他协议)

 

当使用CONNECT 时,代理服务器就只负责建立一个tcp连接通道,不再关心上层是什么协议了

二、普通的http代理

> GET http://phpor.net/test.php HTTP/1.1
> User-Agent: curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
> Host: login.sina.com.cn
> Pragma: no-cache
> Accept: */*
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 OK
< Date: Fri, 15 Nov 2013 12:15:40 GMT
< Server: Apache

 

 Posted by at 下午 8:18
7月 312013
 

测试办法:

1. 使用nc做一个server

nc -l localhost 8181

CTRL-Z

2. 使用nc做client

nc localhost 8181 </dev/zero

3. netstat -an |grep 8181

171008 就是读buffer的大小(约160KB), 1279872就是写buffer的大小(约1.2MB)

现在nc client被write给阻塞住了,如果nc client之发送小于 171008 + 1279872 的数据,则现在已经兴高采烈地quit了,然而,server端却连1个字节都没处理呢,如果在把server给杀掉,则这些数据就都算丢弃了。

 

 

 Posted by at 上午 12:09
7月 302013
 

引言

1. tcp是有read buffer和write buffer的,如何才能确保数据不会死在buffer里,虽然tcp是面向连接的可靠的协议,但是tcp没有可靠到这等程度,有些事情还是需要考应用层来保证的

 

正文

关于shutdown和close的一些说明:

1. 如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2. 在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程. 得自己理解引用计数的用法了. 有Kernel编程知识的更好理解了.
3. 只要TCP栈的读缓冲里还有未读取(read)数据,则调用close时会直接向对端发送RST。
4. shutdown与socket描述符没有关系,即使调用shutdown(fd, SHUT_RDWR)也不会关闭fd,最终还需close(fd)。
5. 可以认为shutdown(fd, SHUT_RD)是空操作,因为shutdown后还可以继续从该socket读取数据,这点也许还需要进一步证实。
6. 在已发送FIN包后write该socket描述符会引发EPIPE/SIGPIPE。
7. 当有多个socket描述符指向同一socket对象时,调用close时首先会递减该对象的引用计数,计数为0时才会发送FIN包结束TCP连接。shutdown不同,只要以SHUT_WR/SHUT_RDWR方式调用即发送FIN包。
8. SO_LINGER与close,当SO_LINGER选项开启但超时值为0时,调用close直接发送RST(这样可以避免进入TIME_WAIT状态,但破坏了TCP协议的正常工作方式),SO_LINGER对shutdown无影响。
9. TCP连接上出现RST与随后可能的TIME_WAIT状态没有直接关系,主动发FIN包方必然会进入TIME_WAIT状态,除非不发送FIN而直接以发送RST结束连接。
参考资料:
 Posted by at 下午 11:40
1月 112013
 

缘起:

使用php的file_get_contents(…) 函数从广州发送一个http请求到北京,该请求的请求头和响应头如下:

现在,从广州到北京的一次数据的往返时间(就是ping的时间)为34ms,请求的执行时间为6ms; 因为请求头和相应头都非常小,分别一次tcp数据包就够,这样的话,一次http请求时间为: 34 + 34 + 6 = 74ms , 而实际却稳定在108ms左右,还有大约34ms不知去向

分析

根据这个丢失的时间长度来看,大概是多了一次数据的发送和接收; 通过tcpdump抓包发现如下现象:

file_get_contents(…)中实现的http请求,首先把请求行发送出去,收到请求行数据包的ack包后继续发送后续的请求头; 这样的话就凭空多出一次网络时间,其各种原因,有时间再看看PHP源码中为何如此实现吧。

测试了一下curl,没有这个问题。

 Posted by at 下午 7:23
1月 092013
 

看了一下如下脚本:

一次IPv6支持的检测需要5ms+的时间,成本是比较大的,但是,同一个进程中只检测一次,所以对于httpd进程来讲,这个是没有问题的

 

 Posted by at 下午 3:05