Linux——网络(tcp)

news2025/2/3 2:39:14

文章目录


目录

文章目录

前言

一、TCP逻辑

1. 面向连接

三次握手(建立连接)

四次挥手(关闭连接)

2. 可靠性

3. 流量控制

4. 拥塞控制

5. 基于字节流

6. 全双工通信

7. 状态机

8. TCP头部结构

9. TCP的应用场景

二、编写tcp代码函数

1. Socket 创建与配置

socket()

setsockopt()

2. 绑定与监听

bind()

listen()

3. 连接与接受连接

connect()

accept()

4. 数据发送与接收

send()

recv()

5. 关闭连接

close()

shutdown()

6. 地址转换与解析

inet_pton()

inet_ntop()

7. 错误处理

perror()

strerror()

三、基本客服端和服务端

1、服务端

2、客户端

总结


前言

Linux——网络基础(1)-CSDN博客

Linux——网络(udp)-CSDN博客

  1. TCP协议概述:简要介绍TCP协议的基本特性,包括连接建立、数据传输、流量控制、拥塞控制等。

  2. Linux网络编程基础:介绍Linux下的Socket编程接口,以及如何使用这些接口进行TCP通信。

  3. TCP服务器与客户端的实现:通过实际的代码示例,展示如何编写一个简单的TCP服务器和客户端程序。

  4. TCP协议的性能优化:探讨如何通过调整TCP参数、使用非阻塞I/O、多线程/多进程等技术来提升TCP应用的性能。

  5. 常见问题与调试技巧:分享一些在实际开发中可能遇到的TCP相关问题,以及如何使用工具进行网络调试和故障排查。


一、TCP逻辑

1. 面向连接

TCP是一种面向连接的协议,这意味着在数据传输之前,通信双方需要先建立一个连接。连接的建立和关闭是通过三次握手和四次挥手来完成的。

三次握手(建立连接)
  1. SYN:客户端向服务器发送一个SYN(同步)报文,表示请求建立连接。

  2. SYN-ACK:服务器收到SYN后,回复一个SYN-ACK(同步-确认)报文,表示同意建立连接。

  3. ACK:客户端收到SYN-ACK后,发送一个ACK(确认)报文,连接正式建立。

四次挥手(关闭连接)
  1. FIN:主动关闭方(客户端或服务器)发送一个FIN(结束)报文,表示希望关闭连接。

  2. ACK:被动关闭方收到FIN后,回复一个ACK报文,表示确认收到关闭请求。

  3. FIN:被动关闭方完成数据发送后,发送一个FIN报文,表示自己也准备关闭连接。

  4. ACK:主动关闭方收到FIN后,回复一个ACK报文,连接正式关闭。


2. 可靠性

TCP通过以下机制确保数据的可靠传输:

  • 序列号与确认机制:每个TCP报文都包含一个序列号(Sequence Number),接收方通过发送确认号(Acknowledgment Number)来确认已收到的数据。如果发送方未收到确认,则会重传数据。

  • 超时重传:如果发送方在一定时间内未收到确认,则会重新发送数据。

  • 数据校验:TCP使用校验和(Checksum)来检测数据在传输过程中是否损坏。


3. 流量控制

TCP通过滑动窗口机制实现流量控制,防止发送方发送数据过快导致接收方缓冲区溢出。

  • 接收窗口:接收方通过TCP头部中的窗口字段告知发送方自己当前可接收的数据量。

  • 动态调整:接收方可以根据自身缓冲区的可用空间动态调整窗口大小。


4. 拥塞控制

TCP通过拥塞控制算法避免网络拥塞,常见的算法包括:

  • 慢启动(Slow Start):初始时发送方以较小的窗口发送数据,随后指数增长。

  • 拥塞避免(Congestion Avoidance):当窗口达到阈值后,发送方以线性方式增加窗口大小。

  • 快速重传(Fast Retransmit):当发送方收到三个重复的ACK时,立即重传丢失的报文。

  • 快速恢复(Fast Recovery):在快速重传后,发送方进入快速恢复阶段,避免窗口大幅减小。


5. 基于字节流

TCP是一种基于字节流的协议,这意味着:

  • 无消息边界:TCP将数据视为连续的字节流,不保留发送方写入的数据边界。例如,发送方发送两次数据(“Hello”和“World”),接收方可能一次性收到“HelloWorld”。

  • 粘包与拆包:由于TCP的字节流特性,接收方需要自己处理数据的边界问题(如通过长度字段或特殊分隔符)。


6. 全双工通信

