最新资讯

  • 【linux】网络套接字编程(四)TCP服务器与客户端的实现(单进程/单线程的TCP服务器),setsockopt,listen,accept,telnet,connect,inet_pton

【linux】网络套接字编程(四)TCP服务器与客户端的实现(单进程/单线程的TCP服务器),setsockopt,listen,accept,telnet,connect,inet_pton

2026-01-29 01:41:05 栏目:最新资讯 7 阅读

小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
linux系统编程专栏<—请点击
linux网络编程专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!


目录

    • 前言
    • 一、TCP服务器TcpServer.hpp(版本一:单进程/单线程版)
      • 基本框架
      • InitServer
        • setsockopt
        • listen
      • StartServer
        • accept
      • Service
    • 二、Main.cc
    • 三、telnet作为客户端进行测试
    • 四、TCP客户端TcpClient.cc
      • 基本框架
      • connect连接
        • inet_pton
      • 开始进行通信
      • 测试
    • 五、源代码
      • makefile
      • TcpServer.hpp
      • TcpClient.cc
      • Main.cc
      • Log.hpp
    • 总结


前言

【linux】网络套接字编程(三)UDP服务器与客户端实现:跨主机执行命令程序,windows与linux通信执行命令程序,多人在线聊天程序,inet_ntop——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习
本文由小编为大家介绍——【linux】网络套接字编程(四)TCP服务器与客户端的实现(单进程/单线程的TCP服务器),setsockopt,listen,accept,telnet,connect,inet_pton


一、TCP服务器TcpServer.hpp(版本一:单进程/单线程版)

  1. 关于TCP协议的介绍,以及socket,bind,htons,ntohs等接口的使用,端口号bind的介绍,小编已经在后方蓝字链接文章中进行了讲解 详情请点击<——
  2. 关于IP地址的讲解 详情请点击<——
  3. 关于日志的实现与基本使用讲解 详情请点击<——
  4. 上述的文章与TCP服务器的编写具有一定的铺垫作用,所以希望读者友友先学习上述文章之后再来进入本文的学习更加轻松
  5. 那么对于TCP的服务器,我们希望进行封装为TcpServer.hpp,并且在包含main函数中的文件中包TCP服务器的头文件TcpServer.hpp进行调用,所以下面我们就来先实现一下TCP服务器
  6. 其实TCP服务器的编写套路和UDP服务器的编写套路十分的类似,尤其是在初始化InitServer部分,几乎就是UDP服务器一样,所以本文会基于UDP服务器的实现的基础上直接进行简要的讲解,UDP服务器与客户端的实现,详情请点击<——

基本框架

  1. 首先小编在日志中直接定义了一个日志的全局变量Log lg,这样其它的文件如果想要使用日志,那么仅需要包含日志的头文件#include “Log.hpp”,然后extern声明外部变量即可使用日志

  2. 那么接下来就是定义IP地址,端口号port,网络文件描述符fd的缺省参数,这里小编还定义了一个backlog为10,这个backlog用于给listen进行传参,关于listen是什么,小编后面会进行讲解

  3. 接下来使用枚举enum定义错误码,然后就可以开始TcpServer服务器的编写了

  4. 首先我们需要了解一下一个TCP服务器的类TcpServer中应该包含什么成员变量,那么TCP服务器的成员变量类似于UDP服务器的成员变量,即TCP服务器的成员变量需要包含网络文件描述符,端口号,IP地址,但是注意,这里小编关于类中定义的网络文件描述符的命名不是和UDP服务器写的都是socket_了,在TCP服务器这里,我们将这个网络文件描述符命名为listensock_,所以为什么呢?

  5. 因为TCP协议是面向连接的,服务器需要先和客户端建立起连接才能进行通信,所以服务器如何和客户端建立连接呢?所以服务器在进行初始化部分的时候,要先创建套接字,绑定,接下来和UDP不一样的是,TCP服务器需要额外使用listen接口,将网络文件描述符listensock_设置为监听状态,即TCP服务器初始化创建的套接字返回的网络文件描述符listensock_仅仅用于监听的作用,即表示当前服务器可以接收外部客户端的连接请求

  6. 那么在构造函数我们就进行对应字段的设置,在析构函数,如果创建了网络文件描述符listensock_大于0,那么我们就close关闭这个网络文件描述符对应的文件对象

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Log.hpp"

const int defaultfd = -1;
const uint16_t defaultport = 8080;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;
extern Log lg;

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip)
        : listensock_(defaultfd), port_(port), ip_(ip)
    {}

    ~TcpServer()
    {
        if (listensock_ > 0)
            close(listensock_);
    }

private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};

InitServer

  1. 那么在初始化InitServer部分,我们要完成socket创建套接字,struct sockaddre_in本地属性初始化,bind套接字绑定,listen将网络文件描述符listensock_设置为监听状态,下面小编将依次进行讲解
  2. 创建套接字要使用socket,并且我们创建的是TCP网络套接字,TCP是一个使用IPv4地址的网络通信协议,所以socket的第一个参数选择协议家族(域)AF_INET,TCP是面向字节流进行通信的,所以选择协议类型为SOCK_STREAM,最后一个参数默认为0即可,socket,bind的使用,详情请点击<——,如果套接字创建失败,那么我们使用日志打印信息,然后终止服务器,如果成功了那么我们打印日志信息即可
setsockopt

  1. 其实服务器如果中断,然后立即重启,会触发偶发性的重启失败,端口号无法绑定的问题,所以这里我们在服务器的初始化的时候,使用setsockopt这个接口就可以有效避免这种情况,setsockopt是作用是设置网络套接字的选项,所以依次传入网络文件描述符listensock_,然后level就是选择协议层,这里我们选择套接字层SOL_SOCKET,接下来就需要传入要设置的选项,那么这里我们设置重新使用IP地址,重新使用端口号即可SO_REUSEADDR|SO_REUSEPORT,optval即要设计选项的值,那么我们在本地定义一个值为1的opt然后取地址传入即可&opt,紧接着是传入这个变量的大小,即sizeof(opt)
  2. 接下来就是进行struct sockaddre_in本地属性初始化,那么我们和UDP一样,进行对应字段的设置,然后将端口号和IP地址的主机字节序列转换为网络字节序列进行传入即可
  3. 接下来就是进行套接字的绑定bind,那么和UDP的套路一样,依次传入网络文件描述符listensock_,要绑定的字段,字段的大小即可,如果绑定失败bind则会返回一个小于0的数,所以我们判断一下,如果绑定失败,那么打印日志信息,然后终止服务器,如果绑定成功,那么打印日志信息即可
listen

  1. 那么接下来就是使用listen将一个网络文件描述符对应的网络套接字设置为监听状态,那么依次传入网络文件描述符listensock_,然后再传入backlog,其中关于这个backlog我们在基本框架已经定义出来了,默认我们设置为10,表示允许这个服务器同时可以监听连接请求的最大数量,一般我们将其设置为10,并且不会将其设置为很大
  2. 如果listen失败bind则会返回一个小于0的数,所以我们判断一下,如果listen监听失败,那么打印日志信息,然后终止服务器,如果listen监听成功,那么打印日志信息即可
void InitServer()
{
    listensock_ = socket(AF_INET, SOCK_STREAM, 0);
    if (listensock_ < 0)
    {
        lg(Fatal, "create socket error, errno: %d, errstring: %s", errno, strerror(errno));
        exit(SocketError);
    }
    lg(Info, "create socket success, listensock_: %d", listensock_);

    //防止偶发性服务器无法立即重启
    int opt = 1;
    setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(port_);
    inet_aton(ip_.c_str(), &(server.sin_addr));
    socklen_t len = sizeof(server);

    if (bind(listensock_, (struct sockaddr *)&server, len) < 0)
    {
        lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
        exit(BindError);
    }
    lg(Info, "bind socket success, listensock_: %d", listensock_);

    if (listen(listensock_, backlog) < 0)
    {
        lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
        exit(ListenError);
    }
    lg(Info, "listen socket success, listensock_: %d", listensock_);
}

StartServer

  1. 这个版本是单进程/单线程版本的启动服务器,那么首先我们打印一个日志消息表示服务器已经启动
  2. 既然是服务器,那么服务器就要24小时的为客户端提供服务,即服务器要一直运行下去,所以这里服务器启动的核心逻辑就要基于死循环for(; ; )进行编写
  3. 之前再服务器初始化的时候我们使用listen将网络文件描述符listensock_对应的网络套接字设置为监听状态,可以监听服务器收到的连接请求,所以此时服务器和客户端建立连接了吗?没有,仅仅是服务器知道了有几个客户端想要连接自己这个服务器,那么如何进行连接呢?accept
