03 网络编程 TCP传输控制协议

news2024/12/25 1:55:04

目录

1、TCP基本特征

2、TCP通信流程基本原理

(1)基本原理

(2)TCP通信代码实现

(3)核心API解析

1)地址绑定--bind

2)设置监听-listen

3)等待连接请求-accept-产生一个已连接套接字

4)发起连接请求--connect

3、服务器广播


  

         TCP全称 Transmition Control Protocol,即:传输控制协议。是面向连接的协议。通常,TCP 通信还会被冠以 可靠传输协议 的头衔。

        但请注意,这里的可靠并非指发出去的数据对方一定能收到(这是不可能的),而仅指TCP能使发送方可靠地知道对方是否收到了数据。

1、TCP基本特征

  • 有连接:通信双方需要事先连接成功,方可传输数据
  • 有确认:一方收到对端的任何数据,都会给另一方发回执确认
  • 保证数据有序、不重复、丢失会重发
  • 如果网络拥堵,会自动调节发送量
  • 采用帧异步的流式通信方式(即通信双方每次的收发数据量不必相等)

        简单来讲,TCP 类似于打电话,说话前需要花一定的时间接通电话,等到对方接听了之后双方才能开始通信,通信的过程中每个数据的传送,接收方都会给发送方回执确认,断开的时候也会互相通知以便于释放各自相关的资源。可以看出来,TCP 相对于 UDP 而言资源开销更大,提供更丰富的功能,TCP适合用在如下情形:

  • 传输质量要求较高,不能丢失数据
  • 大数据量的通信,以至于通信前后的连接和断开的开销可以忽略不计
  • 用户登录、账户管理等相关的功能

2、TCP通信流程基本原理

(1)基本原理

        TCP的通信流程跟打电话是几乎一样的,因此可以将通信的过程细分为主动发起连接者(客户端)和被动接受连接者(服务端)两方来分别讨论。

被动的服务端Server

  1. socket:建立TCP套接字sockfd,即通信端点
  2. bind:绑定套接字sockfd与网络地址,即IP+端口
  3. listing:设定套接字sockfd进入被动监听状态,即将套接字设定为监听套接字
  4. accept:静静等待远程客户端的连接请求
  5. 收到连接请求后,得到一个专用于收发数据的连接套接字connfd
  6. 使用连接套接字connfd与客户端通信

主动的客户端Client

  1. socket:建立TCP套接字sockfd,即通信端点
  2. connect:对服务端发起连接请求
  3. 若连接成功,则直接通过套接字sockfd与服务端通信

注意:

  • 在服务端中,监听套接字和连接套接字是严格区分的,不可混用
  • 服务端所绑定的地址(IP+PORT)需要对外公开,否则客户端无法发起连接
  • 客户端在发起连接前一般无需绑定地址,此时系统会为此连接自动分配恰当的地址资源

(2)TCP通信代码实现

        基本C/S代码(Client客户端、Server服务端),要演示TCP的通信过程,只需要写一个服务端和客户端即可,服务端负责建立被动监听套接字,客户端负责主动发起连接。下面通过一个简单的消息反弹服务器(即将客户端发来的消息直接原样反弹回去)来了解TCP通信的基本流程和所涉及的API。

需要用到的头文件

#include <arpa/inet.h>

#include <netinet/in.h>

服务端:Server

客户端:Client

(3)核心API解析

1)地址绑定--bind

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能
    将套接字 sockfd 与指定的IP和端口绑定
    注意,对于绑定了某个协议套接字的地址,不能重复绑定。
参数
    sockfd  - 套接字文件描述符
    addr    - 地址结构体,包含了IP+PORT
    addrlen - 地址结构体长度
返回值
    成功返回 0
    失败返回-1

一般而言,TCP服务端套接字都需要绑定IP和端口,否则客户端无法发起连接。
另外,除非要指定客户端的地址信息,TCP客户端套接字无需绑定IP和端口。

核心:使用结构体存放IP + 端口号 + 家族协议
因为使用IPV4 、TCP或者UDP,所有具有专属的结构体类型用来存放
const struct sockaddr *addr:通用类结构体类型
const struct sockaddr_in *addr:TCP和UDP专属类结构体类型

struct sockaddr_in
{
  sa_family_t  sin_family;  /*     Address family       */
  in_port_t  sin_port;      /*     Port number          */
  struct in_addr sin_addr;  /*     Internet address     */

