几种TCP连接中出现RST的情况( 比较详细) tcp rst ack报文

  几种TCP连接中出现RST的情况

17人收藏此文章,我要收藏发表于1个月前(2013-05-04 11:40) , 已有314次阅读 ,共0个评论

目录:[-]

1 端口未打开

2 请求超时

3 提前关闭

4 在一个已关闭的socket上收到数据

总结

参考文献:

应该没有人会质疑,现在是一个网络时代了。应该不少程序员在编程中需要考虑多机、局域网、广域网的各种问题。所以网络知识也是避免不了学习的。而且笔者一直觉得TCP/IP网络知识在一个程序员知识体系中必需占有一席之地的。

在TCP协议中RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。

其实在网络编程过程中,各种RST错误其实是比较难排查和找到原因的。下面我列出几种会出现RST的情况。

1 端口未打开

服务器程序端口未打开而客户端来连接。这种情况是最为常见和好理解的一种了。去telnet一个未打开的TCP的端口可能会出现这种错误。这个和操作系统的实现有关。在某些情况下,操作系统也会完全不理会这些发到未打开端口请求。

比如在下面这种情况下,主机241向主机114发送一个SYN请求,表示想要连接主机114的40000端口,但是主机114上根本没有打开40000这个端口,于是就向主机241发送了一个RST。这种情况很常见。特别是服务器程序core dump之后重启之前连续出现RST的情况会经常发生。



当然在某些操作系统的主机上,未必是这样的表现。比如向一台WINDOWS7的主机发送一个连接不存在的端口的请求,这台主机就不会回应。

2 请求超时

曾经遇到过这样一个情况:一个客户端连接服务器,connect返回-1并且error=EINPROGRESS。 直接telnet发现网络连接没有问题。ping没有出现丢包。用抓包工具查看,客户端是在收到服务器发出的SYN之后就莫名其妙的发送了RST。

比如像下面这样:



有89、27两台主机。主机89向主机27发送了一个SYN,表示希望连接8888端口,主机27回应了主机89一个SYN表示可以连接。但是主机27却很不友好,莫名其妙的发送了一个RST表示我不想连接你了。

后来经过排查发现,在主机89上的程序在建立了socket之后,用setsockopt的SO_RCVTIMEO选项设置了recv的超时时间为100ms。而我们看上面的抓包结果表示,从主机89发出SYN到接收SYN的时间多达110ms。(从15:01:27.799961到15:01:27.961886, 小数点之后的单位是微秒)。因此主机89上的程序认为接收超时,所以发送了RST拒绝进一步发送数据。

3 提前关闭

关于TCP,我想我们在教科书里都读到过一句话,'TCP是一种可靠的连接'。 而这可靠有这样一种含义,那就是操作系统接收到的来自TCP连接中的每一个字节,我都会让应用程序接收到。如果应用程序不接收怎么办?你猜对了,RST。

看两段程序:

01//server.c

02

03intmain(intargc,char** argv)

04{

05intlisten_fd, real_fd;

06structsockaddr_in listen_addr, client_addr;

07socklen_t len =sizeof(structsockaddr_in);

08listen_fd = socket(AF_INET, SOCK_STREAM, 0);

09if(listen_fd == -1)

10{

11perror("socket failed ");

12return-1;

13}

14bzero(&listen_addr,sizeof(listen_addr));

15listen_addr.sin_family = AF_INET;

16listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);

17listen_addr.sin_port = htons(SERV_PORT);

18bind(listen_fd,(structsockaddr *)&listen_addr, len);

19listen(listen_fd, WAIT_COUNT);

20while(1)

21{

22real_fd = accept(listen_fd, (structsockaddr*)&client_addr, &len);

23if(real_fd == -1)

24{

几种TCP连接中出现RST的情况( 比较详细) tcp rst ack报文
25perror("accpet fail ");

26return-1;

27}

28if(fork() == 0)

29{

30close(listen_fd);

31charpcContent[4096];

32read(real_fd,pcContent,4096);

33close(real_fd);

34exit(0);

35}

36close(real_fd);

37}

38return0;

39}

这一段是server的最简单的代码。逻辑很简单,监听一个TCP端口然后当有客户端来连接的时候fork一个子进程来处理。注意看的是这一段fork里面的处理:

1charpcContent[4096];

2read(real_fd,pcContent,4096);

3close(real_fd);

每次只是读socket的前4096个字节,然后就关闭掉连接。

然后再看一下client的代码:

01//client.c

02intmain(intargc,char** argv)

03{

04intsend_sk;

05structsockaddr_in s_addr;

06socklen_t len =sizeof(s_addr);

07send_sk = socket(AF_INET, SOCK_STREAM, 0);

08if(send_sk == -1)

09{

10perror("socket failed ");

11return-1;

12}

13bzero(&s_addr,sizeof(s_addr));

14s_addr.sin_family = AF_INET;

15

16inet_pton(AF_INET,SER_IP,&s_addr.sin_addr);

17s_addr.sin_port = htons(SER_PORT);

18if(connect(send_sk,(structsockaddr*)&s_addr,len) == -1)

19{

20perror("connect fail ");

21return-1;

22}

23charpcContent[5000]={0};

24write(send_sk,pcContent,5000);

25sleep(1);

26close(send_sk);

27}