accept

  1. 使用accept即可,那么依次传入网络文件描述符listensock_,并且注意这个accept函数和我们在UDP阶段使用的recvfrom的后两个参数是一样的,所以对于我们来讲上手使用这个accept就没难度了
  2. 那么在本地定义一个sockaddr_in类型的对象client,然后取地址进行类型转换为struct sockaddr*再传入,然后计算出大小传入即可,后续连接上的客户端的字段信息,例如IP地址,端口号等就都在这个client中了,所以此时就可以进行连接客户端和服务端了
  3. 那么接下来重点来了,那么就是accept的返回值,如果连接失败了,那么就会返回一个小于0的数,那么我们进行判断即可,如果返回值小于0,那么就日志打印即可,然后再continue重新执行连接(毕竟着只是一个连接失败,但是不能因为仅仅一个连接失败就将服务器终止吧,所以服务器连接失败的时候,不能终止,而是应该继续进行下一个连接),如果连接成功,那么就会返回一个网络文件描述符sockfd,那么我们就可以使用这个网络文件描述符进行读写式的进行通信了,如何读,如何写?
  4. 那么就和文件操作一样,由于文件是基于字节流的,而TCP恰好也是基于字节流的,所以这里完全可以使用文件的read和write向文件描述符中进行读取或写入,大大降低了我们的学习成本,所以后续服务端想要和客户端进行通信,那么就需要使用到accept的返回值,即使用网络文件描述符sockfd
  5. 那么问题来了,TCP服务器初始化然后socket创建的套接字的返回值listensock_和这里accept连接的返回值sockfd都是网络文件描述符,那么两者的作用分别是什么呢?
    (1)listensock_是网络文件描述符,用于监听服务器收到的连接请求,一般一个TCP服务器只有一个listensock_
    (2)sockfd同样是网络文件描述符,它的作用是用于服务端想要和已经连接上的客户端进行通信,进行读写操作的桥梁,用于服务器和客户端进行网络通信的网络文件描述符,服务器可以和多个客户端进行连接,所以也就意味着sockfd可以有多个
  6. 接下来走到下面accept服务器连接客户端成功,那么客户端的信息,例如IP地址,端口号port的信息就都在类型为struct sockaddr_in的这个client对象中了,但是此时对应的字段信息仍然为网络字节序列,小编想要将IP地址以及端口号提取出来在本主机上进行使用,那么就要网络字节序列转主机字节序列
  7. 那么对于端口号,我们可以使用ntohs进行转换为主机字节序列,那么对于为整数的网络字节序列的IP地址, 我们首先要将网络字节序列转换为为整数的主机字节序列,然后再将其转换为点分十进制的字符串风格的IP地址,这里我们使用inet_ntop
  8. 这里小编将主机序列转换为网络字节序列,并且转换为点分十进制的字符串风格IP地址的时候,则使用inet_ntop进行转换 关于inet_ntop如何使用,在第三点的测试的第二点中进行的讲解,详情请点击<——,那么我们依次传入协议家族(IPv4对应的是AF_INET),struct sockaddr_in中的sin_addr的地址(由于sin_addr的成员就是整数类型的IP地址,所以本质上就是传入IP地址字段),自己维护的缓冲区serverip,缓冲区的大小即可
  9. 所以转化端口号和IP地址完成后,那么接下来我们就可以打印一下日志信息了,将网络文件描述符sockfd进行打印然后打印IP地址和端口号信息,并且这里我们可以猜测一下这里的网络文件描述符sockfd应该是4,因为3是listensock_,2是标准错误,1是标准输出,0是标准输出
  10. 然后我们接下来执行Server函数,Server函数是用于服务端处理数据,然后服务端和客户端进行通信的函数,这个小编后面会进行实现,那么让Server函数执行完毕之后,此时当前服务器和客户端的通信已经结束了,所以我们在服务端将这个网络文件描述符sockfd使用close关闭即可
  11. 这个版本是单进程/单线程版本的启动服务器,因为这里执行了Server之后,当前进程就去进行服务器和客户端的通信了,在处理通信的期间无法继续接收其它客户端的连接请求,只有在处理完成了通信之后,关闭文件描述符sockfd,才可以继续接收其它客户端的连接请求,才可以和其它客户端进行通信,所以我们编写的当前版本是单进程/单线程的TCP服务器
void StartServer()
{
    lg(Info, "tcpserver is running...");

    for (;;)
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        
        int sockfd = accept(listensock_, (struct sockaddr*)&client, &len);
        if (sockfd < 0)
        {
            lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
            continue;
        }
        uint16_t clientport = ntohs(client.sin_port);
        char clientip[32];
        inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

        lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", 
            sockfd, clientip, clientport);
        
        Service(sockfd, clientip, clientport);
        close(sockfd);
    }
}

Service

  1. 现在我们设想的场景是客户端一旦连接上服务器,那么客户端期望和服务器源源不断的进行通信,即由服务器提供长服务,所以这里我们就基于while(true)死循环基础上进行编码
  2. 有了网络文件描述符,并且TCP是基于字节流的,文件也是基于字节流的,所以可以使用read读接收数据,使用write进行写发送数据
  3. 那么此时服务端就要读取数据,首先定义一个缓冲区用于将读取上来的数据放到这个缓冲区中,服务端和客户端约定,相互之间传输的数据是字符串,所以此时当read结束,就将这个缓冲区当作字符串来处理,那么使用n来接收read的返回值,n是read读取的字节的个数
  4. 如果n等于0,那么说明此时客户端已经退出,客户端已经将写端关闭了,所以此时我们我们再进行读取已经没有意义了,因为根本没有数据了,所以此时我们先使用日志打印信息,然后break退出死循环,那么结束服务,之后Service执行完毕,就会close关闭sockfd网络文件描述符
  5. 如果n小于0,说明读取失败,此时有可能sockfd有误或者其它原因无法进行读取,所以此时我们日志打印信息,同样break退出死循环,那么结束服务,之后Service执行完毕,就会close关闭sockfd网络文件描述符
  6. 如果n大于0,那么说明此时读取数据成功,所以此时我们就可以对缓冲区进行处理了,由于文件中的字符串的结尾没有’’,所以这里我们c/c++语言中规定,字符串要以’’结尾,所以我们就在n位置处放一个0即可,即在字符串的结尾添加’’,接下来那么我服务端回显打印一下收到了客户端的什么消息即可,然后定义一个字符串echo_string,使用服务端的信息"tcpserver echo# "初始化,将服务端收到的字符串也进行添加上
  7. 即服务端将收到的字符串进行简单的处理之后,然后再write通过sockfd写回给客户端即可
  8. 注意,这里必须要对n == 0或者n < 0的情况进行处理,因为一旦服务器或者客户端,一方作为读端,另一方作为写端进行网络通信,如果有一端突然退出,不想通信了,那么此时也就意味着信道的读端或者写端关闭了一个
  9. 那么此时我们就以客户端作为写端,服务器作为读端为例进行讲解,写端关闭了,那么此时读端就无法读取到数据了,所以也就意味着读端没有意义存在了,所以如果操作系统检测到了对方的写端关闭,而自己这边的读端还在读取,所以操作系统认为自己这边的读端进行读取没有意义,是在浪费资源的,而操作系统绝对不允许在系统内任何一件浪费时间和空间的事情的,而服务器本质上也是一个进程,既然是进程就统一归操作系统管理,操作系统有终止进程的权限,那么操作系统就会直接终止该服务器进程
  10. 那么这一终止可不得了,你试想一下,直接将服务器给终止了,那么所有的客户端都无法连接上服务器了,如果今天的服务器是微信服务器呢?所以所有的手机电脑上的微信客户端都无法通信,支付了,这本质上是非常严重的,所以我们呢不期望服务器被终止,所以这里我们必须要对read的返回值n进行获取,并且操作,一旦我们接收了read的返回值,并且及时进行了操作,我们服务器及时主动的关闭这边的读端,那么此时操作系统就不会终止这个进程了,所以也就保障了服务器可以一直运行
void Service(int sockfd, const std::string& clientip, const uint16_t& clientport)
{
    while (true)
    {
        char inbuffer[4096];
        ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
        if (n > 0)
        {
            inbuffer[n] = 0;
            std::cout << "client say# " << inbuffer << std::endl;

            std::string echo_string = "tcpserver echo# ";
            echo_string += inbuffer;

            write(sockfd, echo_string.c_str(), echo_string.size());                
        }
        else if(n == 0)
        {
            lg(Info, "%s:%d quit, server colse sockfd: %d", clientip.c_str(), clientport, sockfd);
            break;
        }
        else  
        {
            //异常
            lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", 
                sockfd, clientip.c_str(), clientport);
            break;
        }
    }
}

二、Main.cc

  1. main函数的编写以及调用逻辑和UDP协议的main函数类似,即获取命令行参数,提取port,然后使用智能指针管理new出来的TCP服务器对象,给这个TCP服务器对象传参port,接下来初始化TCP服务器,然后运行TCP服务器即可
#include 
#include 
#include "TcpServer.hpp"


void Usage(const std::string str)
{
    std::cout << "
	Usage: " << str << " port[1024+]
" << std::endl; 
}


int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(UsageError);
    }

    uint16_t port = std::stoi(argv[1]);

    std::unique_ptr<TcpServer> server(new TcpServer(port));
    server->InitServer();
    server->StartServer();


    return 0;
}