TCP支持全双工通信,即通信双方可以同时发送和接收数据。每个TCP连接由两个独立的流组成:

  • 一个流用于从客户端到服务器的数据传输。

  • 另一个流用于从服务器到客户端的数据传输。


7. 状态机

TCP连接的生命周期由一个状态机管理,常见的状态包括:

  • LISTEN:服务器等待客户端连接。

  • SYN_SENT:客户端已发送SYN,等待服务器响应。

  • SYN_RECEIVED:服务器已收到SYN并发送SYN-ACK,等待客户端确认。

  • ESTABLISHED:连接已建立,可以传输数据。

  • FIN_WAIT_1 / FIN_WAIT_2:主动关闭方等待对方的FIN或ACK。

  • CLOSE_WAIT:被动关闭方等待应用程序关闭连接。

  • TIME_WAIT:连接关闭后,等待可能出现的延迟报文。


8. TCP头部结构

TCP头部包含以下关键字段:

  • 源端口和目的端口:标识通信的应用程序。

  • 序列号和确认号:用于数据排序和确认。

  • 标志位:如SYN、ACK、FIN等,用于控制连接状态。

  • 窗口大小:用于流量控制。

  • 校验和:用于数据完整性校验。


9. TCP的应用场景

TCP适用于需要可靠传输的场景,例如:

  • Web浏览(HTTP/HTTPS)

  • 文件传输(FTP)

  • 电子邮件(SMTP/POP3/IMAP)

  • 远程登录(SSH/Telnet)


二、编写tcp代码函数

1. Socket 创建与配置

socket()
  • 功能:创建一个新的套接字(socket),用于网络通信。

  • 原型:

    int socket(int domain, int type, int protocol);
  • 参数:

    • domain:协议族,如 AF_INET(IPv4)或 AF_INET6(IPv6)。

    • type:套接字类型,如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP)。

    • protocol:通常为 0,表示默认协议。

  • 返回值:成功返回套接字文件描述符,失败返回 -1

setsockopt()
  • 功能:设置套接字选项,如重用地址、调整缓冲区大小等。

  • 原型:

    int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
  • 常用选项:

    • SO_REUSEADDR:允许重用本地地址。

    • SO_RCVBUF / SO_SNDBUF:调整接收/发送缓冲区大小。


2. 绑定与监听

bind()
  • 功能:将套接字绑定到本地地址和端口。

  • 原型:

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:

    • sockfd:套接字文件描述符。

    • addr:指向 struct sockaddr 的指针,包含地址和端口信息。

    • addrlen:地址结构体的长度。

listen()
  • 功能:将套接字设置为监听模式,等待客户端连接。

  • 原型:

    int listen(int sockfd, int backlog);
  • 参数:

    • sockfd:套接字文件描述符。

    • backlog:等待连接队列的最大长度。


3. 连接与接受连接

connect()
  • 功能:客户端使用该函数连接到服务器。

  • 原型:

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:

    • sockfd:套接字文件描述符。

    • addr:指向服务器地址结构体的指针。

    • addrlen:地址结构体的长度。

accept()
  • 功能:服务器接受客户端的连接请求,返回一个新的套接字用于通信。

  • 原型:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 参数:

    • sockfd:监听套接字文件描述符。

    • addr:用于存储客户端地址信息。

    • addrlen:地址结构体的长度。


4. 数据发送与接收

send()
  • 功能:通过已连接的套接字发送数据。

  • 原型:

    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 参数:

    • sockfd:套接字文件描述符。

    • buf:指向要发送数据的缓冲区。

    • len:数据长度。

    • flags:标志位,通常为 0

recv()
  • 功能:通过已连接的套接字接收数据。

  • 原型:

    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 参数:

    • sockfd:套接字文件描述符。

    • buf:指向接收数据的缓冲区。

    • len:缓冲区长度。

    • flags:标志位,通常为 0


5. 关闭连接

close()
  • 功能:关闭套接字,释放资源。

  • 原型:

    int close(int sockfd);
  • 参数:

    • sockfd:套接字文件描述符。

shutdown()
  • 功能:优雅地关闭连接,可以选择关闭读、写或读写通道。

  • 原型:

    int shutdown(int sockfd, int how);
  • 参数:

    • sockfd:套接字文件描述符。

    • how:关闭方式,如 SHUT_RD(关闭读)、SHUT_WR(关闭写)、SHUT_RDWR(关闭读写)。


6. 地址转换与解析

