linux tcp源码?linux版软件网站
这篇文章给大家聊聊关于linux tcp源码,以及linux版软件网站对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。
tcp拥塞控制状态机在linux内核源码的什么位置
公平性
公平性是在发生拥塞时各
源端(或同一源端建立的不同TCP连接或UDP数据报)能公平地共享同一网络资源(如带宽、缓存等)。处于相同级别的源端应该得到相同数量的网络资源。产
生公平性的根本原因在于拥塞发生必然导致数据包丢失,而数据包丢失会导致各数据流之间为争抢有限的网络资源发生竞争,争抢能力弱的数据流将受到更多损害。
因此,没有拥塞,也就没有公平性问题。
TCP层上的公平性问题表现在两方面:
(1)
面向连接的TCP和无连接的UDP在拥塞发生时对拥塞指示的不同反应和处理,导致对网络资源的不公平使用问题。在拥塞发生时,有拥塞控制反应机制的TCP
数据流会按拥塞控制步骤进入拥塞避免阶段,从而主动减小发送入网络的数据量。但对无连接的数据报UDP,由于没有端到端的拥塞控制机制,即使网络发出了拥
塞指示(如数据包丢失、收到重复ACK等),UDP也不会像TCP那样减少向网络发送的数据量。结果遵守拥塞控制的TCP数据流得到的网络资源越来越少,
没有拥塞控制的UDP则会得到越来越多的网络资源,这就导致了网络资源在各源端分配的严重不公平。
网络资源分配的不公平反
过来会加重拥塞,甚至可能导致拥塞崩溃。因此如何判断在拥塞发生时各个数据流是否严格遵守TCP拥塞控制,以及如何“惩罚”不遵守拥塞控制协议的行为,成
了目前研究拥塞控制的一个热点。在传输层解决拥塞控制的公平性问题的根本方法是全面使用端到端的拥塞控制机制。
(2)一些TCP连接之间也存在公平性问题。产生问题的原因在于一些TCP在拥塞前使用了大窗口尺寸,或者它们的RTT较小,或者数据包比其他TCP大,这样它们也会多占带宽。
RTT不公平性
AIMD拥塞窗口更新策
略也存在一些缺陷,和式增加策略使发送方发送数据流的拥塞窗口在一个往返时延(RTT)内增加了一个数据包的大小,因此,当不同的数据流对网络瓶颈带宽进
行竞争时,具有较小RTT的TCP数据流的拥塞窗口增加速率将会快于具有大RTT的TCP数据流,从而将会占有更多的网络带宽资源。
附加说明
中美之间的线路质量不是很好,rtt较长且时常丢包。TCP协议是成也丢包,败也丢包;TCP的设计目的是解决不可靠线路上可靠传输的问题,即为了解决丢包,但丢包却使TCP传输速度大幅下降。HTTP协议在传输层使用的是TCP协议,所以网页下载的速度就取决于TCP单线程下载的速度(因为网页就是单线程下载的)。
丢包使得TCP传输速度大幅下降的主要原因是丢包重传机制,控制这一机制的就是TCP拥塞控制算法。
Linux内核中提供了若干套TCP拥塞控制算法,已加载进内核的可以通过内核参数net.ipv4.tcp_available_congestion_control看到。
Vegas
1994
年,Brakmo提出了一种新的拥塞控制机制TCP
Vegas,从另外的一个角度来进行拥塞控制。从前面可以看到,TCP的拥塞控制是基于丢包的,一旦出现丢包,于是调整拥塞窗口,然而由于丢包不一定是由
于网络进入了拥塞,但是由于RTT值与网络运行情况有比较密切的关系,于是TCP
Vegas利用RTT值的改变来判断网络是否拥塞,从而调整拥塞控制窗口。如果发现RTT在增大,Vegas就认为网络正在发生拥塞,于是开始减小拥塞窗
口,如果RTT变小,Vegas认为网络拥塞正在逐步解除,于是再次增加拥塞窗口。由于Vegas不是利用丢包来判断网络可用带宽,而是利用RTT变化来判断,因而可以更精确的探测网络的可用带宽,从而效率更好。然而Vegas的有一个缺陷,并且可以说致命的,最终影响TCP
Vegas并没有在互联网上大规模使用。这个问题就是采用TCP Vegas的流的带宽竞争力不及未使用TCP Vegas的流,
这是因为网络中路由器只要缓冲了数据,就会造成RTT的变大,如果缓冲区没有溢出的话,并不会发生拥塞,但是由于缓存数据就会导致处理时延,从而RTT变
大,特别是在带宽比较小的网络上,只要一开始传输数据,RTT就会急剧增大,这个在无线网络上特别明显。在这种情况下,TCP
Vegas降低自己的拥塞窗口,但是只要没有丢包的话,从上面看到标准的TCP是不会降低自己的窗口的,于是两者开始不公平,再这样循环下去,TCP
Vegas的效率就非常低了。其实如果所有的TCP都采用Vegas拥塞控制方式的话,流之间的公平性会更好,竞争能力并不是Vegas算法本身的问题。
适用环境:很难在互联网上大规模适用(带宽竞争力低)
2. Reno
Reno是目前应用最广泛且较为成熟的算法。该算法所包含的慢启动、拥塞避免和快速重传、快速恢复机制,是现有的众多算法的基础。从Reno运行机制中很容易看出,为了维持一个动态平衡,必须周期性地产生一定量的丢失,再加上AIMD机制--减少快,增长慢,尤其是在大窗口环境下,由于一个数据报的丢失所带来的窗口缩小要花费很长的时间来恢复,这样,带宽利用率不可能很高且随着网络的链路带宽不断提升,这种弊端将越来越明显。公平性方面,根据统计数据,Reno的公平性还是得到了相当的肯定,它能够在较大的网络范围内理想地维持公平性原则。
Reno算法以其简单、有效和鲁棒性成为主流,被广泛的采用。
但是它不能有效的处理多个分组从同一个数据窗口丢失的情况。这一问题在New Reno算法中得到解决。
基于丢包反馈的协议
近几年来,随着高带宽延时网络(High Bandwidth-Delay product network)的普及,针对提高TCP带宽利用率这一点上,又涌现出许多新的基于丢包反馈的TCP协议改进,这其中包括HSTCP、STCP、BIC-TCP、CUBIC和H-TCP。
总的来说,基于丢包反馈
的协议是一种被动式的拥塞控制机制,其依据网络中的丢包事件来做网络拥塞判断。即便网络中的负载很高时,只要没有产生拥塞丢包,协议就不会主动降低自己的
发送速度。这种协议可以最大程度的利用网络剩余带宽,提高吞吐量。然而,由于基于丢包反馈协议在网络近饱和状态下所表现出来的侵略性,一方面大大提高了网络的带宽利用率;但另一方面,对于基于丢包反馈的拥塞控制协议来说,大大提高网络利用率同时意味着下一次拥塞丢包事件为期不远了,所以这些协议在提高网络带宽利用率的同时也间接加大了网络的丢包率,造成整个网络的抖动性加剧。
友好性
BIC-TCP、
HSTCP、STCP等基于丢包反馈的协议在大大提高了自身吞吐率的同时,也严重影响了Reno流的吞吐率。基于丢包反馈的协议产生如此低劣的TCP友好
性的组要原因在于这些协议算法本身的侵略性拥塞窗口管理机制,这些协议通常认为网络只要没有产生丢包就一定存在多余的带宽,从而不断提高自己的发送速率。
其发送速率从时间的宏观角度上来看呈现出一种凹形的发展趋势,越接近网络带宽的峰值发送速率增长得越快。这不仅带来了大量拥塞丢包,同时也恶意吞并了网络
中其它共存流的带宽资源,造成整个网络的公平性下降。
3. HSTCP(High Speed TCP)
HSTCP(高速传输控制协议)是高速网络中基于AIMD(加性增长和乘性减少)的一种新的拥塞控制算法,它能在高速度和大时延的网络中更有效地提高网络的吞吐率。它通过对标准TCP拥塞避免算法的增加和减少参数进行修改,从而实现了窗口的快速增长和慢速减少,使得窗口保持在一个足够大的范围,以充分利用带宽,它在高速网络中能够获得比TCP
Reno高得多的带宽,但是它存在很严重的RTT不公平性。公平性指共享同一网络瓶颈的多个流之间占有的网络资源相等。
TCP发送端通过网络所期望的丢包率来动态调整HSTCP拥塞窗口的增量函数。
拥塞避免时的窗口增长方式: cwnd= cwnd+ a(cwnd)/ cwnd
丢包后窗口下降方式:cwnd=(1-b(cwnd))*cwnd
其中,a(cwnd)和
b(cwnd)为两个函数,在标准TCP中,a(cwnd)=1,b(cwnd)=0.5,为了达到TCP的友好性,在窗口较低的情况下,也就是说在非
BDP的网络环境下,HSTCP采用的是和标准TCP相同的a和b来保证两者之间的友好性。当窗口较大时(临界值LowWindow=38),采取新的a
和b来达到高吞吐的要求。具体可以看RFC3649文档。
4. westwood
无线网络中,在大量研究的基础上发现tcpwestwood是一种较理想的算法,它的主要思想是通过在发送端持续不断的检测ack的到达速率来进行带宽估计,当拥塞发生时用带宽估计值来调整拥塞窗口和慢启动阈值,采用aiad(additive increase and
adaptive decrease)拥塞控制机制。它不仅提高了无线网络的吞吐量,而且具有良好的公平性和与现行网络的互操作性。存在的问题是不能很好的区分传输过程中的拥塞丢包和无线丢包,导致拥塞机制频繁调用。
5. H-TCP
高性能网络中综合表现比较优秀的算法是:h-tcp,但它有rtt不公平性和低带宽不友好性等问题。
6. BIC-TCP
BIC-TCP的缺点:首先就是抢占性较强,BIC-TCP的增长函数在小链路带宽时延短的情况下比起标准的TCP来抢占性强,它在探测阶段相当于是重新启动一个慢启动算法,而TCP在处于稳定后窗口就是一直是线性增长的,不会再次执行慢启动的过程。其次,BIC-TCP的的窗口控制阶段分为binary
search increase、max probing,然后还有Smax和Smin的区分,这几个值增加了算法上的实现难度,同时也对协议性能的分析模型增加了复杂度。在低RTT网络和低速环境中,BIC可能会过于“积极”,因而人们对BIC进行了进一步的改进,即CUBIC。是Linux在采用CUBIC之前的默认算法。
7. CUBIC
CUBIC在设计上简化了BIC-TCP的窗口调整算法,
在BIC-TCP的窗口调整中会出现一个凹和凸(这里的凹和凸指的是数学意义上的凹和凸,凹函数/凸函数)的增长曲线,CUBIC使用了一个三次函数(即
一个立方函数),在三次函数曲线中同样存在一个凹和凸的部分,该曲线形状和BIC-TCP的曲线图十分相似,于是该部分取代BIC-TCP的增长曲线。另
外,CUBIC中最关键的点在于它的窗口增长函数仅仅取决于连续的两次拥塞事件的时间间隔值,从而窗口增长完全独立于网络的时延RTT,之前讲述过的HSTCP存在严重的RTT不公平性,而CUBIC的RTT独立性质使得CUBIC能够在多条共享瓶颈链路的TCP连接之间保持良好的RTT公平性。
CUBIC is a congestion control protocol for TCP(transmission control protocol) and thecurrent default TCP algorithm in Linux.
The protocol modifies the linear window
growth function of existing TCP standards to be a cubic function in
order to improve the scalability of TCP over fast and long distance
networks. It also achieves more equitable bandwidth allocations among
flows with different RTTs(round trip times) by making
the window growth to be independent of RTT– thus those flows grow
their congestion window at the same rate. During steady state, CUBIC
increases the window size aggressively when the window is far from the
saturation point, and the slowly when it is close
to the saturation point.This feature allows
CUBIC to be very scalable when the bandwidth and delay product of the
network is large, and at the same time, be highly stable and also fair
to standard TCP flows.
8. STCP
STCP,Scalable tcp。
STCP算法是由 Tom Kelly于 2003年提出的,通过修改 TCP的窗口增加和减少参数来调整发送窗口大小,以适应高速网络的环境。该算法具有很高的链路利用率和稳定性,但该机制窗口增加和 RTT成反比,在一定的程度上存在着
RTT不公平现象,而且和传统 TCP流共存时,过分占用带宽,其 TCP友好性也较差。
从Linux源码 看 Socket(TCP)的accept
从 Linux源码角度探究 Server端 Socket的 Accept过程(基于 Linux 3.10内核),以下是一系列关键步骤的解析。
创建 Server端 Socket需依次执行 socket、bind、listen和 accept四个步骤。其中,socket系统调用创建了一个 SOCK_STREAM类型的 TCP Socket,其操作函数为 TCP Socket所对应的 ops。在进行 Accept时,关键在于理解 Accept的功能,即创建一个新的 Socket与对端的 connect Socket进行连接。
在具体实现中,核心函数 sock->ops->accept被调用。关注 TCP实现即 inet_stream_ops->accept,其进一步调用 inet_accept。核心逻辑在于 inet_csk_wait_for_connect,用于管理 Accept的超时逻辑,避免在超时时惊群现象的发生。
EPOLL的实现中,"惊群"现象是由水平触发模式下 epoll_wait重新塞回 ready_list并唤醒多个等待进程导致的。虽然 epoll_wait自身在有中断事件触发时不惊群,但水平触发机制仍会造成类似惊群的效应。解决此问题,通常采用单线程专门处理 accept,如 Reactor模式。
针对"惊群"问题,Linux提供了 so_reuseport参数,允许多个 fd监听同一端口号,内核中进行负载均衡(Sharding),将 accept任务分散到不同 Socket上。这样,可以有效利用多核能力,提升 Socket分发能力,且线程模型可改为多线程 accept。
在 accept过程中,accept_queue是关键成员,用于填充添加待处理的连接。用户线程通过 accept系统调用从队列中获取对应的 fd。值得注意的是,当用户线程未能及时处理时,内核可能会丢弃三次握手成功的连接,导致某些意外现象。
综上所述,理解 Linux Socket的 Accept过程需要深入源码,关注核心函数与机制,以便优化 Server端性能,并有效解决"惊群"等问题,提升系统处理能力。
linux shell 脚本实现tcp/upd协议通讯
linux设备里面有个比较特殊的文件:
/dev/[tcp|upd]/host/port只要读取或者写入这个文件,相当于系统会尝试连接:host这台机器,对应port端口。如果主机以及端口存在,就建立一个socket连接。将在,/proc/self/fd目录下面,有对应的文件出现。
一、测试下:/dev/tcp/host/post文件
复制代码
代码如下:
[chengmo@centos5 shell]$ cat/dev/tcp/127.0.0.1/22
SSH-2.0-OpenSSH_5.1
#我的机器shell端口是:22
#实际:/dev/tcp根本没有这个目录,这是属于特殊设备
[chengmo@centos5 shell]$ cat/dev/tcp/127.0.0.1/223
-bash: connect:拒绝连接
-bash:/dev/tcp/127.0.0.1/223:拒绝连接
#223接口不存在,打开失败
[chengmo@centos5 shell]$ exec 8/dev/tcp/127.0.0.1/22
[chengmo@centos5 shell]$ ls-l/proc/self/fd/
总计 0
lrwx------ 1 chengmo chengmo 64 10-21 23:05 0-/dev/pts/0
lrwx------ 1 chengmo chengmo 64 10-21 23:05 1-/dev/pts/0
lrwx------ 1 chengmo chengmo 64 10-21 23:05 2-/dev/pts/0
lr-x------ 1 chengmo chengmo 64 10-21 23:05 3-/proc/22185/fd
lrwx------ 1 chengmo chengmo 64 10-21 23:05 8- socket:[15067661]
#文件描述符8,已经打开一个socket通讯通道,这个是一个可以读写socket通道,因为用:""打开
[chengmo@centos5 shell]$ exec 8-
#关闭通道
[chengmo@centos5 shell]$ ls-l/proc/self/fd/
总计 0
lrwx------ 1 chengmo chengmo 64 10-21 23:08 0-/dev/pts/0
lrwx------ 1 chengmo chengmo 64 10-21 23:08 1-/dev/pts/0
lrwx------ 1 chengmo chengmo 64 10-21 23:08 2-/dev/pts/0
lr-x------ 1 chengmo chengmo 64 10-21 23:08 3-/proc/22234/fd
二、通过重定向读取远程web服务器头信息
复制代码
代码如下:
#!/bin/sh
#testhttphead.sh
#实现通过主机名,端口读取web服务器header信息
#copyright chengmo,qq:8292669
if(($#2));then
echo"usage:$0 host port";
exit 1;
fi
#如果参数缺失,退出程序,返回状态1
exec 6/dev/tcp/$1/$2 2/dev/null;
#打开host的port可读写的socket连接,与文件描述符6连接
if(($?!=0));then
echo"open$1$2 error!";
exit 1;
fi
#如果打开失败,$?返回不为0,终止程序
echo-e"HEAD/ HTTP/1.1/n/n/n/n/n"6;
#将HEAD信息,发送给socket连接
cat6;
#从socket读取返回信息,显示为标准输出
exec 6-;
exec 6-;
#关闭socket的输入,输出
exit 0;
脚本建立后:存为testhttphead.sh
运行结果:
复制代码
代码如下:
[chengmo@centos5~/shell]$ sh testhttphead.sh www.baidu.com 80
HTTP/1.1 200 OK
Date: Thu, 21 Oct 2010 15:17:23 GMT
Server: BWS/1.0
Content-Length: 6218
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Thu, 21 Oct 2010 15:17:23 GMT
Set-Cookie: BAIDUID=1C40B2F8C676180FD887379A6E286DC1:FG=1; expires=Thu, 21-Oct-40 15:17:23 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM"
Connection: Keep-Alive
[chengmo@centos5~/shell]$ sh testhttphead.sh 127.0.0.1 8080
open 127.0.0.1 8080 error!
突然有个奇怪想法:
我们在windows时代就通过telnet可以实现tcp/upd协议通讯,那么如果用传统方法怎么实现呢?
复制代码
代码如下:
[chengmo@centos5~/shell]$ echo-e"HEAD/ HTTP/1.1/n/n/n/n/n"|telnet www.baidu.com 80
Trying 220.181.6.175...
Connected to www.baidu.com.
Escape character is'^]'.
Connection closed by foreign host.
#直接给发送,失败
[chengmo@centos5~/shell]$(telnet www.baidu.com 80)EOF
HEAD/ HTTP/1.1
EOF
Trying 220.181.6.175...
Connected to www.baidu.com.
Escape character is'^]'.
Connection closed by foreign host.
#重定向输入,还是失败?
找到正确方法:
复制代码
代码如下:
[chengmo@centos5 shell]$(echo-e"HEAD/ HTTP/1.1/n/n/n/n/n";sleep 2)|telnet www.baidu.com 80
Trying 220.181.6.175...
Connected to www.baidu.com.
Escape character is'^]'.
HTTP/1.1 200 OK
Date: Thu, 21 Oct 2010 15:51:58 GMT
Server: BWS/1.0
Content-Length: 6218
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Thu, 21 Oct 2010 15:51:58 GMT
Set-Cookie: BAIDUID=0B6A01ACECD5353E4247E088A8CB345A:FG=1; expires=Thu, 21-Oct-40 15:51:58 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM"
Connection: Keep-Alive
#成功了!加入sleep居然可以了,sleep改成1秒也可以
是不是由于sleep后,echo会推出2秒发给通道:telnet呢?推论可以从这2个方面推翻:
一个方面:通过()括的数据是一对命令,会作为一个子命令执行,一起执行完程序结束。每个命令echo语句,就直接发送到屏幕(也就是标准输出),只要有标准输出了,就会通过通道马上传个:telnet,如果接下来命令还有输出,会注意传给telnet,直到()内所有命令执行完,与通道连接就断开了。
再一个方面:如果说是起到推迟发送的话,什么时候有数据过来,发给telnet,什么时候telnet命令启动。跟你推迟一点还是早一点发送过来。没有关系。
这种类型命令,看出sleep,其实就是保持通道跟telnet连接2秒钟。通道连接着了,telnet终端输入也还在,因此可以保持从baidu服务器获得数据。
所以,延迟多久,还是跟服务器处理速度有关系。
如果通过echo向telnet发送数据,保持通道联通,使用sleep是个很好方法。
通过重定向给telnet输入参数这种方法,我还想不到怎么样实现延迟输入。有知道朋友,可以指点指点.
区别:
telnet与echo实现 http访问,与通过打开读写socket是不一样的,打开socket通道,是可以进行交换处理的。传入命令,活动结果,再传入命令,再获得结果。telnet通过echo就不能这样处理了。
三、通过shell脚本重定向实现监控memcache状态
复制代码
代码如下:
#!/bin/sh
#通过传入ip以及端口,发送指令获得返回数据
#copyright chengmo qq:8292669
#函数往往放到最上面
function sendmsg()
{
msg=$1;
echo"$1"8;
getout;
}
#向socket通道发送指令,并且调用获得返回参数
function getout()
{
#read命令-u从打开文件描述符 8读取数据,-d读取数据忽略掉:/r换行符
while read-u 8-d$'/r' name;
do
if ["${name}"=="END"-o"${name}"=="ERROR" ];then
break;
fi;
echo$name;
done
}
#由于:memcached每次通讯完毕,会返回:END或者ERROR(出错),通过判断是否是"END"觉得读取是不是结束,否则循环不会停止
if [$#-lt 2 ];then
echo"usage:$0 host port [command]";
exit 1;
fi;
[[$#-gt 2 ]]command=$3;
#设置默认值如果command为定义则为:stats
command="${command=stats}";
host="$1";
port="$2";
exec 8/dev/tcp/${host}/${port};
#打开通向通道是8
if ["$?"!="0" ];then
echo"open$host$port fail!";
exit 1;
fi
sendmsg"$command";
#发送指定命令
sendmsg"quit";
#发送退出通向命令
exec 8-;
exec 8-;
#关闭socket通道
exit 0;
这是通过重定向,实现socket通讯中,发送然后获取返回的例子。其实,上面代码看似一次只能发送一段。时间上。我们可以反复调用:sendmsg,捕捉输出数据。实现连续的,读与写操作。
实例截图:
其它实现方法:
其实通过:telnet也可以实现的。
[chengmo@centos5 shell]$(echo"stats";sleep 2)|telnet 127.0.0.1 11211
通过nc命令实现:
[chengmo@centos5 shell]$(echo"stats")|nc 127.0.0.1 11211
不需要加延迟,直接打开通道
第二个程序里面,看到shell完全可以处理交互设计了。如果按照这样,登陆ftp,pop3,stmp都可以类似实现。这些,我们通过shell socket类似程序实现,应该不困难,只是捕捉如发送解析的问题了。