通信原理课设(gec6818) 006:网络编程

目录

1、概念

2、通信

3、通信基本流程

TCP:

UDP:

4、函数

I 创建套接字

II 绑定地址

III 字节序转换

IV 地址转换

V 监听

VI accept

VII connect

VIII 从套接字接收信息

IX 从套接字发送消息

X 关闭套接字

5、网络配置

1、确保你的网卡里面有两个虚拟网卡,你的有线网卡的型号也在这里面看      在更改适配器里面看是否有VMnet1 VMnet8 

2、配置电脑的有线网卡ip

3、配置ubuntu的ip

4、配置开发板的ip

6、练习:实现简单的网络编程,客户端和服务器端可以实现通信


1、概念

如果两个计算机想要通信,那么这两台计算机必须在同一个局域网在一个局域网之内,如果想要进行通信,那么这两者都必须要有唯一一个ID --- IP地址
现在我们用的是IPV4 -> 4个字节来表示一台主机,由于这个IPV4资源有限,所以现在扩充到了IPV6

IPV4四个字节,如果一个局域网内将所有的ip分完,那么可以分配给2 ^ 32  个主机

在世界上面来说,局域网的数量也不少,在互联网上面是不同的局域网之内的用户在进行通信,因此我们去找到另外一台主机的时候,除了去区分这个主机以外,还需要区分局域网(局域网+主机)

因此我们的ip地址分为两个部分:网络号 + 主机号
网络号:用来标识我们的局域网
主机号:用来标识我们局域网里面的主机

对于一个ip地址来说,我需要去区分哪些是网络号,哪些是主机号
我们通过4个字节,前面用全部的1构成,后面用全部的0构成
只要我们设置的足够好,那么我就可以使用这些1和0来区分,你的ip地址上面**哪些是网络号,哪些是主机号,这个东西我们就叫子网掩码。

举个例子:

一个点分式ip地址为:192.168.31.249
子网掩码为:              255.255.255.0
---------------->网络号:192.168.31
---------------->主机号:249(注意:主机号一般不为0和255)
11111111 11111111 11111111 11111111 -> 全是网络号,没有主机,因此没有什么作用
00000000 00000000 00000000 00000000 -> 全部是主机,没有网络,可以的,这是世界最大的网

注意:掩码的左边部分一定要是全为1且中间不能有0出现
比方说将255.255.248.0转为二进制是 11111111.11111111.11111000.00000000,可以看到左边都是1,在1的中间没有0出现(0都在1的右边),这样就是一个有效的掩码。我们再来看254.255.248.0,转成二进制是 11111110.11111111.11111000.00000000,这不是一个正确有效的掩码,因为在1中间有一个0的存在。

由于一台电脑里面可能运行多个网络程序,但是他们对应的网卡都是一个,因此ip地址都是共用的,因此我们必须还要有一个机制去区分网络程序 ----- 端口,端口号用于去区分网络程序的,现在是2个字节
0 ~ 1023 -> 知名端口
1024 ~ 49151 -> 注册端口,随便用,只要不冲突就行了
后面一节是私有端口,暂时不要用

所以:网络程序=ip+端口

网络编程都是对应两端的
    1 服务端 --- 服务器
    2 客户端 --- 客户端的应用程序 
客户端发起服务请求,服务器响应这个请求

2、通信

我们的通信有两种
 1 TCP --- 面向连接的,可靠通信,保证数据的无丢失无失序,有重发机制,也就是数据没有成功到达,会重发

 2 UDP --- 面向无连接的,通信是不可靠的,但是效率要高于TCP,大量的实时不可靠通信我们就用UDP

3、通信基本流程

TCP:

服务端 -> tcp_server.c

1.   创建套接字 ---- 什么都是文件,因此你的网络通信也是一个文件,这个文件我们就叫套接字,        是一个特殊的文件描述符 sockfd
2.   我们需要将服务器的IP地址绑定到套接字
3.   监听连接 ---- 创建一个监听队列.建立5个10个可以了
4.   循环等待客户端的连接,如果没有连接则等待,如果有连接则返回一个连接套接字
5.   和客户端进行正常收发
6.   关闭套接字

客户端 -> tcp_client.c
1.   创建套接字
2.   准备服务器的ip地址,准备连接
3.   连接服务器
4.   和服务器进行正常收发
5.   关闭套接字

