通俗易懂的TCP三次握手

一、通俗理解TCP三次握手

三次握手是TCP(传输控制协议)用于建立一个可靠连接的过程。这个协议确保了数据传输的可靠性,并且防止了旧的连接请求突然又传送到了服务器端,从而产生错误。下面我会用一个通俗易懂的例子来解释这个过程:

想象一下,你和你的朋友在两个不同的房间,你们之间有一道门,但门上没有窗户,你们不能直接看到对方。

  1. 第一次握手

    • 你(客户端)想要和你的朋友(服务器)开始聊天,所以你敲门(发送SYN,同步信号)并等待回应。
    • 你的朋友听到了敲门声,但为了确认他听到的是你敲的门,他需要你再次敲门。
  2. 第二次握手

    • 你的朋友(服务器)回应你的敲门(发送SYN-ACK,同步确认信号),并告诉你他听到了你的敲门声。
    • 你听到了朋友的回应,你知道他确实听到了你的敲门,现在你可以和他聊天了。
  3. 第三次握手

    • 你再次敲门(发送ACK,确认信号),告诉你的朋友你可以开始聊天了。
    • 你的朋友听到了你的确认,现在他知道你们可以开始聊天了,门(连接)就打开了。

在这个过程中,你们双方都确认了两件事情:

  1. 你的朋友知道你在敲门(你的朋友准备好接收信息)。
  2. 你知道你的朋友听到了你的敲门(你准备好发送信息)。

这个过程就确保了你们可以开始一个可靠的对话,这就是TCP三次握手的基本原理。

在TCP/IP协议中,SYN和ACK是特殊的数据包,用于建立连接。SYN是同步序列编号,而ACK是确认收到对方的数据包。

  • SYN:同步序列编号,用于建立连接时同步序号。
  • ACK:确认收到对方的数据包。

三次握手完成后,TCP连接就建立起来了,数据就可以在客户端和服务器之间可靠地传输了。




二、Linux网络编程中的TCP socket连接步骤

在Linux网络编程中,使用TCP协议的socket建立连接的过程通常遵循三次握手协议。以下是TCP连接建立的基本步骤:

  1. 服务器监听

    • 服务器调用socket()函数创建一个socket。
    • 服务器使用bind()函数将socket绑定到一个IP地址和端口上。
    • 服务器调用listen()函数监听连接请求,准备接受客户端的连接。
  2. 客户端连接

    • 客户端调用socket()函数创建一个socket。
    • 客户端使用connect()函数发起连接请求,指定服务器的IP地址和端口。
  3. 三次握手

    • 第一次握手:客户端发送一个TCP的SYN(同步序列编号)标志的数据包给服务器以发起一个新的连接,并指定客户端的初始序列号。
    • 第二次握手:服务器接收到客户端的SYN请求后,需要确认客户端的SYN(即发送ACK),同时自己也发送一个SYN请求,即SYN+ACK包,此时服务器进入SYN_RECV状态。
    • 第三次握手:客户端收到服务器的SYN+ACK包后,向服务器发送确认包ACK(acknowledgement),此时包的序列号为收到的序列号加1,同时客户端的TCP连接进入ESTABLISHED状态。服务器收到这个确认包后,也进入ESTABLISHED状态。
  4. 连接建立

    • 经过三次握手后,TCP连接建立成功,客户端和服务器可以开始数据传输。
  5. 数据传输

    • 客户端和服务器通过send()recv()(或write()read())函数进行数据的发送和接收。
  6. 连接终止

    • 数据传输完成后,任一方都可以调用close()函数来关闭连接,这会导致四次挥手过程的开始,最终断开连接。

代码示例

以下是服务器和客户端建立TCP连接的简单代码示例:

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main() {
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    
    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 绑定socket地址
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
      
    // 强制绑定socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
      
    // 监听socket
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
      
    // 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
      
    // 读取客户端发送的数据
    valread = read(new_socket, buffer, 1024);
    printf("Client: %s\n", buffer);
      
    // 关闭连接
    close(new_socket);
    close(server_fd);
    return 0;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    struct sockaddr_in serv_addr;
    int sock = 0;
    char buffer[1024] = "Hello Server";
    
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }
      
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
      
    // 将地址从字符串转换为AF_INET类型
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }
      
    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }
      
    // 发送数据
    send(sock, buffer, strlen(buffer), 0);
    printf("Hello message sent\n");
      
    // 关闭socket
    close(sock);
    return 0;
}

以上仅基本示例,在实际应用中,需考虑错误处理、资源管理、并发连接处理等复杂情况…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值