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

UDP实现文件的发送、UDP实现全双工的聊天、TCP通信协议

我要成为嵌入式高手之3月7日Linux高编第十七天!!
————————————————————————————

回顾

重要程序

1、UDP实现文件的发送

发端:

#include "head.h"int main(void)
{int sockfd = 0;struct sockaddr_in recvaddr;ssize_t nsize = 0;int ret = 0;int fd = 0;char pathname[1024] = {0};char tmpbuff[1024] = {0};ssize_t nret;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to socket");return -1;}recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(33333);recvaddr.sin_addr.s_addr = inet_addr("192.168.1.167");memset(pathname, 0, sizeof(pathname));gets(pathname);nsize = sendto(sockfd, pathname, strlen(pathname), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto");return -1;}fd = open(pathname, O_RDONLY);if (fd == -1){perror("fail to open");return -1;}printf("pathname: %s\n", pathname);while (1){usleep(10);nret = read(fd, tmpbuff, sizeof(tmpbuff));nsize = sendto(sockfd, tmpbuff, nret, 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto tmpbuff");return -1;}if (nret <= 0){break;}}sprintf(tmpbuff, "|__quit__|");nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff)+1, 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto tmpbuff");return -1;}printf("成功发送 %s 文件\n", pathname);close(fd);close(sockfd);return 0;
}

收端:

#include "head.h"int main(void)
{int ret = 0;int sockfd = 0;char tmpbuff[4096] = {0};struct sockaddr_in recvaddr;ssize_t nsize = 0;struct sockaddr_in sendaddr;socklen_t len = sizeof(sendaddr);sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1){perror("fail to socket");return -1;}recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(33333);recvaddr.sin_addr.s_addr = inet_addr("192.168.1.167");ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (ret == -1){perror("fail to bind");return -1;}nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, (struct sockaddr *)&sendaddr, &len);if (nsize == -1){perror("fail to recvfrom");return -1;}//	printf("%s:%d>>接受到%ld个字节:%s\n",inet_ntoa(sendaddr.sin_addr),ntohs(sendaddr.sin_port),nsize,tmpbuff);int fd = 0;char ch[1024]= {0};fd = open(tmpbuff,O_WRONLY | O_CREAT | O_TRUNC, 0664);if (fd == -1){perror("fail to fopen");return -1;}while(nsize != 0){memset(ch, 0, sizeof(ch));nsize = recvfrom(sockfd, ch, sizeof(ch), 0, (struct sockaddr *)&sendaddr, &len);if (nsize == -1){perror("fail to recvfrom");return -1;}if (!strcmp(ch,"1")){break;}write(fd,ch,nsize);printf("写入%ld字节\n",nsize);}printf("接受完成!\n");close(fd);close(sockfd);return 0;
}

2、UDP实现全双工的聊天

发送端