UDP:

服务端 -> udp_server.c

1.   创建套接字
2.   绑定地址
3.   等待客户端给你发送信息
            如果等待了客户端的信息,服务器会知道客户端的地址
            根据刚刚得到的客户端的地址给客户端发送信息即可
4.   最后弄完了关闭套接字

客户端 udp_client.c
1.   创建套接字
2.   准备服务器地址,准备给服务器发送信息
3.   给服务器发送信息,然后可根据我们自己的项目逻辑来进行收发
4.   最后弄完了关闭套接字

4、函数

I 创建套接字

 NAMEsocket - create an endpoint for communication创建一个套接字SYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);

参数解释:

domain:传输层的协议

                AF_UNIX UNIX协议域,可以实现进程间通信

                AF_INET IPV4

                AF_INET6 IPV6

                ....

type:你采用那种协议进程数据传输

           SOCK_STREAM 面向连接 -> TCP

           SOCK_DGRAM 面向无连接 -> UDP

protocol:私有协议 我们直接写0 表示一个不知名的协议

返回值: 成功返回一个套接字,类似于文件描述符 失败返回-1,同时errno被设置

II 绑定地址

 NAME 名称bind - 将一个名字和一个套接字绑定到一起(赋一个名字给一个套接字)SYNOPSIS 概述#include <sys/types.h>#include <sys/socket.h>将 my_addr这个地址绑定到sockfd这个套接字上面去int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
参数解释:
sockfd:套接字 你要绑定到这个套接字上面来

my_addr:我们的地址 struct sockaddr这个地址是一个公版 根据需求我们自己要选用正确的类型,在这里我们应该选用面向网络的struct sockaddr_in 
struct sockaddr_in { //这个类型是面向网络的  因此我们需要选用这个类型sa_family_t sin_family; /* 地址族: AF_INET */                                                        u_int16_t sin_port; /* 按网络字节次序的端口 */struct in_addr sin_addr; /* internet地址 */};  

        sin_family:这里就是socket第一个参数的填法  

        sin_port 端口号  在注册端口里面选用一个即可

        sin_addr  ip地址

                        /* Internet地址. */
                        struct in_addr {
                                                u_int32_t s_addr; /* 按网络字节次序的地址 */ };

                        s_addr:可以看到ip是一个整数,和之前讲的点分式(如192.168.31.249)                                           不同,因为点分式只是为了更加方便人看,192.168.31.249转换成                                           整数就是0xC0A81FF9。那什么又是网络字节序呢?这与大端小端                                           字节序有关:                         

                                       ①大端字节序(Big Endian):最高有效位存于最低内存地址处,                                                                                             最低有效位存于最高内存处;

                                       ②小端字节序(Little Endian):最高有效位存于最高内存地址,
                                                                                           最低有效位存于最低内存处。

                                      UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,这                                          就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,                                        发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,                                        也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送                                        的第一个高位字节

                                      所以:网络字节序就是大端字节序。
                                      但是我们系统的本机字节序是小端字节序,因此需要对应的接口进                                          行转换

addrlen: 地址的长度  实际上就是struct sockaddr_in这个类型的长度

返回值:成功返回0,失败返回-1,同时errno被设置

III 字节序转换

 SYNOPSIS#include <arpa/inet.h>//将主机字节序转换为网络字节序uint32_t htonl(uint32_t hostlong);uint16_t htons(uint16_t hostshort); //将网络字节序转换为主机字节序uint32_t ntohl(uint32_t netlong);uint16_t ntohs(uint16_t netshort);

函数说明:

说明:h -----host;n----network ;s------short;l----long。
htons()--"Host to Network Short"
htonl()--"Host to Network Long"
ntohs()--"Network to Host Short"
ntohl()--"Network to Host Long"
现在我们需要将主机字节序转换为网络字节序,选用短整型就可以,所以我们选用htons

IV 地址转换

上面有讲到点分式,网络字节序,主机字节序。这些都是ip在不同应用中的格式。

以ip地址127.0.0.1为例:

第一步   127   .     0     .     0      .    1   把IP地址每一部分转换为8位的二进制数。

第二步 01111111   00000000    00000000    00000001    =   2130706433   (主机字节序)