  /* Pad to size of `struct sockaddr'. */ 
  让专属结构体和通用结构体大小能对齐,起到扩容专属结构体的作用
  unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int)
      - sizeof(unsigned short int) - sizeof(struct in_addr)];
};

int main()
{
    //创建服务器的套接字
    int ser_fd = socket(AF_INET,SOCK_STREAM,0);
    if(ser_fd == -1)
    {
        perror("socket ... ");
        return -1;
    }
    //等客户端来连接的流程部署 --- 你怎么让客户端能连你 通缉犯
    //服务器绑定套接字: 把服务器的IP地址 和端口号 + 家族协议 绑定到外网把你的内网IP转成内存IP
    // IP地址分为: 公网IP + 内网IP, 
    struct sockaddr_in ser_addr;
    memset(&ser_addr,0,sizeof(ser_addr));
    ser_addr.sin_family      = AF_INET;
    ser_addr.sin_port        = htons(8888);//host主机字节序  network网络字节序
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);//注意不能只绑定一个IP地址,我们电脑是多网卡的,有多个IP
    if(bind(ser_fd,(struct sockaddr *)&ser_addr,sizeof(ser_addr)) == -1)
    {
        perror("bind ... ");
        return -1;
    }
    else
    {
        printf("服务器绑定套接字成功!\n");
    }
    return 0;
}

2)设置监听-listen

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

功能
    将套接字的状态设置为被动监听状态
    设定该套接字的最大等待连接数为backlog
参数
    sockfd - 套接字文件描述符
    backlog - 等待连接数最大值
返回值
    成功返回 0
    失败返回-1    

        套接字被设定为被动监听状态后,该套接字sockfd只能被动接收连接,不能再主动发起连接。

backlog规定的是最大等待连接数,而不是最大连接数,在Linux中,如果backlog被设定为0,实质的最大等待连接数为4,也就是最多允许同时处理4个远端请求。在Linux中,backlog的最大值被限定在文件 /proc/sys/net/core/somaxconn 中。

另外要注意,要将该函数与阻塞等待对端连接的accecpt()区分开:listen()只是设置套接字状态以及设定backlog数目,它本身是不阻塞的,不能望文生义,以为 listen 就是监听等待对方,该函数的名字很容易产生歧义。

3)等待连接请求-accept-产生一个已连接套接字

默认会堵塞--让进程进入睡眠态

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

功能
    阻塞等待TCP连接请求
参数
    sockfd  - 套接字文件描述符,服务器套接字
    addr    - 客户端地址信息结构体,不想查看连接的客户端信息,可设定为NULL
    addrlen - 地址结构体长度指针,  不想查看连接的客户端信息,可设定为NULL
返回值
    成功返回一个新的非负连接套接字描述符-成功连接的客户端套接字,使用其进行通信
    失败返回-1
详解
    该函数默认会阻塞等待客户端连接请求
    当不需要保存客户端地址信息时,后两个参数都可以被设定为NULL
    成功返回一个新的连接套接字,是专用于与客户端通信的、能收发数据的套接字

发送信息:
    write(客户端的对等套接字)---服务器发送给客户端
接收消息:
    read(客户端的对等套接字)      
    
accept进入不可中断睡眠态:想让对应进程或者线程退出--pthread_cancel()
客户端调用close()函数的时候退出了,服务器的read()返回0
客户端ctrl+c退出了            

注意:

由 accept() 函数返回的套接字,称为 已连接套接字,这与其第一个参数 sockfd 被动监听套接字 不同

  • 前者专用于与对端进行读/写操作
  • 后者专用于接收对端的连接请求,它们职责分明,不可混用。

4)发起连接请求--connect

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能
    对指定地址的TCP服务端发起连接请求
参数
    sockfd  - 套接字文件描述符
    addr    - 服务端地址信息结构体
    addrlen - 地址结构体长度
返回值
    成功返回 0
    失败返回-1

该函数会向指定服务器发送连接请求SYN,正常情况下服务器会返回应答ACK和SYN2,
然后该函数再返回一个ACK2给服务器,此过程就是著名的TCP三次握手。
连接的建立是需要一定时间的,在网络环境较差的条件下时间可能会比较长,也就是说 
connect() 函数在网络不通畅的情形下会阻塞。

3、服务器广播