inet_pton()
  • 功能:将点分十进制的IP地址转换为二进制格式。

  • 原型:

    int inet_pton(int af, const char *src, void *dst);
  • 参数:

    • af:地址族,如 AF_INET 或 AF_INET6

    • src:点分十进制字符串。

    • dst:存储二进制结果的缓冲区。

inet_ntop()
  • 功能:将二进制格式的IP地址转换为点分十进制字符串。

  • 原型:

    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
    getaddrinfo()
  • 功能:解析主机名和服务名,返回地址信息。

  • 原型:

    int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);

7. 错误处理

perror()
  • 功能:打印与 errno 相关的错误信息。

  • 原型:

    void perror(const char *s);
strerror()
  • 功能:将错误码转换为可读的字符串。

  • 原型:

    char *strerror(int errnum);

三、基本客服端和服务端

1、服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    char *response = "Hello from server";

    // 1. 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket failed");
        exit(EXIT_FAILURE);
    }

    // 2. 绑定地址和端口
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 3. 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d...\n", PORT);

    // 4. 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("Accept failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 5. 读取客户端数据
    int valread = read(new_socket, buffer, BUFFER_SIZE);
    printf("Client says: %s\n", buffer);

    // 6. 发送响应给客户端
    send(new_socket, response, strlen(response), 0);
    printf("Response sent to client\n");

    // 7. 关闭连接
    close(new_socket);
    close(server_fd);
    return 0;
}

2、客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    char *message = "Hello from client";

    // 1. 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 2. 将IP地址从字符串转换为二进制格式
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        close(sock);
        exit(EXIT_FAILURE);
    }

    // 3. 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection failed");
        close(sock);
        exit(EXIT_FAILURE);
    }

    // 4. 发送数据到服务器
    send(sock, message, strlen(message), 0);
    printf("Message sent to server\n");

    // 5. 接收服务器的响应
    int valread = read(sock, buffer, BUFFER_SIZE);
    printf("Server says: %s\n", buffer);

    // 6. 关闭连接
    close(sock);
    return 0;
}


总结

TCP网络编程是构建高性能、高可靠性网络应用的基础。通过理解TCP协议的工作原理、掌握Linux Socket API的使用方法,并实践编写客户端和服务器程序,我们可以逐步掌握网络编程的核心技能。希望本篇博客能为你的学习之旅提供帮助,期待你在网络编程的世界中探索更多可能性!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2291056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法题(54):插入区间

审题&#xff1a; 需要我们把newinterval的区间与interval的区间合并起来&#xff0c;并返回合并后的二维数组地址 思路&#xff1a; 方法一&#xff1a;排序合并区间 我们可以先把newinterval插入到interval中&#xff0c;进行排序然后复用合并区间的代码 方法二&#xff1a;模…

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)

文章目录 Gradle配置指南&#xff1a;深入解析settings.gradle.kts&#xff08;Kotlin DSL版&#xff09;settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理&#xff08;Plugin Management&#xff09;基础配置模板案例&#xff1a;Android项目标准配…

【机器学习】自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

一、使用pytorch框架实现逻辑回归 1. 数据部分&#xff1a; 首先自定义了一个简单的数据集&#xff0c;特征 X 是 100 个随机样本&#xff0c;每个样本一个特征&#xff0c;目标值 y 基于线性关系并添加了噪声。将 numpy 数组转换为 PyTorch 张量&#xff0c;方便后续在模型中…

Spring Boot - 数据库集成06 - 集成ElasticSearch

Spring boot 集成 ElasticSearch 文章目录 Spring boot 集成 ElasticSearch一&#xff1a;前置工作1&#xff1a;项目搭建和依赖导入2&#xff1a;客户端连接相关构建3&#xff1a;实体类相关注解配置说明 二&#xff1a;客户端client相关操作说明1&#xff1a;检索流程1.1&…

Java篇之继承

目录 一. 继承 1. 为什么需要继承 2. 继承的概念 3. 继承的语法 4. 访问父类成员 4.1 子类中访问父类的成员变量 4.2 子类中访问父类的成员方法 5. super关键字 6. super和this关键字 7. 子类构造方法 8. 代码块的执行顺序 9. protected访问修饰限定符 10. 继承方式…

ArkTS编程规范

文章目录 目标和适用范围规则来源章节概览代码风格编程实践 术语和定义总体原则命名类名、枚举名、命名空间名采用UpperCamelCase风格变量名、方法名、参数名采用lowerCamelCase风格常量名、枚举值名采用全部大写&#xff0c;单词间使用下划线隔开避免使用否定的布尔变量名&…