三、telnet作为客户端进行测试

  1. 其实我们的linux中还有一个工具叫做telnet,这个telnet的底层是使用的是TCP协议,telnet用于在本地通过本地环回地址127.0.0.1然后以及服务端的端口号连接上TCP服务器,可以让telnet作为客户端和我们编写的TCP服务端进行通信
  2. 但是有的读者友友的linux上可能没有安装这个telnet,所以我们使用如下执行安装一下telnet这个工具,然后我们会观察到如下字样complete即为安装telnet工具成功
sudo yum install -y telnet

  1. 所以此时我们将我们的服务器进行编译,然后运行起来,然后使用telnet进行连接,telent是在本地进行连接的服务器,所以使用本地环回的IP地址127.0.0.1,然后再输入服务器绑定的端口号即可建立连接,如下,左侧服务器已经运行起来了
  2. 然后我们在右侧使用telnet作为客户端试着和服务端进行连接,那么启动telnet即输入127.0.0.1 服务器绑定的端口号即可,那么telnet在连接成功之后可以使用ctrl + ]然后再按下回车即可进行输入
  3. 所以此时小编在右侧的使用telnet充当的客户端就可以输入数据和左侧的服务端进行通信了,无误
  4. 那么如何退出右侧telnet的服务端呢?有很多读者友友心中会想,很简单,无脑ctrl+c呀,多简单,那么下面小编尝试一下无脑ctrl+c是否可以退出右侧的telnet服务端,如下很明显,无脑ctrl+c不可以右侧的telnet服务端
  5. 那么正确的退出方式是先按住 ctrl 不松手 然后再按 ] 松开手 此时输入quit即可正常退出telnet客户端
  6. 同样的,如下,如果服务端将信道对应的网络文件描述符socket关闭,或者服务端直接终止(服务端终止,代表着网络文件描述符socket也被关闭了),所以这里小编就ctrl+c在左侧直接终止服务器,同样也会导致telnet的退出

四、TCP客户端TcpClient.cc

  1. 虽然使用telnet工具充当TCP客户端可以让我们观察到服务端和客户端的通信现象,这代表服务端测试无误,可是我们写客户端了吗?没有,仅仅是借助的telnet工具充当客户端,但是关于客户端的原理以及实现,我们还不清楚,所以下面我们来编写一下TCP客户端TcpClient.cc
  2. 其实TCP客户端的编写套路和UDP客户端的编写套路在最初的时候十分的类似,所以小编这里就基于UDP客户端的基础上进行简要讲解,UDP客户端的实现,详情请点击<——

基本框架

  1. 我们期望用户使用 ./udpclient 124.220.4.187 8080 的方式在命令行运行客户端,所以客户端的main函数同样需要参数
  2. 那么如果进行判断argc的个数即可,如果不等于3,那么说明用户传参错误,所以打印提示,然后终止进程即可
  3. 走到下一步说明此时用户传参正确,那么我们提取服务器的IP地址和端口号port即可
  4. 接下来socket创建套接字即可,如果socket的返回值网络文件描述符sockfd小于0,那么说明创建套接字失败,所以我们打印信息,然后终止进程即可
  5. 当最后使用完成了网络文件描述符sockfd之后,使用close关闭网络文件描述符sockfd即可
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void Usage(const std::string& str)
{
    std::cout << "
	Usage: " << str << " serverip serverport" << std::endl; 
}

// ./tcpclient serverip serverport
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        return 0;
    }

    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        std::cerr << "socket create err" << std::endl;
        return 1;
    }

    close(sockfd);


    return 0;
}

connect连接

  1. TCP是面向连接的,所以客户端想要和服务端进行通信,那么客户端需要主动使用connect向服务器发起连接请求
  2. connect的使用方法很简单,先传入网络文件描述符,我们看connect的后两个参数和我们之前使用的sendto的后两个参数完全一样,所以对于我们来讲上手使用connect很简单
  3. 所以我们就在本地定义sockaddr_in的结构体对象server,使用memset将各个字段设置为0,然后进行对应字段的初始化即可,需要注意将端口号port和IP地址的主机序列转换成网络字节序列,端口号port的转换使用hton即可,很简单
inet_pton

  1. 重点是IP地址,这里要将点分十进制的字符串风格的IP地址转换成网络字节序列对应的整数,所以我们使用inet_pton即可,那么依次传入IPv4地址对应的协议家族(域)AF_INET,然后传入要进行转换的点分十进制的字符串风格的IP地址,然后再传入转换后要放入的位置,即server.sin_addr中,那么我们取出server.sin_addr的地址传入即可
  2. 接下来计算出sockaddr_in的结构体对象server的大小len便于进行传参
  3. 所以此时sockaddr_in的结构体对象server的各个字段我们都设置好了,所以接下来就可以进行connect连接了,那么传入网络文件描述符sockfd,然后传入server取地址,接下来强制类型转换为struct sockaddr*,以及传入这个server对象的大小len即可
  4. 所以此时我们就发起了一次连接请求,观察connect的返回值,如果连接并且绑定成功,那么就会返回0,如果连接或者绑定失败就会返回一个小于0的数-1,所以这里我们进行判断,如果返回值小于0,那么代表连接或绑定失败,那么我们就打印信息,然后终止进程
  5. 那么问题来了,客户端要不要bind绑定?客户端要不要显示的bind绑定?客户端是什么时候进行绑定的?
    (1)客户端要bind绑定(2)客户端不需要显示的绑定,而是由操作系统进行自动的随机绑定(3)bind绑定是在客户端发起connect请求的时候,操作系统会自动进行端口号的随机bind绑定
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(serverport);
inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));
socklen_t len = sizeof(server);

//客户端发起connect请求的时候,操作系统会自动进行端口号的随机bind绑定
int n = connect(sockfd, (struct sockaddr*)&server, len);
if(n < 0)
{
    std::cerr << "connect err..." << std::endl;
    return 2;
}

开始进行通信

  1. 那么我们定义一个string类型的字符串,用于接收用户输入,接下来定义一个inbuffer缓冲区用于拷贝服务器发来的在网络文件描述符sockfd对应的套接字对象中缓冲区的数据
  2. 我们期望客户端一旦开始和服务器进行通信,那么就一直进行通信,所以通信的代码逻辑应该基于while死循环的基础上进行编码
  3. 所以首先我们打印消息,提示用户可以开始进行输入,那么使用getline获取一行输入,将输入结果放到message中,所以用户的输入此时就保存在message中
  4. 由于TCP是面向字节流的,并且TPC网络文件描述符fd对应的是一个套接字文件对象,文件同样也是面向字节流的,所以我们就可以使用文件中的读写方式进行通信,即使用read读接收数据,使用write进行写发送数据
  5. 那么作为客户端我们首先要将数据使用write通过网络文件描述符sockfd发送给服务器,并且约定相互之间发送的数据是一个字符串,文件中的字符串不以’’结尾,所以我们可以使用message的size接口求出字符串的大小,符合我们需求
  6. 那么我们使用write依次传入网络文件描述符sockfd,字符串,字符串的大小即可
  7. 但是write写入也有可能会失败,那么就会返回一个小于0的数,所以这里我们接收一下返回值,并且进行判断,如果写入失败,那么打印信息,然后break退出循环即可
  8. 下一步说明数据已经成功的发送给了服务器,那么服务器处理完成之后就要将数据发回给客户端,所以我们客户端此时就收到数据了,数据被放在了网络文件描述符sockfd对应的文件描述符对象的读缓冲区中,所以我们使用read进行读取即可
  9. 那么对于read依次传入网络文件描述符sockfd,然后传入接收缓冲区inbuffer,以及缓冲区的大小 - 1,这个-1是为了防止缓冲区被写满导致最后无法在结尾添加’’所以要预留出防止’’的空间
  10. 使用n接收read的返回值,read返回的是读取的字节数,所以如果read读取成功,那么n应该大于0,所以此时我们将缓冲区的n位置添加上’’,然后将字符串进行打印即可
  11. 如果n等于0,那么代表此时服务器对应的写端已经关闭,所以此时我们read读取已经没有意义了,所以此时直接break,如果n小于0,那么代表网络文件描述符不正确,读取失败等,所以此时我们同样break退出
std::string message;
char inbuffer[4096];
while(true)
{
    std::cout << "Please Enter# ";
    std::getline(std::cin, message);

    int n = write(sockfd, message.c_str(), message.size());
    if(n < 0)
    {
        std::cerr << "write err" << std::endl;
        break;
    }

    n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
    if(n > 0)
    {
        inbuffer[n] = 0;
        std::cout << inbuffer << std::endl;
    }
    else
    {
        break;
    }
}

