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

Linux 网络通信

(一)套接字Socket概念

Socket 中文意思是“插座”,在 Linux 环境下,用于表示进程 x 间网络通信的特殊文件
类型
。本质为内核借助缓冲区形成的伪文件。

既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。Linux 系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致

在 TCP/IP 协议中,“IP 地址+TCPUDP 端口号”唯一标识网络通讯中的一个进程。

“IP 地址+端口号”就对应一个 socket。 欲建立连接的两个进程各自有一个 socket 来标识,那么这两个 socket 组成的 socket pair 就唯一标识一个连接。因此可以用 Socket 来描述网络连接的一对一关系。

在这里插入图片描述

在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。

(二)TCP通信流程图

在这里插入图片描述

(三)Socket编程基础知识

1 网络字节序

在计算机世界里,有两种字节序:

大端字节序 - 低地址高字节,高地址低字节
小段字节序 - 低地址低字节,高地址高字节

内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的
多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有
大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓
冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的
字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存
,因此,
网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高
地址。

TCP/IP 协议规定,网络数据流应采用大端字节序即低地址高字节。

为使网络程序具有可移植性,使同样的 C 代码在大端和小端计算机上编译后
都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#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,l 表示 32 位长整数,s 表示 16 位短整数。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如
果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

2 socketaddr 数据结构

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

struct sockaddr {sa_family_t 	sa_family;			/* 地址系列,AF_xxx */char 			sa_data[14]; 		/* 14字节的协议地址 */
};
struct sockaddr_in {sa_family_t 	sin_family; 		/* 地址族:一般为AF_INET */in_port_t 		sin_port;			/* 按网络字节顺序排列的端口*/struct in_addr  sin_addr; 			/* 网络地址 */
};/* 网络地址 */
struct in_addr {uint32_t 		s_addr;				/* 按网络字节顺序排列的网络地址 */
};

IPv4 地址用 sockaddr_in 结构体表示,包括 16 位端口号和 32 位 IP 地址
,但是 sock API 的实现早于 ANSI C 标准化,那时还没有 void *类型,
因此这些像 bind 、accept 函数的参数都用 struct sockaddr * 类型表示,
在传递参数之前要强制类型转换一下,例如:

struct sockaddr_in servaddr;
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)); 

3 IP地址转换函数

对于IP地址"a.b.c.d"
小端字节序和大端字节序分别表示:
在这里插入图片描述

#include <arpa/inet.h>
int          inet_pton(int af, const char *src, void *dst);
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size);

af 取值可选为 AF_INET 和 AF_INET6 ,即对应IPv4 和 IPv6
其中 inet_pton 和 inet_ntop 不仅可以转换 IPv4 的 in_addr,
还可以转换 IPv6的 in6_addr。
因此函数接口是 void *dst 和 void *src。

(四)Socket 编程主要的函数介绍

1 套接字设置 socket()

头文件:

#include <sys/types.h>
#include <sys/socket.h>

函数原型:

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

参数解释:
domain:

AF_INET 		使用 TCP 或 UDP 来传输,用Pv4 的地址
AF_INET6 		与AF_INET类似,不过是来用 IPv6 的地址
AF_UNIX 		本地协议,使用在 Unix 和 Linux 系统上,一般都是当客户端和服务器在同一台及其上的时候使用

type:

SOCK_STREAM 	这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket 类型,这个socket 是使用TCP来进行传输。
SOCK_DGRAM 		这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用 UDP 来进行它的连接。
SOCK_SEQPACKET 	该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW 		socket类型提供单一的网络访问,这个 socket 类型使用 ICMP 公共协议。SOCK_RDM 		这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

protocol:

传 0 表示使用默认协议。

返回值:
成功:返回指向新创建的 socket 的文件描述符
失败:返回-1,设置 errno

注意事项:

对于 IPv4,domain 参数指定为 AF_INET。对于 TCP 协议,type 参数指定为 SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的指定为 0 即可。

2 绑定标签 bind()

头文件:

#include <sys/types.h>
#include <sys/socket.h>

函数原型:

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

参数解释:

sockfd:		socket 文件描述符
addr:			构造出 IP 地址加端口号
addrlen:		sizeof(addr)长度

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

注意事项:
服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知
服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用
bind 绑定一个固定的网络地址和端口号

bind()的作用是将参数 sockfd 和 addr 绑定在一起,使 sockfd 这个用于网
络通讯的文件描述符监听 addr 所描述的地址和端口号
。前面讲过,struct
sockaddr *是一个通用指针类型,addr 参数实际上可以接受多种协议的 sockaddr
结构体,而它们的长度各不相同,所以需要第三个参数 addrlen 指定结构体的长
度。如:

struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);

首先将整个结构体清零,然后设置地址类型为 AF_INET,网络地址为 INADDR_ANY,
这个宏表示本地的任意 IP 地址,因为服务器可能有多个网卡,每个网卡也可能
绑定多个 IP 地址,
这样设置可以在所有的 IP 地址上监听,直到与某个客户端建
立了连接时才确定下来到底用哪个 IP 地址和端口号。

3 设置监听 listen()

头文件:
#include <sys/types.h>
#include <sys/socket.h>

函数原型

int listen(int sockfd, int backlog);

参数解释:

sockfd:		socket 文件描述符
backlog:	在 Linux 系统中,它是指排队等待建立 3 次握手队列长度

注意事项:
查看系统默认 backlog

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

改变 系统限制的 backlog 大小

vim /etc/sysctl.conf

最后添加

net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 1024

保存,然后执行

sysctl -p

4 接受连接 accept()

头文件:

#include <sys/types.h>
#include <sys/socket.h>

函数原型:

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

参数解释:

sockdf:		socket 文件描述符
addr:		传出参数,返回链接客户端地址信息,含 IP 地址和端口号
addrlen: 	sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小

返回值:

成功: 返回一个新的 socket 文件描述符,用于和客户端通信,
失败: 返回-1,设置 errno

注意事项:

三次握手完成后,服务器调用 accept()接受连接,如果服务器调用 accept()
时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr 是一个
传出参数,accept()返回时传出客户端的地址和端口号
。addrlen 参数是一个传
入传出参数,传入的是调用者提供的缓冲区 addr的长度以避免缓冲区溢出问题,
传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。
如果给 addr 参数传 NULL,表示不关心客户端的地址。

服务器程序结构是这样的:

while (1) {cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&cliaddr_len);n = read(connfd, buf, MAXLINE);......close(connfd);
}

整个是一个 while 死循环,每次循环处理一个客户端连接。由于 cliaddr_len
是传入传出参数,每次调用 accept()之前应该重新赋初值。
accept()的参数
listenfd 是先前的监听文件描述符,而 accept()的返回值是另外一个文件描述
符 connfd,
之后与客户端之间就通过这个 connfd 通讯,最后关闭 connfd 断开
连接,而不关闭 listenfd,再次回到循环开头 listenfd 仍然用作 accept 的参
数。accept()成功返回一个文件描述符,出错返回-1。

5 请求连接 connect()

头文件:
#include <sys/types.h>
#include <sys/socket.h>

函数原型:

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

参数解释:

sockdf:   	socket 文件描述符
addr:		传入参数,指定服务器端地址信息,含 IP 地址和端口号
addrlen:	传入参数,传入 sizeof(addr)大小

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

注意事项:

客户端需要调用 connect()连接服务器,connect 和 bind 的参数形式一致,
区别在于bind的参数是自己的地址而connect的参数是对方的地址

(五)应用实例

1 服务端demo代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>#define SERVER_PORT 6666int main(void) {//1创建连接的套接字int sock;sock = socket(AF_INET, SOCK_STREAM, 0);//IPV4,TCP方式,默认协议//2设置标签(地址,端口号)struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));			//将server_addr的内容清零server_addr.sin_family = AF_INET;					//协议组IPV4server_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//监听本地所有ipserver_addr.sin_port = htons(SERVER_PORT);			//设置端口号//3绑定标签bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));//4设置监听并指定监听最大数量listen(sock, 128);//5等待连接printf("等待客户端连接请求\n");int done = 1;while (done) {//5-1有连接则重新分配套接字接受连接struct sockaddr_in clinet;int  client_sock, len;			//客户端的 套接字char client_ip[64];				//客户端的 ipchar buf[256];					//客户端的 发送的内容socklen_t client_addr_len;		//套接字地址结构长度client_addr_len = sizeof(clinet);//5-2接受分配的套接字client_sock = accept(sock, (struct sockaddr*)&clinet, &client_addr_len);//5-3查看客户端IP和端口号inet_ntop(AF_INET, &clinet.sin_addr.s_addr, client_ip, sizeof(client_ip));printf("客户端IP:%s	,端口号:%d\n", client_ip, ntohs(clinet.sin_port));//5-4客户端发来的数据len = read(client_sock, buf, sizeof(buf) - 1);buf[len] = '\0';printf("收到客户端发来的长度为%d数据%s\n", len, buf);//5-4服务端给客户写数据len = write(client_sock, buf, len);printf("已完成对客户端的写操作\n");close(client_sock);}close(sock);return 0;
}

