Linux应用——socket函数及TCP通信

        网络通信实质上也是实现进程间通信,只是与之前进程间通信不同的是,现在在不同的计算机上进行进程间通信。比如:利用QQ工具实现聊天,在两个电脑上有不同的QQ进程之间在通信。而网络通信是如何使用进程间通信呢?采用的是socket技术。下面将对socket技术进行学习;

一、socket介绍

           所谓 socket(套接字),本身的意思是插座的意思。对网络中不同主机上的应用进程之间进行双向通信的端点的抽象 。socket将数据包的层层协议进行简化了,将四层网络模型简化成端到端的通信。一个sicket就是网络上进程通信的一端。它能够将层层协议的数据封装好,我们只需要学习使用对应的API即可。

        socket 可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的 API,也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 socket 中,该 socket 通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 socket 中,使对方能够接收到这段信息。socket 是由 IP 地址端口结合的,提供向应用层进程传送数据包的机制。

        LINUX中一切皆文件!socket质为内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux 系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递

socket通信分两部分:
- 服务器端:被动接受连接,一般不会主动发起连接
- 客户端:主动向服务器发起连接
socket是一套通信的接口,Linux 和 Windows 都有,但是有一些细微的差别.

        socket是通过文件描述符操作数据,先通过fd往主机A中的写缓冲区写入数据,数据经过四层网络模型加上对应的封装,再通过数据链路层传输至主机B,主机B经过分用,将数据传至读缓冲区,主机B的fd通过读缓冲区获得主机A传递的数据。我们只需要调用API进行数据的读与写,不需要去查看底层是如何实现的。

二、字节序

2.1简介

        现代 CPU 的累加器一次都能装载(至少)4 字节(这里考虑 32 位机),即一个整数。那么这 4字节在内存中排列的顺序将影响它被累加器装载成的整数的值,这就是字节序问题。

        字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。

        字节序分为大端字节序(Big-Endian)小端字节序(Little-Endian)。大端字节序是指一个整数的最高位字节(23 ~ 31 bit)存储在内存的低地址处,低位字节(0 ~ 7 bit)存储在内存的高地址处;小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地址处。

2.2举例

小端字节序:

0X 01 02 03 04 四个字节;

内存方向:低位——高位;

内存存储顺序:04 03 02 01(高字节在高位,低字节在低位);

大端字节序:

0X 01 02 03 04 四个字节 ;

内存方向:低位——高位;

内存存储顺序: 01 02 03 04(高字节在低位,低字节在高位);

不同计算机的存储方向不同,那如果不同大小端的主机进行通信时, 如果不达成一致的规则,通信双方将无法进行正确的编码/译码从而导致通信失败。

2.3判断大小端

#include <stdio.h>int main()
{
union 
{short value;//两个字节;char bytes[sizeof(short)];//char[2];
}text;text.value=0x0102;
if(text.bytes[0]==1&&(text.bytes[1]==2))
{printf("该系统为大端存储\n");
}else if(text.bytes[0]==2&&(text.bytes[1]==1))
{printf("该系统为小端存储\n");
}else
{printf("未知\n");
}return 0;
}

运行结果: 

        程序中用到联合体,联合体又称共用体,是指在同一段内存单元中存放不同类型的变量,先将数据通过value存储,再通过数组取出来,使之上是同一块地址的数据。

三、字节序转换函数

        当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误的接收。

        解决问题的方法是:发送端总是要把数据换成大端字节数据后在发送,而接收端知道对方传过来的数据总是以大端字节序,所以接收端可以根据自身采用的字节决定是否对接收到的数据进行转化(小端机转化,大端机不转化)。

        网络字节顺序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用大端排序方式。

#include <arpa/inet.h>
// 转换端口
uint16_t htons(uint16_t hostshort);
// 主机字节序 - 网络字节序(short类型,端口16位)

