C/C++网络编程--文件分块传输

news2024/9/21 0:30:30

文件分块传输是网络编程中一个常见的任务,尤其是在处理大文件时,将文件分块可以提高传输效率,简化错误处理,并可以实现并发传输。下面,写个从客户端向服务器发送大型数据的demo。

客户端

客户端有两点需要注意,在传输分两个一个是文件总块数和文件块,。传输文件总块数让服务器知道有多少文件块需要接收,确保所有数据都被完整地发送到服务器,避免因文件块数不对导致文件重组失败。

传输文件总块数

int sendAll(SOCKET s, const char* buf, int len, int flags) {
    int total = 0;
    int bytesLeft = len;
    int n;

    while (total < len) {
        n = send(s, buf + total, bytesLeft, flags);
        if (n == SOCKET_ERROR) {
            return SOCKET_ERROR;
        }
        total += n;
        bytesLeft -= n;
    }

    return total;
}

传输文件块

int sendFileBlock(SOCKET clientSocket, FileBlock* block) {
    int retry_count = 0;
    while (retry_count < MAX_RETRY_COUNT) {
        if (sendAll(clientSocket, (char*)&block->id, sizeof(block->id), 0) == SOCKET_ERROR ||
            sendAll(clientSocket, (char*)&block->size, sizeof(block->size), 0) == SOCKET_ERROR ||
            sendAll(clientSocket, block->data, block->size, 0) == SOCKET_ERROR ||
            sendAll(clientSocket, (char*)&block->crc32, sizeof(block->crc32), 0) == SOCKET_ERROR) {
            
            printf("发送块 %lld 失败,重试中...\n", block->id);
            retry_count++;
            Sleep(1000);  // 等待1秒后重试
        } else {
            return 1;  // 成功发送
        }
    }
    printf("发送块 %lld 失败,已达到最大重试次数\n", block->id);
    return 0;
}

服务器端

在服务器接收文件块时得做两件事:文件块接收和文件重组。

文件块接收

文件块接收牵扯到是否接收正确的判断,这里可以采用CRC32校验和判断服务器是否有接收正确文件块:

uint32_t calculateCRC32(const char* data, int32_t size) {
    uint32_t crc = 0xFFFFFFFF;
    for (int i = 0; i < size; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
        }
    }
    return ~crc;
}

稍微解释一下,第一个for遍历全部字节,第二个for是得到每一位的crc值,crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));,其中0xEDB88320是多项式常数,客户端和服务器应该一致。这个表达式将CRC值右移一位,如果CRC值的最低位是1,则将CRC值与0xEDB88320进行异或操作。

文件重组

文件重组还是比较简单的,首先在服务器目录下建立一个新的文件,遍历每个文件块fwrite写入创建好的文件,但是这里一定要记住在整个客户端和服务器端建立连接通信过程,一定要记得释放缓冲区内存!!!

void reassembleFile(const char* filename) {
    FILE* file = fopen(filename, "wb"); // 以二进制写模式打开文件
    if (file == NULL) {
        perror("无法创建输出文件");
        return;
    }
    // 写入文件
    for (int i = 0; i < totalBlocksExpected; i++) {
        fwrite(receivedBlocks[i].data, 1, receivedBlocks[i].size, file);
        free(receivedBlocks[i].data); // 释放内存
    }
    fclose(file); // 关闭文件
    printf("文件已重组并保存为 %s\n", filename);
}

最后,讲下服务器处理客户端发送的文件,首先接收客户端发来的文件总块数,先开辟相应大小的缓存数组:receivedBlocks = (FileBlock*)malloc(sizeof(FileBlock) * totalBlocksExpected);这里值得一提FileBlock结构体,它是由块ID,data,size,crc32值组成。然后,将接收文件数据放入缓冲数组

 block.data = (char*)malloc(block.size);
 int totalReceived = 0;
 while (totalReceived < block.size) {
     bytesReceived = recv(clientSocket, buffer, (BUFFER_SIZE<block.size - totalReceived?BUFFER_SIZE:block.size - totalReceived), 0);
     if (bytesReceived <= 0) {
         free(block.data);
         goto cleanup;
     }
     memcpy(block.data + totalReceived, buffer, bytesReceived);
     totalReceived += bytesReceived;
 }

