利用tcpdump监控tcp连接三次握手和关闭四次握手

学习网络编程最主要的是能理解底层编程细节,一开始看《UNIX网络编程卷1:套接字联网API》的时候搞不懂什么seq、ack到底是什么东西,最近了解了tcpdump的一些用法后感觉两者结合起来还是比较容易理握手过程的。以下就通过tcpdump工具来监控相关内容,并和书本上的流程进行对比介绍,希望对入门的童靴有些帮助吧

服务端代码如下:

#include <sys/socket.h> //socket listen bind
#include <arpa/inet.h> // sockaddr head
#include <string.h>  //memset and strlen head
#include <sys/socket.h> //socket listen bind
#include <iostream>
#include <time.h>
#include <stdio.h>                                                                  

#define MAXLINE 4096
#define LISTENQ 1024                                                                

using namespace std;                                                                

int main(int argc, char ** argv)
{
    int listenfd, connfd;
    socklen_t len;
    struct sockaddr_in servaddr, cliaddr;
    char buff[MAXLINE];
    time_t ticks;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(10000);                                               

    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    int ret = listen(listenfd,LISTENQ);
    cout << "go to listen" <<ret<< endl;
    for(; ;)
    {
        len=sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
        cout << "connfd = " << connfd << inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)) << endl;
        sleep(20);
        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        write(connfd, buff, strlen(buff));
        cout << "write date ok" << endl;
        sleep(20);
        close(connfd);
    }
    return 0;
}    

客户端代码如下:

#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
#include <stdio.h>
#include <errno.h>                                                               

using namespace std;                                                             

#define MAXLINE     4096    /* max text line length */
int main(int argc, char ** argv)
{
    int sockfd, n;
    char recvline[MAXLINE+1];
    struct sockaddr_in serveraddr;
    if(argc != 2)
    {
        cout << "para error " << endl;
        return 0;
    }
    if((sockfd=socket(AF_INET, SOCK_STREAM, 0))<0)
    {
        cout << "socket error" << endl;
        return 0;
    }
    memset(&serveraddr,0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(10000);
    if(inet_pton(AF_INET, argv[1], &serveraddr.sin_addr)<=0)
    {
        cout << "inet_pton error for " << argv[1] << endl;
        return 0;
    }
    int tmp = connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if(tmp <0)
    {
        cout << "connect error" << tmp << endl;
        cout << "error info " << errno << endl;
        return 0;
    }
    while((n=read(sockfd, recvline, MAXLINE)) > 0)
    {
        recvline[n] = 0;
        if(fputs(recvline, stdout) == EOF)
        {
            cout << "fputs error" << endl;
        }
    }
    close(sockfd);
    if(n<0)
    {
        cout << "read error" << endl;
    }
    return 1;
} 

先在192.168.11.220上运行服务端程序,然后在192.168.11.223上运行客户端程序。同时在两个服务器上以root用户执行tcpdump工具,监控10000端口

tcpdump命令如下:

tcpdump ‘port 10000‘ -i eth0 -S

建立连接时服务端220的监控内容如下:

14:52:19.772673 IP 192.168.11.223.55081 > npsc-220.ndmp: Flags [S], seq 1925249825, win 14600, options [mss 1460,sackOK,TS val 11741993 ecr 0,nop,wscale 6], length 0
14:52:19.772695 IP npsc-220.ndmp > 192.168.11.223.55081: Flags [S.], seq 821610649, ack 1925249826, win 14480, options [mss 1460,sackOK,TS val 20292985 ecr 11741993,nop,wscale 7], length 0
14:52:19.773256 IP 192.168.11.223.55081 > npsc-220.ndmp: Flags [.], ack 821610650, win 229, options [nop,nop,TS val 11741994 ecr 20292985], length 0

下面结合上图和下面三次握手示意图,解释握手细节:

第一行显示客户端192.168.11.223先发送一个seq,1925249825给服务端,对应下面三次握手示意图中的SYN J

第二行显示服务端192.168.11.220(npsc-220)确认第一行的请求:seq 1925249825, ack的值为第一行的seq值+1,即(ack 1925249826),同时发送一个请求序列号821610649。对应下图三次握手中的(SYN K, ACK J+1)

第三行显示客户端192.168.11.223确认服务端的请求序号(第二行中的seq 821610649),对应下图tcp三路握手中的 (ACK K+1)

下图显示了传递一次数据的通信过程

14:52:39.773434 IP npsc-220.ndmp > 192.168.11.223.55081: Flags [P.], seq 821610650:821610676, ack 1925249826, win 114, options [nop,nop,TS val 20312985 ecr 11741994], length 26
14:52:39.774208 IP 192.168.11.223.55081 > npsc-220.ndmp: Flags [.], ack 821610676, win 229, options [nop,nop,TS val 11761994 ecr 20312985], length 0

由于代码中服务端建立连接后直接给客户端发送本地时间的数据给客户端,所以上面第一行中的信息可以看出由npsc-220(服务端)发送数据给客户端192.168.11.223,请求序号为:821610650:821610676 共26个字节,

第二行表示客户端223收到数据后给服务端的发送了一个ack的确认信息

下图显示了断开连接的通信过程(其中客户端代表被动断开的一端,服务端代表主动断开的一端)

14:52:59.773523 IP npsc-220.ndmp > 192.168.11.223.55081: Flags [F.], seq 821610676, ack 1925249826, win 114, options [nop,nop,TS val 20332985 ecr 11761994], length 0
14:52:59.774342 IP 192.168.11.223.55081 > npsc-220.ndmp: Flags [F.], seq 1925249826, ack 821610677, win 229, options [nop,nop,TS val 11781994 ecr 20332985], length 0
14:52:59.774351 IP npsc-220.ndmp > 192.168.11.223.55081: Flags [.], ack 1925249827, win 114, options [nop,nop,TS val 20332986 ecr 11781994], length 0

由于我的程序是由服务端主动关闭连接,所以和下图的四次握手示意图稍微有些差别

第一行显示:服务端(npsc-220)主动发送了一个FIN给客户端192.168.11.223,对应下图的FIN M ,其中M的值为821610676

第二行显示:客户端192.168.11.223确认了服务端的821610676(即下图的ACK M+1, 即ack 821610677),并发送了一个FIN给服务端,对应下图的FIN N

第三行显示:服务端(npsc-220)确认了客户端的FIN  ack 19252429827,即下图的ACK N+1 ,

下图是断开连接的四次握手示意图

时间: 2024-10-03 13:20:49

利用tcpdump监控tcp连接三次握手和关闭四次握手的相关文章

为什么TCP连接需要三次握手分开需要四次握手?

原文地址:http://lixiangfeng.com/blog/article/content/7908246 TCP的三次握手和四次断开TCP是一个面向连接的服务,面向连接的服务是电话系统服务模式的抽象,每一次完整的数据传输都必须经过建立连接,数据传输和终止连接3个过程,TCP建立连接的过程称为三次握手,下面看一下三次握手的具本过程TCP三次握手过程1  主机A通过向主机B 发送一个含有同步序列号的标志位的数据段给主机B ,向主机B 请求建立连接,通过这个数据段,主机A告诉主机B  两件事:

TCP连接三次握手,四次挥手告别

三次握手: 第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服器,主机B由SYN=1知道,A要求建立联机: 第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包 第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1)