2 客户端demo代码

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>#define SERVER_PORT 6666
#define SERVER_IP "127.0.0.1"int main(int argc,char **argv) {int sockfd;char* message;struct sockaddr_in servaddr;int n;char buf[64];if (argc!=2)//参数不合法{printf("参数不合法!  ./xxxx.exe  message\n");exit(-1);}message = argv[1];//获取要发送的消息printf("待发送的数据:%s\n",message);//创建套接字sockfd = socket(AF_INET,SOCK_STREAM,0);//将server_addr的内存初始化memset(&servaddr,'\0',sizeof(struct sockaddr_in));servaddr.sin_family = AF_INET;inet_pton(AF_INET,SERVER_IP,&servaddr.sin_addr);servaddr.sin_port=htons(SERVER_PORT);//连接服务器connect(sockfd, (struct sockaddr*)&servaddr,sizeof(servaddr));//写数据write(sockfd,message,strlen(message));//读数据n = read(sockfd,buf,sizeof(buf)-1);if (n>0) {buf[n] = '\0';printf("收到的数据:%s\n",buf);}else {perror("error!!!");}printf("finished\n");close(sockfd);return 0;
}

3演示效果:

在这里插入图片描述

相关文章:

Linux 网络通信

(一)套接字Socket概念 Socket 中文意思是“插座”&#xff0c;在 Linux 环境下&#xff0c;用于表示进程 x 间网络通信的特殊文件 类型。本质为内核借助缓冲区形成的伪文件。 既然是文件&#xff0c;那么理所当然的&#xff0c;我们可以使用文件描述符引用套接字。Linux 系统…...

借力互联网,民营医院探索互联网医疗服务的发展方向

民营医院互联网医疗服务是指利用互联网技术和平台&#xff0c;为患者提供更加便捷、高效的医疗服务。在当前数字化时代&#xff0c;互联网医疗服务正逐渐成为医疗行业的新趋势&#xff0c;也为民营医院开拓了更广阔的发展空间。下面将围绕这一主题进行讨论&#xff1a; 首先&a…...

office tool plus工具破解word、visio等软件步骤

第一步&#xff1a;下载工具 破解需要用到office tool plus软件 office tool plus软件下载地址&#xff1a;Office Tool Plus 官方网站 - 一键部署 Office 选择其中一个下载到本地&#xff08;本人选择的是第一个的云图小镇下载方式&#xff09; 第二步&#xff1a;启动工具 …...

python之pyqt专栏5-信号与槽1

在上一篇文章&#xff0c;我们了解到如果想要用代码改变QLabel的文本内容&#xff0c;可以调用QLabel类的text()函数。 但是现在有个这样的需求&#xff0c;界面中有一个Button与一个Label&#xff0c;当点击Button时&#xff0c;将Label的内容改变为“Hello world&#xff01;…...

【JMeter】不同场景下的接口请求

场景1: 上传文件接口即Content-Type=multipart/form-data 步骤: 1. 接口url,method以及path正常填写 2.文件上传content-type是multipart/form-data,所以可以勾选【use multipart/form-data】,如果还有其他请求头信息可以添加一个请求头元件 3.请求参…...

十八数字文化受邀参加版博会“区块链+版权”创新应用试点研讨会

2023年11月23日至25日&#xff0c;以“版权新时代 赋能新发展”为主题的第九届中国国际版权博览会在成都市中国西部国际博览城和天府国际会议中心举办。版博会是我国版权领域唯一的综合性、国际性、国家级版权专业博览会&#xff0c;本届版博会由国家版权局主办&#xff0c;四川…...

Centos 7 离线安装(tar) NodeJS 16 和 Vue

目录 一、下载Nodejs二、安装Nodejs2.1、创建安装目录2.2、上传安装包(无网络) or 直接下载(有网络)2.3、解压缩2.4、配置环境变量2.5、创建软连接2.6、更换镜像源2.7、验证是否安装成功 三、安装Vue四、卸载Nodejs 一、下载Nodejs Nodejs&#xff1a;https://nodejs.org/en/ …...

卸载软件最最最彻底的工具——Uninstall Tool

卸载软件最最最彻底的工具——Uninstall Tool Uninstall Tool 是一款功能强大的专业卸载工具。针对一些普通卸载不彻底的问题&#xff0c;它可以做到最优&#xff0c;比如Matlab等软件的卸载难的问题也可以较好地解决。 它比 Windows 自带的“添加/删除程序”功能快 3 倍&…...

2022年MathorCup大数据竞赛B题北京移动用户体验影响因素研究求解全过程文档及程序