最后验证CRC是否正确,将接收到的块重组成文件。

代码汇总

客户端代码

#include "p2p_common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")
#pragma execution_character_set("utf-8")
#define BUFFER_SIZE 1024
#define MAX_RETRY_COUNT 5

void setConsoleCodePage() {
    SetConsoleOutputCP(65001);
    SetConsoleCP(65001);
}

uint32_t calculateCRC32(const char* data, int32_t size) {
    uint32_t crc = 0xFFFFFFFF;
    for (int i = 0; i < size; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
        }
    }
    return ~crc;
}
//传输总块数
int sendAll(SOCKET s, const char* buf, int len, int flags) {
    int total = 0;
    int bytesLeft = len;
    int n;

    while (total < len) {
        n = send(s, buf + total, bytesLeft, flags);
        if (n == SOCKET_ERROR) {
            return SOCKET_ERROR;
        }
        total += n;
        bytesLeft -= n;
    }

    return total;
}

int sendFileBlock(SOCKET clientSocket, FileBlock* block) {
    int retry_count = 0;
    while (retry_count < MAX_RETRY_COUNT) {
        if (sendAll(clientSocket, (char*)&block->id, sizeof(block->id), 0) == SOCKET_ERROR ||
            sendAll(clientSocket, (char*)&block->size, sizeof(block->size), 0) == SOCKET_ERROR ||
            sendAll(clientSocket, block->data, block->size, 0) == SOCKET_ERROR ||
            sendAll(clientSocket, (char*)&block->crc32, sizeof(block->crc32), 0) == SOCKET_ERROR) {
            
            printf("发送块 %lld 失败,重试中...\n", block->id);
            retry_count++;
            Sleep(1000);  // 等待1秒后重试
        } else {
            return 1;  // 成功发送
        }
    }
    printf("发送块 %lld 失败,已达到最大重试次数\n", block->id);
    return 0;
}

void displayProgress(int64_t current, int64_t total) {
    const int barWidth = 50;
    float progress = (float)current / total;
    int pos = barWidth * progress;

    printf("\r[");
    for (int i = 0; i < barWidth; ++i) {
        if (i < pos) printf("=");
        else if (i == pos) printf(">");
        else printf(" ");
    }
    printf("] %d%%", (int)(progress * 100.0));
    fflush(stdout);
}
int main() {
    setConsoleCodePage();

    WSADATA wsaData;
    SOCKET clientSocket;
    struct sockaddr_in serverAddr;
    char filename[BUFFER_SIZE];

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        printf("WSAStartup 失败!\n");
        return -1;
    }

    printf("请输入要上传的文件名: ");
    scanf("%s", filename);
    getchar(); // 清除输入缓冲

    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        perror("无法打开文件");
        WSACleanup();
        return -1;
    }
    // 获取文件大小,
    fseek(fp, 0, SEEK_END);
    long fileSize = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    //向上取整
    int totalBlocks = (fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE;

    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket == INVALID_SOCKET) {
        printf("套接字创建失败!\n");
        fclose(fp);
        WSACleanup();
        return -1;
    }

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        printf("连接失败!\n");
        closesocket(clientSocket);
        fclose(fp);
        WSACleanup();
        return -1;
    }

    printf("已连接到服务器。\n");

    if (sendAll(clientSocket, (char*)&totalBlocks, sizeof(totalBlocks), 0) == SOCKET_ERROR) {
        printf("发送总块数失败\n");
        closesocket(clientSocket);
        fclose(fp);
        WSACleanup();
        return -1;
    }

    FileBlock block;
    for (int64_t i = 0; i < totalBlocks; i++) {
        block.id = i;
        block.size = (i == totalBlocks - 1) ? (fileSize % BLOCK_SIZE) : BLOCK_SIZE;
        if (block.size == 0) block.size = BLOCK_SIZE;

        block.data = (char*)malloc(block.size);
        fread(block.data, 1, block.size, fp);

        block.crc32 = calculateCRC32(block.data, block.size);

        if (!sendFileBlock(clientSocket, &block)) {
            printf("\n发送块 %lld 失败,传输中断\n", block.id);
            free(block.data);
            closesocket(clientSocket);
            fclose(fp);
            WSACleanup();
            return -1;
        }

        displayProgress(i + 1, totalBlocks);
        free(block.data);
    }

    printf("\n文件传输完成。\n");

    // 等待服务器确认
    char confirmation[BUFFER_SIZE];
    int received = recv(clientSocket, confirmation, BUFFER_SIZE, 0);
    if (received > 0) {
        confirmation[received] = '\0';
        printf("服务器响应: %s\n", confirmation);
    } else {
        printf("未收到服务器确认\n");
    }

    fclose(fp);
    closesocket(clientSocket);
    WSACleanup();

    printf("上传成功。按任意键退出...\n");
    getchar();
    return 0;
}