uint16_t ntohs(uint16_t netshort);
//网络字节序 - 主机字节序
// 转IP
uint32_t htonl(uint32_t hostlong);
// 主机字节序 - 网络字节序(long类型,IP32位)
uint32_t ntohl(uint32_t netlong);
// 主机字节序 - 网络字节序

 案例操作:

#include <stdio.h>
#include <arpa/inet.h>
int main()
{//htons: 转换端口;unsigned short a=0x0102;//两个字节,在计算机中存储,小端存储;printf("%x\n",a);//输出结果应该为01 02unsigned short b= htons(a);//转换为网络字节序,大端排序。printf("%x\n",b);//输出结果应该为02 01printf("-------------------------\n");//htonl:转化IPchar buf[4]={192,168,1,100};//四个字节,在计算机中存储,小端存储;int n=* (int *)buf;int sum= htonl(n);unsigned char *p=(char *)&sum;printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));//输出结果应该为100 1 168 192printf("-------------------------\n");//ntohl:转IPunsigned char buf1[4]={1,1,168,192};//四个字节,网络字节序,大端排序;int n1=*(int*)buf1;int sum1=ntohl(n1);unsigned char *p1=(unsigned char *)&sum1;printf("%d %d %d %d\n",*p1,*(p1+1),*(p1+2),*(p1+3));//输出结果应该为 192 168 1 1printf("-------------------------\n");//ntohs:转换端口;unsigned short a1=0x3412;//两个字节,在网络字节序,大端排序;printf("%x\n",a1);//输出结果应该为34 12unsigned short b1=ntohs(a1);//转化为计算机存储,小端存储;printf("%x\n",b1);//输出结果应该为12 34return 0;
}

运行结果: 

四、socket地址

       客户端访问——>服务器;服务器需要告诉客户端IP、端口号;

        socket是一个结构体,用来封装端口号和IP等信息。

        后面socket相关的api中需要用到socket地址;

 socket 网络编程接口中表示 socket 地址的是结构体 sockaddr;

#include <bits/socket.h>
typedef unsigned short int sa_family_t;struct sockaddr {
sa_family_t sa_family;
char  sa_data[14];
};

        sa_family 成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。常见的协议族(protocol family,也称 domain)和对应的地址族入下所示:

        sa_data 成员用于存放 socket 地址值。但是,不同的协议族的地址值具有不同的含义和长度,如下所示:

        由上表可知,14 字节的 sa_data 根本无法容纳多数协议族的地址值。因此,Linux 定义了下面这个新的通用的 socket 地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的。 

上面的结构体是给IPV4用的,后面的这个才是为IPV6应用;

#include <bits/socket.h>
struct sockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[ 128 - sizeof(__ss_align) ];
};
typedef unsigned short int sa_family_t;

         __ss_padding于存放 socket 地址值,包括IPV6的端口号,流标识,地址,范围ID等;

专用 socket 地址

        很多网络编程函数诞生早于 IPv4 协议,那时候都使用的是 struct sockaddr 结构体,为了向前兼容,现在sockaddr 退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in 还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。

#include <netinet/in.h>
struct sockaddr_in
{sa_family_t sin_family;
/* __SOCKADDR_COMMON(sin_) */in_port_t sin_port;         /* Port number. */struct in_addr sin_addr;    /* Internet address. *//* Pad to size of `struct sockaddr'. */unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE -sizeof (in_port_t) - sizeof (struct in_addr)];
};  
struct in_addr
{in_addr_t s_addr;
};
struct sockaddr_in6
{sa_family_t sin6_family;in_port_t sin6_port;
/* Transport layer port # */uint32_t sin6_flowinfo; /* IPv6 flow information */struct in6_addr sin6_addr; /* IPv6 address */uint32_t sin6_scope_id; /* IPv6 scope-id */
};
typedef unsigned short  uint16_t;
typedef unsigned int    uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

         所有专用 socket 地址(以及 sockaddr_storage)类型的变量在实际使用时都需要转化为通用 socket 地址类型 sockaddr(强制转化即可),因为所有 socket 编程接口使用的地址参数类型都是 sockaddr。