            然后把上面的四部分二进制数从右往左按部分重新排列,那就变为:

第三步 00000001  00000000    00000000    01111111     =   16777343        (网络字节序)

以下就是一些地址转换函数:

    SYNOPSIS#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);in_addr_t inet_addr(const char *cp);//如果是结构体里面用结构体  采用这个就可以了in_addr_t inet_network(const char *cp);char *inet_ntoa(struct in_addr in);//将得到的ip地址转换成点分式字符串struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host);in_addr_t inet_lnaof(struct in_addr in);

V 监听

    NAME 名称listen - listen for connections on a socket 在一个套接字上倾听连接//创建一个监听队列,监听我们的连接SYNOPSIS 概述#include <sys/socket.h>int listen(int s, int backlog);

参数解释

s:表示在哪个套接字上面进行监听

backlog:你需要创建多长的队列,在这里我们需求不大,队列5 -10就可以
返回值:成功返回0,失败返回-1,同时errno被设置

VI accept

 NAME 名称accept - 在一个套接字上接收一个连接SYNOPSIS 概述#include <sys/types.h>#include <sys/socket.h>int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

参数解释:

s:套接字
addr:保存连接对方的ip地址,实际上就是客户端的
addrlen:地址的长度,一定要带长度进去
返回值:返回一个连接套接字,服务器的通信是基于这个连接套接字的
               失败返回-1,同时errno被设置

VII connect

    NAMEconnect - initiate a connection on a socket//连接服务器SYNOPSIS#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

 sockfd:套接字
 addr:服务器的ip地址,你需要提前准备
 addrlen:这个地址的长度
 返回值:成功返回0,失败返回-1,同时errno被设置

VIII 从套接字接收信息

SYNOPSIS#include <sys/types.h>#include <sys/socket.h>  ssize_t read(int fd, void *buf, size_t count);ssize_t recv(int sockfd, void *buf, size_t len, int flags);ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

TCP上面三个函数都可以用,但是UDP是无连接的,因此只能使用recvfrom

recvfrom参数解释

前面三个参数请参数read的
flags:一个标志  填0即可
src_addr:保存对方的ip地址
addrlen:保存对方的ip地址长度
返回值:成功返回实际读到的字节数
               失败返回-1,同时errno被设置   

IX 从套接字发送消息

#include <sys/types.h>#include <sys/socket.h>ssize_t write(int fd, const void *buf, size_t count);int send(int s, const void *msg, size_t len, int flags);int  sendto(int s, const void *msg, size_t len, int flags, const structsockaddr *to, socklen_t tolen);

TCP上面三个函数都可以用,UDP只能使用sendto

参数解释

flags:一个标志
to:对方的ip地址 你要把这个消息发送给谁
tolen:你的地址的长度
返回值:成功返回实际发送的字节数
              失败返回-1,同时errno被设置

X 关闭套接字

SYNOPSIS#include <sys/socket.h>int close(int fd);//关闭套接字的读写int shutdown(int sockfd, int how);

参数解释

sockfd:套接字
how:怎么关闭
            SHUT_RD     关闭读
            SHUT_WR     关闭写 
            SHUT_RDWR   关闭读写

5、网络配置

1、确保你的网卡里面有两个虚拟网卡,你的有线网卡的型号也在这里面看
      在更改适配器里面看是否有VMnet1 VMnet8 
2、配置电脑的有线网卡ip

     进入更改适配器选项-> 右击你的有线网卡 -> 属性 -> TCP/IPV4 -> 使用下面ip地址 ->设置你的ip -> 确定

     其中: 192.168.1.x -> 电脑
                 192.168.1.y -> 乌班图
                 192.168.1.z -> 开发板
                  x,y,z在10 ~ 250之间,不相同即可

    子网掩码 255.255.255.0
    网关:192.168.1.1

3、配置ubuntu的ip

     首先关闭ubuntu
     以管理员方式打开VMware,不要打开乌班图(选中这个乌班图即可)
     palyer版本 -> player -> 虚拟机设置 -> 网络适配器 -> 选择桥接模式 -> 适配适配器
                -> 一定要选择你的有线网卡 -> 前面的√只打这一个 -> 确定 -> 开启这个乌班图
     pro版本 -> 编辑 -> 虚拟网络编辑器 -> 桥接至 你的有线网卡(不要选择自动) -> 确定