服务器端代码

#include "p2p_common.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <windows.h> 
#include <winsock2.h> // Windows套接字库
#include <ws2tcpip.h> // TCP/IP协议相关库
#include <process.h> 

#pragma comment(lib, "ws2_32.lib") // 链接ws2_32库
#pragma execution_character_set("utf-8") // 设置执行字符集为UTF-8
#define MAX_BLOCKS 1000000 // 定义最大块数
#define BUFFER_SIZE 1024 // 定义缓冲区大小

FileBlock* receivedBlocks = NULL; // 接收到的文件块数组
int blockCount = 0; // 已接收的块数
CRITICAL_SECTION blockMutex; // 用于线程同步的临界区
int serverRunning = 1; // 服务器运行状态标志
int totalBlocksExpected = 0; // 预期接收的总块数

// 设置控制台代码页为UTF-8
void setConsoleCodePage() {
    SetConsoleOutputCP(65001); // 设置输出代码页为UTF-8
    SetConsoleCP(65001); // 设置输入代码页为UTF-8
}

// CRC32校验和计算函数
uint32_t calculateCRC32(const char* data, int32_t size) {
    uint32_t crc = 0xFFFFFFFF;
    for (int i = 0; i < size; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
        }
    }
    return ~crc;
}
// 文件重组函数
void reassembleFile(const char* filename) {
    FILE* file = fopen(filename, "wb"); // 以二进制写模式打开文件
    if (file == NULL) {
        perror("无法创建输出文件");
        return;
    }

    // 写入文件
    for (int i = 0; i < totalBlocksExpected; i++) {
        fwrite(receivedBlocks[i].data, 1, receivedBlocks[i].size, file);
        //fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
        free(receivedBlocks[i].data); // 释放内存
    }

    fclose(file); // 关闭文件
    printf("文件已重组并保存为 %s\n", filename);
}

