Effective TCP/IP Programming读书笔记

TCP/IP深入思考



这是我读Effective TCP/IP Programming的 读书笔记和思考,以及做的一些实验。强烈建议后端工程师有空读一读这本书,有些细节的确是我们平时没有注意的,读了最好自己动手做一些实验加深理解。

fin的含义

对端发送fin会导致read()返回,但send()照样可以发送,也就是单纯的fin其实相当于shutdown(SHUT_WR)。

当对端应用程序崩溃后(未close),本段一直调用send(),对端会返回RST,此时read()会返回Connection reset by peer。

当对端应用程序崩溃后或close连接,本段调用read()返回0,

调用send()会导致EPIPE(Broken pipe),第二次send()才会出错。

对端主机崩溃

由于主机崩溃,或不结束应用程序关机,或直接关闭modern,导致对方接受不到fin,rst等,recv()会永久阻塞。解决办法:

1.开启keepalive机制,默认情况下(2+9*75/60)小时后超时

2.recv()超时机制

3.心跳,其实就是发送send(),一段时间会检测到连接断了

SO_LINGER深入理解

如果应用程序执行主动关闭,最后会在TIME_WAIT状态保持2MSL时间,而SO_LINGER选项能迫使连接立刻关闭,不走正常4步关闭流程。

server

from socket import *
s = socket(AF_INET,SOCK_STREAM)
s.bind(("localhost",9123))
s.listen(10)
cc = s.accept()
print cc #查看零时端口为47128

client

from socket import *
c = socket(AF_INET,SOCK_STREAM)
c.connect(("localhost",9123))
c.close()

由于client主动关闭,这时client应该处于FIN_WAIT2,server对应处于CLOSE_WAIT

[[email protected]10-9-22-239 ~]# netstat -an | grep 47128
tcp        1      0 127.0.0.1:9123          127.0.0.1:47128         CLOSE_WAIT
tcp        0      0 127.0.0.1:47128         127.0.0.1:9123          FIN_WAIT2  

注意netstat要加n参数,不然会根据/etc/services解析成服务名。

当server端再调用cc[0].close()时,此时clinet将处于TIME_WAIT状态。我们将client的socket加个SO_LINGER选项。

from struct import *
c.setsockopt(SOL_SOCKET,SO_LINGER,pack("ii",1,0))

此时我们查看发现没有对应状态,也就是未新户型FIN_WAIT2的状态,直接关闭,不走正常四步关闭连接流程。

当然强壮的应用服务器不应该干扰TIME_WAIT状态,这是TCP可靠机制的重要组成部分。

SO_LINGER选项还有其它作用,通常当close()一条连接时,即使发送缓冲区仍然有数据要发送,close()也会立即返回。当然TCP还是会尝试发送未发送出去的数据,但应用程序并不知道是否发送成功,SO_LINGER就是为解决这个问题的。

struct linger{
    int l_onoff; // on/off选项
    int l_linger; //逗留时间
};

1.l_onoff为0,linger不启用,行为和默认close()相同

2.l_onoff非0,如果l_linger非0,close()在等待数据发送完毕或逗留时间超时,如果逗留时间到,仍然有未发送数据,close()返回EWOULDBLOCK;如果linger为0,就将丢弃连接,也就是上面我们展示的那样。

Nagle算法和延迟ACK

Nagle算法有助于预防网络中的小报文泛洪,但与延迟ACK交互可能会导致200ms延迟。BSD实现ACK延迟200ms,RFC规定不能大于500ms,我在Linux上做的实验发现都是40ms延迟ACK。

关闭Nagle算法

const int on = 1;
setsocket(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
//from tornado
try:
    self.socket.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY, 1)
except socket.error as e:
    # Sometimes setsockopt will fail if the socket is closed
    # at the wrong time.  This can happen with HTTPServer
    # resetting the value to false between requests.
    if e.errno not in (errno.EINVAL, errno.ECONNRESET):
        raise

应对方法:

1.将写操作合并,可使用writev()

2.多用buff,如go中bufio.Reader,bufio.Writer