五、IP地址转换

        通常,人们习惯可读性好的字符串表示IP地址,比如用点分十进制字符串表示IPV4地址,以及用十六进制数字串表示IPV6地址。但是编程的时候,我们需要先把它们转化为整数(二进制数)方便实用,而记录日志时则相反,我们要把整数表示的IP地址转化为可读的字符串。下面3个函数可用于点分十进制字符串表示的IPV4地址和网络字节序整数表示的IPV4地址之间的转换。

1、将字符串的IP转化成整数;

2、主机、网络字节序的转换。

        下面的只适合IPV4的函数操作: 

 #include <arpa/inet.h>
        in_addr_t inet_addr(const char *cp);
        int inet_aton(const char *cp, struct in_addr *inp);
        char *inet_ntoa(struct in_addr in);

        下面这对更新的函数也能完成前面 3 个函数同样的功能,并且它们同时适用 IPv4 地址和 IPv6 地址: 

#include <arpa/inet.h>
// p:点分十进制的IP字符串,n:表示network,网络字节序的整数
int inet_pton(int af, const char *src, void *dst);
af:地址族: AF_INET  AF_INET6
   src:需要转换的点分十进制的IP字符串
   dst:转换后的结果保存在这个里面
// 将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
af:地址族: AF_INET  AF_INET6
   src: 要转换的ip的整数的地址
   dst: 转换成IP地址字符串保存的地方
   size:第三个参数的大小(数组的大小)
返回值:返回转换后的数据的地址(字符串),和 dst 是一样的

#include <arpa/inet.h>
#include <stdio.h>int main()
{//将点分十进制的IP字符串转化为网络字节序的整数;//创建一个IP字符串;char buff[]="192.168.1.4";//点分十进制字符串;unsigned int num=0;inet_pton(AF_INET,buff,&num);unsigned char *p=(unsigned char *)(&num);printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));printf("------------------------\n");//将网络字节的IP整数转化为十进制的字符串;char buff1[16];inet_ntop(AF_INET, &num, buff1, 16);printf("%s\n",buff1);return 0;
}

 六、TCP通信流程

TCP与UDP:

        都是传输层协议;

UDP:用户数据报协议,面向无连接,可以单播,多播,广播;面向数据报,不可靠。

TCP:传输控制协议,面向连接的,可靠的,基于字节流,仅支持单播传输。        

UDPTCP
是否创建连接无连接面向连接
是否可靠不可靠可靠的
连接的对象个数一对一、一对多、多对一、多对多支持一对一
传输方式面向数据报面向字节流
首部开销8字节

最少20字节

适应场景实时应用可靠性高的应用

 TCP通信流程:

服务器端(被动接收连接的角色)

1、创建一个 用于监听的套接字(fd);

        监听:监听有客户端的连接;

        套接字:实质就是一个文件描述符;

2、将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息);

        客户端连接服务器的时候使用的就是这个IP和端口。

3、设置监听,监听的fd开始工作。

4、阻塞等待,当有客户端发起连接,解除阻塞,接受客户端的连接,会得到一个和客户端通信的套接字(fd)。

5、通信

        -接收数据

        -发送数据

6、通信结束,断开连接。

客户端

1、创建一个用于通信的套接字(fd)

2、连接服务器,需要指定连接的服务器的IP和端口;

3、连接成功了,客户端直接与服务器通信。

        -接收数据

        -发送数据

4、通信结束,断开连接。

七、socket函数

涉及头文件:

        #include <sys/types.h>      
        #include <sys/socket.h>
        #include <arpa/inet.h> // 包含了这个头文件,上面两个就可以省略;

int sockrt(int domain, int type,int protocol);

功能:

        创建一个套接字;