// 处理客户端连接的线程函数
unsigned __stdcall handleClient(void* arg) {
    SOCKET clientSocket = *(SOCKET*)arg; // 客户端套接字
    FileBlock block;
    char buffer[BUFFER_SIZE];
    int bytesReceived;

    // 接收总块数针对服务器的预期
    if (totalBlocksExpected == 0) {//开始接收文件块之前,服务器需要知道总共有多少个文件块需要接收
        if (recv(clientSocket, (char*)&totalBlocksExpected, sizeof(totalBlocksExpected), 0) <= 0) {
            printf("接收总块数失败\n");
            closesocket(clientSocket);
            return 0;
        }
        printf("预期接收总块数:%d\n", totalBlocksExpected);
        receivedBlocks = (FileBlock*)malloc(sizeof(FileBlock) * totalBlocksExpected);
        if (receivedBlocks == NULL) {
            printf("内存分配失败\n");
            closesocket(clientSocket);
            return 0;
        }
    }

    while (1) {
        // 接收块ID
        if (recv(clientSocket, (char*)&block.id, sizeof(block.id), 0) <= 0) {
            break;
        }

        // 接收数据大小
        if (recv(clientSocket, (char*)&block.size, sizeof(block.size), 0) <= 0) {
            break;
        }

        // 分配内存并接收数据
        block.data = (char*)malloc(block.size);
        int totalReceived = 0;
        while (totalReceived < block.size) {
            bytesReceived = recv(clientSocket, buffer, (BUFFER_SIZE<block.size - totalReceived?BUFFER_SIZE:block.size - totalReceived), 0);
            if (bytesReceived <= 0) {
                free(block.data);
                goto cleanup;
            }
            memcpy(block.data + totalReceived, buffer, bytesReceived);
            totalReceived += bytesReceived;
        }

        // 接收CRC32校验和
        if (recv(clientSocket, (char*)&block.crc32, sizeof(block.crc32), 0) <= 0) {
            free(block.data);
            break;
        }

        // 验证CRC32校验和
        uint32_t calculatedCRC32 = calculateCRC32(block.data, block.size);
        if (calculatedCRC32 != block.crc32) {
            printf("块 %lld 的CRC32校验和不匹配\n", block.id);
            free(block.data);
            continue;
        }

        // 将块添加到接收列表
        EnterCriticalSection(&blockMutex);
        if (block.id < totalBlocksExpected) {
            receivedBlocks[block.id] = block;
            blockCount++;
            printf("接收到块 %lld,大小:%d 字节(%d/%d)\n", block.id, block.size, blockCount, totalBlocksExpected);
            
            if (blockCount == totalBlocksExpected) {
                printf("已接收所有块,准备重组文件...\n");
                reassembleFile("demo.mp4");
                serverRunning = 0;
                send(clientSocket, "File received successfully", 27, 0);
            }
        } else {
            printf("收到无效的块ID: %lld\n", block.id);
            free(block.data);
        }
        LeaveCriticalSection(&blockMutex);
    }

cleanup:
    closesocket(clientSocket);
    return 0;
}

// 服务器线程函数
unsigned __stdcall serverThread(void* arg) {
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0); // 创建服务器套接字
    if (serverSocket == INVALID_SOCKET) {
        perror("无法创建套接字");
        return 1;
    }

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        perror("绑定套接字失败");
        closesocket(serverSocket);
        return 1;
    }

    if (listen(serverSocket, 5) == SOCKET_ERROR) {
        perror("监听失败");
        closesocket(serverSocket);
        return 1;
    }

    printf("服务器正在监听端口 %d\n", PORT);

    while (serverRunning) {
        struct sockaddr_in clientAddr;
        int clientAddrLen = sizeof(clientAddr);
        SOCKET clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
        if (clientSocket == INVALID_SOCKET) {
            if (serverRunning) {
                perror("接受连接失败");
            }
            continue;
        }

        unsigned threadId;
        HANDLE threadHandle = (HANDLE)_beginthreadex(NULL, 0, handleClient, &clientSocket, 0, &threadId);
        if (threadHandle == NULL) {
            perror("创建线程失败");
            closesocket(clientSocket);
        } else {
            CloseHandle(threadHandle);
        }
    }

    closesocket(serverSocket);
    return 0;
}

// 主函数
int main() {
    setConsoleCodePage(); // 设置控制台代码页

    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        perror("WSAStartup 失败");
        return 1;
    }

    InitializeCriticalSection(&blockMutex); // 初始化临界区

    unsigned threadId;
    HANDLE serverThreadHandle = (HANDLE)_beginthreadex(NULL, 0, serverThread, NULL, 0, &threadId);

    if (serverThreadHandle == NULL) {
        perror("创建服务器线程失败");
        DeleteCriticalSection(&blockMutex);
        WSACleanup();
        return 1;
    }

    printf("服务器已启动。等待接收文件块...\n");

    WaitForSingleObject(serverThreadHandle, INFINITE); // 等待服务器线程结束
    CloseHandle(serverThreadHandle);

    DeleteCriticalSection(&blockMutex); // 删除临界区
    if (receivedBlocks) {
        free(receivedBlocks); // 释放内存
    }
    WSACleanup(); // 清理Winsock库

    printf("程序已完成。按回车键退出...\n");
    getchar();

    return 0;
}