非阻塞connect

非阻塞connect()会立即返回EINPROGRESS,如果连接成功套接字会立刻可写,那如何检查是否连接成功呢?

status = connect( sock, ......); // 返回0,成功连接
if ( status != 0 && errno != EINPROGRESS) {
    close(sock);
}

可以使用getsockopt检查是否出错,当然之前必须等待该socket状态变化

int error;
socklen_t len = sizeof(error);
int code = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
if (code < 0 || error) {  //返回值小于0或error不等于0说明连接错误
    close(s);
    return SOCKET_ERROR;
}

用python模拟如下:

import socket
import select
import errno

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setblocking(False)
try:
  s.connect(("www.google.com",80))
except socket.error as e:
  if e.errno == errno.EINPROGRESS:
    print("INprocess")
  else:
    raise

r,w,x = select.select([s],[s],[s])
err = s.getsockopt(socket.SOL_SOCKET,socket.SO_ERROR)
if err != 0:
  print("error",errno.errorcode[err])
  s.close()
else:
  print("connect ok")

很明显,不翻墙www.google.com暂时连接不了,出错信息

INprocess
(‘error‘, ‘ETIMEDOUT‘)

理解udp connect

使用udp connect好处:

1.使用connect()对性能有较大提高,BSD实现中sendto()是connect的特列,内核暂时让套接字与目的地址连接,发送数据包,然后解除连接。

2.可以接受异步错误,由于udp无状态,数据发送出去,系统就会忘记,所以即使返回icmp报文,也不知道是哪个应用程序发送的数据包,使用connect会记录对应信息。

s=socket(AF_INET,SOCK_DGRAM)
s.connect(("localhost",9999))
s.send("1111")
s.recv() //error: [Errno 111] Connection refused

send()之后,icmp报文报告不可达,再次recv或recvfrom会报错。

缓冲区大小

发送缓冲区设置为MSS的3倍大,可有效减少Nagle算法与延迟ACK导致的交互问题。

Linux默认发送缓冲区为4K,以太网mss是1460,还是很合理的。

发送缓冲区大小大于等于对方的接受缓冲区,因为发送方只能收到ACK才会释放已发送数据,所以发送缓冲区容易满,不发送新的数据,就会产生40ms延迟ACK。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-12 04:17:09

Effective TCP/IP Programming读书笔记的相关文章

《图解tcp/ip》读书笔记(二)

<图解tcp/ip>读书笔记(二) 本周主要阅读的是本书的第三章--数据链路. 当然了,从某些角度讲,我认为这一章就是计算机网络的最基本的内容之一.整章讲述了数据链路层的作用和相关技术,主要描述了以太网.无线通信.ppp.公共网络以及其他的一些数据链路一些细节性的技术. 由于之前已经学习过相关计算机网络的课程,因此,就不再详细的记录整个阅读内容了,很多让我突破以前思维定式的一些知识,我挑一些列在下面. 其实这些知识花几分钟.几个小时,就可以得到,或者查阅互联网会得到比这本书更新的技术,但是,有

《图解TCP/IP》读书笔记

一.国际惯例:书托 这是一本图文并茂的网络管理技术书籍,旨在让广大读者理解TCP/IP的基本知识.掌握TCP/IP的基本技能. 书中讲解了网络基础知识.TCP/IP基础知识.数据链路.IP协议.IP协议相关技术.TCP与UDP.路由协议.应用协议.网络安全等内容,引导读者了解和掌握TCP/IP,营造一个安全的.使用放心的网络环境. 同时,这本书也是我的2016年度读书计划中的一本,下面我将会把我看书中的重点内容总结和摘录下来,所谓把书读薄,就是把精华内容留下,以供以后随时参考. 二.网络基础知识

《图解TCP/IP》读书笔记1 - 网络基础