支持多个客户端连接,客户端发的消息,让服务器帮忙妆发,其他客户端都能收到

服务器思路:

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

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

相关文章

WSL2与Windows之间的网络互访

文章目录 1.环境2.WSL访问Windows上的服务3.Windows访问WSL上的服务 1.环境 1.宿主机 Windows 10 2.WSL ubuntu 18.04 LTS 3.Windows 10上的 vEthernet (WSL) 已启用 2.WSL访问Windows上的服务 1.防火墙设置 2.查看访问Windows的IP 172.21.112.1, 使用该IP访问Windows上的服务…

玩机进阶教程-----回读 备份 导出分区来制作线刷包 回读分区的写入与否 修改xml脚本

很多工作室需要将修改好的系统导出来制作线刷包。前面分享过很多制作线刷包类的教程。那么一个机型中有很多分区。那些分区回读后要写入。那些分区不需要写入。强写有可能会导致不开机 不进系统的故障。首先要明白。就算机型全分区导出后在写回去 都不一定可以开机进系统。那么…

【JVM】JVM 实战调优指南赋案例(保姆篇)

文章目录 JVM 实战调优指南引言1. JVM基础知识1.1 JVM架构1.2 JVM垃圾回收 2. 垃圾回收调优2.1 垃圾回收日志2.2 GC日志分析2.3 调优策略2.3.1 调整堆大小2.3.2 选择合适的GC算法2.3.3 调整垃圾回收线程 3. 内存管理调优3.1 内存泄漏检测3.2 堆转储分析3.3 内存分配策略 4. 线程…

基于飞桨框架的稀疏计算使用指南

本文作者-是 Yu 欸&#xff0c;华科在读博士生&#xff0c;定期记录并分享所学知识&#xff0c;博客关注者5w。本文将详细介绍如何在 PaddlePaddle 中利用稀疏计算应用稀疏 ResNet&#xff0c;涵盖稀疏数据格式的础知识、如何创建和操作稀疏张量&#xff0c;以及如何开发和训练…

在阿里云上部署 Docker并通过 Docker 安装 Dify

目录 一、在服务器上安装docker和docker compose 1.1 首先关闭防火墙 1.2 安装docker依赖包 1.3 设置阿里云镜像源并安装docker-ce社区版 1.4 开启docker服务并设置开机自启动 1.5 查看docker版本信息 1.6 设置镜像加速 1.7 将docker compose环境复制到系统的bin目录下…

【计算机网络】应用层自定义协议与序列化

记得在上一节我们说过TCP中的读取时需要改进&#xff0c;这节就可以解决读取问题了。 目录 应用层再谈 "协议"网络版计算机方案一方案二 序列化 和 反序列化 重新理解 read、write、recv、send 和 tcp 为什么支持全双工 应用层 再谈 “协议” 我们在UDP与TCP中写的…

力扣高频SQL 50题(基础版)第四十七题之1321.餐馆营业额变化增长

力扣高频SQL 50题&#xff08;基础版&#xff09;第四十七题 1321.餐馆营业额变化增长 题目说明 表: Customer ---------------------- | Column Name | Type | ---------------------- | customer_id | int | | name | varchar | | visited_on | date | | amount | …

后端开发刷题 | 排序算法--冒泡排序

描述 有一个长度为7的无序数组&#xff0c;按照从小到大的顺序排序后输出。 输入描述&#xff1a; 数组中的数据 输出描述&#xff1a; 数组中数据排序后输出 示例1&#xff1a; 输入&#xff1a; 13 11 9 7 5 3 1输出&#xff1a; 1 3 5 7 9 11 13 算法思想&#xf…

Type-C PD芯片与OTG功能:边充电边数据同时进行 LDR6028

在科技飞速发展的今天&#xff0c;智能设备已成为我们日常生活中不可或缺的一部分。从智能手机到平板电脑&#xff0c;再到笔记本电脑&#xff0c;这些设备不仅极大地丰富了我们的生活方式&#xff0c;也对充电与数据传输技术提出了更高要求。Type-C PD&#xff08;Power Deliv…

WPF篇(19)-TabControl控件+TreeView树控件

TabControl控件 TabControl表示包含多个共享相同的空间在屏幕上的项的控件。它也是继承于Selector基类&#xff0c;所以TabControl也只支持单选操作。另外&#xff0c;TabControl的元素只能是TabItem&#xff0c;这个TabItem继承于HeaderedContentControl类&#xff0c;所以Ta…

