Linux网络套接字之TCP网络程序

news2024/11/17 5:31:32

 (。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~icon-default.png?t=N7T8https://blog.csdn.net/ky233?type=blog

点个关注不迷路⌯'▾'⌯

目录

一、接口介绍

1.socket

2.listen

3.accept

3.connect

4.send

二.基础代码

1.tcp_server

2.tcp_server.hpp

 3.tcp_client

4.结果

三、多进程版本

四、多线程版本

五、线程池版本

六、变成小写转换大写的方法


一、接口介绍

1.socket

不做过多介绍,前文有

SOCK_STREM,TCP用这个

2.listen

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

       int listen(int sockfd, int backlog);

将TCP套接字设置成监听状态

  • 参数一:创建好的套接字
  • 参数二:目前无法理解,

3.accept

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

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

获取链接

  • 参数一:套接字
  • 参数二:输出型参数
  • 参数三:输出输入型参数
  • 返回值:成功返回成功的套接字,失败则返回-1

3.connect

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

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

根据创建好的套接字,让客户端具有连接服务器的能力,会自动绑客户端的ip和端口

  • 参数一:套接字
  • 参数二:输出型参数
  • 参数三:输入型参数

4.send

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

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

基于TCP向目标返回消息

参数四:一般为0

5.recv

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

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

基于TCP来读消息

参数四:一般为0

二.基础代码

1.tcp_server

#pragma once
#include "tcp_server.hpp"
#include <memory>
 


static void usage(std::string proc)
{
    std::cout<<"\nUsage:"<<"proc\n"<<std::endl;
}


int main(int argc,char* argv[])
{
    if (argc!=2)
    {
        usage(argv[0]);
        exit(1);
    }
    
    //存储端口号
    uint16_t port=atoi(argv[1]);
    std::unique_ptr<TcpServer> svr(new TcpServer(port));
    svr->initServer();
    svr->start();
    return 0;
}

2.tcp_server.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"

static void service(int sock, const std::string &client_ip, const uint16_t &client_port)
{
    // echo server
    char buffer[1024];
    while (1)
    {
        // 先读取
        // read和write可以直接被使用,套接字也就是文件描述符
        ssize_t s = read(sock, &buffer, sizeof buffer);
        if (s > 0)
        {
            buffer[s] = 0; // 直接将发送过来的数据当作字符串打印
            std::cout << client_ip << ":" << client_port << "# " << buffer << std::endl;
        }
        else if (s = 0) // 对端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else // 读取失败
        {
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(sock, &buffer, sizeof buffer);
    }
}
class TcpServer
{

    const static int g_backlog = 20; // 不能太大也不能太小
public:
    TcpServer(uint16_t port, std::string ip = "")
        : port_(port), ip_(ip), listensock_(-1)
    {
    }

    void initServer()
    {
        // 1.创建套接字
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            logMessage(FATAL, "create socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success, listensock_: %d", listensock_);

        // 2.bind,将服务器和端口信息进行绑定
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)))
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }

        // 因为TCP是面向连接的,所以正是通信的时候需要先建立连接
        // 3.开始监听
        if (listen(listensock_, g_backlog) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }

    void start()
    {
        signal(SIGCHLD,SIG_IGN);//子进程退出会像父进程发送SIGCHLD信号,子进程退出的时候,会自动释放自己的僵尸状态
        while (1)
        {
            // 4.获取连接,服务器要获取客户端的连接,这样来方便返回
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // listensock_和listensock_有什么区别呢?
            // 其中listensock_通过这个套接字只是为了把底层的连接获取上来
            // 而listensock_才是真正的进行连接的
            int listensock = accept(listensock_, (struct sockaddr *)&src, &len);
            if (listensock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            // 获取成功了
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, listensock_: %d | %s : %d |\n",
                       listensock, client_ip.c_str(), client_port);
            // 开始进行通信
            // 单进程循环版,只能够一次处理一个客户端,处理完成了才能处理下一个,很明显是不可以的
            //这是因为单进程的,下面函数是个死循环,所以不退出就没办法获取新的连接
            //service(listensock_, client_ip, client_port);
            //多进程版本
            //创建子进程,那么子进程可以打开父进程曾经打开的fd吗?
            //是可以的,父进程创建子进程时候,子进程的文件描述符表,会继承自于父进程,所以会看到同一个文件
            pid_t id= fork();
            assert(id!=-1);
            if(id==0)//子进程
            {
                //子进程会不会继承父进程打开的文件与文件描述符fd呢?这是肯定的
                //子进程是来提供服务的,需不需要监听socket呢?
                service(listensock_, client_ip, client_port);

                close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
                exit(0);//子进程退出会造成僵尸进程
            }
            close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
            //父进程
            //waitpid是阻塞式等待,也会占用资源无意义,所以这里用signal

            
            
        }
    }

    ~TcpServer()
    {
    }

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

 3.tcp_client

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>