第一章:网络基础知识 1 协议: 互联网 ->TCP IP HTTP LAN -> IPX/SPX 2 分组通信/分组交换协议->Packet 3 OSI ->层与层之间通过某种协议通信 4 数据逐层添加首部,接受后逐层分离 5 表示层识别编码 6 传输方式: 有连接 - 建立连接后发送数据 无连接 - 直接发送 TCP:面向有连接的分组发送协议 7 网络通信方式: 电路交换:电话网 分组交换:TCP/IP 分解成数据包,使多个计算机可以同时交换数据 8 分组交换: 路由器连接通信

tcp/ip 卷一 读书笔记(1)tcp/ip 四层协议

广域网 WAN TCP/IP通常被认为是一个四层协议系统,包括 链路层 包括arp,rarp协议,包括操作系统中的网卡驱动程序和对应的网络接口卡,一起处理数据在电缆之间传输的细节,这一层是同一个链路网络内,不同接口之间通过mac地址通信.arp协议是根据ip地址,请求对应的mac地址,rarp协议是根据mac地址,请求ip地址(可以用来做开机获取ip地址,实际现在已经不这么做了),二层的典型设备是交换机,交换机内有一张mac地址和对应的端口规则的表,每当收到一个包,如果是arp广播包,那么就将这

tcp/ip 卷一 读书笔记(3)为什么既要有IP地址又要有MAC地址

网络层 首先明确一点,并不是所有的网络之间传输数据都需要mac地址和ip地址,比如说点对点线路之间的通信就没有MAC地址,网络层使用ipx协议时就没有ip地址,但是在当前的主流网络中,我们都使用ip地址和mac地址 既然mac地址唯一,为什么还要有IP地址? 之前我们提到,mac地址是唯一的,那理论上,在任何两个设备之间,我应该都可以通过mac地址发送数据,为什么还需要ip地址? mac地址就好像个人的身份证号,人的身份证号和人户口所在的城市,出生的日期有关,但是和人所在的位置没有关系,人是会移

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记

编写高质量的iOS代码--Effective Objective-C 2.0 读书笔记 这本书年初刷完,感觉不错,介绍了很多小点,都是平日不怎么关注的. 第1章 熟悉Objective-C 这章没什么好介绍 第1条:了解Objective-C语言的起源 第2条:在类的头文件中尽量少引入其他头文件 第3条:多用字面量语法,少用与之等价的方法 第4条:多用类型常量,少用#define预处理指令 要理解为啥要少用#define预处理指令. 然后具体用哪个, 自己定吧 第5条:用枚举表示状态.选项.状态

tcp/ip协议学习笔记一

一. 简述 以前在学校学习计算机网络的时候学习多是网络7层模型OSI,了解了一些基本的计算机网络概念和协议通信格式,但是一直没弄明白其中的原理,包括各层之间的关系,应用,还有一些常见的令牌环网到底是什么东西,这个OSI它和 TCP/IP协议簇到底是什么关系,为什么有很多协议一样?ip指令格式是什么样的?为什么老是忘记,记不住?3次握手,4次握手协议是什么?ack,syn等等说不清道不明字段是指什么?为什么以太网网卡通信速率有100mbps,两台主机之间的通信却只有不到120kpbs?...所有的

TCP/IP详解 笔记十四

TCP/IP协议(二)  连接的建立与终止 tcpdump -S输出TCP报文的格式 格式: 源>目的:标志 (标志就是tcp头部).标识首字符意义如下: 例如:telnet 某服务的输出(包括连接建立和终止) 标识解释:S 1415531521:1415531521(0) win 4096 <mss 1024> S(SYN):代表建立一个连接 1415531521:1415531521(0) :本次传送的首字节序号是1415531521(这里是ISN),尾字节序号是1415531521

【DAY18】Socket编程,ROSE建模与TCP/IP的学习笔记

IDE eclipse调试 ------------------ 1.Debug 2.Step into : F5  ,单步进入. 3.Step return : F7,单步返回. 4.Stop over : F6,单步跳过. 安装Rose建模软件 ----------------- 1.安装虚拟光驱软件:DTLite.exe 2.加载Rose镜像文件. 3.一路安装,next... 4.安装完成注册License. a.在license管理器界面 开始 --> IBM Rose -> Lic