Socket编程(TCP/UDP详解)

前言:之前因为做项目和找实习没得空,计算机网络模块并没有写成博客,最近得闲了,把计算机网络模块博客补上。

目录

一,UDP编程

1)创建套接字

2)绑定端口号

3)发送与接收数据

4)UDP简单的发送数据和接收数据服务器

二,TCP编程

1)创建套接字

2)绑定端口号

3)使套接字进入监听状态

4)获取成功建立连接的的文件描述符和主机信息

5)发送与接收数据

6)连接其他主机

7)TCP简单的发送数据和接收数据服务器


scoket编程即套接字编程,是网络编程的基础,它允许两台或者多台计算机进行网络通信,这篇文章主要讲socket编程利用里面的TCP和UDP相关接口实现网络通信。

一,UDP编程

在udp编程里面,我们首先要创建一个套接字,也就是文件描述符。用来接收数据与发送数据,但注意,UDP为每一个套接字维护一个缓冲区,但是发送缓冲区是临时的、不可见的。这是为什么呢?UDP是面向无连接的,每次发送数据都是相对独立的,这允许我们可以使用临时的缓冲区,UCP数据发送完就不管任何事了,不会像TCP一样要确认对方收到,没收到还要进行重传等操作。不维护一个长久的缓冲区,也可以节省空间资源,使UDP变得轻量与高效。如果接收缓冲区设置成临时的那么数据到达后,如果应用程序没有及时读取可能出现丢失,那么如果一直等到读取完再销毁,一个套接字缓冲区可能接收很多主机的信息,可能接收缓冲区会频繁的创建,销毁,这会有很多不必要的开销。

1)创建套接字

第一个参数是网络通信协议,如IPV4或者IPV6等,具体参考下图

第二个参数是套接字的类型,使用什么方式通信,如数据报(UDP)或者字节流(TCP)等

返回值为-1代表创建失败,并设置错误码,大于0代表成功创建。

使用例子:

        //AF_INET代表IPV4协议格式,SOCK_DGRAM代表以UDP数据报形式发送,0代表选择IPV4和UDP的默认协议int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;}

2)绑定端口号

在我的上一篇文章,我们以及明白绑定端口号加上IP才能确定互联网内的唯一一台主机,客户端可以不绑定端口号,这样子操作系统就会随机分配端口号,但是服务端不能这样,不然其他人无法主动连接服务端,因为其他人根本无法发现它,需要被别人第一次主动发现需要绑定端口号。现在我们来学习绑定端口号的接口。

scokfd就是我们前面使用socket接口创建的文件描述符。我们重点介绍接下来第二个参数,第三个参数是第二个参数的长度。

addr是结构体强转后得到的,它可以由IPV4结构体格式强转得到,也可以由IPV6格式强转得到,socketaddr_in是IPV4协议,socketaddr_un是IPV6协议。可以看下图理解

struct socketaddr里面的内容

struct socketaddr_in里面的内容

上图struct in_addr里面的内容

具体初始化和使用例子:

//IPV4结构体struct sockaddr_in _addr; //设置为IPV4协议_addr.sin_family=AF_INET;//端口号网络字节序_addr.sin_port=htons(PORT);//IP地址网络字节序,inet_addr函数将C风格字符串的IP地址形式转化成uint32_t的网络字节序类型_addr.sin_addr.s_addr=inet_addr(IP);//成功返回0,失败返回-1设置错误码,设置成功只能接收来自IP主机发送给PORT的信息int result=bind(fd,(struct sockaddr*)&_addr,(socklen_t)sizeof(_addr));if(result!=0){cout<<"绑定端口号失败"<<endl;}

3)发送与接收数据

发送数据,UDP协议使用的是sendto接口

socketfd就是套接字文件描述符,buf是发送的数据地址,len是发送数据的长度,flag是位图,使用|可以实现对发送的方法控制

  • 发送标志,可以是一个或多个标志的组合,用于修改 sendto 的行为。常见的标志包括:
    • MSG_CONFIRM:请求确认消息已被接收(某些实现可能不支持)。
    • MSG_DONTROUTE:避免路由,直接发送到本地接口。
    • MSG_DONTWAIT:非阻塞发送,如果操作会阻塞,则立即返回错误。
    • MSG_EOR:表示记录结束(对某些协议有意义)。
    • MSG_MORE:指示发送的数据是更大消息的一部分。