#include "head.h"char name[32] = {0};
int sockfd = 0;
struct sockaddr_in recvaddr;
pthread_t tid_send;
pthread_t tid_recv;void *sendfun(void *arg)
{ssize_t nsize = 0;struct msgbuf sendmsg;while(1){memset(&sendmsg, 0, sizeof(sendmsg));sendmsg.type = MSG_TYPE_CHAT;sprintf(sendmsg.name, "%s", name);gets(sendmsg.text);    if (!strcmp(sendmsg.text, ".quit")){sendmsg.type = MSG_TYPE_END;}nsize = sendto(sockfd, &sendmsg, sizeof(sendmsg), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto");return NULL;}if (sendmsg.type == MSG_TYPE_END){break;}}pthread_cancel(tid_recv);return NULL;
}void *recvfun(void *arg)
{struct msgbuf recvmsg;ssize_t nsize = 0;while(1){memset(&recvmsg, 0, sizeof(recvmsg));nsize = recvfrom(sockfd, &recvmsg, sizeof(recvmsg), 0, NULL, NULL);if (-1 == nsize){perror("fail to recvfrom");return NULL;}if (recvmsg.type == MSG_TYPE_CHAT){printf("%s(%s:%d)>%s\n", recvmsg.name, RECV_ADDR, RECV_PORT, recvmsg.text);}else if (recvmsg.type == MSG_TYPE_END){break;}}pthread_cancel(tid_send);return NULL;
}int main(void)
{ssize_t nsize = 0;struct msgbuf sendmsg;/*设置接收方信息*/recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(RECV_PORT);recvaddr.sin_addr.s_addr = inet_addr(RECV_ADDR);/*输入昵称*/printf("请输入您的昵称:\n");gets(name);/*创建套接字*/sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1){perror("fail to sockfd");return -1;}/*设置要发送的信息*/memset(&sendmsg, 0, sizeof(sendmsg));sendmsg.type = MSG_TYPE_START;sprintf(sendmsg.name, "%s", name);/*发送信息*/nsize = sendto(sockfd, &sendmsg, sizeof(sendmsg), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (nsize == -1){perror("fail to sendto");return -1;}pthread_create(&tid_send, NULL, sendfun, NULL);pthread_create(&tid_recv, NULL, recvfun, NULL);pthread_join(tid_send, NULL);pthread_join(tid_recv, NULL);close(sockfd);return 0;
}

接收端

#include "head.h"char name[32] = {0};
int sockfd = 0;
struct sockaddr_in recvaddr;
struct sockaddr_in sendaddr;
pthread_t tid_send;
pthread_t tid_recv;void *sendfun(void *arg)
{ssize_t nsize = 0;struct msgbuf sendmsg;while(1){memset(&sendmsg, 0, sizeof(sendmsg));sendmsg.type = MSG_TYPE_CHAT;sprintf(sendmsg.name, "%s", name);gets(sendmsg.text);    if (!strcmp(sendmsg.text, ".quit")){sendmsg.type = MSG_TYPE_END;}nsize = sendto(sockfd, &sendmsg, sizeof(sendmsg), 0, (struct sockaddr *)&sendaddr, sizeof(sendaddr));if (nsize == -1){perror("fail to sendto");return NULL;}if (sendmsg.type == MSG_TYPE_END){break;}}pthread_cancel(tid_recv);return NULL;
}void *recvfun(void *arg)
{struct msgbuf recvmsg;ssize_t nsize = 0;while(1){memset(&recvmsg, 0, sizeof(recvmsg));nsize = recvfrom(sockfd, &recvmsg, sizeof(recvmsg), 0, NULL, NULL);if (-1 == nsize){perror("fail to recvfrom");return NULL;}if (recvmsg.type == MSG_TYPE_CHAT){printf("%s(%s:%d)>%s\n", recvmsg.name, inet_ntoa(sendaddr.sin_addr), ntohs(sendaddr.sin_port), recvmsg.text);}else if (recvmsg.type == MSG_TYPE_END){break;}}pthread_cancel(tid_send);return NULL;
}int main(void)
{char tmpbuff[1024] = {0};struct msgbuf recvmsg;int ret = 0;socklen_t addrlen = sizeof(sendaddr);/*设置接收方信息*/recvaddr.sin_family = AF_INET;recvaddr.sin_port = htons(RECV_PORT);recvaddr.sin_addr.s_addr = inet_addr(RECV_ADDR);/*输入昵称*/printf("请输入您的昵称:\n");gets(name);/*创建套接字*/sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1){perror("fail to sockfd");return -1;}ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));if (-1 == ret){perror("fail to bind");return -1;}/*设置要发送的信息*/memset(&recvmsg, 0, sizeof(recvmsg));/*接收信息*/ret = recvfrom(sockfd, &recvmsg, sizeof(recvmsg), 0, (struct sockaddr *)&sendaddr, &addrlen);if (ret == -1){perror("fail to recvfrom");return -1;}pthread_create(&tid_send, NULL, sendfun, NULL);pthread_create(&tid_recv, NULL, recvfun, NULL);pthread_join(tid_recv, NULL);pthread_join(tid_send, NULL);close(sockfd);return 0;
}

head.h

#ifndef _HEAD_H
#define _HEAD_H#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <stdlib.h>
#include <grp.h>
#include <sys/wait.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>struct msgbuf
{int type;      //消息类型char name[32]; //昵称char text[32]; //消息
};#define MSG_TYPE_START        100               //开始聊天消息类型
#define MSG_TYPE_END          200               //退出聊天消息类型
#define MSG_TYPE_CHAT         300               //聊天消息类型
#define RECV_ADDR             "192.168.1.172"   //接收端地址
#define RECV_PORT             50000             //接收端端口#endif

学习笔记

TCP通信

TCP发端(客户端)

        socket -> connect -> send / recv-> close

TCP收端(服务端)

        socket -> bind -> listen -> accept -> send / recv -> close

 1、connect

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

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

功能:发起链接请求

参数:

        sockfd:套接字的描述符

        addr:目的地址存放空间首地址

        addrlen:IP地址的大小

返回值:成功0,失败-1;

2、send

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

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

功能:发送数据

参数:

        sockfd:套接字描述符

        buf:发送数据空间的首地址

        len:发送数据的长度

        flags:属性默认为0

返回值:

        成功返回实际发送字节数

        失败返回-1;

3、recv

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

功能:接收数据

参数:

        sockfd:套接字描述符

        buf:存放数据空间首地址

        len:最大接收数据的长度

        flags:属性默认0

返回值:

        成功返回实际接收字节数,失败返回-1;

        若对方退出,返回0

客户端:

#include "head.h"int main(void)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveaddr;char tmpbuff[1024] = {0};ssize_t nsize = 0;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){perror("fail to socket");return -1;}serveaddr.sin_family = AF_INET;serveaddr.sin_port = htons(50000);serveaddr.sin_addr.s_addr = inet_addr("192.168.1.101");ret = connect(sockfd, (struct sockaddr *)&serveaddr, sizeof(serveaddr));if (ret == -1){perror("fail to connect");return -1;}gets(tmpbuff);nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);if (nsize == -1){perror("fail to send");return -1;}memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);if (nsize == -1){perror("fail to recv");return -1;}printf("RECV: %s\n", tmpbuff);close(sockfd);return 0;
}

4、listen

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

功能:监听客户端发送的链接请求,不会阻塞

参数:

        sockfd:套接字描述符

        backlog:允许等待的尚未被处理的三次握手请求的最大个数

返回值:成功0,失败-1;

5、accept

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

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

功能:

       处理等待链接队列中的第一个链接请求,若没有人发送链接请求会阻塞等待,直到有连接请求

参数:

        sockfd:套接字描述符

        addr:存放IP地址的空间首地址

        addrlen:存放IP地址大小空间首地址

返回值:

        成功返回一个新的文件描述符

        失败返回-1;

服务端:

#include "head.h"int main(void)
{int sockfd = 0;struct sockaddr_in serveaddr;int ret = 0;int confd = 0;ssize_t nsize = 0;char tmpbuff[1024] = {0};serveaddr.sin_family = AF_INET;serveaddr.sin_port = htons(50000);serveaddr.sin_addr.s_addr = INADDR_ANY;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1){perror("fail to socket");return -1;}ret = bind(sockfd, (struct sockaddr *)&serveaddr, sizeof(serveaddr));if (ret == -1){perror("fail to bind");return -1;}ret = listen(sockfd, 10);if (-1 == ret){perror("fail to listen");return -1;}confd = accept(sockfd, NULL, NULL);if (-1 == confd){perror("fail to accept");return -1;}nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if (-1 == nsize){perror("fail to recv");return -1;}printf("RECV: %s\n", tmpbuff);memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if (-1 == nsize){perror("fail to send");return -1;}close(confd);close(sockfd);return 0;
}

相关文章:

UDP实现文件的发送、UDP实现全双工的聊天、TCP通信协议

我要成为嵌入式高手之3月7日Linux高编第十七天&#xff01;&#xff01; ———————————————————————————— 回顾 重要程序 1、UDP实现文件的发送 发端&#xff1a; #include "head.h"int main(void) {int sockfd 0;struct sockaddr_i…...

Yocto - Project Quick Build

欢迎光临&#xff01; 这篇简短的文档将向您介绍使用 Yocto 项目构建典型镜像的过程。本文还介绍了如何为特定硬件配置构建。您将使用 Yocto Project 构建一个名为 Poky 的参考嵌入式操作系统。 Welcome! This short document steps you through the process for a typical i…...

深入探讨C++中的可变参数列表(Variadic Templates)

文章目录 导言可变参数列表的基本用法使用std::initializer_list应用场景 导言 在C编程中&#xff0c;处理可变数量参数的能力是一种非常有用的功能。通过可变参数列表&#xff0c;你可以编写更加通用和灵活的函数&#xff0c;从而提高代码的可读性和重用性。本文将详细介绍C中…...

MS2548 国产自动方向控制、半双工 RS-485 收发器 替代MAX13487

MS2548 国产自动方向控制、半双工 RS-485 收发器 替代MAX13487 北京冠宇铭通科技有限公司 肖小姐 产品简述 MS2548 是一个 5V 供电、半双工 RS-485 收发器。 芯片具有自动换向控制功能&#xff0c;可用于隔离485 端口&#xff0c;驱动器输入与使能信号一起配合控制芯片的状态&…...

数据库大师之路:Oracle在线学习平台全指南!

介绍数据库是由甲骨文公司开发的一款关系数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;在数据库领域具有领先地位&#xff0c;并且以其系统可移植性而闻名。以下是对Oracle数据库的详细介绍&#xff1a; 市场地位&#xff1a;Oracle数据库是目前世界上流行的关系数…...

如何在Windows系统部署Jellyfin Server并实现公网访问内网影音文件

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…...

华为北向网管NCE开发教程(3)CORBA协议开发

华为北向网管NCE开发教程&#xff08;1&#xff09;闭坑选接口协议 华为北向网管NCE开发教程&#xff08;2&#xff09;REST接口开发 华为北向网管NCE开发教程&#xff08;3&#xff09;CORBA协议开发 如果你真的还有选择的余地&#xff0c;能用REST&#xff0c;尽量用REST&…...

【算法训练营】最长公共子序列,倒水问题,奶牛吃草(Python实现)