效果展示

请添加图片描述

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

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

相关文章

vue组件中的数据传递(2)--子组件传父组件

两种情况 子主动传 vue 父传子 子传父实现方式_vue父传子-CSDN博客 vue父子组件传值&#xff0c;父传子&#xff0c;子传父_父传子 且随时变化-CSDN博客 父主动要 Vue2.0的三种常用传值方式、父传子、子传父、非父子组件传值_父传子传-CSDN博客

File Transfer Server 文件传输服务器插件

您需要在本地不同设备之间传输文件吗?现在你可以做到了,你不必安装任何专用服务器。 文件传输服务器为您的游戏或应用程序添加了将文件从任何受支持的平台传输到任何受支持平台的能力。从移动到独立,从移动到移动等(查看支持的平台) 优势: -完整的源代码可用。 -不需要预…

【揭秘心梗元凶】不容忽视的七大生活习惯,竟是心梗“幕后推手”!

在这个快节奏的时代&#xff0c;心梗&#xff08;急性心肌梗死&#xff09;这一健康杀手正悄然逼近&#xff0c;威胁着越来越多人的生命安全。心梗不仅发病急骤&#xff0c;后果往往也极为严重。那么&#xff0c;心梗究竟是如何引起的&#xff1f;今天&#xff0c;我们就来揭开…

Leetcode面试经典150题-239.滑动窗口最大值

解法都在代码里&#xff0c;不懂就留言或者私信 官方定级hard难度&#xff0c;其实是medium&#xff0c;确实字节考过 class Solution {public int[] maxSlidingWindow(int[] nums, int k) {if(nums.length 1) {return new int[]{nums[0]};}/**我们要返回的是一个数组&#…

SoM的理解

对于终端客户来说&#xff0c;要思考到底怎么做一款产品。目前好像主流的就是SoC和SoM。以前联发科是有Turnkey项目&#xff0c;不过我记得我参与的项目&#xff0c;都是直接拿原厂的参考设计&#xff0c;基本上就是改一个壳&#xff0c;电路板&#xff0c;IO啥的都不动&#x…

土壤湿度传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 三、程序设计 main.c文件 TS.h文件 TS.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 传感器适用于土壤的湿度检测&#xff0c;模块中蓝色的电位器是用于土壤湿度的阈值调节&#xff0c;数字量输出DO可以与…

进程间的通信(IPC)基础了解,匿名管道使用,有名管道使用

进程间通信基本知识 进程间通信的定义 进程间通信方式分类 匿名管道&#xff08;pipe&#xff09; 匿名管道介绍 创建方式&#xff1a;使用 pipe 系统调用创建&#xff0c;返回一对文件描述符&#xff08;读端和写端&#xff09;。生命周期&#xff1a;匿名管道的生命周期与…

为什么说RAG是AI 2.0时代的“杀手级”应用?

复旦AI博士&#xff0c;分享AI领域全维度知识与研究。应极客时间邀请开设《RAG快速开发实战》课程&#xff0c;感兴趣的同学可以访问关注 https://time.geekbang.com/column/intro/100804101 随着 AI 2.0 时代的来临&#xff0c;我们正站在一个技术革新和行业变革的交汇点。大语…

Vue3优化表单标签与布局,解决文字过长问题(附Demo)

目录 前言1. 增加标签宽度&#xff08;生效&#xff09;2. 工具提示 Tooltip&#xff08;勉勉强强&#xff09;3. 缩小字体&#xff08;不生效&#xff09;4. CSS 控制换行&#xff08;不推荐&#xff09; 前言 好不容易构思整个表单的布局&#xff0c;但是个别表单的文字过长…

springboot整合logback进行日志管理(上篇)

1、前言: 在日常开发中日志的打印与日志的记录是非常重要的。市面上主流的日志管理框架有log4j、logback,二者各有优缺点v,由于项目中比较常用的是logback(我们自己项目就是用的logback),进行就主要介绍一下logback在真是项目中是如何整合的。 2、springboot默认整合的logb…