参数:

        domain:协议族;

                AF_INET : ipv4  
                AF_INET6 : ipv6     
                AF_UNIX, AF_LOCAL : 本地套接字通信(进程间通信)

        type:通信过程中使用的协议类型

                SOCK_STREAM : 流式协议
                SOCK_DGRAM : 报式协议

        protocol:具体的一个协议。一般写0;

                如果参数2写的是SOCK_STREAM:流式协议默认使用TCP;

                如果参数2写的是SOCK_DGRAM:报式协议默认是UDP;

返回值:

        成功,返回文件描述符,操作的就是内核缓冲区;

        失败:-1;               

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

功能:

        绑定,将fd和本地的IP+端口号进行绑定;

参数:

        sockfd:通过socket函数获得的文件描述符;

        addr:需要绑定的sockrt地址,这个地址封装了ip和端口号的信息;

        addrlen:第二个参数结构体占的内存大小;

返回值:

        成功:0;

        失败:-1;

 int listen(int sockfd, int backlog);

功能:

        监听这个 socket上的连接;

参数:

        sockfd:通过socket函数获得的文件描述符;

        backlog:未连接和已经连接的和最大值;5;

返回值:

        成功:0;

        失败:-1;

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

        接收客户端连接,默认是一个阻塞的函数,阻塞等待客户端连接。
 参数:   
           sockfd : 用于监听的文件描述符
           addr : 传出参数,记录了连接成功后客户端的地址信息(ip,port)
           addrlen : 指定第二个参数的对应的内存大小
  返回值:
           成功 :用于通信的文件描述符
           失败 :  1 。

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

 功能: 客户端连接服务器
 参数:
            sockfd : 用于通信的文件描述符
            addr : 客户端要连接的服务器的地址信息
           addrlen : 第二个参数的内存大小
返回值:

                成功: 0

                失败 :-1

ssize_t write(int fd, const void *buf, size_t count);// 写数据
ssize_t read(int fd, void *buf, size_t count);// 读数据

八、TCP通信实现      

8.1服务器端    

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{// 1、创建用于监听的套接字int lfd = socket(AF_INET, SOCK_STREAM,0 );if(lfd==-1){perror("socket");exit(-1);}// 2、绑定struct sockaddr_in saddr;saddr.sin_family=AF_INET;//inet_pton(AF_INET,"192.168.193.128", saddr.sin_addr.s_addr);saddr.sin_addr.s_addr=INADDR_ANY;saddr.sin_port=htons(9999);int ret=bind(lfd,(const struct sockaddr *)&saddr,sizeof(saddr));if(ret==-1){perror("socket");exit(-1);}//3、监听ret = listen(lfd,8);if(ret==-1){perror("listen");exit(-1);}//4、接收客户端连接struct sockaddr_in clientadder;socklen_t len=sizeof(clientadder); int cfd=accept(lfd,(struct sockaddr *)&clientadder, &len);if(cfd==-1){perror("accept");exit(-1);}
//输出客户端信息char clinetIP[16];inet_ntop(AF_INET, &clientadder.sin_addr.s_addr,clinetIP,sizeof(clinetIP));unsigned short clientport=ntohs(clientadder.sin_port);printf("IP:%s\n",clinetIP);printf("Port:%d\n",clientport);//5、通信
//获取客户端数据
char recivebuff[1024]={0};
int num =read(cfd, recivebuff, sizeof(recivebuff));// 写数据
if(num==-1)
{
perror("read");exit(-1);
}else if(num>0)
{printf("recive client data:%s\n",recivebuff);}
else if(num==0)
{
//表示客户端断开连接。
printf("clinet closed...\n");
}
//给客户端发送信息
char *data="hello,1234!";write(cfd, data, strlen(data));// 读数据//关闭文件描述符close(cfd);close(lfd);return 0;
}