后面两个参数就不必多少,目标地址的信息和长度强转得来。最后成功返回发送数据的长度,失败返回-1,并设置错误码。

接收数据,UDP协议用的是recvfrom函数,

socketfd就是套接字文件描述符,buf是接收数据存放的地址,len是接收数据的最大长度,flag是位图,使用|可以实现对接收数据的方法控制

  • 接收标志,可以是一个或多个标志的组合,用于修改 recvfrom 的行为。常见的标志包括:
    • MSG_PEEK:查看数据而不从队列中删除它。
    • MSG_WAITALL:请求接收完整的消息(对于某些协议可能不适用)。
    • MSG_DONTWAIT:非阻塞接收,如果操作会阻塞,则立即返回错误。
    • MSG_TRUNC:即使数据被截断也继续接收(通常与 MSG_PEEK 一起使用)。
    • MSG_CTRUNC:如果控制消息被截断,则设置 msg_flags 的 MSG_CTRUNC 标志。

src_addr会返回发送数据的信息,如端口号,IP地址,addrlen是src_addr的长度。成功返回收到数据的长度,失败返回-1。

4)UDP简单的发送数据和接收数据服务器

中间可能有一个地方没讲清楚,bind函数不论接收,数据还是发送数据都最好设置,设置成功能接收你设置的主机发过来的特点端口号消息,sendto函数里面设置的是要发送给的人的IP和端口号。recvfrom函数里面的struct sockeaddr是接收消息的发送主机信息,方便你回信息和处理。

发送端

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include<unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include<iostream>using namespace std;#define PORT 8081//本地环回通信测试#define IP "127.0.0.1"int main(){//AF_INET代表IPV4协议格式,SOCK_DGRAM代表以UDP数据报形式发送,0代表选择IPV4和UDP的默认协议int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;return -1;}//不绑定端口号,操作系统随机分配char msg[13]="hello world!";struct sockaddr_in _send; _send.sin_family=AF_INET;_send.sin_port=htons(8080);_send.sin_addr.s_addr=inet_addr(IP);//给地址为IP主机8080端口号发送消息int result=sendto(fd,(void*)msg,13,0,(struct sockaddr*)&_send,(socklen_t)sizeof(_send));if(result<0){cout<<"发送数据失败"<<endl;return -1;}close(fd);return 0;}

接收端

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include<unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include<iostream>using namespace std;#define PORT 8080int main(){//AF_INET代表IPV4协议格式,SOCK_DGRAM代表以UDP数据报形式发送,0代表选择IPV4和UDP的默认协议int fd=socket(AF_INET,SOCK_DGRAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;return -1;}//IPV4结构体struct sockaddr_in _addr; //设置为IPV4协议_addr.sin_family=AF_INET;//端口号网络字节序_addr.sin_port=htons(PORT);//接收所有主机的信息_addr.sin_addr.s_addr=INADDR_ANY;//成功返回0,失败返回-1设置错误码int result=bind(fd,(struct sockaddr*)&_addr,(socklen_t)sizeof(_addr));if(result!=0){cout<<"绑定端口号失败"<<endl;return -1;}char msg[20];struct sockaddr_in recv;//必须写,不能为空。socklen_t len=sizeof(recv);result=recvfrom(fd,(void*)msg,20,0,(struct sockaddr*)&recv,&len);if(result<0){cout<<"接收数据数据失败"<<endl;return -1;}for(int i=0;i<result;i++){cout<<msg[i];}close(fd);return 0;}

二,TCP编程

1)创建套接字

创建套接字,与UDP创建套接字相似,只要把SOCK_DGRAM改为SOCK_STREAM

        //SOCK_STREAM代表字节流,适用于TCPint fd=socket(AF_INET,SOCK_STREAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;return -1;}

2)绑定端口号

绑定端口号与UDP没有差别,就是接收来自指定的主机的连接请求,UDP是没有连接,需要发送消息时指定目的地址的。暂时简单理解就行。