EE trade:黄金的基础知识点

黄金&#xff0c;这种闪耀着金色光芒的贵金属&#xff0c;自古以来就吸引着人类的目光&#xff0c;并深深地影响着人类文明进程。从古代文明的装饰品到现代社会的投资工具&#xff0c;黄金始终扮演着重要的角色。本文整理了黄金的必备常识、黄金的基础知识点。 一、黄金的独特…

达梦数据库系列—48.DMHS实现Mysql到DM8的同步

目录 DMHS实现Mysql到DM8的同步 1、准备介质 2、安装 3、准备源端Mysql和目标端DM8 软件安装 数据库创建 打开归档 开启附加日志 创建辅助表 Mysql客户端驱动 Mysql端安装ODBC 检查依赖包 创建连接用户 创建测试表 4、同步配置 修改服务配置 Mysql到Dm单向同步…

CVPR2023《DNF: Decouple and Feedback Network for Seeing in the Dark》暗光图像增强论文阅读笔记

相关链接 论文链接 https://openaccess.thecvf.com/content/CVPR2023/papers/Jin_DNF_Decouple_and_Feedback_Network_for_Seeing_in_the_Dark_CVPR_2023_paper.pdf 代码链接 https://github.com/Srameo/DNF 摘要 RAW数据的独特属性在低光照图像增强方面展现出巨大潜力。…

ansible环境搭建

任务背景 公司的服务器越来越多, 维护⼀些简单的事情都会变得很繁琐。⽤ shell脚本来管理少量服务器效率还⾏, 服务器多了之后, shell脚本⽆ 法实现⾼效率运维。这种情况下&#xff0c;我们需要引⼊⾃动化运维⼯具, 对 多台服务器实现⾼效运维。 任务要求 通过管理服务器能够…

nginx核心配置示例

目录 1、nginx location的详细使用 &#xff08;1&#xff09;精确匹配 &#xff08;2&#xff09;区分大小写 &#xff08;3&#xff09;不区分大小写 &#xff08;4&#xff09;匹配文件名后缀 2、nginx下的用户认证 3、nginx自定义错误页面 4、自定义错误日志 5、n…

Scrapy框架进阶攻略:代理设置、请求优化及链家网实战项目全解析

scrapy框架 加代理 付费代理IP池 middlewares.py # 代理IP池 class ProxyMiddleware(object):proxypool_url http://127.0.0.1:5555/randomlogger logging.getLogger(middlewares.proxy)async def process_request(self, request, spider):async with aiohttp.ClientSess…

【乐吾乐大屏可视化组态编辑器】状态切换

状态切换 开关状态 开关的断开和闭合。可以拖拽国家电网图库中的“开”与“关”两个组件&#xff0c;选中对齐重叠在一起后&#xff0c;右键选择“组合为状态”&#xff0c;在“外观”面板可以任意切换状态。 想实现点击开关图元就可以切换开关状态&#xff0c;可以选中图元添…

基于 springboot 2 和 vue 3 的 博客论坛系统

1. 网站信息 博客论坛系统&#xff1a;http://106.53.164.141:8200 本网站是 基于 SpringBootVue 前后端分离的博客论坛系统 前台用户&#xff1a;注册登录&#xff1b;博客和活动相关的展示、浏览、点赞、收藏、评论、编辑等功能 后台管理员&#xff1a;管理公告、博客、活…

日撸Java三百行(day25:栈实现二叉树深度遍历之中序遍历)

目录 一、栈实现二叉树遍历的可行性 二、由递归推出栈如何实现中序遍历 1.左子树入栈 2.根结点出栈 3.右子树入栈 4.实例说明 三、代码实现 总结 一、栈实现二叉树遍历的可行性 在日撸Java三百行&#xff08;day16&#xff1a;递归&#xff09;中&#xff0c;我们讲过…

Debian 12 基于KubeAdm搭建多节点K8S 1.28.x集群

背景 CentOS 7 官方支持和更新已于2024年6月30日结束。这意味着CentOS 7 不再接受官方的更新和补丁。并且官方推荐用户迁移到新的操作系统&#xff1b;而转移到Debian的优势有&#xff1a; 更加成熟的软件包管理系统&#xff1a;Debian 的包管理系统是 APT&#xff08;Advanc…