2022年MathorCup高校数学建模挑战赛—大数据竞赛 B题 北京移动用户体验影响因素研究 原题再现&#xff1a; 移动通信技术飞速发展&#xff0c;给人们带来了极大便利&#xff0c;人们也越来越离不开移动通信技术带来的各种便捷。随着网络不断的建设&#xff0c;网络覆盖越来越…...

C#,《小白学程序》第二十课:大数的加法(BigInteger Add)

大数的&#xff08;加减乘除&#xff09;四则运算、阶乘运算。 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法。 重复了部分 19 课的代码。 1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary>…...

通用功能——git 攻略

摘要 本文主要介绍git常用命令的使用方法&#xff0c;同时介绍一些常见问题的处理方法&#xff0c;持续更新中… git命令通用选项 大多数git命令都适用的选项列表如下&#xff1a; -v, --verbose show hash and subject, give twice for upstream branch -q, --quie…...

LemMinX-Maven:帮助在eclipse中更方便地编辑maven的pom文件

LemMinX-Maven&#xff1a;https://github.com/eclipse/lemminx-maven LemMinX-Maven可以帮助我们在eclipse中更方便地编辑maven工程的pom.xml文件&#xff0c;例如补全、提示等。不用单独安装&#xff0c;因为在安装maven eclipse插件的时候已经自动安装了&#xff1a; 例…...

CAD与 PDM系统如何协同工作的?

在产品研发中&#xff0c;CAD&#xff08;计算机辅助设计&#xff09;和PDM&#xff08;产品数据管理&#xff09;是两个核心的工具&#xff0c;它们在产品从设计到制造的整个生命周期中发挥着重要的作用。虽然这两个工具在功能上有所不同&#xff0c;但它们在使用上却有着密切…...

vue-历史模式部署

项目部署 本项目采用nginx进行部署&#xff0c;历史模式的部署需要服务端的配合&#xff0c;本次采用nginx进行配合。 1 配置 const basePath process.env.VUE_APP_BASE_PATH; module.exports {publicPath: basePath #静态资源的路径 /ecology/ }2 创建路由 const createR…...

『Linux升级路』基础开发工具——make/Makefile

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;Linux &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、认识make/Makefile &#x1f4d2;1.1make/Makefile的优点 &#x1f4d2;…...

Python开发技能实战-如何在Visio中添加和删除任意连接点?

问题 在学习或者工作中&#xff0c;我们经常会借助Visio这个软件绘制流程图&#xff0c;在Visio中一般连接点是固定的&#xff0c;固定的连接点只能绘制一条连接线&#xff0c;如下图所示&#xff1a; 但有时候我们需要在两个方框之间绘制双向连接线&#xff0c;达到以下的效果…...

中科驭数受邀出席2023 ODCC冬季全会,共谋开放数据中心创新发展

近日&#xff0c;2023年开放数据中心委员会&#xff08;简称“ODCC”&#xff09;冬季全会在宁夏银川成功召开&#xff0c;中科驭数作为ODCC的新成员单位&#xff0c;受邀出席本次重要会议。 ▲ 中科驭数正式加入ODCC开放数据中心委员会 开放数据中心委员会是在中国通信标准化…...

Leetcode—907.子数组的最小值之和【中等】

2023每日刷题&#xff08;四十二&#xff09; Leetcode—907.子数组的最小值之和 算法思想 参考自y神思想 实现代码 class Solution { public:int sumSubarrayMins(vector<int>& arr) {long long ans 0;const int mod 1e97;int n arr.size();stack<int>…...

下载文件并重命名

//下载文件并重命名 // 无需数字化归档模版下载 function nodigitalMeth(){ let filenameunescape("/projectapp/ghsjy/template/noNeedDigital.docx")//原文件为英文名字 downloadFileRename(filename,"无需成果数据汇交模版") } // 需要数字化归档模版下…...

BGP路由的选路综合实验

题目要求 1.使用PreVal策略&#xff0c;确保R1通过R3到达192.168.10.0/24 2.使用AS_Path策略&#xff0c;确保R1通过R3到达192.168.11.0/24 3.配置MED策略&#xff0c;确保R1通过R3到达192.168.12.0/24 4.使用Local Preference策略&#xff0c;确保R4通过R2到达192.168.1.0/24…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

13.10 LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析

LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析 LanguageMentor 对话式训练系统架构与实现 关键词:多轮对话系统设计、场景化提示工程、情感识别优化、LangGraph 状态管理、Ollama 私有化部署 1. 对话训练系统技术架构 采用四层架构实现高扩展性的对话训练…...

Redis上篇--知识点总结

Redis上篇–解析 本文大部分知识整理自网上&#xff0c;在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库&#xff0c;Redis 的键值对中的 key 就是字符串对象&#xff0c;而 val…...