struct sockaddr_in _addr; //设置为IPV4协议_addr.sin_family=AF_INET;//端口号网络字节序_addr.sin_port=htons(PORT);//IP地址网络字节序,inet_addr函数将C风格字符串的IP地址形式转化成uint32_t的网络字节序类型_addr.sin_addr.s_addr=inet_addr(IP);//成功返回0,失败返回-1设置错误码int result=bind(fd,(struct sockaddr*)&_addr,(socklen_t)sizeof(_addr));if(result!=0){cout<<"绑定端口号失败"<<endl;return -1;}

3)使套接字进入监听状态

在TCP编程里面,创建套接字后并不能直接使用,TCP套接字只用来接收来自其他主机的连接请求,UDP发送完数据就不管了,是无连接的,TCP是面向连接的,双方会建立一个连接,也就是会为两台主机间创建单独的文件描述符,并且进行管理,这个文件描述符只能用来双方通信,而UDP可以实现一个文件描述符也就是socket就向所有主机发送消息。只有将套接字变成监听状态才会接收来自其他主机的连接。

第一个参数无需多言,就是我们使用socket函数创建的套接字,backlog是允许同时与多少台主机建立连接,也就是同时创建多少个通信的文件描述符,成功返回0,失败返回-1,并设置错误码。

        //允许同时最大与三个主机建立连接result=listen(fd,3);if(result!=0){cout<<"套接字启动监听失败"<<endl;return -1;}

4)获取成功建立连接的的文件描述符和主机信息

套接字进入监听状态后,我们需要获得建立连接的文件描述符,这样基于文件描述符才能和建立连接的主机通信,我们使用accept函数获取建立连接的消息,一般使用一个while循环来获取得到的多个连接信息。

第一个参数是套接字,第二个参数是连接主机的信息,第三个是第二个参数的长度,方便区分类型。成功返回建立连接的文件描述符,失败返回-1,并设置错误码。

        while(1){//这里不对对方主机信息进行处理,设置为空int fd_net=accept(fd,NULL,NULL);if(fd_net==-1){cout<<"TCP连接失败"<<endl;return -1;}//进行处理,发送或者接收数据}

5)发送与接收数据

TCP可以使用UDP的sendto和recvfrom函数发送与接收数据,但一般不这么做,因为TCP以及建立连接了,每个连接文件描述符都只和一台主机通信,被唯一的四元组来标识的,这个四元组包括源IP地址、源端口号、目的IP地址和目的端口号。没必要使用这两个函数,这两个函数里面还需要包括目的主机地。一般使用send和write,read与recv。

flag常用标志

  1. MSG_DONTWAIT(或MSG_NONBLOCK)
    • 作用:允许非阻塞操作。如果套接字被设置为非阻塞模式,并且发送缓冲区已满,则send函数会立即返回,而不是阻塞等待缓冲区空间可用。
    • 返回值:在非阻塞模式下,如果发送缓冲区已满,send函数可能返回-1,并设置errnoEAGAINEWOULDBLOCK,表示资源暂时不可用。
  2. MSG_OOB(Out-of-Band Data)
    • 作用:发送带外数据。带外数据通常用于发送紧急数据,这些数据会被接收方优先处理。然而,并非所有协议都支持带外数据,且其使用方式可能因协议而异。
    • 限制MSG_OOB标志通常仅适用于流式套接字(如SOCK_STREAM),而不适用于数据报套接字(如SOCK_DGRAM)。
  3. MSG_DONTROUTE
    • 作用:勿将数据路由出本地网络。这个标志告诉系统不要通过网关或路由器发送数据,而只在本地网络上发送。然而,并非所有系统都支持这个标志,且其效果可能因系统而异。

成功返回发送数据大小,失败返回-1,设置错误码。

fd是文件描述符,也就是accept函数的返回值,buf被发送的数据,count是发送的大小。