NASA数据集:50 m分辨率的雪水当量(SWE)地图的集合

ASO L4 Lidar Snow Water Equivalent 50m UTM Grid V001 ASO L4 激光雷达雪水当量 50 米UTM 网格&#xff0c;第 1 版 简介 该数据集包含 50 米网格雪水当量 (SWE) 值&#xff0c;是 NASA/JPL 机载雪地观测站 (ASO) 飞机勘测活动的一部分。 这些数据来自 ASO L4 Lidar Snow …

OLED预警系统与按键菜单交互代码实操

引言 OLED顾名思义就是一个屏幕, 我们让一个屏幕在特定的时间, 显示特定的画面, 就是我们所需要的, 因为这里是涉及到环境预警,所以需要加入一个应急接管页面的选项, 所以我们要把按键直接操作画面, 变成按键操作完, 我们根据优先级判断之后, 才能确定要显示的是哪个画面. 比如…

【无标题】书生大模型实战营闯关记录----第十二关:茴香豆:企业级知识库问答工具;Web版茴香豆使用教程;茴香豆本地化标准版部署搭建教程;知识库构建问答

0 茴香豆介绍 茴香豆 是由书生浦语团队开发的一款开源、专门针对国内企业级使用场景设计并优化的知识问答工具。在基础 RAG 课程中我们了解到&#xff0c;RAG 可以有效的帮助提高 LLM 知识检索的相关性、实时性&#xff0c;同时避免 LLM 训练带来的巨大成本。在实际的生产和生活…

Yolov5 AI学习笔记

Yolov5 AI学习笔记 环境准备 需要Python的开发环境&#xff0c;安装Anaconda。 Anaconda的一些命令&#xff1a; # 创建虚拟环境 conda create -n yolo_cpu python3.9 # 查看虚拟环境 conda env list # 激活虚拟环境 conda activate <env_name>Yolov5上手 下载源码 …

上下文的弹性

“上下文的弹性”是指在自然语言处理中&#xff0c;模型对输入文本的上下文信息的理解和利用能力。它描述了模型在处理文本时能够根据上下文信息来调整其输出的程度。具有弹性上下文的模型可以更好地处理自然语言中的语义和语境&#xff0c;从而提供更准确和有用的回答。这种弹…

这才是老板喜欢的产品经理简历

速创猫今天给大家分享的是应届毕业生产品经理简历优化案例&#xff0c;希望对大家求职有帮助。速创猫总结了以下七条简历制作干货&#xff0c;希望对大家有帮助&#xff1a; 明确目标岗位&#xff1a;在简历的开头&#xff0c;明确指出你申请的职位&#xff0c;让招聘者一眼就能…

聚焦AI4SE软件工程领域,基于Multi Agent System多智能体系统开发的最新成果,实现软件开发领域的PUGC!

可能有很多小伙伴不了解AI4SE是什么&#xff0c;其实从字意上就不难看出一定是和AI相关。 AI4SE&#xff08;Artificial Intelligence for Software Engineering&#xff09;是指将人工智能技术应用于软件工程领域。 其核心目标是通过自动化和智能化技术降低软件开发的复杂性…

MySQL 官方高可用方案 InnoDB Cluster

文章目录 前言1. 方案构成2. 使用要求和限制3. 集群部署3.1 环境说明3.2 软件下载3.2 MySQL Server 安装3.3 MySQL Shell 安装3.4 检测实例是否符合资格3.5 创建集群3.6 向集群中添加节点3.7 配置 Router3.8 测试验证 4. 集群运维4.1 Router 服务管理4.2 MySQL 服务管理4.3 集群…

结束Linux特定端口上的进程,超级实用!

在使用 Linux 时&#xff0c;您可能会遇到特定端口被进程占用的情况。了解如何终止在特定端口上运行的进程可能非常有用&#xff0c;特别是对于排除故障和有效地管理系统而言。 本文中&#xff0c;我们将完成查找端口号、识别使用该端口的进程以及安全停止该进程。 详细步骤 …

【最全深度学习介绍】基本概念、类型、应用、优缺点、与机器学习区别是什么?

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…