最长公共子序列 时间限制&#xff1a;1 sec 空间限制&#xff1a;256 MB 问题描述 给定两个 1 到 n 的排列 A,B &#xff08;即长度为 n 的序列&#xff0c;其中 [1,n] 之间的所有数都出现了恰好一次&#xff09;。 求它们的最长公共子序列长度。 输入格式 第一行一个整数 n &a…...

Armadillo:矩阵类、向量类、Cube类和泛型类

文章目录 矩阵类、向量类、Cube类和泛型类Mat<type>matcx_matCol<type>veccx_vecRow<type>rowveccx_rowvecCube<type>cubecx_cubefield<object_type>SpMat<type>sp_matsp_cx_mat运算符&#xff1a; − * % / &#xff01; < > <…...

【守护健康】小脑萎缩患者必备营养指南

当生活给予我们挑战&#xff0c;我们选择用科学和关爱予以回应。面对小脑萎缩这一难题&#xff0c;正确的营养补充不仅是一剂强心针&#xff0c;更是患者康复之路上的坚实伙伴。今天&#xff0c;让我们一起了解那些能够助力小脑萎缩患者的神奇维生素&#xff01; 1. 维生素B群…...

lvs集群中NAT模式

群集的含义 由多台主机构成&#xff0c;但对外表现为一个整体&#xff0c;只提供一个访问入口&#xff0c;相当于一台大型的计算机。 横向发展:放更多的服务器&#xff0c;有调度分配的问题。 垂直发展&#xff1a;升级单机的硬件设备&#xff0c;提高单个服务器自身功能。 …...

FPGA——三速自适应以太网设计(2)GMII与RGMII接口

FPGA——以太网设计&#xff08;2&#xff09;GMII与RGMII 基础知识&#xff08;1&#xff09;GMII&#xff08;2&#xff09;RGMII&#xff08;3&#xff09;IDDR GMII设计转RGMII接口跨时钟传输模块 基础知识 &#xff08;1&#xff09;GMII GMII:发送端时钟由MAC端提供 下…...

【校园导航小程序】2.0版本 静态/云开发项目 升级日志

演示视频 【校园导航小程序】2.0版本 静态/云开发项目 演示 首页 重做了首页&#xff0c;界面更加高效和美观 校园指南页 新增了 “校园指南” 功能&#xff0c;可以搜索和浏览校园生活指南 地图页 ①弃用路线规划插件&#xff0c;改用SDK开发包。可以无阻通过审核并发布…...

深入揭秘Lucene:全面解析其原理与应用场景(二)

本系列文章简介&#xff1a; 本系列文章将深入揭秘Lucene&#xff0c;全面解析其原理与应用场景。我们将从Lucene的基本概念和核心组件开始&#xff0c;逐步介绍Lucene的索引原理、搜索算法以及性能优化策略。通过阅读本文&#xff0c;读者将会对Lucene的工作原理有更深入的了解…...

Java中synchronized关键字、ReentrantLock、volatile关键字是如何实现线程同步的。

在Java中&#xff0c;synchronized关键字、ReentrantLock和volatile关键字这三个是编程中常用于实现线程同步的机制&#xff0c;下面结合代码详细说明一下这三个关键字的用法。 1. synchronized关键字&#xff1a; synchronized关键字是Java语言提供的内置锁机制&#xff0c;…...

路由拦截器

路由拦截可以分为几种不同的类型&#xff0c;每种类型都有其特定的作用和适用场景。以下是常见的几种路由拦截类型及其用途&#xff1a; 身份验证拦截器&#xff1a; 作用&#xff1a; 检查用户是否已经登录或具有有效的身份认证&#xff0c;并根据认证状态决定是否允许用户访问…...

Springboot+vue的物业管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的物业管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的物业管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff…...

STM32的启动流程分析 和 一些底层控制的原理

阅读引言&#xff1a; 阅读本文之后&#xff0c; 你将对单片机&#xff0c; 甚至是嵌入式系统&#xff0c; 或者是传统的PC机系统的启动流程有一个大致的了解&#xff0c; 本文更加偏向于单片机的启动流程分析。 目录 一、基础知识 1.STM32系列的微控制器&#xff08;mcu&…...

C#面:几种注释类型

三种常见的注释类型&#xff1a;单行注释、多行注释和 XML 注释。 单行注释&#xff1a; 以双斜线 // 开头&#xff0c;用于在一行中注释单个语句或代码块。单行注释会被编译器忽略&#xff0c;不会对程序的执行产生任何影响。 例如&#xff1a; // 这是一个单行注释 int a…...

#onenet网络请求http(GET,POST)

参考博文&#xff1a; POST: https://blog.csdn.net/qq_43350239/article/details/104361153 POST请求&#xff08;用串口助手测试&#xff09;&#xff1a; POST /devices/1105985351/datapoints HTTP/1.1 api-key:AdbrV5kCRsKsRCfjboYOCVcF9FY Host:api.heclouds.com Con…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

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.…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...