flag常用标志

  1. MSG_PEEK
    • 作用:查看接收队列中的数据,但不从队列中移除它们。这允许调用者在不实际消耗数据的情况下检查是否有数据可读。
    • 使用场景:在需要多次读取同一份数据或检查数据是否到达时非常有用。
  2. MSG_WAITALL
    • 作用:阻塞调用,直到接收到指定长度的数据或连接关闭。然而,需要注意的是,并非所有系统都支持这个标志,且其行为可能因系统而异。
    • 使用场景:在需要确保接收到完整消息时非常有用,但应谨慎使用,因为它可能导致程序在数据不足时长时间阻塞。
  3. MSG_DONTWAIT(或MSG_NONBLOCK
    • 作用:在非阻塞模式下接收数据。如果当前没有数据可读,则立即返回,而不是阻塞等待。
    • 使用场景:在需要避免阻塞等待数据到达时非常有用,例如在非阻塞I/O或事件驱动的编程模型中。
  4. MSG_OOB
    • 作用:接收带外数据(Out-of-Band Data)。带外数据通常用于发送紧急数据,这些数据会被接收方优先处理。然而,并非所有协议都支持带外数据。
    • 使用场景:在需要处理紧急数据或优先级较高的消息时非常有用,但应确保所使用的协议支持带外数据。
  5. MSG_TRUNC
    • 作用:如果接收到的数据长度超过了缓冲区长度,则只返回缓冲区长度的数据,并截断多余的数据。然而,需要注意的是,并非所有系统都支持这个标志。
    • 使用场景:在需要限制接收数据的大小或处理不完整数据时可能有用。
  6. MSG_CTRUNC
    • 作用:类似于MSG_TRUNC,但用于控制信息的截断。如果接收到的控制信息长度超过了缓冲区长度,则只返回缓冲区长度的控制信息。
    • 使用场景:在处理带有控制信息的套接字时可能有用。
  7. MSG_ERRQUEUE
    • 作用:接收错误信息。如果接收到的数据包出现错误,则会将错误信息放入错误队列中,可以通过此标志来接收这些错误信息。
    • 使用场景:在需要处理套接字错误或诊断网络问题时非常有用。

fd是文件描述符,也就是accept函数的返回值,buf存放数据,count是接收数据的最大大小,防止越界。

6)连接其他主机

上面我们只说了如何被动连接其他主机,但我们该如何主动连接其他主机呢?使用connect函数我们主动连接其他主机,是需要设置协议和IP,端口号信息的。注意connect连接成功之后这个scokfd就被占用了,用来后续的通信,需要继续使用socket函数创建与多台主机建立连接。这是与accept函数不同的地方,accept函数是创建了新的文件描述符,sockfd还可以继续监听。

成功返回0,失败返回-1,其他这些前面都讲过,老生常谈了,无需多言。

7)TCP简单的发送数据和接收数据服务器

服务端

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include<unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include<iostream>using namespace std;#define PORT 8080#define IP "127.0.0.1"int main(){//SOCK_STREAM代表字节流,适用于TCPint fd=socket(AF_INET,SOCK_STREAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;return -1;}//IPV4结构体struct sockaddr_in _addr; //设置为IPV4协议_addr.sin_family=AF_INET;//端口号网络字节序_addr.sin_port=htons(PORT);//IP地址网络字节序,inet_addr函数将C风格字符串的IP地址形式转化成uint32_t的网络字节序类型_addr.sin_addr.s_addr=inet_addr(IP);//成功返回0,失败返回-1设置错误码int result=bind(fd,(struct sockaddr*)&_addr,(socklen_t)sizeof(_addr));if(result!=0){cout<<"绑定端口号失败"<<endl;return -1;}//允许同时最大与三个主机建立连接result=listen(fd,3);if(result!=0){cout<<"套接字启动监听失败"<<endl;return -1;}while(1){//这里不对对方主机信息进行处理,设置为空int fd_net=accept(fd,NULL,NULL);if(fd_net==-1){cout<<"TCP连接失败"<<endl;return -1;}char msg[13]="hello world!";//进行处理,发送或者接收数据result=send(fd_net,(void*)msg,13,0);close(fd);}return 0;}