测试

  1. 由于小编使用的是云服务器,并且云服务器默认不开放端口号,所以我们要先开放云服务器的TCP的端口号8080,才可以使用我们的客户端连接服务器,那么如何开放云服务器的特定端口号呢?如下是开放腾讯云服务器的特定端口号的操作步骤

  2. 首先,进入腾讯云服务器的控制台,找到登录并点击上图红色框框内的任意位置,进入服务器主界面

  3. 接下来点击上方防火墙后,找到下面的添加规则并点击

  4. 然后应用类型默认自定义即可,来源选择全部IPv4地址,由于本文小编使用的是TCP协议进行的网络通信数据传输,所以协议类型选择TCP协议,端口则输入你想要绑定的端口号即可,最后下方点击确定即可添加成功端口号

  5. 所以下面我们就可以开始进行测试了,那么我们编译服务器和客户端即可,然后依次运行服务器,客户端,无误


  6. 然后ctrl+c依次退出客户端,退出服务端即可,无误

五、源代码

makefile

all:tcpserver tcpclient

tcpserver:Main.cc
	g++ -o $@ $^ -std=c++11
tcpclient:TcpClient.cc
	g++ -o $@ $^ -std=c++11

.PHONT:clean
clean:
	rm -f tcpserver tcpclient

TcpServer.hpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Log.hpp"

const int defaultfd = -1;
const uint16_t defaultport = 8080;
const std::string defaultip = "0.0.0.0";
const int backlog = 10;
extern Log lg;

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip)
        : listensock_(defaultfd), port_(port), ip_(ip)
    {}

    void InitServer()
    {
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            lg(Fatal, "create socket error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create socket success, listensock_: %d", listensock_);

        //防止偶发性服务器无法立即重启
        int opt = 1;
        setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));

        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(server.sin_addr));
        socklen_t len = sizeof(server);

        if (bind(listensock_, (struct sockaddr *)&server, len) < 0)
        {
            lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind socket success, listensock_: %d", listensock_);

        if (listen(listensock_, backlog) < 0)
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "listen socket success, listensock_: %d", listensock_);
    }

    void StartServer()
    {
        lg(Info, "tcpserver is running...");

        for (;;)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            
            int sockfd = accept(listensock_, (struct sockaddr*)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", 
                sockfd, clientip, clientport);
            
            Service(sockfd, clientip, clientport);
            close(sockfd);
        }
    }

    void Service(int sockfd, const std::string& clientip, const uint16_t& clientport)
    {
        while (true)
        {
            char inbuffer[4096];
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                inbuffer[n] = 0;
                std::cout << "client say# " << inbuffer << std::endl;

                std::string echo_string = "tcpserver echo# ";
                echo_string += inbuffer;

                write(sockfd, echo_string.c_str(), echo_string.size());                
            }
            else if(n == 0)
            {
                lg(Info, "%s:%d quit, server colse sockfd: %d", clientip.c_str(), clientport, sockfd);
                break;
            }
            else  
            {
                //异常
                lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", 
                    sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }

    ~TcpServer()
    {
        if (listensock_ > 0)
            close(listensock_);
    }

private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};

TcpClient.cc

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void Usage(const std::string& str)
{
    std::cout << "
	Usage: " << str << " serverip serverport" << std::endl; 
}

// ./tcpclient serverip serverport
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        return 0;
    }

    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        std::cerr << "socket create err" << std::endl;
        return 1;
    }

    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));
    socklen_t len = sizeof(server);
    
    //客户端发起connect请求的时候,操作系统会自动进行端口号的随机bind绑定
    int n = connect(sockfd, (struct sockaddr*)&server, len);
    if(n < 0)
    {
        std::cerr << "connect err..." << std::endl;
        return 2;
    }

    std::string message;
    char inbuffer[4096];
    while(true)
    {
        std::cout << "Please Enter# ";
        std::getline(std::cin, message);

        int n = write(sockfd, message.c_str(), message.size());
        if(n < 0)
        {
            std::cerr << "write err" << std::endl;
            break;
        }

        n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
        if(n > 0)
        {
            inbuffer[n] = 0;
            std::cout << inbuffer << std::endl;
        }
        else
        {
            break;
        }
    }

    close(sockfd);


    return 0;
}

Main.cc

#include 
#include 
#include "TcpServer.hpp"


void Usage(const std::string str)
{
    std::cout << "
	Usage: " << str << " port[1024+]
" << std::endl; 
}


int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(UsageError);
    }

    uint16_t port = std::stoi(argv[1]);

    std::unique_ptr<TcpServer> server(new TcpServer(port));
    server->InitServer();
    server->StartServer();


    return 0;
}

Log.hpp

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SIZE 1024

#define Info   0
#define Debug  1
#define Warning 2
#define Error  3
#define Fatal  4

#define Screen 1     //输出到屏幕上
#define Onefile 2    //输出到一个文件中
#define Classfile 3  //根据事件等级输出到不同的文件中

#define LogFile "log.txt" //日志名称


class Log
{
public:
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }

    void Enable(int method) //改变日志打印方式
    {
        printMethod = method;
    }

    ~Log()
    {}

    std::string levelToString(int level)
    {
        switch(level)
        {
            case Info:
                return "Info";
            case Debug:
                return "Debug";
            case Warning:
                return "Warning";
            case Error:
                return "Error";
            case Fatal:
                return "Fata";
            default:
                return "";
        }
    }

    void operator()(int level, const char* format, ...)
    {
        //默认部分 = 日志等级 + 日志时间
        time_t t = time(nullptr);
        struct tm* ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(), 
        ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, 
        ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        char logtxt[2 * SIZE];
        snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

        printLog(level, logtxt);
    }

    void printLog(int level, const std::string& logtxt)
    {
        switch(printMethod)
        {
            case Screen:
                std::cout << logtxt << std::endl;
                break;
            case Onefile:
                printOneFile(LogFile, logtxt);
                break;
            case Classfile:
                printClassFile(level, logtxt);
                break;
            default:
                break;
        }
    }

    void printOneFile(const std::string& logname, const std::string& logtxt)
    {
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if(fd < 0)
            return;
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }

    void printClassFile(int level, const std::string& logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level);

        printOneFile(filename, logtxt);
    }


private:
    int printMethod;
    std::string path;
};

Log lg;


总结

以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!

本文地址:https://www.yitenyun.com/1082.html

搜索文章

Tags