运行结果: 

 8.2客户端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{//1、创建套接字int fd = socket(AF_INET,SOCK_STREAM,0);if(fd==-1){perror("socket");exit(-1);}//2、连接服务器端struct sockaddr_in serve_addr;serve_addr.sin_family=AF_INET;inet_pton(AF_INET,"192.168.254.170",&serve_addr.sin_addr.s_addr);serve_addr.sin_port=htons(9999);int ret= connect(fd,(const struct sockaddr *)&serve_addr,sizeof(serve_addr));if(ret==-1){perror("connect");exit(-1);}//3、进行通信char * data="I am client\n";write(fd, data, strlen(data));char readbuff[1024]={0};int len =read(fd,readbuff,sizeof(readbuff));if(len==-1)
{
perror("read");exit(-1);
}else if(len>0)
{printf("recive client data:%s\n",readbuff);}
else if(len==0)
{
//表示服务器端断开连接。
printf("serve closed...\n");
}
//关闭文件描述符;close(fd);return 0;}

运行结果: 

上面的代码是,服务器与客户端只能一次通信,各自发送提前准备好的数据;

下面的代码是多次通信,而且客户端的数据由键盘输入,服务器收到什么数据,就发送什么数据。

服务器:

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{// 1、创建用于监听的套接字int lfd = socket(AF_INET, SOCK_STREAM,0 );if(lfd==-1){perror("socket");exit(-1);}// 2、绑定struct sockaddr_in saddr;saddr.sin_family=AF_INET;//inet_pton(AF_INET,"192.168.193.128", saddr.sin_addr.s_addr);saddr.sin_addr.s_addr=INADDR_ANY;saddr.sin_port=htons(9999);int ret=bind(lfd,(const struct sockaddr *)&saddr,sizeof(saddr));if(ret==-1){perror("socket");exit(-1);}//3、监听ret = listen(lfd,8);if(ret==-1){perror("listen");exit(-1);}//4、接收客户端连接struct sockaddr_in clientadder;socklen_t len=sizeof(clientadder); int cfd=accept(lfd,(struct sockaddr *)&clientadder, &len);if(cfd==-1){perror("accept");exit(-1);}
//输出客户端信息char clinetIP[16];inet_ntop(AF_INET, &clientadder.sin_addr.s_addr,clinetIP,sizeof(clinetIP));unsigned short clientport=ntohs(clientadder.sin_port);printf("IP:%s\n",clinetIP);printf("Port:%d\n",clientport);//5、通信
//获取客户端数据char recivebuff[1024]={0};
while(1){int num =read(cfd, recivebuff, sizeof(recivebuff));// 读数据if(num==-1){perror("read");exit(-1);}else if(num>0){printf("recive client data:%s\n",recivebuff);}else if(num==0){//表示客户端断开连接。printf("clinet closed...\n");break;}//给客户端发送信息write(cfd, recivebuff, sizeof(recivebuff));// 写数据// char *data="hello,1234!";//  write(cfd, data, strlen(data));// 读数据
}//关闭文件描述符close(cfd);close(lfd);return 0;
}

客户端 :


#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{//1、创建套接字int fd = socket(AF_INET,SOCK_STREAM,0);if(fd==-1){perror("socket");exit(-1);}//2、连接服务器端struct sockaddr_in serve_addr;serve_addr.sin_family=AF_INET;inet_pton(AF_INET,"192.168.254.170",&serve_addr.sin_addr.s_addr);serve_addr.sin_port=htons(9999);int ret= connect(fd,(const struct sockaddr *)&serve_addr,sizeof(serve_addr));if(ret==-1){perror("connect");exit(-1);}//3、进行通信char readbuff[1024]={0};char writebuff[1024]={0};while(1){memset(writebuff,0,sizeof(writebuff));printf("请输入内容:\n");scanf("%s",writebuff);//char * data="I am client";write(fd, writebuff, sizeof(writebuff));sleep(1);int len =read(fd,readbuff,sizeof(readbuff));if(len==-1){perror("read");exit(-1);}else if(len>0){printf("recive client data:%s\n",readbuff);}else if(len==0){//表示服务器端断开连接。printf("serve closed...\n");break;}}//关闭文件描述符;close(fd);return 0;}

 运行结果:

客户端:

服务器 :

        以上是利用socket实现了TCP通信的建立,并实现了客户端与服务器之间进行的数据的收发。

        创作不易,感谢大家多多支持!!!

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

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

相关文章

力扣高频SQL 50 题(基础版)第一题

文章目录 力扣高频SQL 50 题&#xff08;基础版&#xff09;第一题1757.可回收且低脂的产品题目说明思路分析实现过程准备数据&#xff1a;实现方式&#xff1a;结果截图&#xff1a; 力扣高频SQL 50 题&#xff08;基础版&#xff09;第一题 1757.可回收且低脂的产品 题目说…

pdf2docx - pdf 提取内容转 docx

文章目录 一、关于 pdf2docx主要功能限制 二、安装1、 PyPI2、从remote安装3、从源码安装4、卸载 三、转化 PDF例 1: convert all pages例 2: 转换指定页面例 3: multi-Processing例 4: 转换加密的pdf 四、提取表格五、命令行交互1、按页面范围2、按页码3、Multi-Processing 六…

Java之集合底层-数据结构

Java集合之数据结构 1 概述 数据结构是计算机科学中研究数据组织、存储和操作的一门学科。它涉及了如何组织和存储数据以及如何设计和实现不同的数据操作算法和技术。常见的据结构有线性数据结构&#xff08;含数组、链表、栈和队列等&#xff09;&#xff0c;非线性数据结构…

探索算法系列 - 双指针

目录 移动零&#xff08;原题链接&#xff09; 复写零&#xff08;原题链接&#xff09; 快乐数&#xff08;原题链接&#xff09; 盛最多水的容器&#xff08;原题链接&#xff09; 有效三角形的个数&#xff08;原题链接&#xff09; 查找总价格为目标值的两个商品&…

数据库表结构创建

一、原型图 二、分析 1、天气&#xff0c;值字段只有实测值&#xff0c;可用一个字段表示&#xff08;单位、来源同上&#xff09; 2、气温有默认值与实测值两个选项&#xff0c;一个字段无法表示默认值与实测值&#xff08;单位&#xff0c;来源同上&#xff09; 3、因为有…

SpringMVC 控制层框架-下

五、SpringMVC其他扩展 1. 异常处理机制 1.1 异常处理概念 开发过程中是不可避免地会出现各种异常情况&#xff0c;例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题&#xff0c;甚至直接导致程序崩溃。因此&#xff0c;在开发过程中&a…

LoFTR关键点特征匹配算法环境构建与图像匹配测试Demo

0&#xff0c;LoFTR CVPR 2021论文《LoFTR: Detector-Free Local Feature Matching with Transformers》开源代码 1&#xff0c;项目主页 LoFTR: Detector-Free Local Feature Matching with Transformers 2&#xff0c;GItHub主页 GitHub - zju3dv/LoFTR: Code for "…

Vue 状态管理 Vue CLI

Vue 状态管理 & Vue CLI 1、状态管理2、集中状态管理2.1 Vuex2.1.1 Vuex核心概念2.1.2 Vuex Store实例2.1.3 Vuex Getter2.1.4 Vuex Mutation2.1.4 Vuex Actions2.1.4 Vuex Module 2.2 Pinia2.2.1功能增强 3、Vuex 实现原理4、Pinia 实现原理5、CLI5.1 实现 1、状态管理 将…

vue 搜索框

效果 创建搜索组件&#xff1a; 在Vue项目中&#xff0c;首先需要创建一个搜索组件。这个组件通常包含一个输入框和一个搜索按钮。使用v-model指令将输入框与组件的数据属性&#xff08;如searchKeyword&#xff09;进行双向绑定&#xff0c;以便获取用户输入的关键词。处理搜索…

MongoDB教程(二十一):MongoDB大文件存储GridFS

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、GridFS…

科技云报道:算网筑基AI注智,中国联通如何讲出AI时代的“新故事”?

科技云报道原创。 AI从未停止进化&#xff0c;也从未停止给人类带来惊喜。 从ChatGPT代表的文生文、Dall-E代表的文生图&#xff0c;到Sora代表的文生视频&#xff0c;Suno为代表的文生音乐&#xff0c;生成式AI的“暴力美学”持续突破内容生产的天花板&#xff0c;大模型技术…

【LLM】-07-提示工程-聊天机器人

目录 1、给定身份 1.1、基础代码 1.2、聊天机器人 2、构建上下文 3、订餐机器人 3.1、窗口可视化 3.2、构建机器人 3.3、创建JSON摘要 利用会话形式&#xff0c;与具有个性化特性&#xff08;或专门为特定任务或行为设计&#xff09;的聊天机器人进行深度对话。 在 Ch…

vue import from

vue import from 导入文件&#xff0c;从XXXX路径&#xff1b;引入文件 import xxxx from “./minins/resize” import xxxx from “./minins/resize.js” vue.config.js 定义 : resolve(src)&#xff1b;就是指src 目录 import xxxx from “/utils/auth” im…

新版GPT-4omini上线!快!真TM快!

大半夜&#xff0c;OpenAI突然推出了GPT-4o mini版本。 当我看到这条消息时&#xff0c;正准备去睡觉。mini版本质上是GPT-4o模型的精简版本&#xff0c;没有什么革命性的创新&#xff0c;因此我并没有太在意。 结果今天早上一觉醒来发现伴随GPT-4o mini上线&#xff0c;官网和…

RAS--APEI 报错解析流程(2)

RAS--APEI 报错解析流程(1) 除了APEI 中除了GHES会记录错误&#xff0c;在Post过程中的错误通常是通过BERT Table汇报 1.BERT Boot Error Record Table is used to report unhandled errors that occurred in a previous boot&#xff0c;it is reported as a ‘one-time polle…

stats 监控 macOS 系统

Stats 监控 macOS 系统 CPU 利用率GPU 利用率内存使用情况磁盘利用率网络使用情况电池电量 brew install stats参考 stats github

Ansible的脚本-----playbook剧本【上】

目录 1.playbook剧本组成 2.playbook剧本实战演练 2.1 实战演练一&#xff1a;给被管理主机安装httpd服务 2.2 实战演练二&#xff1a;定义、引用变量 2.3 实战演练三&#xff1a;指定远程主机sudo切换用户 2.4 实战演练四&#xff1a;when条件判断 2.5 实战演练五&…

ElasticSearch(六)— 全文检索

一、match系列查询 前面讲到的query中的查询&#xff0c;都是精准查询。可以理解成跟在关系型数据库中的查询类似。match系列的查询&#xff0c;是全文检索的查询。会通过分词进行评分&#xff0c;匹配&#xff0c;再返回搜索结果。 1.1 match 查询 "query": {&qu…

.Net Core 微服务之Consul(三)-KV存储分布式锁

引言: 集合上两期.Net Core 微服务之Consul(一)(.Net Core 微服务之Consul(一)-CSDN博客) 。.Net Core 微服务之Consul(二)-集群搭建)(.Net Core 微服务之Consul(二)-集群搭建-CSDN博客) 目录 一. Consul KV 存储 1. KV 存储介绍 1.1 数据模型 1.2 一致性和…

Centos安装、迁移gitlab

Centos安装迁移gitlab 一、下载安装二、配置rb修改&#xff0c;起服务。三、访问web&#xff0c;个人偏好设置。四、数据迁移1、查看当前GitLab版本2、备份旧服务器的文件3、将上述备份文件拷贝到新服务器同一目录下&#xff0c;恢复GitLab4、停止新gitlab数据连接服务5、恢复备…