客户端

       #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include<unistd.h>#include <arpa/inet.h>#include <netinet/in.h>#include<iostream>using namespace std;#define PORT 8080#define IP "127.0.0.1"int main(){//SOCK_STREAM代表字节流,适用于TCPint fd=socket(AF_INET,SOCK_STREAM,0);if(fd<0){cout<<"创建套接字失败"<<endl;return -1;}//IPV4结构体struct sockaddr_in _addr; //设置为IPV4协议_addr.sin_family=AF_INET;//端口号网络字节序_addr.sin_port=htons(PORT);_addr.sin_addr.s_addr=inet_addr(IP);int result=connect(fd,(struct sockaddr*)&_addr,(socklen_t)sizeof(_addr));if(result==-1){cout<<"连接主机失败"<<endl;return -1;}char msg[20];result=recv(fd,msg,20,0);for(int i=0;i<result;i++){cout<<msg[i];}close(fd);return 0;}

创造不易,我为人人,人人为我,如果大家有所收获的话可以点赞加关注,下一篇文章将会着重讲TCP与UDP的特性。

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

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

相关文章

【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势

文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…

【知识分享】离散行业有哪些?

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。】 离散行业是指生产过程由一系列独立、非连续的工序或环节组成&#xff0c;产品形态和性质发生变化的行业&#xff0c;常见的离散行业有以下几类&#xff1a; 装备制造行业 包括通用装备制造、专…

【Spark源码分析】规则框架- `analysis`分析阶段使用的规则

analysis分析阶段使用的规则 规则批策略规则说明SubstitutionfixedPointOptimizeUpdateFields该规则优化了 UpdateFields 表达式链&#xff0c;因此看起来更像优化规则。但是&#xff0c;在处理深嵌套模式时&#xff0c;UpdateFields 表达式树可能会非常复杂&#xff0c;导致分…

Qt详解QUiLoader 动态加载UI文件

文章目录 详解 QUiLoader 模块的使用1. QUiLoader 简介1.1 应用场景 2. 准备工作2.1 添加模块依赖2.2 引入头文件 3. 使用 QUiLoader 加载界面3.1 示例代码form.uimain.cpp 4. 常用方法详解4.1 load函数原型作用参数返回值示例代码 4.2 createWidget函数原型作用参数返回值示例…

【Git 工具】用 IntelliJ IDEA 玩转 Git 分支与版本管理

文章目录 一、使用 IDEA 配置和操作 Git1.1 查看 Idea 中的 Git 配置1.2 克隆 Github 项目到本地 二、版本管理2.1 提交并推送修改2.2 拉取远程仓库2.3 查看历史2.4 版本回退 三、分支管理3.1 新建分支3.2 切换分支3.2 合并分支3.4 Cherry-Pick 参考资料 一、使用 IDEA 配置和操…

shell编程(4)脚本与用户交互以及if条件判断

声明&#xff1a; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

架构-微服务-服务调用Dubbo

文章目录 前言一、Dubbo介绍1. 什么是Dubbo 二、实现1. 提供统一业务api2. 提供服务提供者3. 提供服务消费者 前言 服务调用方案--Dubbo‌ 基于 Java 的高性能 RPC分布式服务框架&#xff0c;致力于提供高性能和透明化的 RPC远程服务调用方案&#xff0c;以及SOA服务治理方案。…

【Python网络爬虫笔记】2-HTTP协议中网络爬虫需要的请求头和响应头内容

1 HTTP 协议整理 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;即超文本传输协议&#xff0c;是用于从万维网&#xff08;WWW&#xff09;服务器传输超文本到本地浏览器的传送协议&#xff0c;直白点儿&#xff0c;就是浏览器和服务器之间的数据交互就是通过 HTT…

【前端开发】小程序无感登录验证

概述 封装的网络请求库&#xff0c;主要用于处理 API 请求并支持自动处理 token 过期 和 token 刷新&#xff0c;适用于需要身份验证的应用场景&#xff0c;特别是在移动端中。 主要功能 自动附加 Token 在每个请求中自动附加 Authorization 头部&#xff0c;使用存储的 acces…

关于Spring基础了解