void usage(std::string proc)
{
    std::cout << "\nUsage: " << proc << " serverIp serverPort\n"
              << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }

    // 获取ip和port
    std::string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    // 创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket error" << std::endl;
        exit(2);
    }

    // client是不需要显示bind的,因为如果bind了就是一个非常具体的端口号了,多个客户端可能会出现冲突,可能会导致启动失败,所以不需要显示的bind
    // 让OS自动选择
    // 但是客户端必须拥有连接的能力
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = ntohs(port);
    server.sin_addr.s_addr = inet_addr(ip.c_str());

    if (connect(sock, (struct sockaddr *)&server, sizeof(server)))
    {
        std::cerr << "connect error" << std::endl;
        exit(3); // TODO
    }
    std::cout << "connect success" << std::endl;

    //连接成功直接通信
    while(1)
    {
        std::string line;
        std::cout<< "请输入# ";
        std::getline(std::cin,line);

        //发送数据
        send(sock,line.c_str(),line.size(),0);
        char buffer[1024];
        ssize_t s=recv(sock,buffer,sizeof(buffer)-1,0);
        if(s>0)
        {
            buffer[s]=0;
            std::cout << "server 回显# " << buffer << std::endl;
        }
        else if(s==0)
        {
            break;
        }
        else
        {
            break;
        }
    }

    return 0;
}

4.结果

可以看到我们的server是由两个的,一个是子进程一个是父进程

三、多进程版本

上面的其实已经是多进程版本的了,但是我们使用的signal信号来实现子进程退出的,下面我们用另一种方式来实现

为什么我们创建了子进程之后还要再创建一下呢?这是因为我们让子进程退出之间再次fork一下,会留下一个孙子进程,孙子进程变成了孤儿进程,会被OS领养,会被OS自己退出,所以父进程等待是不会阻塞的!

tcp_server.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include "log.hpp"