深度学习之“向量范数和距离度量”

在深度学习中&#xff0c;范数和向量距离是两个不同的概念。向量范数是一种函数&#xff0c;用于将一个实数或复数向量映射为一个值。虽然范数通常用于度量向量之间的距离&#xff0c;但是同样也有其它的一些表示距离的方式。 范数距离 范数是具有“长度”概念的函数。在向量…

基于Python的简单企业维修管理系统的设计与实现

以下是一个基于Python的简单企业维修管理系统的设计与实现&#xff0c;这里我们会使用Flask作为Web框架&#xff0c;SQLite作为数据库来存储相关信息。 1. 需求分析 企业维修管理系统主要功能包括&#xff1a; 维修工单的创建、查询、更新和删除。设备信息的管理。维修人员…

< OS 有关 > Android 手机 SSH 客户端 app: connectBot

connectBot 开源且功能齐全的SSH客户端,界面简洁,支持证书密钥。 下载量超 500万 方便在 Android 手机上&#xff0c;连接 SSH 服务器&#xff0c;去运行命令。 Fail2ban 12小时内抓获的 IP ~ ~ ~ ~ rootjpn:~# sudo fail2ban-client status sshd Status for the jail: sshd …

【算法设计与分析】实验7:复杂装载及0/1背包问题的回溯法设计与求解

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 针对复杂装载问题、及0/1背包问题开展分析、建模、评价&#xff0c;算法设计与优化&#xff0c;并进行编码实践。 理解复杂装载…

仿真设计|基于51单片机的温湿度、一氧化碳、甲醛检测报警系统

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 &#xff08;1&#xff09;温湿度传感器、CO传感器、甲醛传感器实时检测温湿度值、CO值和甲醛值进…

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…

深入理解Spring事务管理

一、事务基础概念 1.1 什么是事务&#xff1f; 事务&#xff08;Transaction&#xff09;是数据库操作的最小工作单元&#xff0c;具有ACID四大特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务中的操作要么全部成功&#xff0c;要么全部失败 一致…

自制虚拟机(C/C++)(二、分析引导扇区,虚拟机读二进制文件img软盘)

先修复上一次的bug&#xff0c;添加新指令&#xff0c;并增加图形界面 #include <graphics.h> #include <conio.h> #include <windows.h> #include <commdlg.h> #include <iostream> #include <fstream> #include <sstream> #inclu…

ASP.NET Core 启动并提供静态文件

ASP.NET Core 启动并提供静态文件 即是单个可执行文件&#xff0c;它既运行 API 项目&#xff0c;也托管 前端项目&#xff08;通常是前端的发布文件&#xff09;。 这种方式一般是通过将 前端项目 的发布文件&#xff08;例如 HTML、CSS、JavaScript&#xff09;放入 Web AP…

4 [危机13小时追踪一场GitHub投毒事件]

事件概要 自北京时间 2024.12.4 晚间6点起&#xff0c; GitHub 上不断出现“幽灵仓库”&#xff0c;仓库中没有任何代码&#xff0c;只有诱导性的病毒文件。当天&#xff0c;他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒&#xff0c;等待不…

变量和常量

一.变量 1.标准声明 var 变量名 变量类型 变量声明行末不需要分号 2..批量声明 package main import "fmt" func main(){var(a string b int c boold float32)}3.变量的初始化 var a int 10 var b float321.1 4.类型推导 var name"tom" var age18 fmt.Pr…

大模型概述(方便不懂技术的人入门)

1 大模型的价值 LLM模型对人类的作用&#xff0c;就是一个百科全书级的助手。有多么地百科全书&#xff0c;则用参数的量来描述&#xff0c; 一般地&#xff0c;大模型的参数越多&#xff0c;则该模型越好。例如&#xff0c;GPT-3有1750亿个参数&#xff0c;GPT-4可能有超过1万…

流浪 Linux: 外置 USB SSD 安装 ArchLinux

注: ArchLinux 系统为滚动更新, 变化很快, 所以本文中的安装方法可能很快就过时了, 仅供参考. 实际安装时建议去阅读官方文档. 最近, 突然 (也没有那么突然) 有了一大堆 PC: 4 个笔记本, 2 个台式主机 (M-ATX 主板), 1 个小主机 (迷你主机). 嗯, 多到用不过来. 但是, 窝又不能…

Hot100之子串

560和为K的子数组 题目 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列 思路解析 ps&#xff1a;我们的presum【0】就是0&#xff0c;如果没有这个0的话我们的第一个元素就无法减去上…