这段代码更简单,就是打开一个socket然后连接一个服务器并发送5000个字节。刚才我们看服务器的代码,每次只接收4096个字节,那么就是说客户端发送的剩下的4个字节服务端的应用程序没有接收到,服务器端的socket就被关闭掉,这种情况下会发生什么状况呢,还是抓包看一看。



前三行就是TCP的3次握手,从第四行开始看,客户端的49660端口向服务器的9877端口发送了5000个字节的数据,然后服务器端发送了一个ACK进行了确认,紧接着服务器向客户端发送了一个RST断开了连接。和我们的预期一致。

4 在一个已关闭的socket上收到数据

如果某个socket已经关闭,但依然收到数据也会产生RST。

代码如下:

客户端:

01intmain(intargc,char** argv)

02{

03intsend_sk;

04structsockaddr_in s_addr;

05socklen_t len =sizeof(s_addr);

06send_sk = socket(AF_INET, SOCK_STREAM, 0);

07if(send_sk == -1)

08{

09perror("socket failed ");

10return-1;

11}

12bzero(&s_addr,sizeof(s_addr));

13s_addr.sin_family = AF_INET;

14

15inet_pton(AF_INET,SER_IP,&s_addr.sin_addr);

16s_addr.sin_port = htons(SER_PORT);

17if(connect(send_sk,(structsockaddr*)&s_addr,len) == -1)

18{

19perror("connect fail ");

20return-1;

21}

22charpcContent[4096]={0};

23write(send_sk,pcContent,4096);

24sleep(1);

25write(send_sk,pcContent,4096);

26close(send_sk);

27}

服务端:01intmain(intargc,char** argv)

02{

03intlisten_fd, real_fd;

04structsockaddr_in listen_addr, client_addr;

05socklen_t len =sizeof(structsockaddr_in);

06listen_fd = socket(AF_INET, SOCK_STREAM, 0);

07if(listen_fd == -1)

08{

09perror("socket failed ");

10return-1;

11}

12bzero(&listen_addr,sizeof(listen_addr));

13listen_addr.sin_family = AF_INET;

14listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);

15listen_addr.sin_port = htons(SERV_PORT);

16bind(listen_fd,(structsockaddr *)&listen_addr, len);

17listen(listen_fd, WAIT_COUNT);

18while(1)

19{

20real_fd = accept(listen_fd, (structsockaddr*)&client_addr, &len);

21if(real_fd == -1)

22{

23perror("accpet fail ");

24return-1;

25}

26if(fork() == 0)

27{

28close(listen_fd);

29charpcContent[4096];

30read(real_fd,pcContent,4096);

31close(real_fd);

32exit(0);

33}

34close(real_fd);

35}

36return0;

37}

客户端在服务端已经关闭掉socket之后,仍然在发送数据。这时服务端会产生RST。

总结

总结,本文讲了几种TCP连接中出现RST的情况。实际上肯定还有无数种的RST发生,我以后会慢慢收集把更多的例子加入这篇文章。

参考文献:

1 从TCP协议的原理来谈谈RST攻击http://russelltao.iteye.com/blog/1405349

2 TCP客户-服务器程序例子http://blog.csdn.net/youkuxiaobin/article/details/6917880

  

爱华网本文地址 » http://www.413yy.cn/a/25101013/181816.html

更多阅读

家装中水泥砂浆有几种配比 水泥砂浆的配比

家装中有多种水泥砂浆配比,不同的水泥砂浆配比应用到家装不同的施工项目,下面给你介绍几种家装中常用的水泥砂浆配比:家装中水泥砂浆有几种配比——家装中常用水泥沙配比:家装中水泥砂浆有几种配比 1、砌各种隔断墙和各类砌体使用1:2的水

小学生的几种学习方法

小学生学习方法介绍小学生的几种学习方法——工具/原料学法的掌握,如同知识的获得一样,有一个从无到有,从少到多,从不会到会的发展过程。开始,在很大程序上要靠教师在教给知识的过程中,主动明确的指点。诸如怎样发言答问,怎样执笔写字,怎样

鹿角胶的几种吃法 鹿角胶如何服用好

鹿角胶的几种吃法——简介鹿角胶为鹿角经水煎熬,浓缩制成的固体胶,温补肝肾,益精养血~是进补的佳品,下面介绍几种他的常见吃法~鹿角胶的几种吃法——食材鹿角胶 适量蜂蜜 适量牛奶 适量鹿角胶的几种吃法——方法/步骤鹿角胶的几种吃

扎头发的方法有几种 精 简单的扎头发方法

今天在网上看到了几种扎头发的方法,真的是简单易学,而且都很漂亮精致,下面小编就为大家一一介绍吧。扎头发的方法有几种 精——第一款扎头发的方法有几种 精 1、先把头顶的头发分成三份扎头发的方法有几种 精 2、把2放在3的下面扎头发

教你几种打开组策略编辑器的方法 打开本地组策略编辑器

教你几种打开组策略编辑器的方法——简介 对电脑进行一些高级的设置,通常需要用到组策略编辑器。很多人不知道怎么打开组策略编辑器,其实打开它的方法有很多,有的很简单,但操作比较麻烦,有的很麻烦,但是操作简单。今天我就来一一说明。

声明:《几种TCP连接中出现RST的情况( 比较详细) tcp rst ack报文》为网友月下弄人醉分享!如侵犯到您的合法权益请联系我们删除