当前位置: 首页 > news >正文

Linux网络——TCP的运用

系列文章目录


文章目录

  • 系列文章目录
    • 一、服务端实现
      • 1.1 创建套接字socket
      • 1.2 指定网络接口并bind
      • 2.3 设置监听状态listen
      • 2.4 获取新链接accept
      • 2.5 接收数据并处理(服务)
      • 2.6 整体代码
    • 二、客户端实现
      • 2.1 创建套接字socket
      • 2.2 指定网络接口
      • 2.3 发起链接connect
      • 2.4 发送数据并接收
      • 2.5 整体代码
      • 2.6 绑定问题
    • 三、问题与改进
      • 3.1 问题描述
      • 3.2 解决方法
        • 3.2.1 问题版本
        • 3.2.2 多进程版
        • 3.4.3 进程池(暂未实现)
        • 3.4.4 多线程版
        • 3.4.5 线程池版
    • 四、TCP与UDP的对比


一、服务端实现

1.1 创建套接字socket

和上篇文章UDP的使用一致,创建套接字

调用系统接口socket函数,帮助我们创建套接字,本质是把文件和网卡关联起来
在这里插入图片描述

参数介绍:

domain:一个域,标识了这个套接字的通信类型(网络或者本地)
在这里插入图片描述

只用关注上面三个类,第一个与第二个AF_UNIX/AF_LOCAL表示本地通信,而AF_INET表示网络通信
type:套接字提供服务的类型
在这里插入图片描述
我们用UDP实现,所以使用SOCK_DGRAM
protocol:想使用的协议,默认为0即可,因为前面的两个参数决定了,就已经决定了是TCP还是UDP协议了

返回值:

成功则返回打开的文件描述符(指向网卡文件,其实就是文件描述符),失败返回-1

创建套接字的本质其实就是创建了一个文件描述符,并返回该文件描述符的值
只是该文件描述符是用于对应服务的网路数据传输

        // 1. 创建套接字_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){lg.LogMessage(Fatal, "socket error, sockfd : %d\n", _listensock);exit(1);}lg.LogMessage(Info, "socket success, sockfd : %d\n", _listensock);

1.2 指定网络接口并bind

和上篇文章UDP的使用一致,服务端需要手动bind

在这里插入图片描述

参数介绍:

socket:创建套接字的返回值
address:通用结构体(上一章Linux网络——网络套接字有详细介绍)
address_len:传入结构体的长度

我们要先定义一个sockaddr_in结构体,将结构体内对应的字段填充好,再将结构体作为参数传递
在这里插入图片描述

struct sockaddr_in {short int sin_family;           // 地址族,一般为AF_INET或PF_INETunsigned short int sin_port;    // 端口号,网络字节序struct in_addr sin_addr;        // IP地址unsigned char sin_zero[8];      // 用于填充,使sizeof(sockaddr_in)等于16
};

创建结构体后要先清空数据(初始化),我们可以用memset,也可以用系统接口:

#include <strings.h>void bzero(void *s, size_t n);

填充端口号的时候要注意端口号是两个字节的数据,涉及到大小端问题
在计算机中的普遍规定:在网络中传输的数据都是大端的
所以为了统一,无论我们机器是大端还是小端,在调用接口的时候,都将IP与端口号从主机序列转化为网路序列

端口号的接口

#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);

IP的接口
对于IP,其实有两步:首先将字符串转换为整型,再解决大小端问题
系统给了直接能解决这两个问题的接口

#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);struct in_addr inet_makeaddr(int net, int host);in_addr_t inet_lnaof(struct in_addr in);in_addr_t inet_netof(struct in_addr in);

这里的inet_addr就是把一个点分十进制的字符串转化成整数再进行大小端处理

代码:

		// 2. 指定网络接口并bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = bind(_listensock, (struct sockaddr *)&local, sizeof(local));if (n != 0){lg.LogMessage(Fatal, "bind error\n");exit(2);}lg.LogMessage(Debug, "bind socket success, sockfd: %d\n", _listensock);

2.3 设置监听状态listen

这里TCP跟UDP有所不同