static void service(int sock, const std::string &client_ip, const uint16_t &client_port)
{
    // echo server
    char buffer[1024];
    while (1)
    {
        // 先读取
        // read和write可以直接被使用,套接字也就是文件描述符
        ssize_t s = read(sock, &buffer, sizeof buffer);
        if (s > 0)
        {
            buffer[s] = 0; // 直接将发送过来的数据当作字符串打印
            std::cout << client_ip << ":" << client_port << "# " << buffer << std::endl;
        }
        else if (s = 0) // 对端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else // 读取失败
        {
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(sock, &buffer, sizeof buffer);
    }
}
class TcpServer
{

    const static int g_backlog = 20; // 不能太大也不能太小
public:
    TcpServer(uint16_t port, std::string ip = "")
        : port_(port), ip_(ip), listensock_(-1)
    {
    }

    void initServer()
    {
        // 1.创建套接字
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            logMessage(FATAL, "create socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success, listensock_: %d", listensock_);

        // 2.bind,将服务器和端口信息进行绑定
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)))
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }

        // 因为TCP是面向连接的,所以正是通信的时候需要先建立连接
        // 3.开始监听
        if (listen(listensock_, g_backlog) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }

    void start()
    {
        // signal(SIGCHLD,SIG_IGN);//子进程退出会像父进程发送SIGCHLD信号,子进程退出的时候,会自动释放自己的僵尸状态
        while (1)
        {
            // 4.获取连接,服务器要获取客户端的连接,这样来方便返回
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // listensock_和servicesock有什么区别呢?
            // 其中listensock_通过这个套接字只是为了把底层的连接获取上来
            // 而servicesock才是真正的进行连接的
            int servicesock = accept(listensock_, (struct sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            // 获取成功了
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n",
                       servicesock, client_ip.c_str(), client_port);
            // 开始进行通信
            // 单进程循环版,只能够一次处理一个客户端,处理完成了才能处理下一个,很明显是不可以的
            // 这是因为单进程的,下面函数是个死循环,所以不退出就没办法获取新的连接
            // service(listensock_, client_ip, client_port);

            // 多进程版本
            // 创建子进程,那么子进程可以打开父进程曾经打开的fd吗?
            // 是可以的,父进程创建子进程时候,子进程的文件描述符表,会继承自于父进程,所以会看到同一个文件
            //  pid_t id= fork();
            //  assert(id!=-1);
            //  if(id==0)//子进程
            //  {
            //      //子进程会不会继承父进程打开的文件与文件描述符fd呢?这是肯定的
            //      //子进程是来提供服务的,需不需要监听socket呢?
            //      service(listensock_, client_ip, client_port);

            //     close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
            //     exit(0);//子进程退出会造成僵尸进程
            // }
            // close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
            // //父进程
            // //waitpid是阻塞式等待,也会占用资源无意义,所以这里用signal

            // 2.2多进程版本,不用signal
            pid_t id = fork();
            if (id == 0)
            {
                if (fork() > 0)//这是因为我们让子进程退出之间再次fork一下,会留下一个孙子进程,孙子进程变成了孤儿进程
                //会被OS领养,会被OS自己退出,所以父进程等待是不会阻塞的!
                {
                    close(listensock_);
                    exit(0);
                    service(servicesock, client_ip, client_port);
                    exit(0);
                }
            }
            // 父进程
            waitpid(id, nullptr, 0);
            close(servicesock);
        }
    }

    ~TcpServer()
    {
    }

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

四、多线程版本

tcp_server.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <pthread.h>
#include "log.hpp"

static void service(int sock, const std::string &client_ip, const uint16_t &client_port)
{
    // echo server
    char buffer[1024];
    while (1)
    {
        // 先读取
        // read和write可以直接被使用,套接字也就是文件描述符
        ssize_t s = read(sock, &buffer, sizeof buffer);
        if (s > 0)
        {
            buffer[s] = 0; // 直接将发送过来的数据当作字符串打印
            std::cout << client_ip << ":" << client_port << "# " << buffer << std::endl;
        }
        else if (s = 0) // 对端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else // 读取失败
        {
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(sock, &buffer, sizeof buffer);
    }
}

class ThreadData
{
    public:
    int sock_;
    std::string ip_;
    uint16_t port_;
};

class TcpServer
{

    const static int g_backlog = 20; // 不能太大也不能太小
    static void* threadRoutine(void* args)//这里我们要让新线程去干事情,肯定需要套接字,但是上面已经写了所以我们直接调用这个函数就可以了
    {
        pthread_detach(pthread_self());//为了避免内存泄漏要进行线程分离,让子线程执行完毕自动销毁
        ThreadData *td=static_cast<ThreadData *>(args);
        service(td->sock_, td->ip_,td->port_);
        delete td;

        return nullptr;
    }
public:
    TcpServer(uint16_t port, std::string ip = "")
        : port_(port), ip_(ip), listensock_(-1)
    {
    }

    void initServer()
    {
        // 1.创建套接字
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            logMessage(FATAL, "create socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success, listensock_: %d", listensock_);

        // 2.bind,将服务器和端口信息进行绑定
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)))
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }

        // 因为TCP是面向连接的,所以正是通信的时候需要先建立连接
        // 3.开始监听
        if (listen(listensock_, g_backlog) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }

    void start()
    {
        // signal(SIGCHLD,SIG_IGN);//子进程退出会像父进程发送SIGCHLD信号,子进程退出的时候,会自动释放自己的僵尸状态
        while (1)
        {
            // 4.获取连接,服务器要获取客户端的连接,这样来方便返回
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // listensock_和servicesock有什么区别呢?
            // 其中listensock_通过这个套接字只是为了把底层的连接获取上来
            // 而servicesock才是真正的进行连接的
            int servicesock = accept(listensock_, (struct sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            // 获取成功了
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n",
                       servicesock, client_ip.c_str(), client_port);

            //3.0多线程版本
            ThreadData *td = new ThreadData();
            td->sock_ = servicesock;
            td->ip_= client_ip;
            td->port_ = client_port;
            pthread_t tid;
            //在多线程这里是不用关闭特定的文件描述符的,因为主线程与副线程是共享文件描述符的
            pthread_create(&tid,nullptr,threadRoutine,td);
            //close(servicesock)//走到最后主线程结束还是要关闭的


            // 1.0开始进行通信
            // 单进程循环版,只能够一次处理一个客户端,处理完成了才能处理下一个,很明显是不可以的
            // 这是因为单进程的,下面函数是个死循环,所以不退出就没办法获取新的连接
            // service(listensock_, client_ip, client_port);

            // 2.0多进程版本
            // 创建子进程,那么子进程可以打开父进程曾经打开的fd吗?
            // 是可以的,父进程创建子进程时候,子进程的文件描述符表,会继承自于父进程,所以会看到同一个文件
            //  pid_t id= fork();
            //  assert(id!=-1);
            //  if(id==0)//子进程
            //  {
            //      //子进程会不会继承父进程打开的文件与文件描述符fd呢?这是肯定的
            //      //子进程是来提供服务的,需不需要监听socket呢?
            //      service(listensock_, client_ip, client_port);

            //     close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
            //     exit(0);//子进程退出会造成僵尸进程
            // }
            // close(listensock);//这里让父子关闭不需要的文件描述符,不然文件描述符会越来越少
            // //父进程
            // //waitpid是阻塞式等待,也会占用资源无意义,所以这里用signal

            // 2.1多进程版本,不用signal
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     if (fork() > 0)//这是因为我们让子进程退出之间再次fork一下,会留下一个孙子进程,孙子进程变成了孤儿进程
            //     //会被OS领养,会被OS自己退出,所以父进程等待是不会阻塞的!
            //     {
            //         close(listensock_);
            //         exit(0);
            //         service(servicesock, client_ip, client_port);
            //         exit(0);
            //     }
            // }
            // // 父进程
            // waitpid(id, nullptr, 0);
            // close(servicesock);
        }
    }

    ~TcpServer()
    {
    }

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

五、线程池版本

代码自取

六、变成小写转换大写的方法

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

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

相关文章

conda 设置国内源 windows+linux

默认的conda源连接不好&#xff0c;时好时坏&#xff0c;而且速度很慢&#xff0c;可以使用国内的源 如果没有安装conda&#xff0c;可以参考&#xff1a; miniconda安装&#xff1a;链接 anaconda安装winlinux&#xff1a;链接 windows使用命令提示符&#xff0c;linux使用…

后端八股笔记------Redis

Redis八股 上两种都有可能导致脏数据 所以使用两次删除缓存的技术&#xff0c;延时是因为数据库有主从问题需要更新&#xff0c;无法达到完全的强一致性&#xff0c;只能达到控制一致性。 一般放入缓存中的数据都是读多写少的数据 业务逻辑代码&#x1f447; 写锁&#x1f4…

Linux网络基础2之https

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ http是明文的可以通过一些的工具获取到正文层&#…

【Spring Boot系列】快速上手 Spring Boot

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【数学建模】传染病模型笔记

传染病的基本数学模型&#xff0c;研究传染病的传播速度、空间范围、传播途径、动力学机理等问题&#xff0c;以指导对传染病的有效地预防和控制。常见的传染病模型按照传染病类型分为 SI、SIR、SIRS、SEIR 模型等&#xff0c;按照传播机理又分为基于常微分方程、偏微分方程、网…

《计算机网络》考研:2024/3/7 2.1.4 奈氏准则和香农定理

2024/3/7 (作者转行去干LLMs了&#xff0c;但是又想搞定考研&#xff0c;忙不过来了就全截图了呜呜呜。。。 生活真不容易。) 2.1.4 奈氏准则与香农定理

出现“error: failed to push some refs to ‘https://github.com/****.git‘”,如何解决问题

一、出错情况&#xff1a; 今天继续推送整理的知识点的时候&#xff0c;出现了一个报错。“error: failed to push some refs to https://github.com/.git”&#xff0c;百思不得其解&#xff0c;之前推送的时候都可以轻松推送成功&#xff0c;如今却说本地库与远程库不一致。…

STM32电源及时钟介绍

一、STM32最小系统 二、电源电路 2.1供电电压VDD&#xff0c;VSS F103VET6 的引角图 在 F103VET6 的引角图中可找到 49\50 角&#xff0c; 74\75 角&#xff0c; 99\100 角&#xff0c; 27\28角&#xff0c;10 \11角一共 5 对的VDD&#xff0c;VSS&#xff0c;也就是给我们芯片…

体系班第十三节

1判断完全二叉树递归做法 有四种情况&#xff1a;1 左树完全&#xff0c;右数满&#xff0c;且左高为右高加一 2左满 &#xff0c;右满&#xff0c;左高为右高加一 3左满&#xff0c;右完全&#xff0c;左右高相等 4左右均满且高相等 #include<iostream> #include&l…

外边距折叠的原因和解决

参考文章 什么时候出现外边距塌陷 外边距塌陷&#xff0c;也叫外边距折叠&#xff0c;在普通文档流中&#xff0c;在垂直方向上的2个或多个相邻的块级元素&#xff08;父子或者兄弟&#xff09;外边距合并成一个外边距的现象&#xff0c;不过只有上下外边距才会有塌陷&#x…

Guiding Large Language Models viaDirectional Stimulus Prompting

1. 通过定向刺激提示指导大语言模型 论文地址&#xff1a;[2302.11520] Guiding Large Language Models via Directional Stimulus Prompting (arxiv.org) 源码地址&#xff1a;GitHub - Leezekun/Directional-Stimulus-Prompting: [NeurIPS 2023] Codebase for the paper: &qu…

[mmucache]-ARMV8-aarch64的虚拟内存(mmutlbcache)介绍-概念扫盲

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 思考: 1、cache的entry里都是有什么&#xff1f; 2、TLB的entry里都是有什么? 3、MMU操作…

保持长期高效的七个法则(一)7 Rules for Staying Productive Long-Term(1)

Easily the best habit I’ve ever started was to use a productivity system.The idea is simple:organizing all the stuff you need to do (and how you’re going to do it) prevents a lot of internal struggle to get things done. 无疑&#xff0c;我曾经建立过的最好…

简单了解TCP/IP四层模型

什么是计算机网络&#xff1f; 计算机网络我们可以理解为一个巨大的城市地图&#xff0c;我们想从A地前往B地&#xff0c;其中要走的路、要避开的问题都交给计算机网络解决&#xff0c;直到我们可以正常的到达目的地&#xff0c;那么我们会把其中的过程抽象成一个网络模型&…

分布式执行引擎ray入门--(3)Ray Train

Ray Train中包含4个部分 Training function: 包含训练模型逻辑的函数 Worker: 用来跑训练的 Scaling configuration: 配置 Trainer: 协调以上三个部分 Ray TrainPyTorch 这一块比较建议直接去官网看diff&#xff0c;官网色块标注的比较清晰&#xff0c;非常直观。 impor…

APP2:android studio如何使用lombok

一、前言 不知道从哪个版本开始&#xff0c;android studio便无法在plugins中下载lombok了&#xff0c;有人说是内置了&#xff0c;好像有这么回事儿。我主要面临如下两个问题&#xff1a; 使用内置lombok&#xff0c;可以自动生成setter、setter、toString等。但是&#xff0…

政安晨:【深度学习处理实践】(五)—— 初识RNN-循环神经网络

RNN&#xff08;循环神经网络&#xff09;是一种在深度学习中常用的神经网络结构&#xff0c;用于处理序列数据。与传统的前馈神经网络不同&#xff0c;RNN通过引入循环连接在网络中保留了历史信息。 RNN中的每个神经元都有一个隐藏状态&#xff0c;它会根据当前输入和前一个时…

【QT+QGIS跨平台编译】之七十:【QGIS_Analysis跨平台编译】—【qgsrastercalcparser.cpp生成】

文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…

free pascal 调用 C#程序读 Freeplane.mm文件,生成测试用例.csv文件

C# 请参阅&#xff1a;C# 用 System.Xml 读 Freeplane.mm文件&#xff0c;生成测试用例.csv文件 Freeplane 是一款基于 Java 的开源软件&#xff0c;继承 Freemind 的思维导图工具软件&#xff0c;它扩展了知识管理功能&#xff0c;在 Freemind 上增加了一些额外的功能&#x…

构建LVS集群

一、集群的基本理论&#xff08;一&#xff09;什么是集群 人群或事物聚集&#xff1a;在日常用语中&#xff0c;群集指的是一大群人或事物密集地聚在一起。例如&#xff0c;“人们群集在广场上”&#xff0c;这里的“群集”是指大量人群聚集的现象。 计算机技术中的集群&…