     开启乌班图
     右上键电源那个地方点击 -> 有线连接 -> 有线关闭 -> 右边的齿轮点进去-> IPV4 -> 手动 -> 按照windows填的方式填(但是ip不能和window一样) -> 应用 -> 打开有线连接
     在终端我们可以看一下自己的ip是否改好,ifconfig命令
      可以ping我们的windows的ip
      ping 192.168.1.x -> 没有看到time是多少的就是没有通

4、配置开发板的ip

      进入开发板的profile文件,写入 ifconfig eth0 192.168.1.z netmask 255.255.255.0 up(将192.168.1.z改成你自己设的具体的IP),这样开发板每次开机都会自己开网。

6、练习:实现简单的网络编程,客户端和服务器端可以实现通信

tcp_client.c

//客户端
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
//全局的套接字
int sockfd = -1;//将套接字创建好  并且绑定 监听
//将ip地址和端口号传进来 端口号释放需要时间(轮询机制)
void TcpInit(const char * ipaddr,unsigned short port)
{//1 创建套接字 ---- 什么2都是文件,因此你的网络通信也是一个文件sockfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == sockfd){perror("server socket error");exit(1);//没有必要运行了}//2 我们需要将服务器的IP地址绑定到套接字struct sockaddr_in sa;sa.sin_family = AF_INET;//协议族sa.sin_port = htons(port);//端口号  内存是小端的 我们要转大端sa.sin_addr.s_addr = inet_addr(ipaddr);//将我们点分式的ip地址转换为一个大端整数//连接服务器int r = connect(sockfd,(struct sockaddr *)&sa,sizeof(sa));if(-1 == r){perror("connect error");exit(2);}}//开始正常的收发
void function(void)
{char buf[1024] = {0};while(1){printf("输入你要发送的信息(输入quit退出):");fflush(stdout);scanf("%s",buf);if(!strcmp(buf,"quit")){break;}send(sockfd,buf,strlen(buf) + 1,0);recv(sockfd,buf,1024,0);printf("服务器回我的信息是:%s\n",buf);}
}int main(int argc,char * argv[])
{if(argc < 3){printf("参数都不齐\n");return -1;}TcpInit(argv[1],atoi(argv[2]));function();close(sockfd);return 0;
}

tcp_sever.c

//服务器
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>//全局的套接字
int sockfd = -1;//将套接字创建好  并且绑定 监听
//将ip地址和端口号传进来 端口号释放需要时间(轮询机制)
void TcpInit(const char * ipaddr,unsigned short port)
{//1 创建套接字 ---- 神马都是文件,因此你的网络通信也是一个文件sockfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == sockfd){perror("server socket error");exit(1);//没有必要运行了}//2 我们需要将服务器的IP地址绑定到套接字struct sockaddr_in sa;sa.sin_family = AF_INET;//协议族sa.sin_port = htons(port);//端口号  内存是小端的 我们要转大端sa.sin_addr.s_addr = inet_addr(ipaddr);//将我们点分式的ip地址转换为一个大端整数//printf("ipaddr = %x port = %x\n",inet_addr(ipaddr),htons(port));int r = bind(sockfd,(struct sockaddr *)&sa,sizeof(sa));if(-1 == r){perror("server bind error");exit(2);//没有必要运行了}//3 监听连接 ---- 创建一个监听队列   建立5个10个可以了listen(sockfd,5);}//专门用于去服务一个客户的线程
void * ClinetFunction(void * arg)
{pthread_detach(pthread_self());//将其分离int * accceptfd = (int *)arg;printf(" * accceptfd = %d\n", * accceptfd);char buf[1024] = {0};//你发什么信息过来  我就在这个信息之前加上一节 然后回发给你while(1){char sendbuf[1024] = {"SB250->"};int r = recv(*accceptfd,buf,1024,0);//阻塞等待数据过来if(-1 == r){perror("recv error");break;}else if(0 == r)//客户端已经断了{printf("对方断开连接了\n");break;}else//接收到信息了{printf("recv buf = %s\n",buf);strcat(sendbuf,buf);send(*accceptfd,sendbuf,strlen(sendbuf) + 1,0);}}close(*accceptfd);free(accceptfd);}//等待客户端的连接 
void waitconnect(void)
{//我们要基于这个连接套接字去通信struct sockaddr_in sa;socklen_t addrlen = sizeof(sa);while(1){printf("一直等待对方的连接.......\n");int * accceptfd = malloc(4);//避免释放 因此我们要动态内存分配才可以*accceptfd = accept(sockfd,(struct sockaddr *)&sa,&addrlen);printf("连接者为:%s %d\n",inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));//开一个线程出去  让它去服务与我的连接pthread_t thread;if(pthread_create(&thread,NULL,ClinetFunction,(void *)accceptfd) != 0){perror("create thread error");continue;}}close(sockfd);
}//通过main函数的参数 我们将这个ip地址和端口给进去
//./a.out 192.168.31.251 8888
int main(int argc,char * argv[])
{if(argc < 3){printf("参数都不齐\n");return -1;}TcpInit(argv[1],atoi(argv[2]));waitconnect();return 0;
}

参考博客:

计算机网络——网络字节序(大端字节序(Big Endian)\小端字节序(Little Endian))-CSDN博客

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

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

相关文章

WeNet语音识别分词制作词云图

在线体验 ,点击识别语音需要等待一会&#xff0c;文件太大缓存会报错 介绍 本篇博客将介绍如何使用 Streamlit、jieba、wenet 和其他 Python 库&#xff0c;结合语音识别&#xff08;WeNet&#xff09;和词云生成&#xff0c;构建一个功能丰富的应用程序。我们将深入了解代码…

JavaScript 中类和构造函数的区别

JavaScript 中的类和构造函数在实现上有一些区别&#xff0c;但它们的目的相同&#xff0c;都是用于创建对象。 构造函数是一种特殊的函数&#xff0c;它用于创建对象。构造函数使用 new 关键字来创建一个对象实例&#xff0c;并将属性和方法添加到该实例上。构造函数一般以大…

XXL-JOB学习笔记-基于注解实现自动注册新建任务

项目每次注册新建任务都需要手动操作配置xxl-job&#xff0c;不同的环境都需要手动操作配置一次&#xff0c;比较麻烦&#xff0c;为此想要简化相关的手动操作工作&#xff0c;基于注解的形式实现自动注册新建任务。 本篇是在之前一篇基于代码实现新建任务的基础上进一步实现。…

AUTOSAR从入门到精通- 虚拟功能总线(RTE)(三)

目录 前言 RTE的主要功能 几个高频面试题目 RTE基础面试题目 什么是数据转换?

第2课 使用FFmpeg读取rtmp流并用openCV显示视频

本课对应源文件下载链接&#xff1a; https://download.csdn.net/download/XiBuQiuChong/88680079 这节课我们开始利用ffmpeg和opencv来实现一个rtmp播放器。播放器的最基本功能其实就两个:显示画面和播放声音。在实现这两个功能前&#xff0c;我们需要先用ffmpeg连接到rtmp服…

LVS负载均衡配置虚拟引起微服务注册混乱

线上小程序突然报错&#xff0c;查看网关日志&#xff0c;访问下游微服务A时大量报错&#xff1a; 1&#xff09;检查微服务是否未注册。登录eureka页面&#xff0c;发现三个节点均正常注册 三个微服务节点地址分别为&#xff1a;13.9.1.91:8080&#xff0c;13.9.1.92:8080和1…

开源服务指南使用手册

开源服务指南是什么&#xff1f;从哪里来&#xff1f;往哪里去&#xff1f; 定位 用中文推荐优质开源项目&#xff0c;让开发者更容易找到趁手的开源工具。 Slogan 发现开源之美&#xff0c;碰撞无限可能。 我们想要让大家知道更多优秀的开源项目&#xff0c;发现开源的美…

ARM CCA机密计算软件架构之软件堆栈概述

Arm CCA平台通过硬件添加和固件组件的混合方式实现,例如在处理元素(PEs)中的RME以及特定的固件组件,特别是监视器和领域管理监视器。本节介绍Arm CCA平台的软件堆栈。 软件堆栈概述 领域VM的执行旨在与Normal world(正常世界)隔离,领域VM由Normal world Host(正常世界…

【软件工程】融通未来的工艺:深度解析统一过程在软件开发中的角色

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言&#xff1a; 正文 统一过程&#xff08;Unified Process&#xff09; 介绍和解释&#xff1a; 应用&#xff1a; 优缺点&#xf…

C/C++ 函数的默认参数

下面介绍一项新内容 - 默认参数。 默认参数指的是当函数调用中省略了实参时自动使用的一个值。 例如&#xff0c;如果将 void wow (int n)设置成n 有默认值为1&#xff0c;则函数调用 wow()相当于 wow(1)这极大地提高了使用函数的灵活性。 假设有一个名为left()的函数&#xff…

SpringIOC之ApplicationObjectSupport

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

pytorch与cuda版本对应关系汇总

pytorch与cuda版本关系 cuda版本支持pytorch版本cuda10.21.5 ~ 1.12cuda11.01.7 ~ 1.7.1cuda11.11.8 ~ 1.10.1cuda11.31.8.1 ~ 1.12.1cuda11.61.12.0 ~ 1.13.1cuda11.71.13.0 ~ 2.0.1cuda11.82.0.0 ~ 2.1.1cuda12.12.1.0 ~ 2.1.1 cuda 与 cudnn关系 cuda版本支持cudnn版本cu…

微信小程序:跳转页面

实际调用需要根据自己业务实际情况决定&#xff0c;虽然各种方式一定程度上能减少内存损耗&#xff0c;但是业务上面流转优化才是最终要满足的&#xff0c;一定要从业务流转去优化去考虑&#xff0c;不要为了性能增加了流转复杂度 1、wx.navigateTo 保留当前页面&#xff0c;跳…

12、defer

defer defer意思是推迟、延迟。语法很简单&#xff0c;就在正常的语句前加上defer就可以了。 ​ 在某函数中使用defer语句&#xff0c;会使得defer后跟的语句进行延迟处理&#xff0c;当该函数即将返回时&#xff0c;或发生panic时&#xff0c;defer后语句开始执行。注意os.E…

算法基础之最短Hamilton路径

最短Hamilton路径 核心思想&#xff1a; 数位dp 用二进制数 存当前所有点 遍历过为1 遍历i图中j点 若j点走过 则求j点路径长度 f[state][j] f[state_k][k] w[k][j] state为除去j点的图 #include<iostream>#include<cstring>#include<algorithm>using n…

java web开发

什么是javaEE javaEE是企业版 是一个web开发平台 规范了web技术标准 技术有 JDBC JSP XML Servlet 硬件服务器&#xff1a;和pc一样属于计算机 软件服务器&#xff1a;文件服务器 数据库服务器 应用服务器java EE 应用服务器 是收费的 实现了EE技术 web 服务器 实现了部分技…

<JavaEE> TCP 的通信机制(一) -- 确认应答 和 超时重传

目录 TCP的通信机制的核心特性 一、确认应答 1&#xff09;什么是确认应答&#xff1f; 2&#xff09;如何“确认”&#xff1f; 3&#xff09;如何“应答”&#xff1f; 二、超时重传 1&#xff09;丢包的概念 2&#xff09;什么是超时重传&#xff1f; 3&#xff09…

详解信道容量,信道速率,安全速率的区别

目录 一. 信道容量与信道速率 二. 小结 三. 安全速率与物理层安全 3.1 香农物理层安全模型 3.2 安全信道速率 四. 补充安全中断概率&#xff08;Secrecy Outage Probability, SOP&#xff09; 五. 补充安全分集度&#xff08;Secrecy Diversity Order, SDO&#xff09; …

如何通过 useMemo 和 useCallback 提升你的 React 应用性能

背景 在 React 中&#xff0c;useMemo 和 useCallback 这两个 hook 是我们优化应用性能的有力工具。它们会返回 memoized 版本的值或函数&#xff0c;只在依赖项发生变化时才进行重新计算或定义。 Hook 介绍 useMemo useMemo 的作用是返回一个 memoized 值&#xff0c;它接…

AAAI 2024 | 用逆向思维图(ReX-GoT)进行多选对话常识推理

©PaperWeekly 原创 作者 | 郑理 单位 | 武汉大学硕士生 研究方向 | 自然语言处理 论文题目&#xff1a; Reverse Multi-Choice Dialogue Commonsense Inference with Graph-of-Thought 论文作者&#xff1a; 郑理&#xff0c;费豪&#xff0c;李霏&#xff0c;李波波&am…