要把socket套接字的状态设置为listen状态,只有这样才能一直获取新链接,接收新的链接请求

举个例子:
我们买东西如果出现了问题会去找客服,如果客服不在那么就回复不了,所以规定了客服在工作的时候必须要时刻接收回复消息,这个客服所处的状态就叫做监听状态

在这里插入图片描述

关于第二个参数backlog后边讲TCP协议的时候介绍,目前先直接用

		const static int default_backlog = 1;// 3. 设置socket为监听状态int m = listen(_listensock, default_backlog);if (m != 0){lg.LogMessage(Fatal, "listen error\n");exit(3);}lg.LogMessage(Debug, "listen socket success, sockfd: %d\n", _listensock);

做完这些,初始化工作就完成了,总代码

  void Init(){// 1. 创建套接字_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){lg.LogMessage(Fatal, "socket error, sockfd : %d\n", _listensock);exit(1);}lg.LogMessage(Info, "socket success, sockfd : %d\n", _listensock);// 2. 指定网络接口并bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = bind(_listensock, (struct sockaddr *)&local, sizeof(local));if (n != 0){lg.LogMessage(Fatal, "bind error\n");exit(2);}lg.LogMessage(Debug, "bind socket success, sockfd: %d\n", _listensock);// 3. 设置socket为监听状态int m = listen(_listensock, default_backlog);if (m != 0){lg.LogMessage(Fatal, "listen error\n");exit(3);}lg.LogMessage(Debug, "listen socket success, sockfd: %d\n", _listensock);}

2.4 获取新链接accept

上面初始化完毕,现在开始就是要运行服务端,而TCP不能直接发数据,因为它是面向链接的,必须要先建立链接。
在这里插入图片描述

参数介绍

sockfd文件描述符,找到套接字
addr输入输出型参数,是一个结构体,用来获取客户端的信息
addrlen输入输出型参数,客户端传过来的结构体大小

返回值

成功返回一个文件描述符
失败返回-1

而我们知道sockfd本来就是一个文件描述符,那么这个返回的文件描述符是什么呢?
举个例子:

我们去吃饭的时候会发现每个店铺门口都会有人来招揽顾客,这个人把我们领进去门店后,然后他就会继续站在门口继续招揽顾客,而我们会有里面的服务员来招待我们,给我们提供服务

这里的揽客的人就是_listensock,而服务员就是返回值的文件描述符
意思就是_listensock的作用就是把链接从底层获取上来,返回值的作用就是跟客户端通信
从这里就知道了成员变量中的_listensock`并不是通信用的套接字,而是专门用来获取链接的套接字

    void Start(){_is_running = true;while (_is_running){// 4. 获取连接struct sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = accept(_listensock, (struct sockaddr *)&peer, &len);if (sockfd < 0){lg.LogMessage(Fatal, "socket accept error");continue;}lg.LogMessage(Debug, "accept socket success, get a new sockfd: %d\n", sockfd);Service(sockfd);close(sockfd);}}

2.5 接收数据并处理(服务)

当客户访问服务器的时候,必定是想要完成某件事,并且得到某件事完成的结果,我们称这个过程为服务
服务端收到客户端发来的信息或请求后,进行分析判断,完成客户端想要完成的任务,并返回给客户端

我们这里写一个简单的运用,此处的服务就是读取发来的信息并发回给客户端

void Service(int sockfd){char buffer[1024];while (true){int n = read(sockfd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;std::cout << "client say# " << buffer << std::endl;std::string echo_string = "server echo# ";echo_string += buffer;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n == 0) // read如果返回值是0,表示读到了文件结尾(对端关闭了连接!){lg.LogMessage(Info, "client quit...\n");break;}else{lg.LogMessage(Error, "read socket error");break;}}}

2.6 整体代码

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "Log.hpp"
#include "nocopy.hpp"static const int default_fd = -1;
const static int default_backlog = 1;class TcpServer : public nocopy
{
public:TcpServer(const uint16_t port): _port(port), _listensock(default_fd), _is_running(false){}void Init(){// 1. 创建套接字_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){lg.LogMessage(Fatal, "socket error, sockfd : %d\n", _listensock);exit(1);}lg.LogMessage(Info, "socket success, sockfd : %d\n", _listensock);// 2. 指定网络接口并bindstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = bind(_listensock, (struct sockaddr *)&local, sizeof(local));if (n != 0){lg.LogMessage(Fatal, "bind error\n");exit(2);}lg.LogMessage(Debug, "bind socket success, sockfd: %d\n", _listensock);// 3. 设置socket为监听状态int m = listen(_listensock, default_backlog);if (m != 0){lg.LogMessage(Fatal, "listen error\n");exit(3);}lg.LogMessage(Debug, "listen socket success, sockfd: %d\n", _listensock);}void Service(int sockfd){char buffer[1024];while (true){int n = read(sockfd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;std::cout << "client say# " << buffer << std::endl;std::string echo_string = "server echo# ";echo_string += buffer;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n == 0) // read如果返回值是0,表示读到了文件结尾(对端关闭了连接!){lg.LogMessage(Info, "client quit...\n");break;}else{lg.LogMessage(Error, "read socket error");break;}}}void Start(){_is_running = true;while (_is_running){// 4. 获取连接struct sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = accept(_listensock, (struct sockaddr *)&peer, &len);if (sockfd < 0){lg.LogMessage(Fatal, "socket accept error");continue;}lg.LogMessage(Debug, "accept socket success, get a new sockfd: %d\n", sockfd);Service(sockfd);close(sockfd);}}~TcpServer(){}private:uint16_t _port;int _listensock;bool _is_running;
};#include "TcpServer.hpp"
#include <memory>void Usage(const std::string s)
{std::cout << "Usagr: " << s << " local_port" << std::endl;
}int main(int argc,char *argv[])
{if (argc != 2){Usage(argv[0]);return 1;}std::unique_ptr<TcpServer> tcpser = std::make_unique<TcpServer>(std::stoi(argv[1]));tcpser->Init();tcpser->Start();return 0;
}

二、客户端实现

2.1 创建套接字socket

    // 1. 创建socketint _sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_sockfd < 0){lg.LogMessage(Fatal, "socket error, sockfd : %d\n", _sockfd);exit(1);}lg.LogMessage(Info, "socket success, sockfd : %d\n", _sockfd);

2.2 指定网络接口

    // 2. 指定网络接口struct sockaddr_in send;memset(&send, 0, sizeof(send));send.sin_family = AF_INET;send.sin_port = htons(stoi(argv[2]));send.sin_addr.s_addr = inet_addr(argv[1]);

2.3 发起链接connect

在这里插入图片描述

参数说明:

这里的addraddrlen填入的是服务端信息

在UDP通信中,客户端在sendto的时候会自动绑定IP和port,TCP这里就是在connect的时候绑定

// 3. 进行连接int n = connect(_sockfd, (struct sockaddr *)&send, sizeof(send));

2.4 发送数据并接收

  while (true){std::string inbuffer;std::cout << "Please Enter# ";getline(cin, inbuffer);int n = write(_sockfd, inbuffer.c_str(), inbuffer.size());if (n > 0){char buffer[1024];int m = read(_sockfd, buffer, sizeof(buffer) - 1);if (m > 0){buffer[m] = 0;cout << "get a echo messsge -> " << buffer << endl;}else if (m == 0 || m < 0){break;}}else{break;}}

2.5 整体代码

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "Log.hpp"void usage(std::string s)
{std::cout << "Usagr: " << s << " server_ip server_port" << std::endl;
}int main(int argc, char *argv[])
{if (argc != 3){usage(argv[0]);return 0;}// 1. 创建socketint _sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_sockfd < 0){lg.LogMessage(Fatal, "socket error, sockfd : %d\n", _sockfd);exit(1);}lg.LogMessage(Info, "socket success, sockfd : %d\n", _sockfd);// 2. 指定网络接口struct sockaddr_in send;memset(&send, 0, sizeof(send));send.sin_family = AF_INET;send.sin_port = htons(stoi(argv[2]));send.sin_addr.s_addr = inet_addr(argv[1]);// 3. 进行连接int n = connect(_sockfd, (struct sockaddr *)&send, sizeof(send));while (true){std::string inbuffer;std::cout << "Please Enter# ";getline(cin, inbuffer);int n = write(_sockfd, inbuffer.c_str(), inbuffer.size());if (n > 0){char buffer[1024];int m = read(_sockfd, buffer, sizeof(buffer) - 1);if (m > 0){buffer[m] = 0;cout << "get a echo messsge -> " << buffer << endl;}else if (m == 0 || m < 0){break;}}else{break;}}return 0;
}

2.6 绑定问题

首先bind的作用是允许应用程序指定一个端口号用于监听传入的数据报或数据流

对于服务端:
需要绑定一个公开的端口号,允许大家访问,如果是随机的,其他人不知道,也就访问不了,所以服务端需要绑定

对于客户端:
客户端在给服务器发信息的同时,服务器也可能给客户端发信息,所以客户端为了监听服务器有没有给自己回信息也需要bind一个端口号用于监听,但客户端不需要显式的bind,因为客户端的端口号不会被所有人访问,别人不需要知道,所以OS自动帮我们bind一个随机的端口号,另外也是为了防止端口号重复,避免破坏唯一性

那么为什么前面服务端必须显示的绑定port呢?

因为服务器的端口号是众所周知的,不能改变,如果变了就找不到服务器了

而客户端只需要有就可以,只用标识唯一性即可
举个例子:

我们手机上有很多的app,而每个服务端是一家公司写的,但是客户端却是多个公司写的
如果我们绑定了特定的端口,万一两个公司都用了同一个端口号呢?这样就直接冲突了

OS会自动填充主机IP和随机生成端口号进行绑定(在发送数据的时候自动绑定)
所以创建客户端我们只用创建套接字即可

三、问题与改进

3.1 问题描述

在这里插入图片描述

上述图片是服务端的代码,由于整个服务端都是单进程的,所以这意味着在同一时间只能有一个客户端的链接能被accept,其他客户端的信息是接受不到的,因为一但某个客户端被成功accept了,那么单进程就会走到Service中,Service是一个死循环服务,所以只要客户端不退出,服务端是无法accept到其他链接的

3.2 解决方法

3.2.1 问题版本

在这里插入图片描述

3.2.2 多进程版

使用多进程,主进程进行accept,子进程进行Service服务

引入新问题
主进程需要阻塞等待子进程退出,还是accept不了新连接

两个解决办法

  1. 用孙子进程执行服务
            pid_t pid = fork();if (pid < 0){lg.LogMessage(Fatal, "fork error");close(sockfd);continue;}else if (pid == 0){close(_listensock);if (fork() == 0){Service(sockfd);close(sockfd);exit(0);}exit(0);}close(sockfd);waitpid(pid, nullptr, 0);
  1. 自定义信号,让父进程忽略子进程结束时发送给父进程的信号
        	signal(SIGCHLD,SIG_IGN);pid_t pid = fork();if (pid < 0){lg.LogMessage(Fatal, "fork error");close(sockfd);continue;}else if(pid == 0){close(_listensock);Service(sockfd);close(sockfd);exit(0);}close(sockfd);
3.4.3 进程池(暂未实现)

存在问题:
如果先创建子进程备用,子进程拿不到主进程accept的sockfd

3.4.4 多线程版

篇幅较长,Gitee连接:多线程版

3.4.5 线程池版

篇幅较长Gitee连接:线程池版

四、TCP与UDP的对比

对比UDP服务器,TCP服务器多了获取新链接和监听的操作
因为UDP是不可靠传输,而TCP是是可靠传输,所以TCP在传输数据之前会进行连接的建立

UDP和TCP的区别:

对于TCP协议有几个特点:

  1. 传输层协议
  2. 有连接(正式通信前要先建立连接)
  3. 可靠传输(在内部帮我们做可靠传输工作)
  4. 面向字节流

对于UDP协议有几个特点:

  1. 传输层协议
  2. 无连接
  3. 不可靠传输
  4. 面向数据报

注意:
这里的可靠与不可靠并不是贬义词,而是中性词,可靠或者不可靠形容的是特点,而不是优劣
并不是说可靠传输就好用,而是要区分应用场景和需求

相关文章:

Linux网络——TCP的运用

系列文章目录 文章目录 系列文章目录一、服务端实现1.1 创建套接字socket1.2 指定网络接口并bind2.3 设置监听状态listen2.4 获取新链接accept2.5 接收数据并处理&#xff08;服务&#xff09;2.6 整体代码 二、客户端实现2.1 创建套接字socket2.2 指定网络接口2.3 发起链接con…...

Vue3之状态管理Vuex

Vuex作为Vue.js的官方状态管理库&#xff0c;在大型或复杂的前端项目中扮演着至关重要的角色。本文将从Vuex的原理、特点、应用场景等多个方面进行深入解析&#xff0c;并通过代码示例展示如何在Vuex中实现特定功能。 一、Vuex原理 Vuex是一个专为Vue.js应用程序开发的状态管…...

DPO(Direct Preference Optimization)算法解释:中英双语

中文版 DPO paper: https://arxiv.org/pdf/2305.18290 DPO 算法详解&#xff1a;从理论到实现 1. 什么是 DPO&#xff1f; DPO&#xff08;Direct Preference Optimization&#xff09;是一种直接基于人类偏好进行优化的算法&#xff0c;旨在解决从人类偏好数据中训练出表现…...

Hostapd2.11解析笔记

最近在调试Hostapd,尝试通过配置使能一个支持MLO的AP,不过不知道hostapd conf里面哪些选项开启后可以使能,所以对Hostapd做一个整体解析. 简介 hostapd 是用于接入点和身份验证服务器的用户空间守护程序。它实现 IEEE 802.11 接入点管理、IEEE 802.1X/WPA/WPA2/WPA3/EAP 身份…...

js控制文字溢出显示省略号

.text{display: -webkit-box;overflow: hidden;white-space: normal;text-overflow: ellipsis;word-wrap: break-word;-webkit-line-clamp: 2;-webkit-box-orient: vertical; }本人有个需求就是在一个盒子内有一段文本&#xff0c;然后控制文本显示两行&#xff0c;第二行要显示…...

WPF+MVVM案例实战与特效(四十七)-实现一个路径绘图的自定义按钮控件

文章目录 1、案例效果2、创建自定义 PathButton 控件1、定义 PathButton 类2、设计样式与控件模板3、代码解释3、控件使用4、直接在 XAML 中绑定命令3、源代码获取4、总结1、案例效果 2、创建自定义 PathButton 控件 1、定义 PathButton 类 首先,我们需要创建一个新的类 Pat…...

操作002:HelloWorld

文章目录 操作002&#xff1a;HelloWorld一、目标二、具体操作1、创建Java工程①消息发送端&#xff08;生产者&#xff09;②消息接收端&#xff08;消费者&#xff09;③添加依赖 2、发送消息①Java代码②查看效果 3、接收消息①Java代码②控制台打印③查看后台管理界面 操作…...

odoo中@api.model, @api.depends和@api.onchange 装饰器的区别

文章目录 1. api.model用途特点示例 2. api.depends用途特点示例 3. api.onchange用途特点示例 总结 在 Odoo 中&#xff0c;装饰器&#xff08;decorators&#xff09;用于修饰方法&#xff0c;以指定它们的行为和触发条件。api.model、api.depends 和 api.onchange 是三个常用…...

有哪些精益工具可以帮助企业实现转型?

为了在激烈的市场竞争中立于不败之地&#xff0c;许多企业开始寻求通过精益转型来优化运营、降低成本、提高效率和客户满意度。然而&#xff0c;精益转型并非一蹴而就&#xff0c;而是需要一系列精益工具的辅助&#xff0c;这些工具能够帮助企业识别浪费、优化流程、提升质量&a…...

以太网帧结构

以太网帧结构 目前&#xff0c;我们局域网当中应用最广的技术或者协议啊&#xff0c;就是以太网。我们首先来看一下以太网的真结构。这块内容这里边再系统的来给大家去展开说一下&#xff0c;以太网真格式就如下面这个图。所示前面有八个字节&#xff0c;是用于时钟同步的&…...

QT调用Sqlite数据库

QT设计UI界面&#xff0c;后台访问数据库&#xff0c;实现数据库数据的增删改查。 零售商店系统 数据库表&#xff1a; 分别是顾客表&#xff0c;订单详情表&#xff0c;订单表&#xff0c;商品表 表内字段详情如下&#xff1a; 在QT的Pro文件中添加sql&#xff0c;然后添加头…...

前端

前端页面 Web页面 PC端程序页面 移动端APP页面 ... HTML页面 HTML超文本标记页面 超文本&#xff1a;文本&#xff0c;声音&#xff0c;图片&#xff0c;视频&#xff0c;表格&#xff0c;链接 标记&#xff1a;由许多标签组成 HTML页面运行到浏览器上面 vscode便捷插件使用 vs…...

【Git】—— 使用git操作远程仓库(gitee)

目录 一、远程仓库常用命令 1、从远程仓库克隆项目 2、查看关联的远程仓库 3、添加关联的远程仓库 4、移除关联的远程仓库 5、将本地仓库推送到远程仓库 6、从远程仓库拉取项目 二、分支命令 1、查询分支 2、创建分支 3、切换分支 4、推送到远程分支 5、合并分支 …...

Paddler负载均衡器

Paddler负载均衡器 Paddler本身是用Go语言编写的,没有直接的Python接口,但可以通过以下方式在Python中使用: 执行命令行调用 在Python中可以使用 subprocess 模块来调用Paddler的命令行工具,实现负载均衡功能 。例如: import subprocessdef start_paddler_agent():com…...

OSCP - Proving Grounds - Slort

主要知识点 文件包含 windows的reveseshell 具体步骤 执行nmap,依旧是很多端口开放&#xff0c;尝试了ftp,smb等均失败 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-13 12:00 UTC Nmap scan report for 192.168.53.53 Host is up (0.00095s latency). Not sho…...

YoloV9改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用

摘要 论文介绍 本文介绍了一种名为DynamicHead的模块,该模块旨在通过注意力机制统一目标检测头部,以提升目标检测的性能。论文详细阐述了DynamicHead的工作原理,并通过实验证明了其在COCO基准测试上的有效性和效率。 创新点 DynamicHead模块的创新之处在于它首次尝试在一…...

BFD综合详细实验配置案例

前言 本实验的目的是通过配置BGP&#xff08;边界网关协议&#xff09;、OSPF&#xff08;开放式最短路径优先协议&#xff09;、VRRP&#xff08;虚拟路由冗余协议&#xff09;以及BFD&#xff08;双向转发检测&#xff09;等网络协议&#xff0c;模拟企业级网络环境中的多协…...

自然语言处理与知识图谱的融合与应用

目录 前言1. 知识图谱与自然语言处理的关系1.1 知识图谱的定义与特点1.2 自然语言处理的核心任务1.3 二者的互补性 2. NLP在知识图谱构建中的应用2.1 信息抽取2.1.1 实体识别2.1.2 关系抽取2.1.3 属性抽取 2.2 知识融合2.3 知识推理 3. NLP与知识图谱融合的实际应用3.1 智能问答…...

c# RSA加解密工具,.netRSA加解密工具

软件介绍 名称: c# RSA加解密工具,.netRSA加解密工具依赖.net版本: .net 8.0工具类型: WinForm源码下载 c# RSA加解密工具,.netRSA加解密工具 依赖项 WinFormsRSA.csproj <Project...

Metricbeat安装教程——Linux——Metricbeat监控ES集群

Metricbeat安装教程——Linux 一、安装 下载安装包&#xff1a; 官网下载地址&#xff1a;https://www.elastic.co/cn/downloads/beats/metricbeat 上传包到linux 切换到安装目录下 解压&#xff1a;tar -zxvf metricbeat-7.17.1-linux-x86_64.tar.gz 重命名安装文件夹 mv met…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...