TCP连接 三次握手 四次挥手

前言: TCP协议是面向连接.安全可靠.基于字节流的传输层协议,在进行http协议访问时就用到了tcp连接.在建立TCP连接时需要经历三次握手,断开连接时需要经历四次挥手.在此进行记录. 内容: TCP三次握手 第一次握手:由客户端发起,客户端生成一个SYN,以及一个随机数标记数X,然后将随机标记数X和SYN发送为服务端,此时客户端进入SYN_SENT状态,等待服务端响应. 第二次握手:服务端接收到SYN后得知客户端请求连接,然后服务端将SYN和ACK都置为1,并将ack=X+1,再生成一个随机

TCP中三次握手建立和四次握手释放以及相关问题

本文基于个人所学和网上博文所整理,若有不妥处,欢迎留言指出 TCP连接过程中标志位的意义: 字符缩写 描述 SYN 同步序号,表示此报文是一个连接请求或连接接受报文 ACK 确认位,对接收到的报文的确认 FIN 终止位,表示发送方完成数据发送,用来释放一个连接 RST 复位连接,表示TCP连接中出现严重错误 PSH 推送位,尽可能快递将数据送往接受进程 一.三次握手建立 1.三次握手建立连接详解 TCP建立连接要进行"三次握手",即交换三个分组.大致流程如下: (1)客户端向服务器发送

ZABBIX监控TCP连接状态

一.获取监控数据 # /bin/netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}' LISTEN 6 ESTABLISHED 1 TIME_WAIT 1 TCP各监控状态描述 ESTABLISHED socket已经建立连接 CLOSED socket没有被使用,无连接 CLOSING 服务器端和客户端都同时关闭连接 CLOSE_WAIT 等待关闭连接 TIME_WAIT 表示收到了对方的FIN报文,并发送出了ACK报文

客户端与服务端建立tcp连接三次握手之前做了什么----DNS

操作系统在握手之前进行了DNS查询   DNS 迭代查询 1.操作系统会首先在本地缓存中查询IP 2.没有的话会去系统配置的DNS服务中去查询 3.如果这时候还没得话,会直接去 DNS 根服务器查询,这一步查询会找出负责 com 这个一级域名的服务器 4.然后去该服务器查询 google 这个二级域名 5.接下来三级域名的查询其实是我们配置的,你可以给 www 这个域名配置一个 IP,然后还可以给别的三级域名配置一个 IP PS:DNS 是基于 UDP 做的查询, 原文地址:https://ww

zabbix 监控tcp连接的状态

Tcp的连接状态对于我们web服务器来说是至关重要的,尤其是并发量ESTAB:或者是syn_recv值,假如这个值比较大的话我们可以认为是不是受到了攻击,或是是time_wait值比较高的话,我们要考虑看我们内核是否需要调优,太高的time_wait值的话会占用太多端口,要是端口少的话后果不堪设想: 一.我的上一篇已经写了步骤,这里我只是列出脚本: #!/bin/bash #xiaoluo #scripts for tcp status function SYNRECV { /usr/sbin/

利用zabbix监控tcp连接数

一.客户端执行 cd /usr/local/zabbix/conf/ wget http://img006.com/badusoft/zabbix/tcp.sh chmod +x tcp.sh sed -i 's/# UnsafeUserParameters=0/UnsafeUserParameters=1/g' /usr/local/zabbix/conf/zabbix_agentd.conf sed -i '$a UserParameter=tcp[*],sh /usr/local/zabb

使用zabbix监控TCP连接状态

一 监控原理 $ /bin/netstat -an|awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]}' TIME_WAIT 3464 FIN_WAIT1 31 FIN_WAIT2 3 ESTABLISHED 12 SYN_RECV 6 CLOSING 8 LISTEN 7 可以使用man netstat查看TCP的各种状态信息描述 ESTABLISHED       socket已经建立连接 CLOSED            socket没有