Spring简介 Spring框架是一个开源的Java应用框架&#xff0c;旨在简化企业级应用程序的开发。它提供了一系列强大的工具和服务&#xff0c;帮助开发者构建高质量的Java应用程序。Spring框架的核心理念是使开发过程更加模块化、可测试和可维护。 主要特性 依赖注入&#xff08…

解析 SpringBoot 新冠密接者跟踪系统:灵活的权限管理机制

第2章 程序开发技术 2.1 Mysql数据库 为了更容易理解Mysql数据库&#xff0c;接下来就对其具备的主要特征进行描述。 &#xff08;1&#xff09;首选Mysql数据库也是为了节省开发资金&#xff0c;因为网络上对Mysql的源码都已进行了公开展示&#xff0c;开发者根据程序开发需要…

TYUT设计模式大题

对比简单工厂&#xff0c;工厂方法&#xff0c;抽象工厂模式 比较安全组合模式和透明组合模式 安全组合模式容器节点有管理子部件的方法&#xff0c;而叶子节点没有&#xff0c;防止在用户在叶子节点上调用不适当的方法&#xff0c;保证了的安全性&#xff0c;防止叶子节点暴露…

SpringBoot集成Kafka和avro和Schema注册表

Schema注册表 为了提升kafka的性能&#xff0c;减少网络传输和存储的数据大小&#xff0c;可以把数据的schema部分单独存储到外部的schema注册表中&#xff0c;整体架构如下图所示&#xff1a; 1&#xff09;把所有数据需要用到的 schema 保存在注册表里&#xff0c;然后在记…

Nodemailer使用教程:在Node.js中发送电子邮件

目录 1. 简介 2. 安装 3. 基本配置 3.1 创建传输器 3.2 配置说明 4. 发送邮件 4.1 基本发送示例 4.2 发送验证码示例 5. 常见问题解决 5.1 "Greeting never received" 错误 5.2 安全建议 SMTP与邮件加密协议详解 1. SMTP简介 1.1 基本特点 2. 加密协…

Cause: java.sql.SQLException: No value specified for parameter 4

问题 执行更新sql时报错&#xff0c;异常栈如下 org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: java.sql.SQLException: No value specified for parameter 4 ### The error may exist in com/my/mapper/MyMapper.java (best gue…

Wireshark 4.4.2:安全更新、错误修复、更新协议支持

流行的网络协议分析器Wireshark已更新至4.4.2版本。它可用于网络故障排除、分析、开发和教育。 已修复以下漏洞&#xff1a; wnpa-sec-2024-14 FiveCo RAP 解剖器无限循环。wnpa-sec-2024-15 ECMP 解析器崩溃。 更新的协议支持&#xff1a; ARTNET、ASN.1 PER、BACapp、B…

【一维DP】【三种解法】力扣983. 最低票价

在一个火车旅行很受欢迎的国度&#xff0c;你提前一年计划了一些火车旅行。在接下来的一年里&#xff0c;你要旅行的日子将以一个名为 days 的数组给出。每一项是一个从 1 到 365 的整数。 火车票有 三种不同的销售方式 &#xff1a; 一张 为期一天 的通行证售价为 costs[0] …

C语言中数据类型对应的打印格式

提示&#xff1a;文章 文章目录 前言一、背景二、C语言中数据类型对应的打印格式三、3.1 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 最近 二、C语言中数据类型对应的打印格式 int 对应 %d long 对应 %ld char 对应 %c float 对应 %f long long 对应 %…

《Django 5 By Example》阅读笔记:p339-p358

《Django 5 By Example》学习第12天&#xff0c;p339-p358总结&#xff0c;总计20页。 一、技术总结 1.项目(购物网站) django-admin startproject myshop 虽然这里只是示例&#xff0c;但我觉得这种命名为 myxxx 的习惯非常不好&#xff0c;因为在实际应用中&#xff0c;是…

Vue 项目开发常用知识点

一、基础语法与指令 1. 插值表达式 插值表达式是 Vue 中最基础的数据绑定方式&#xff0c;使用双大括号{{ }}将数据包裹起来&#xff0c;例如{{ message }}&#xff0c;它会将 Vue 实例中的message属性的值渲染到页面相应位置。这种方式可以方便地在页面中展示动态数据&#x…