#服务器 #python #pip #conda #ios面试 #ios弱网 #断点续传 #ios开发 #objective-c #ios #ios缓存 #人工智能 #微信 #远程工作 #Trae #IDE #AI 原生集成开发环境 #Trae AI #kubernetes #笔记 #平面 #容器 #linux #学习方法 香港站群服务器 多IP服务器 香港站群 站群服务器 #运维 #学习 #分阶段策略 #模型协议 #银河麒麟高级服务器操作系统安装 #银河麒麟高级服务器V11配置 #设置基础软件仓库时出错 #银河麒高级服务器系统的实操教程 #生产级部署银河麒麟服务系统教程 #Linux系统的快速上手教程 #科技 #深度学习 #自然语言处理 #神经网络 #hadoop #hbase #hive #zookeeper #spark #kafka #flink #华为云 #部署上线 #动静分离 #Nginx #新人首发 #docker #fastapi #html #css #tcp/ip #网络 #qt #C++ #harmonyos #鸿蒙PC #物联网 #websocket #github #git #进程控制 #gemini #gemini国内访问 #gemini api #gemini中转搭建 #Cloudflare #大数据 #职场和发展 #程序员创富 #经验分享 #安卓 #PyTorch #模型训练 #星图GPU #低代码 #爬虫 #音视频 #开源 #kylin #arm #ARM服务器 # GLM-4.6V # 多模态推理 #Conda # 私有索引 # 包管理 #unity #c# #游戏引擎 #数信院生信服务器 #Rstudio #生信入门 #生信云服务器 #飞牛nas #fnos #语言模型 #大模型 #ai #ai大模型 #agent #word #umeditor粘贴word #ueditor粘贴word #ueditor复制word #ueditor上传word图片 #内网穿透 #cpolar #ci/cd #jenkins #gitlab #MobaXterm #ubuntu #node.js #langchain #数据库 #儿童书籍 #儿童诗歌 #童话故事 #经典好书 #儿童文学 #好书推荐 #经典文学作品 #开发语言 #云原生 #iventoy #VmWare #OpenEuler #flutter #ssh #vscode #mobaxterm #计算机视觉 #RTP over RTSP #RTP over TCP #RTSP服务器 #RTP #TCP发送RTP #矩阵 #线性代数 #AI运算 #向量 #ide #区块链 #测试用例 #生活 #后端 #前端 #nginx #serverless #diskinfo # TensorFlow # 磁盘健康 #Harbor #c++ #算法 #牛客周赛 #aws #云计算 #centos #svn #AI编程 #自动化 #ansible #分布式 #华为 #android #腾讯云 #sql #AIGC #agi #FTP服务器 #Reactor #http #项目 #高并发 #java-ee #文心一言 #AI智能体 #多个客户端访问 #IO多路复用 #回显服务器 #TCP相关API #javascript #vue上传解决方案 #vue断点续传 #vue分片上传下载 #vue分块上传下载 #openHiTLS #TLCP #DTLCP #密码学 #商用密码算法 #fabric #postgresql #缓存 #microsoft #java #jar #Dell #PowerEdge620 #内存 #硬盘 #RAID5 #windows #flask #企业开发 #ERP #项目实践 #.NET开发 #C#编程 #编程与数学 #iBMC #UltraISO #pytorch #PyCharm # 远程调试 # YOLOFuse #php #mcu #鸿蒙 #架构 #安全 #mysql #信息与通信 #pycharm #程序人生 #科研 #博士 #网络协议 #jmeter #功能测试 #软件测试 #自动化测试 #uni-app #小程序 #notepad++ #散列表 #哈希算法 #数据结构 #leetcode #风控模型 #决策盲区 #数学建模 #2026年美赛C题代码 #2026年美赛 #内存治理 #django #vue.js #dify #spring boot #es安装 #web #webdav #golang #redis #驱动开发 #mvp #个人开发 #设计模式 #游戏 #京东云 #性能优化 #计算机网络 #spring cloud #spring #json #jvm #mmap #nio #DeepSeek #服务器繁忙 #AI #蓝桥杯 #ecmascript #elementui #rocketmq #Ansible # 自动化部署 # VibeThinker #课程设计 #Ubuntu服务器 #硬盘扩容 #命令行操作 #VMware #MCP #MCP服务器 #鸭科夫 #逃离鸭科夫 #鸭科夫联机 #鸭科夫异地联机 #开服 #阻塞队列 #生产者消费者模型 #服务器崩坏原因 #数据仓库 #c语言 #vllm #Streamlit #Qwen #本地部署 #AI聊天机器人 #LLM #vim #gcc #yum #我的世界 #jetty #prometheus #开源软件 #web安全 #单片机 #stm32 #嵌入式硬件 #需求分析 #udp #scala #测试工具 #压力测试 #网络安全 #adb #钉钉 #机器人 #阿里云 #AI论文写作工具 #学术论文创作 #论文效率提升 #MBA论文写作 #信息可视化 #claude code #codex #code cli #ccusage #数据集 #ModelEngine #Ascend #MindIE #DisM++ # 系统维护 #gpu算力 #语音识别 #深度优先 #DFS #rabbitmq #protobuf #企业微信 #设备驱动 #芯片资料 #网卡 #大模型学习 #AI大模型 #大模型教程 #大模型入门 #Android #Bluedroid #智能手机 #全能视频处理软件 #视频裁剪工具 #视频合并工具 #视频压缩工具 #视频字幕提取 #视频处理工具 #everything #todesk #Linux #TCP #线程 #线程池 #ffmpeg #asp.net大文件上传 #asp.net大文件上传下载 #asp.net大文件上传源码 #ASP.NET断点续传 #asp.net上传文件夹 #酒店客房管理系统 #毕设 #论文 #ping通服务器 #读不了内网数据库 #bug菌问答团队 #测试流程 #金融项目实战 #P2P #数码相机 #webrtc #chatgpt #DS随心转 #epoll #高级IO #debian #mcp #mcp server #AI实战 #流程图 #论文阅读 #论文笔记 #毕业设计 #面试 #Coze工作流 #AI Agent指挥官 #多智能体系统 #asp.net #1024程序员节 #claude #LoRA # RTX 3090 # lora-scripts #VS Code调试配置 #vue3 #天地图 #403 Forbidden #天地图403错误 #服务器403问题 #天地图API #部署报错 #react.js #ddos #SSH # ProxyJump # 跳板机 #fiddler #opencv #数据挖掘 #googlecloud #银河麒麟 #系统升级 #信创 #国产化 #银河麒麟操作系统 #openssh #华为交换机 #信创终端 #arm开发 #Modbus-TCP #azure #FL Studio #FLStudio #FL Studio2025 #FL Studio2026 #FL Studio25 #FL Studio26 #水果软件 #编辑器 #金融 #金融投资Agent #Agent #svm #amdgpu #kfd #ROCm #ida #中间件 #研发管理 #禅道 #禅道云端部署 #n8n #超算服务器 #算力 #高性能计算 #仿真分析工作站 #守护进程 #复用 #screen #幼儿园 #园长 #幼教 #RAID #RAID技术 #磁盘 #存储 #里氏替换原则 #STUN # TURN # NAT穿透 #unity3d #服务器框架 #Fantasy #elasticsearch #智能路由器 #transformer #sizeof和strlen区别 #sizeof #strlen #计算数据类型字节数 #计算字符串长度 #正则 #正则表达式 #凤希AI伴侣 #AI写作 #iphone #生信 #java大文件上传 #java大文件秒传 #java大文件上传下载 #java文件传输解决方案 #journalctl #wordpress #雨云 #LobeChat #vLLM #GPU加速 #机器学习 #程序员 #流量监控 #RAG #全链路优化 #实战教程 #openresty #lua #架构师 #系统架构 #软考 #系统架构师 #MC #电脑 #SSH反向隧道 # Miniconda # Jupyter远程访问 #grafana #几何学 #拓扑学 #链表 #链表的销毁 #链表的排序 #链表倒置 #判断链表是否有环 #SSH Agent Forwarding # PyTorch # 容器化 #zabbix #运营 #信令服务器 #Janus #MediaSoup #TensorRT # Triton # 推理优化 #wsl #Jetty # CosyVoice3 # 嵌入式服务器 #搜索引擎 #产品经理 #ui #团队开发 #墨刀 #figma #智慧校园解决方案 #智慧校园一体化平台 #智慧校园选型 #智慧校园采购 #智慧校园软件 #智慧校园专项资金 #智慧校园定制开发 #CFD #YOLO #建筑缺陷 #红外 #X11转发 #Miniconda #SMTP # 内容安全 # Qwen3Guard #HeyGem # 远程访问 # 服务器IP配置 #sqlserver #边缘计算 #MS #Materials #改行学it #创业创新 #apache #北京百思可瑞教育 #百思可瑞教育 #北京百思教育 #L2C #勒让德到切比雪夫 #tdengine #时序数据库 #制造 #涛思数据 #ms-swift # 一锤定音 # 大模型微调 #deepseek #机器视觉 #6D位姿 #risc-v #cpp #autosar #SSH公钥认证 # 安全加固 #PowerBI #企业 #Qwen3-14B # 大模型部署 # 私有化AI #tensorflow #推荐算法 #screen 命令 #log #macos #操作系统 #vp9 #ssl #支付 #远程桌面 #远程控制 #fpga开发 #LVDS #高速ADC #DDR # GLM-TTS # 数据安全 #bash #振镜 #振镜焊接 #进程 #llama #ceph #智能一卡通 #门禁一卡通 #梯控一卡通 #电梯一卡通 #消费一卡通 #一卡通 #考勤一卡通 #AI产品经理 #大模型开发 #蓝耘智算 #求职招聘 #版本控制 #Git入门 #开发工具 #代码托管 #目标检测 #嵌入式 #C语言 #大语言模型 #长文本处理 #GLM-4 #Triton推理 #重构 #个人博客 #ONLYOFFICE #MCP 服务器 #tomcat #数模美赛 #matlab #前端框架 #嵌入式编译 #ccache #distcc #nas #cursor #分类 #ssm #spine #进程创建与终止 #shell #状态模式 #若依 #quartz #框架 #ollama #llm #RustDesk #IndexTTS 2.0 #本地化部署 #信号处理 #tcpdump #embedding #visual studio code #流量运营 #用户运营 #车辆排放 #迁移重构 #数据安全 #漏洞 #代码迁移 #oracle #SA-PEKS # 关键词猜测攻击 # 盲签名 # 限速机制 #树莓派4b安装系统 #我的世界服务器搭建 #minecraft #paddleocr #Spring AI #STDIO协议 #Streamable-HTTP #McpTool注解 #服务器能力 #esp32教程 #模版 #函数 #类 #笔试 #pencil #pencil.dev #设计 #双指针 #sqlite #Playbook #AI服务器 #WEB #simulink #laravel #Triton # CUDA #selenium #AB包 #CPU利用率 #海外服务器安装宝塔面板 #负载均衡 #SSH保活 #远程开发 #Canal #数组 #目标跟踪 #流媒体 #NAS #飞牛NAS #监控 #NVR #EasyNVR #openlayers #bmap #tile #server #vue #简单数论 #埃氏筛法 #openEuler #Hadoop #客户端 #DIY机器人工房 #vuejs #ESXi #eBPF #.net #homelab #Lattepanda #Jellyfin #Plex #Emby #Kodi #Shiro #反序列化漏洞 #CVE-2016-4437 #nacos #银河麒麟aarch64 #uvicorn #uvloop #asgi #event #pdf #人脸识别 #人脸核身 #活体检测 #身份认证与人脸对比 #H5 #微信公众号 #1panel #vmware #React安全 #漏洞分析 #Next.js #其他 #PTP_1588 #gPTP #贪心算法 #微服务 #学习笔记 #jdk #eclipse #servlet #p2p #Windows #数据分析 #5G #汇编 #RXT4090显卡 #RTX4090 #深度学习服务器 #硬件选型 #gitea #群晖 #音乐 #IntelliJ IDEA #Spring Boot #neo4j #NoSQL #SQL #typescript #npm #idm #网站 #截图工具 #批量处理图片 #图片格式转换 #图片裁剪 #LangGraph #模型上下文协议 #MultiServerMCPC #load_mcp_tools #load_mcp_prompt #万悟 #联通元景 #智能体 #镜像 #maven #结构体 #TCP服务器 #开发实战 #微信小程序 #健身房预约系统 #健身房管理系统 #健身管理系统 #ThingsBoard MCP #可撤销IBE #服务器辅助 #私钥更新 #安全性证明 #双线性Diffie-Hellman #Android16 #音频性能实战 #音频进阶 #硬件工程 #gateway #Comate #遛狗 #SSE # AI翻译机 # 实时翻译 #clickhouse #代理 #平板 #零售 #交通物流 #智能硬件 #国产PLM #瑞华丽PLM #瑞华丽 #PLM #CTF #结构与算法 #scrapy #Windows 更新 #r-tree #聊天小程序 #arm64 #无人机 #Deepoc #具身模型 #开发板 #未来 #wpf #串口服务器 #Modbus #MOXA #渗透测试 #服务器解析漏洞 #扩展屏应用开发 #android runtime #UOS #海光K100 #统信 #NFC #智能公交 #服务器计费 #FP-增长 #TLS协议 #HTTPS #漏洞修复 #运维安全 #CANN #Proxmox VE #虚拟化 #硬件 #Fun-ASR # 语音识别 # WebUI # IndexTTS 2.0 # 远程运维 #CUDA #交互 #私有化部署 #intellij-idea #idea #intellij idea #考研 #软件工程 #部署 #GPU服务器 #8U #硬件架构 #昇腾300I DUO #NPU #vnstat #c++20 #cosmic #AutoDL #跨域 #发布上线后跨域报错 #请求接口跨域问题解决 #跨域请求代理配置 #request浏览器跨域 #运维开发 #opc ua #opc #cnn #UDP的API使用 #处理器 #计组 #数电 #黑群晖 #虚拟机 #无U盘 #纯小白 #浏览器自动化 #python #指针 #anaconda #虚拟环境 #SSH跳板机 # Python3.11 #东方仙盟 #游戏机 #JumpServer #堡垒机 #API限流 # 频率限制 # 令牌桶算法 #ip #SSH免密登录 #集成测试 #Gunicorn #WSGI #Flask #并发模型 #容器化 #Python #性能调优 #OBC #teamviewer #蓝湖 #Axure原型发布 #黑客技术 #网安应急响应 #计算机 # 目标检测 #ai编程 #微PE # GLM # 服务连通性 #log4j #ambari #单元测试 #select #Socket网络编程 #上下文工程 #langgraph #意图识别 #turn #数据恢复 #视频恢复 #视频修复 #RAID5恢复 #流媒体服务器恢复 #ESP32 #传感器 #MicroPython #3d #RK3576 #瑞芯微 #硬件设计 #muduo库 #数据采集 #浏览器指纹 #uv #uvx #uv pip #npx #Ruff #pytest #milvus #springboot #知识库 #910B #昇腾 #web server #请求处理流程 #jupyter #框架搭建 #edge #迭代器模式 #观察者模式 #twitter #SRS #直播 #Anaconda配置云虚拟环境 #MQTT协议 #vivado license #CVE-2025-68143 #CVE-2025-68144 #CVE-2025-68145 #html5 #chrome #RSO #机器人操作系统 #glibc #可信计算技术 #UDP套接字编程 #UDP协议 #网络测试 #winscp #政务 #mybatis #集成学习 #https #powerbi #Host #SSRF #Clawdbot #个人助理 #数字员工 #lvs # 双因素认证 #rustdesk #连接数据库报错 #音乐分类 #音频分析 #ViT模型 #Gradio应用 #鼠大侠网络验证系统源码 #whisper #Docker #游戏私服 #云服务器 #源码 #闲置物品交易系统 #YOLOFuse # Base64编码 # 多模态检测 #IPv6 #DNS #bootstrap #LabVIEW知识 #LabVIEW程序 #LabVIEW功能 #labview #SPA #单页应用 #web3.py #系统安全 #ipmitool #BMC #C #prompt #YOLOv8 # Docker镜像 #Fluentd #Sonic #日志采集 #麒麟OS #swagger #IndexTTS2 # 阿里云安骑士 # 木马查杀 #C# # REST API # GLM-4.6V-Flash-WEB #flume #mamba #restful #ajax #mariadb #视频去字幕 #CLI #JavaScript #langgraph.json #CMake #Make #C/C++ #零代码平台 #AI开发 #UDP #策略模式 # 高并发部署 #聚类 #OPCUA #vps #环境搭建 #Anything-LLM #IDC服务器 #pandas #matplotlib #raid #raid阵列 #rust #OSS #firefox #安恒明御堡垒机 #windterm #学术写作辅助 #论文创作效率提升 #AI写论文实测 #电气工程 #PLC # 水冷服务器 # 风冷服务器 # 硬件配置 #算力一体机 #ai算力服务器 #VoxCPM-1.5-TTS # 云端GPU # PyCharm宕机 #webpack #database #青少年编程 #SMP(软件制作平台) #EOM(企业经营模型) #应用系统 #翻译 #开源工具 #自动驾驶 #rdp #能源 #JAVA #Java #Dify #ARM架构 #鲲鹏 #tornado #esp32 arduino #ComfyUI # 推理服务器 #libosinfo #项目申报系统 #项目申报管理 #项目申报 #企业项目申报 #reactjs #web3 #联机教程 #局域网联机 #局域网联机教程 #局域网游戏 #模拟退火算法 #产品运营 #内存接口 # 澜起科技 # 服务器主板 #windows11 #系统修复 #yolov12 #研究生life #文件传输 #电脑文件传输 #电脑传输文件 #电脑怎么传输文件到另一台电脑 #电脑传输文件到另一台电脑 #说话人验证 #声纹识别 #CAM++ #性能 #优化 #RAM #mongodb #Termux #Samba #SSH别名 #企业存储 #RustFS #对象存储 #高可用 #三维 #3D #三维重建 #asp.net上传大文件 #RAGFlow #DeepSeek-R1 #rtsp #转发 #编程 #c++高并发 #百万并发 #uip #游戏程序 #信创国产化 #达梦数据库 #CVE-2025-61686 #路径遍历高危漏洞 #ICPC #Llama-Factory # 大模型推理 #SMARC #ARM #全文检索 #土地承包延包 #领码SPARK #aPaaS+iPaaS #数字化转型 #智能审核 #档案数字化 #农产品物流管理 #物流管理系统 #农产品物流系统 #农产品物流 # 代理转发 #xss #echarts #GPU ##租显卡 #进程等待 #wait #waitpid # 服务器IP # 端口7860 #paddlepaddle #web服务器 # 公钥认证 #ShaderGraph #图形 #VSCode # SSH # GPU租赁 # 自建服务器 #VibeVoice # 语音合成 # 云服务器 #devops #VMware Workstation16 #服务器操作系统 #A2A #GenAI #VMWare Tool #MinIO服务器启动与配置详解 #2026AI元年 #年度趋势 #H5网页 #网页白屏 #H5页面空白 #资源加载问题 #打包部署后网页打不开 #HBuilderX #磁盘配额 #存储管理 #文件服务器 #形考作业 #国家开放大学 #系统运维 #自动化运维 #多线程 #性能调优策略 #双锁实现细节 #动态分配节点内存 #插件 #markdown #建站 #DHCP #C++ UA Server #SDK #跨平台开发 #游戏美术 #技术美术 #游戏策划 #用户体验 #心理健康服务平台 #心理健康系统 #心理服务平台 #心理健康小程序 #SSH复用 # 远程开发 #区间dp #二进制枚举 #图论 #大学生 #大作业 #GATT服务器 #蓝牙低功耗 #DAG #HBA卡 #RAID卡 #outlook #错误代码2603 #无网络连接 #2603 #注入漏洞 #nvidia #ue5 #Chat平台 #密码 #safari # ControlMaster #排序算法 #插入排序 #TFTP #NSP #下一状态预测 #aigc #性能测试 #LoadRunner #memory mcp #Cursor #测试覆盖率 #可用性测试 #网路编程 #海外短剧 #海外短剧app开发 #海外短剧系统开发 #短剧APP #短剧APP开发 #短剧系统开发 #海外短剧项目 #IFix # 远程连接 #kmeans #数字孪生 #三维可视化 #工厂模式 #Buck #NVIDIA #交错并联 #DGX #智慧城市 #攻防演练 #Java web #红队 # 树莓派 # ARM架构 #随机森林 #经济学 #memcache #大剑师 #nodejs面试题 #WinDbg #Windows调试 #内存转储分析 #C2000 #TI #实时控制MCU #AI服务器电源 #TTS私有化 # IndexTTS # 音色克隆 #AI+ #coze #AI入门 #AI赋能 #Node.js #漏洞检测 #CVE-2025-27210 #导航网 #ranger #MySQL8.0 #PyTorch 特性 #动态计算图 #张量(Tensor) #自动求导Autograd #GPU 加速 #生态系统与社区支持 #与其他框架的对比 #GB28181 #SIP信令 #SpringBoot #视频监控 #WT-2026-0001 #QVD-2026-4572 #smartermail #cascadeur #设计师 #AI视频创作系统 #AI视频创作 #AI创作系统 #AI视频生成 #AI工具 #文生视频 #AI创作工具 #Xshell #Finalshell #生物信息学 #组学 #React #Next #CVE-2025-55182 #RSC # ARM服务器 #存储维护 #screen命令 #分布式数据库 #集中式数据库 #业务需求 #选型误 # Connection refused #智能体来了 #智能体对传统行业冲击 #行业转型 #系统管理 #服务 #管道Pipe #system V #chat #统信UOS #win10 #qemu #源代码管理 #elk #ngrok # 高并发 #视觉检测 #visual studio #appche #YOLO26 #muduo #TcpServer #accept #高并发服务器 #HarmonyOS #SAP #ebs #metaerp #oracle ebs #CosyVoice3 # IP配置 # 0.0.0.0 #iot #智能家居 #SSH跳转 #Spring #go #postman # GPU集群 #Nacos #gRPC #注册中心 #Rust #Tokio #异步编程 #系统编程 #Pin #http服务器 #win11 #机器人学习 #AI-native #dba #LangFlow # 轻量化镜像 # 边缘计算 #国产化OS #opc模拟服务器 #汽车 #weston #x11 #x11显示服务器 #量子计算 #WinSCP 下载安装教程 #SFTP #FTP工具 #服务器文件传输 #excel #计算几何 #斜率 #方向归一化 #叉积 #galeweather.cn #高精度天气预报数据 #光伏功率预测 #风电功率预测 #高精度气象 #samba #copilot # 批量管理 #线性回归 #ASR #SenseVoice #硬盘克隆 #DiskGenius #c #媒体 #贴图 #材质 #ArkUI #ArkTS #鸿蒙开发 #勒索病毒 #勒索软件 #加密算法 #.bixi勒索病毒 #数据加密 #手机h5网页浏览器 #安卓app #苹果ios APP #手机电脑开启摄像头并排查 #语音生成 #TTS #IO #实时音视频 #业界资讯 #证书 #知识 #JT/T808 #车联网 #车载终端 #模拟器 #仿真器 #开发测试 #JNI #CPU #测评 #CCE #Dify-LLM #Flexus #mapreduce #论文复现 # 数字人系统 # 远程部署 #宝塔面板部署RustDesk #RustDesk远程控制手机 #手机远程控制 #hibernate #AI赋能盾构隧道巡检 #开启基建安全新篇章 #以注意力为核心 #YOLOv12 #AI隧道盾构场景 #盾构管壁缺陷病害异常检测预警 #隧道病害缺陷检测 #puppeteer #openclaw #KMS #slmgr #Discord机器人 #云部署 #程序那些事 #AI技术 #TRO #TRO侵权 #TRO和解 #运维工具 #POC #问答 #交付 #动态规划 #AITechLab #cpp-python #CUDA版本 #xlwings #Excel #Ubuntu #ESP32编译服务器 #Ping #DNS域名解析 #YOLO11 #自由表达演说平台 #演说 #移动端h5网页 #调用浏览器摄像头并拍照 #开启摄像头权限 #拍照后查看与上传服务器端 #摄像头黑屏打不开问题 #nfs #iscsi #连锁药店 #连锁店 #服务器IO模型 #非阻塞轮询模型 #多任务并发模型 #异步信号模型 #多路复用模型 # 黑屏模式 # TTS服务器 #前端开发 #ARM64 # DDColor # ComfyUI #领域驱动 # keep-alive #Karalon #AI Test #文件IO #输入输出流 #面向对象 #文件管理 #国产开源制品管理工具 #Hadess #一文上手 #taro #abtest #kong #Kong Audio #Kong Audio3 #KongAudio3 #空音3 #空音 #中国民乐 #范式 #scanf #printf #getchar #putchar #cin #cout #ET模式 #非阻塞 # 大模型 # 模型训练 #Claude #clamav #CogVideoX #AI部署 #企业级存储 #网络设备 #多模态 #微调 #超参 #LLamafactory #Smokeping #命令模式 #pve #dubbo #排序 #Linux多线程 #Java程序员 #Java面试 #后端开发 #Spring源码 #zotero #WebDAV #同步失败 #代理模式 #工具集 #图像处理 #yolo #大模型应用 #API调用 #PyInstaller打包运行 #服务端部署 #Langchain-Chatchat # 国产化服务器 # 信创 #软件 #本地生活 #电商系统 #商城 #高品质会员管理系统 #收银系统 #同城配送 #最好用的电商系统 #最好用的系统 #推荐的前十系统 #JAVA PHP 小程序 #欧拉 #ipv6 #duckdb #CSDN #aiohttp #asyncio #异步 #逻辑回归 #麒麟 #cesium #可视化 #.netcore # 自动化运维 #儿童AI #图像生成 #pjsip # 模型微调 #AI生成 # outputs目录 # 自动化 #寄存器 #实体经济 #商业模式 #软件开发 #数智红包 #商业变革 #创业干货 ##程序员和算法的浪漫 #Go并发 #高并发架构 #Goroutine #系统设计 #Tracker 服务器 #响应最快 #torrent 下载 #2026年 #Aria2 可用 #迅雷可用 #BT工具通用 #net core #kestrel #web-server #asp.net-core #Zabbix #语音合成 #HistoryServer #Spark #YARN #jobhistory #FASTMCP #ZooKeeper #ZooKeeper面试题 #面试宝典 #深入解析 #大模型部署 #mindie #大模型推理 #n8n解惑 # 显卡驱动备份 #长文本理解 #glm-4 #推理部署 #Aluminium #Google #EMC存储 #NetApp存储 #社科数据 #数据统计 #经管数据 #因果学习 #eureka #广播 #组播 #并发服务器 #x86_64 #数字人系统 #CS2 #debian13 #BoringSSL #gpu #nvcc #cuda #漏洞挖掘 #unix #Coturn #TURN #k8s #高仿永硕E盘的个人网盘系统源码 #模块 # 权限修复 #ICE # 鲲鹏 #SQL注入主机 #http头信息 #VPS #搭建 #递归 #线性dp #webgl #支持向量机 #树莓派 #温湿度监控 #WhatsApp通知 #IoT #MySQL # HiChatBox # 离线AI #文件上传漏洞 #文本生成 #CPU推理 #Kylin-Server #国产操作系统 #服务器安装 #短剧 #短剧小程序 #短剧系统 #微剧 # 智能运维 # 性能瓶颈分析 #空间计算 #原型模式 #nosql #戴尔服务器 #戴尔730 #装系统 #音诺ai翻译机 #AI翻译机 # Ampere Altra Max #sklearn #junit #bug #网络编程 #I/O模型 #并发 #水平触发、边缘触发 #多路复用 #数据访问 #vncdotool #链接VNC服务器 #如何隐藏光标 # 服务器IP访问 # 端口映射 #统信操作系统 #wireshark #网络安全大赛 #人形机器人 #人机交互 #FHSS #CNAS #CMA #程序文件 #xml #门禁 #梯控 #智能梯控 #电梯 #电梯运力 #电梯门禁 #lucene #nodejs #云服务器选购 #Saas #域名注册 #新媒体运营 #网站建设 #国外域名 #mssql #算力建设 #DDD #tdd #easyui #ETL管道 #向量存储 #数据预处理 #DocumentReader #HarmonyOS APP #esb接口 #走处理类报异常 #题解 #图 #dijkstra #迪杰斯特拉 #bond #服务器链路聚合 #网卡绑定 #数据报系统 #b树 # GPU服务器 # tmux #程序开发 #程序设计 #计算机毕业设计 #具身智能 #SSH密钥 #idc #练习 #基础练习 #循环 #九九乘法表 #计算机实现 #dynadot #域名 #smtp #smtp服务器 #PHP #银河麒麟部署 #银河麒麟部署文档 #银河麒麟linux #银河麒麟linux部署教程 #声源定位 #MUSIC #windbg分析蓝屏教程 #智能制造 #供应链管理 #工业工程 #库存管理 #le audio #蓝牙 #低功耗音频 #通信 #连接 #RK3588 #RK3588J #评估板 #核心板 #嵌入式开发 #fs7TF # Qwen3Guard-Gen-8B #ROS #N8N #安全架构 #Moltbook #Cpolar #国庆假期 #服务器告警 #AI 推理 #NV #npu #ServBay # OTA升级 # 黄山派 #内网 # IndexTTS2 #ansys #ansys问题解决办法 # 网络延迟 #resnet50 #分类识别训练 #远程软件 #OpenManage #视频 #代理服务器 #Spire.Office #隐私合规 #网络安全保险 #法律风险 #风险管理 #编程助手 #远程访问 #远程办公 #飞网 #安全高效 #配置简单 #快递盒检测检测系统 #雨云服务器 #Minecraft服务器 #教程 #MCSM面板 #Apple AI #Apple 人工智能 #FoundationModel #Summarize #SwiftUI #静脉曲张 #腿部健康 #跳槽 #工作 #超时设置 #客户端/服务器 #挖矿 #Linux病毒 #sql注入 #vertx #vert.x #vertx4 #runOnContext #FaceFusion # Token调度 # 显存优化 #WRF #WRFDA #公共MQTT服务器 # 服务器配置 # GPU #华为od #华为机试 # DIY主机 # 交叉编译 #网络配置实战 #Web/FTP 服务访问 #计算机网络实验 #外网访问内网服务器 #Cisco 路由器配置 #静态端口映射 #网络运维 #react native #RPA #影刀RPA #AI办公 #Gateway #认证服务器集成详解 #服务器开启 TLS v1.2 #IISCrypto 使用教程 #TLS 协议配置 #IIS 安全设置 #服务器运维工具 #ftp #sftp #uniapp #合法域名校验出错 #服务器域名配置不生效 #request域名配置 #已经配置好了但还是报错 #uniapp微信小程序 #远程连接 #路由器 #cpu #Socket #套接字 #I/O多路复用 #字节序 #工程设计 #预混 #扩散 #燃烧知识 #层流 #湍流 # 批量部署 #视觉理解 #Moondream2 #多模态AI # 键鼠锁定 #mtgsig #美团医药 #美团医药mtgsig #美团医药mtgsig1.2 #后端框架 #CA证书 #服务器线程 # SSL通信 # 动态结构体 #RWK35xx #语音流 #实时传输 #node #报表制作 #职场 #数据可视化 #用数据讲故事 #CS336 #Assignment #Experiments #TinyStories #Ablation #LE Audio #BAP #星际航行 #pxe #agentic bi #参数估计 #矩估计 #概率论 #MCP服务器注解 #异步支持 #方法筛选 #声明式编程 #自动筛选机制 #娱乐 #敏捷流程 #可再生能源 #绿色算力 #风电 #Keycloak #Quarkus #AI编程需求分析 #麦克风权限 #访问麦克风并录制音频 #麦克风录制音频后在线播放 #用户拒绝访问麦克风权限怎么办 #uniapp 安卓 苹果ios #将音频保存本地或上传服务器 # child_process #ARMv8 #内存模型 #内存屏障 #sentinel #AI应用编程 #dlms #dlms协议 #逻辑设备 #逻辑设置间权限 #r语言 #scikit-learn #安全威胁分析 #canvas层级太高 #canvas遮挡问题 #盖住其他元素 #苹果ios手机 #安卓手机 #调整画布层级 #测速 #iperf #iperf3 #学术生涯规划 #CCF目录 #基金申请 #职称评定 #论文发表 #科研评价 #顶会顶刊 #仙盟创梦IDE #GLM-4.6V-Flash-WEB # AI视觉 # 本地部署 #网络攻击模型 #pyqt #Kuikly #openharmony #STDIO传输 #SSE传输 #WebMVC #WebFlux #分子动力学 #化工仿真 #SEO优化 #Minecraft #PaperMC #我的世界服务器 #EN4FE #节日 #基础语法 #标识符 #常量与变量 #数据类型 #运算符与表达式 #地理 #遥感 #工业级串口服务器 #串口转以太网 #串口设备联网通讯模块 #串口服务器选型 #入侵 #日志排查 #外卖配送 #主板 #总体设计 #电源树 #框图 #人大金仓 #Kingbase #Archcraft #小艺 #搜索 #Spring AOP #Linly-Talker # 数字人 # 服务器稳定性 #图像识别 #多进程 #python技巧 #实在Agent #工程实践 #传统行业 #租显卡 #训练推理 #就业 #gnu #gpt #API #glances #wps #电子电气架构 #系统工程与系统架构的内涵 #Routine #轻量化 #低配服务器 #V11 #kylinos #KMS激活 #poll #numpy #百度 #ueditor导入word #Syslog #系统日志 #日志分析 #日志监控 #Autodl私有云 #深度服务器配置 # WebRTC #coffeescript #人脸识别sdk #视频编解码 #挖漏洞 #攻击溯源 #stl #IIS Crypto #blender #warp #composer #symfony #java-zookeeper #ue4 #DedicatedServer #独立服务器 #专用服务器 #Prometheus #H3C #AI大模型应用开发 #个性化推荐 #BERT模型 #Puppet # TTS #程序定制 #毕设代做 #课设 #语义搜索 #嵌入模型 #Qwen3 #AI推理 #交换机 #三层交换机 #高斯溅射 #tcp/ip #网络 #云开发 #个人电脑 #KMS 激活 #AI智能棋盘 #Rock Pi S #MC群组服务器 #电商 #隐函数 #常微分方程 #偏微分方程 #线性微分方程 #线性方程组 #非线性方程组 #复变函数 #云计算运维 #职场发展 #UDP服务器 #recvfrom函数 #claude-code #银河麒麟服务器系统 #高精度农业气象 #Ward #思爱普 #SAP S/4HANA #ABAP #NetWeaver #WAN2.2 #4U8卡 AI 服务器 ##AI 服务器选型指南 #GPU 互联 #GPU算力 #日志模块 #dash #实时检测 #卷积神经网络 #rtmp #效率神器 #办公技巧 #自动化工具 #Windows技巧 #打工人必备 #AI电商客服 #spring ai #oauth2 #nmodbus4类库使用教程 #docker-compose # 高温监控 # 局域网访问 # 批量处理 #旅游 #西门子 #汇川 #Blazor #gerrit #dreamweaver # 环境迁移 #晶振 #夏天云 #夏天云数据 #hdfs #华为od机试 #华为od机考 #华为od最新上机考试题库 #华为OD题库 #华为OD机试双机位C卷 #od机考题库 #运维 #xshell #host key #Python3.11 #rsync # 数据同步 #AI工具集成 #容器化部署 #分布式架构 #odoo #智能电视 #claudeCode #content7 #clawdbot #CMC # 串口服务器 # NPort5630 #Matrox MIL #二次开发 #OpenHarmony #Python办公自动化 #Python办公 #防火墙 #0day漏洞 #DDoS攻击 #漏洞排查 #单例模式 #懒汉式 #恶汉式 #YOLO识别 #YOLO环境搭建Windows #YOLO环境搭建Ubuntu # ms-swift #PN 结 #基金 #股票 #超算中心 #PBS #lsf #反向代理 #数据迁移 #余行补位 #意义对谈 #余行论 #领导者定义计划 #adobe #系统安装 #铁路桥梁 #DIC技术 #箱梁试验 #裂纹监测 #四点弯曲 #AE #MinIO #rag #express #cherry studio #gmssh #宝塔 #Exchange #free #vmstat #sar #ossinsight #cocos2d #图形渲染 #AI Agent #开发者工具 #小智 #游戏服务器断线 #期刊 #SCI #边缘AI # Kontron # SMARC-sAMX8 #okhttp #计算机外设 #remote-ssh #健康医疗 #AI应用 #语义检索 #向量嵌入 #高考 #boltbot #榛樿鍒嗙被 #bigtop #hdp #hue #kerberos #Beidou #北斗 #SSR #人脸活体检测 #live-pusher #动作引导 #张嘴眨眼摇头 #苹果ios安卓完美兼容 #信息安全 #信息收集 #强化学习 #策略梯度 #REINFORCE #蒙特卡洛 #docker安装seata #L6 #L10 #L9 #生产服务器问题查询 #日志过滤 #阿里云RDS #VMware创建虚拟机 #远程更新 #缓存更新 #多指令适配 #物料关联计划 #软件需求 # AI部署 #材料工程 #vrrp #脑裂 #keepalived主备 #高可用主备都持有VIP #m3u8 #HLS #移动端H5网页 #APP安卓苹果ios #监控画面 直播视频流 #决策树 #DooTask #sglang #防毒面罩 #防尘面罩 #UEFI #BIOS #Legacy BIOS # 服务器迁移 # 回滚方案 #开关电源 #热敏电阻 #PTC热敏电阻 #身体实验室 #健康认知重构 #系统思维 #微行动 #NEAT效应 #亚健康自救 #ICT人 #Qwen3-VL # 服务状态监控 # 视觉语言模型 #DuckDB #协议 #Tetrazine-Acid #1380500-92-4 #新浪微博 #传媒 #Arduino BLDC #核辐射区域探测机器人 #esp32 #mosquito #2025年 #FRP #AI教程 #自动化巡检 #istio #服务发现 #jquery #运动 #fork函数 #进程创建 #进程终止 #moltbot #session #JADX-AI 插件 #OpenAI #故障 #starrocks #二值化 #Canny边缘检测 #轮廓检测 #透视变换 #tekton