• 传说中的成大大
    2019-09-09
    看到后面我好像理解了我上面那个提问,当崩溃重启过后是重新三次握手建立连接,创建新的套接字,只是在网络上传输的包,因为是通过ip地址和端口方式进行的寻址,所以新连接上去的客户端会接收到之前还没接收到的包,然后新连接的客户端没有这些包的tcp分组信息所以就会给服务器端(对端)发送一个RST

    作者回复: 正解。

    
     6
  • tim
    2019-10-09
    >>"但是,发送端并无法获取对应数据流的 ACK 情况"
    对上面这段话不理解,TCP 的 ACK不是带着序号的吗?发送端根据这个序号能计算出是哪次发送的ACK。
    哪位大牛能解释一下吗?

    作者回复: 这里是从应用层报文数据角度出发来说的,因为数据是一个流,没有办法判断数据的哪些部分没对端收到。

    从TCP角度来说,确实是通过ACK来感知TCP包的接收情况的。

     2
     2
  • 张立华
    2019-09-20
    这篇文章提醒我们的是,从代码的角度将注意三点:
    1,程序启动的时候,忽略 SIGPIPE
    2,read, write 要判断返回值,根据返回值知道socket断开了
    3,应用层使用 心跳包,心跳包达到超时阀值,则认定socket断开了
    
     2
  • yusuf
    2019-09-09
    # uname -a
    Linux tst 3.10.0-957.21.3.el7.x86_64 #1 SMP Tue Jun 18 16:35:19 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
    #
    # ./reliable_client01 127.0.0.1
    good
    peer connection closed
    #
    # ./reliable_client01 127.0.0.1
    bad
    bad
    bad2
    peer connection closed
    #
    # ./reliable_client02 127.0.0.1
    send into buffer 19
    send into buffer -1
    send error: Connection reset by peer (104)
    展开

    作者回复: 基本和我的Linux下结果一致。

    
     1
  • HerofH
    2020-01-09
    老师您好,我想请问一个关于感知到RST后的一个处理问题。
    如前所述,如果对端调用shutdown(SD_RD)关闭读端,那么此时本端向对端进行写操作后收到对端的RST;而如果对端是突然崩溃后重启,由于本端不知道对端已经崩溃,此时本端发送的数据到达对端,也会收到RST。
    针对这两种情况的处理方式,根据我的理解,前者应该是关闭本端的写,而后者则应该直接关闭本端到对端的连接。那么如何区分这两种情况呢?我感觉在本端的反应都是同样的read返回,然后errno被设置为ECONNRESET,我该怎么知道到底是哪种情况呢?

    作者回复: 为啥要区分这两种情况呢?程序这端都是连接无效,无法进行数据的有效传输。

    
    
  • 盘尼西林
    2020-01-06
    没有理解 reset by peer 和 broken pipe 的区别。。

    作者回复: 一个是TCP RST的状态异常,一个是SIGPIPE 信号将进程进行回收。

    
    
  • godtrue
    2019-11-23
    假如让你设计一个网络通信协议,你会怎么设计?

    作者回复: 这个问题很大。。。。

    
    
  • 林林
    2019-11-20
    老师好,有个问题想请教下。
    有进程A和B(在同一物理机下),A会监听B的连接。在我对进程A kill -2后,B与A的连接一直保持着ESTABILISH, 进程A重启时,绑定监听端口会出现端口被占用的异常。

    这种情况是否表示B没有收到A的fin包,所以才一直保持着ESTABILISH的状态? 这种情况应该怎么解决?

    如果我给进程B加上一个对A的心跳检测,能否解决这个问题?

    期待老师能给我答疑
    展开

    作者回复: kill掉A进程后,B进程如果收不到FIN包,它的却能保持ESTABLISHED状态,通过对链路进行读写可以感知链路的状态,当然,你也可以加上心跳检测,检测出链路的状态。

    
    
  • JasonZhi
    2019-10-16
    老师你好,文章的最后一个例子还有一些疑问。我的理解是对于一个已经关闭的socket ,执行两次write ,第一次write 会导致对端返回RST,第二次write 由于对收到RST的socket 执行写操作,会触发SIGPIPE。但是为什么例子却说会返回peer reset的错误呢?是不是我哪里理解错了。

    作者回复: 如文中所说,我在MAC系统上实验的结果却是是SIGPIPE,但是在Linux 4.4内核上的实验结果却是直接返回了RST结果,传统教科书都是说应该返回SIGPIPE,但是我得到的Linux 4.4上的结果却不是这样的。

    我建议你通过实验再尝试一下。

    
    
  • Leon📷
    2019-10-13
    老师,你文章的案例默认fd都是阻塞的吧,如果是非阻塞的话,返回的n < 0 不一定是错误啊

    作者回复: 到现在为止,都是阻塞的,后面会切成非阻塞的。

    
    
  • JasonZhi
    2019-10-09
    老师你好,我在linux环境下测试最后一个例子时,在客户端代码的count--后面加上sleep(4),那么关闭服务端后,连续向服务端写入就会返回PIPIE错误,并且会收到SIGPIPIE信号,能解释其中原因吗?
    贴上代码:
     while (count > 0) {
            n_written = send(socket_fd, msg, strlen(msg), 0);
            fprintf(stdout, "send into buffer %ld \n", n_written);

            if (n_written <= 0) {
                error(1, errno, "send error");
                return -1;
            }
            count--;

            sleep(4);
        }
    展开

    作者回复: 休眠4秒之后往一个已经关闭的套接字记下写数据,于是得到了SIGPIPE信号。

     1
    
  • W.T
    2019-09-22
    老师,最后一行的Connection reset by peer是从哪里打印输出的?是内核协议栈打印输出到终端上的吗?在程序代码中没找到对应的printf语句

    作者回复: 是打印出来的error信息,
    if (err)
       fprintf(stderr, ": %s (%d)\n", strerror(err), err);

    
    
  • gogo
    2019-09-16
    老师 我提一个read直接感知FIN包的疑问哈:

    我停留在 stdin这里 等我输入完之后,就能调用read感知到对端已经关闭了呀? 是因为等到stdin之后,再感知是不是太晚了呀?

    作者回复: 这就是为什么需要使用select、poll等事件分发机制,正确的解法是一旦有事件发生,比如这里read读到EOF,就应用直接去处理此类事件,而不是阻塞在这里等待用户的输入。好消息是,很快我们就会详细学习这部分内容了。

    
    
  • 徐凯
    2019-09-11
    第二题 客户端--------服务器

    1.  客户端发送FIN包,处于发送缓冲区的数据会逐一发送(可能通过一次或多次write操作发送),FIN包处于这段数据的末尾,当数据到达接收端的接收缓冲区时,FIN起到了一个结束符的作用,当接收端接收数据时遇到FIN包,read操作返回EOF通知应用层。然后接收端返回一个ACK表示对这次发送的确认。(此时客户端进入FIN_WAIT1,服务端进入CLOSE_WAIT状态)

    2.  客户端接收到ACK之后,关闭自己的发送通道,客户端此时处于半关闭状态。等待服务器发送FIN包。

      (客户端进入FIN_WAIT2状态)

    3.  服务端发送FIN包,同上类似处于发送缓冲区的内容会连同FIN包一起发过去,当客户端接收成功后同时将FIN解析为EOF信号使得上层调用返回。(客户端进入TIME_WAIT状态 服务端进入LAST_ACK状态)

    4. 客户端等待2MSL的时间,在此期间向服务器发送ACK。如果丢包进行重传。如果服务器收到ACK后 服务器进入CLOSED状态 客户端也进入CLOSED状态。

    5. 连接关闭
    我想问一下 如果最后一次挥手一直丢包 在2MSL的时间内都没到 TCP会咋办 会重置计时器么 还是就不管了直接关闭呢
    展开

    作者回复: 我猜想是会直接关闭的,没有对ACK的ACK包。

    
    
  • 传说中的成大大
    2019-09-09
    Linux VM-0-13-ubuntu 4.15.0-54-generic #58-Ubuntu SMP Mon Jun 24 10:55:24 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
    这个是客户端不停的发送然后服务器端突然关闭
    ./client: send error: Connection reset by peer
    
    
  • 传说中的成大大
    2019-09-09
    第一问因为要写代码所以等会来回答先回答第二问
    其实服务器正常退出和异常突出我觉得都差不多,都需要靠read或者write去感知,如果对方已经断开连接就会发送一个fin到本方的接收缓冲区变为eof,read函数也返回0,调用write会失败
    
    
  • 传说中的成大大
    2019-09-09
    其实我也一直想问 比如 我客户端突然崩溃了 然后再启动客户端连接上服务器 到底是新建立一个链接 还是老的连接 并且发送rst?

    作者回复: 你已经回答自己的问题了,当然是新的连接。

    
    
  • 石将从
    2019-09-09
    这篇读了几遍还是很懵,很多概念理不清楚,不知道对端到底是服务器端还是客户端,都混淆了

    作者回复: 因为TCP是双向的,对端是一个相对的概念,连接建立之后,服务器和客户端彼此互为对方的对端。

    建议你再多理几遍,欢迎提具体的问题。

     1
    
  • 刘晓林
    2019-09-09
    没有看出“通过 write 产生 RST,read 调用感知 RST”和“向一个已关闭连接连续写,产生SIGPIPE”二者有什么区别呀。前者两个write之间多了一次read,为何在linux下的返回结果就不一样了呀?

    作者回复: 这里想要表达的就是通过read/write来感知TCP链路的状态,一个是通过read来感知,一个是在没有read的情况下使用write来感知。

     1
    
我们在线,来聊聊吧