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

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

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

 实现一个简单的对话发消息的功能!

目录

一.新增的接口:

1.socket

2.bing

3.inet_addr

4.recvform

5.inet_ntoa

5.sendto

6.popen

二、初步代码以及结果

1.udp_server.hpp

2.udp_server.cc 

3.udp_client

4.log.hpp

5.结果 

三、爆改多线程

1.udp_client.cc

2.udp_server.cc

3.udp_server.hpp

 4.thread.hpp

5.结果


一.新增的接口:

1.socket

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

       int socket(int domain, int type, int protocol);
  • 参数一:叫做域,用来判断是那个类型的,AF_UNIX, AF_LOCAL(用于本地通信)AF_INET(用于ipv4的网络通信)
  • 参数二:类型,通信的种类是什么,SOCK_DGRAM(套接字的类别,数据报的方式)
  • 参数三:协议,比如用AF_INET,SOCK_DGRAM,一般直接写0
  •  创建成功会得到一个文件描述符,失败返回-1

2.bing

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

       int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
  • 参数一:创建的套接字
  • 参数二:填充sockaddr结构体
  • 参数三:所传入这个结构体对象的长度

3.inet_addr

#include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
n_addr_t inet_addr(const char *cp);
  • 将点分十进制转换成四字节,并且将主机序列转换成网络序列
  • 参数一:传入的ip

4.recvform

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
  • 用于从套接字接收数据。该函数通常与无连接的数据报服务
  • 参数一:套接字
  • 参数二和参数三:读取数据的缓冲区,用于存放读取到的数据,len叫做最终的大小
  • 参数四:读取的方式,0为阻塞的方式读取
  • 参数五和参数六:是输出型参数,我们还要知道是谁给我们发的消息

5.inet_ntoa

#include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
char *inet_ntoa(struct in_addr in);
  • 将点分四字节转换成点分十进制,并且将网络序列转换成主机序列
  • 参数一:从网络中获取到的ip

5.sendto

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
  • 参数一:套接字
  • 参数二和参数三:要发送的数据和长度
  • 参数四:默认为0,阻塞
  • 参数五:要把数据发给谁,
  • 参数六:这个缓冲区的长度是多少

6.popen

#include <stdio.h>

       FILE *popen(const char *command, const char *type);

二、初步代码以及结果

1.udp_server.hpp

#ifndef _UDP_SERVER_HPP
#define _UDP_SERVER_HPP

#include <iostream>
#include <string>
#include <sys/types.h>        
#include <sys/socket.h>
#include "log.hpp"
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <cstdio>
#include <unistd.h>


#define SIZE 1024

class UDPServer
{
public:
    UDPServer(uint16_t port,std::string ip="")
    :port_(port),ip_(ip),sock_(-1)
    {}

    bool initServer()
    {
        //这里开始使用网络部分
        //1.创建套接字
        sock_=socket(AF_INET,SOCK_DGRAM,0);
        if(sock_<0)
        {
            logMessage(FATAL,"%d:%s",errno,strerror(errno));
            exit(2);
        }
        //2.bind绑定:将用户设置的ip和端口号在内核中和我们的进程强关联
        //"192.168.1.0"->点分十进制
        //以.来分隔,每个区域的取值范围为0——255,
        //正好为1字节,四个区域理论上需要四字节
        //所以我们的看的时候会由4字节显示,转换为点分十进制
        
        //初始化结构体完成
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        //填充结构体
        local.sin_family=AF_INET;
        //服务器的IP和端口号,未来也是要发送给对方主机才能互相通信的
        //所以要先把数据发送到网络,要用htons
        local.sin_port=htons(port_);
        //同上要先把点分十进制转换成四字节ip
        //还需要要把四字节主机序列,转换成网络序列
        //所以用inet_addr一次性转成网络四字节序列
        //local.sin_addr.s_addr=inet_addr(ip_.c_str());
        //一般情况下,只要是这个端口的,那么我们就直接全部都接受,而不是指定端口
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        //这里需要做强转,因为bind需要的是sockaddr类型而不是sockaddr_in类型
        if(bind(sock_,(struct sockaddr*)&local,sizeof(local))<0)
        {
            logMessage(FATAL,"%d:%s",errno,strerror(errno));
            exit(2);
        }
        //至此初始化服务器写完,首先创建套接字,接着用bind来绑定ip和端口号写进内核中
        logMessage(NORMAL, "init udp server done ... %s", strerror(errno));
        return true;
    }

    void strat()
    {
        //作为一款网络服务器,是永远不退出的!
        // 服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在,除非挂了!
        //echo服务器,主机给我们发送消息,我们原封不动的返回
        char buffer[SIZE];
        for( ; ;)
        {
            //1.读取数据
            //注意peer,纯输出型参数
            struct sockaddr_in peer;
            bzero(&peer,sizeof(peer));
            //输入:peer 缓冲区大小
            //输入:实际读到的peer大小
            //所以len的大小要为实际的peer大小
            socklen_t len = sizeof(peer);
            //这样就把数据读取到buffer里了
            ssize_t s= recvfrom(sock_,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(s>0)
            {
                buffer[s]=0;//我们目前数据当作字符串
                //1.输出发送的数据信息
                //2.是谁?提取!
                uint16_t cil_port=ntohs(peer.sin_port);//从网络中来的,所以要进行转成主机端口号
                std::string cli_p=inet_ntoa(peer.sin_addr);//将点分四字节转换成点分十进制,并且将网络序列转换成主机序列
                printf("[%s:%d]# %s\n",cli_p.c_str(),cil_port,buffer);
            }
            //2.分析和处理数据

            //3.写回数据
            sendto(sock_,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,len);
        }
    }

    ~UDPServer()
    {
        if(sock_>=0)
        {
            close(sock_);
        }
    }

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

#endif

2.udp_server.cc 

#include "udp_server.hpp"
#include <memory>
#include <cstdlib>

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

int main(int argc,char *argv[])
{
    //检查传入ip和端口号是否错误
    if(argc!=2)
    {
        usage(argv[0]);
        exit(1);

    }
    //初始化服务器,利用unique_ptr
    uint16_t port=atoi(argv[1]);
    //std::string ip=argv[1];
    std::unique_ptr<UDPServer> svr(new UDPServer(port));
    svr->initServer();
    svr->strat();
    return 0;
}

3.udp_client

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include "thread.hpp"

static 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);
    }
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        
        std::cerr << "socket error" << std::endl;
        exit(2);
    }
    //client要不要bind?要bind,但是client不会显示的bind,程序员不会自己bind
    //client是一个客户端,是普通人下载并使用的
    //如果需要显示的bind,也就要求了客户端也bind了一个固定的端口
    //万一其他的客户端提前真用了端口号了呢,这时这个客户端就无法启动了
    //所以不用显示的bind指定端口号,直接让OS自动随机选择
    std::string message;
    //给谁发的信息如下
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(atoi(argv[2]));
    server.sin_addr.s_addr=inet_addr(argv[1]);

    char buffer[1024];
    while(1)
    {
        std::cout<<"请输入你的信息# ";
        std::getline(std::cin,message);
        if(message=="quit")
        {
            break;
        }
        //当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和port
        sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
        //至此客户端和服务器已经建成

        //这里需要定义两个占位的
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t s= recvfrom(sock,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);
        if(s>0)
        {
            buffer[s]=0;
            std::cout<<"server echo# "<<buffer<<std::endl;
        }

    }
    close(sock);
    return 0;
}

4.log.hpp

#pragma once

#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <ctime>
#include <string>

// 日志是有日志级别的
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4

const char *gLevelMap[] = {
    "DEBUG",
    "NORMAL",
    "WARNING",
    "ERROR",
    "FATAL"
};

#define LOGFILE "./threadpool.log"

// 完整的日志功能,至少: 日志等级 时间 支持用户自定义(日志内容, 文件行,文件名)
void logMessage(int level, const char *format, ...)
{
#ifndef DEBUG_SHOW
    if(level== DEBUG) return;
#endif
    // va_list ap;
    // va_start(ap, format);
    // while()
    // int x = va_arg(ap, int);
    // va_end(ap); //ap=nullptr
    char stdBuffer[1024]; //标准部分
    time_t timestamp = time(nullptr);
    // struct tm *localtime = localtime(&timestamp);
    snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", gLevelMap[level], timestamp);

    char logBuffer[1024]; //自定义部分
    va_list args;
    va_start(args, format);
    // vprintf(format, args);
    vsnprintf(logBuffer, sizeof logBuffer, format, args);
    va_end(args);

    //FILE *fp = fopen(LOGFILE, "a");
    printf("%s%s\n", stdBuffer, logBuffer);
    //fprintf(fp, "%s%s\n", stdBuffer, logBuffer);
    //fclose(fp);
}

5.结果 

这个叫做本地环回:client和server发送数据只在本地协议栈中进行数据流动,不会把我们的数据发送到网络中,通常用于本地网络服务器的测试

 ——————————————————————————————————————————

其中客户端时OS随机绑定的,全0IP是因为只要是这个端口的我都要,不要具体IP的

三、爆改多线程

我们要把这个代码改成一个类似QQ群一样的模式,所有人发的消息都可以看到

1.udp_client.cc

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include "thread.hpp"

uint16_t serverport=0;
std::string serverip;

//发现:无论是多线程读还是写,用的sock都是一个,sock代表就是文件,UDP是全双工的-> 可以同时进行收发而不受干扰


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

//发送逻辑的回调
static void *udpSend(void *args)
{
    //根据线程的封装,先转换成data*的然后获取里面的args_,然后在转会int*
    //获得一个指针指向args里面的sock,然后解引用
    int sock=*(int*)((ThreadData*)args)->args_;
    std::string name = ((ThreadData*)args)->name_;
    //下面逻辑与之前一样,构建发送的字符串,套接字信息
    std::string message;
    //给谁发的信息如下
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(serverport);
    server.sin_addr.s_addr=inet_addr(serverip.c_str());

    //开始不间断的发送
    while(1)
    {
        std::cerr<<"请输入你的信息# ";
        std::getline(std::cin,message);
        if(message=="quit")
        {
            break;
        }
        //当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和port
        sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
        //至此客户端和服务器已经建成
    }
    return nullptr;
}

//接受逻辑的回调
static void *udpRecv(void *args)
{
    int sock=*(int*)((ThreadData*)args)->args_;
    std::string name = ((ThreadData*)args)->name_;

    //需要不断地去读,要去指定的套接字中读取
    while(1)
    {
        char buffer[1024];
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        ssize_t s= recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);
        if(s>0)
        {
            buffer[s]=0;
            std::cout<<buffer<<std::endl;
        }

    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        
        std::cerr << "socket error" << std::endl;
        exit(2);
    }

    serverport=atoi(argv[2]);
    serverip=argv[1];
    //client要不要bind?要bind,但是client不会显示的bind,程序员不会自己bind
    //client是一个客户端,是普通人下载并使用的
    //如果需要显示的bind,也就要求了客户端也bind了一个固定的端口
    //万一其他的客户端提前真用了端口号了呢,这时这个客户端就无法启动了
    //所以不用显示的bind指定端口号,直接让OS自动随机选择

    //爆改多线程,一个线程发送数据到各个主机,一个线程接受各个数据。
    std::unique_ptr<Thread> sender(new Thread(1,udpSend,(void*)&sock));
    std::unique_ptr<Thread> recver(new Thread(2,udpRecv,(void*)&sock));

    sender->start();
    recver->start();

    sender->join();
    recver->join();
    close(sock);



    // std::string message;
    // //给谁发的信息如下
    // struct sockaddr_in server;
    // memset(&server,0,sizeof(server));
    // server.sin_family=AF_INET;
    // server.sin_port=htons(atoi(argv[2]));
    // server.sin_addr.s_addr=inet_addr(argv[1]);

    // char buffer[1024];
    // while(1)
    // {
    //     std::cout<<"请输入你的信息# ";
    //     std::getline(std::cin,message);
    //     if(message=="quit")
    //     {
    //         break;
    //     }
    //     //当client首次发送消息给服务器的时候,OS会自动给client bind它的ip和port
    //     sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
    //     //至此客户端和服务器已经建成

    //     //这里需要定义两个占位的
    //     struct sockaddr_in temp;
    //     socklen_t len = sizeof(temp);
    //     ssize_t s= recvfrom(sock,&buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);
    //     if(s>0)
    //     {
    //         buffer[s]=0;
    //         std::cout<<"server echo# "<<buffer<<std::endl;
    //     }

    // }
    // close(sock);
    return 0;
}

2.udp_server.cc

#include "udp_server.hpp"
#include <memory>
#include <cstdlib>

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

int main(int argc,char *argv[])
{
    //检查传入ip和端口号是否错误
    if(argc!=2)
    {
        usage(argv[0]);
        exit(1);

    }
    //初始化服务器,利用unique_ptr
    uint16_t port=atoi(argv[1]);
    //std::string ip=argv[1];
    std::unique_ptr<UDPServer> svr(new UDPServer(port));
    svr->initServer();
    svr->strat();
    return 0;
}

3.udp_server.hpp

#ifndef _UDP_SERVER_HPP
#define _UDP_SERVER_HPP

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <cstdio>
#include <unistd.h>
#include <unordered_map>

#define SIZE 1024

class UDPServer
{
public:
    UDPServer(uint16_t port, std::string ip = "")
        : port_(port), ip_(ip), sock_(-1)
    {
    }

    bool initServer()
    {
        // 这里开始使用网络部分
        // 1.创建套接字
        sock_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock_ < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }
        // 2.bind绑定:将用户设置的ip和端口号在内核中和我们的进程强关联
        //"192.168.1.0"->点分十进制
        // 以.来分隔,每个区域的取值范围为0——255,
        // 正好为1字节,四个区域理论上需要四字节
        // 所以我们的看的时候会由4字节显示,转换为点分十进制

        // 初始化结构体完成
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        // 填充结构体
        local.sin_family = AF_INET;
        // 服务器的IP和端口号,未来也是要发送给对方主机才能互相通信的
        // 所以要先把数据发送到网络,要用htons
        local.sin_port = htons(port_);
        // 同上要先把点分十进制转换成四字节ip
        // 还需要要把四字节主机序列,转换成网络序列
        // 所以用inet_addr一次性转成网络四字节序列
        // local.sin_addr.s_addr=inet_addr(ip_.c_str());
        // 一般情况下,只要是这个端口的,那么我们就直接全部都接受,而不是指定端口
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        // 这里需要做强转,因为bind需要的是sockaddr类型而不是sockaddr_in类型
        if (bind(sock_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }
        // 至此初始化服务器写完,首先创建套接字,接着用bind来绑定ip和端口号写进内核中
        logMessage(NORMAL, "init udp server done ... %s", strerror(errno));
        return true;
    }

    void strat()
    {
        // 作为一款网络服务器,是永远不退出的!
        //  服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在,除非挂了!
        // echo服务器,主机给我们发送消息,我们原封不动的返回
        char buffer[SIZE];
        for (;;)
        {
            // 1.读取数据
            // 注意peer,纯输出型参数
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            // 输入:peer 缓冲区大小
            // 输入:实际读到的peer大小
            // 所以len的大小要为实际的peer大小
            socklen_t len = sizeof(peer);
            // 这样就把数据读取到buffer里了
            ssize_t s = recvfrom(sock_, &buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            char result[256];
            char key[64];
            std::string cmd_echo;
            if (s > 0)
            {
                buffer[s] = 0; // 我们目前数据当作字符串
                // 1.输出发送的数据信息
                // 2.是谁?提取!
                // if(strcasestr(buffer,"rm")!=nullptr||strcasestr(buffer,"rmdir")!=nullptr)
                // {
                //     std::string err_message="坏人";
                //     std::cout<<err_message<<buffer<<std::endl;
                //     sendto(sock_, err_message.c_str(), err_message.size(), 0, (struct sockaddr *)&peer, len);

                //     continue;
                // }
                // FILE *fp = popen(buffer, "r");
                // if (nullptr == fp)
                // {
                //     logMessage(ERROR, "%d:%s", errno, strerror(errno));
                //     continue;
                // }

                // while (fgets(result, sizeof(result), fp) != nullptr)
                // {
                //     cmd_echo += result;
                // }
                // fclose(fp);
                uint16_t cil_port = ntohs(peer.sin_port);     // 从网络中来的,所以要进行转成主机端口号
                std::string cil_ip = inet_ntoa(peer.sin_addr); // 将点分四字节转换成点分十进制,并且将网络序列转换成主机序列
                // printf("[%s:%d]# %s\n",cli_p.c_str(),cil_port,buffer);
                snprintf(key, sizeof(key), "%s-%d", cil_ip.c_str(), cil_port);
                logMessage(NORMAL,"key: %s",key);
                auto it = users_.find(key);
                if(it==users_.end())
                {
                    logMessage(NORMAL,"add new user:%s",key);
                    users_.insert({key,peer});
                }

            }
            // 2.分析和处理数据

            // 3.写回数据
            // sendto(sock_,buffer,sizeof(buffer),0,(struct sockaddr*)&peer,len);
            //sendto(sock_, cmd_echo.c_str(), cmd_echo.size(), 0, (struct sockaddr *)&peer, len);
            for(auto &iter:users_)
            {
                std::string sendMessage=key;
                sendMessage+="# ";
                sendMessage+=buffer;
                logMessage(NORMAL,"push message to %s",iter.first.c_str());
                sendto(sock_, sendMessage.c_str(), sendMessage.size(), 0, (struct sockaddr *)&(iter.second), sizeof(iter.second));

            }
        }
    }

    ~UDPServer()
    {
        if (sock_ >= 0)
        {
            close(sock_);
        }
    }

private:
    uint16_t port_;
    std::string ip_;
    int sock_;
    std::unordered_map<std::string, struct sockaddr_in> users_;
};

#endif

 4.thread.hpp

#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <cstdio>

using namespace std;

typedef void*(*fun_t)(void*);

class ThreadData
{
public:
    void* args_;
    string name_;
};

class Thread
{
public:
    Thread(int num,fun_t callback,void* args):func_(callback)
    {
        char namebuffer[64];
        snprintf(namebuffer,sizeof(namebuffer),"Thread-%d",num);
        name_=namebuffer;

        tdata_.args_=args;
        tdata_.name_=name_;
    }

    void start()
    {
        pthread_create(&tid_,nullptr,func_,&tdata_.args_);
    }

    void join()
    {
        pthread_join(tid_,nullptr);
    }
    
    string name()
    {
        return name_;
    }
    ~Thread()
    {

    }

private:
    string name_;
    fun_t func_;
    ThreadData tdata_;
    pthread_t tid_;
};

5.结果

利用管道可以更好的观看

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:RotationGesture)

用于触发旋转手势事件&#xff0c;触发旋转手势的最少手指为2指&#xff0c;最大为5指&#xff0c;最小改变度数为1度。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 接口 RotationGesture(value?: …

Oracle SQL优化(读懂执行计划 一)

目录 SQL执行计划的作用示例演示执行计划概念介绍执行计划实例DISPLAY_CURSOR 类型DISPLAY_AWR 类型 指标详解 SQL执行计划的作用 示例演示 执行计划概念介绍 执行计划实例 DISPLAY_CURSOR 类型 DISPLAY_AWR 类型 指标详解

C/C++指针详解

接下来我们来介绍一下什么是指针&#xff1f; 指针其实就是元素存放地址&#xff0c;更加形象的比喻&#xff1a;在酒店中如果你想要去注必须去付费不然不能住&#xff0c;在计算机也同样如此&#xff08;但是不需要付费哦&#xff09;每当我们使用一个变量或其他需要申请空间…

三、N元语法(N-gram)

为了弥补 One-Hot 独热编码的维度灾难和语义鸿沟以及 BOW 词袋模型丢失词序信息和稀疏性这些缺陷&#xff0c;将词表示成一个低维的实数向量&#xff0c;且相似的词的向量表示是相近的&#xff0c;可以用向量之间的距离来衡量相似度。 N-gram 统计语言模型是用来计算句子概率的…

数据结构(二)——线性表(双链表)

2.3.3 双链表 单链表&#xff1a;单链表结点中只有一个指向其后继的指针&#xff0c;使得单链表只能从前往后依次遍历,无法逆向检索&#xff0c;有时候不太方便 双链表的定义&#xff1a;双链表结点中有两个指针prior和next&#xff0c;分别指向其直接前驱和直接后继 表头结点…

Jmeter---非GUI命令行的执行生成报告、使用ant插件执行接口测试脚本生成报告

非GUI命令行的执行 1. 在jmx后缀的文件目录下打开命令行 2. 运行&#xff1a; jmeter -n -t filename.jmx&#xff08;-n : 非GUI的方式 -t: 指定需要执行的脚本&#xff09; 生成jtl报告 运行&#xff1a; jmeter -n -t filename.jmx -l result_filename.jtl 生成html报…

C语言笔记:文件的操作各种文件函数讲解

突然发现自己的C语言文件部分还没有学&#xff0c;赶紧来补一下~~ 1.文件分类 文本文件磁盘文件&#xff08;二进制文件&#xff09;C语言特殊文件标识&#xff1a;stdin&#xff08;标准输入&#xff1a;通指键盘输入&#xff09;&#xff0c;stdout&#xff08;标准输出&am…

基于SpringBoot的招聘网站

基于jspmysqlSpring的SpringBoot招聘网站项目&#xff08;完整源码sql&#xff09; 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》…

网络编程总结

文章目录 1.浏览器输入一个 url 中间经历的过程2.TCP,UDP 的区别3.HTTP 协议HTTP 协议有哪些部分组成&#xff1f;响应状态码GET 和 POST 的区别什么是幂等的什么是 HTTP 的长链接cookie 和 session 的区别TCP socket 编程原理 4.IO 多路复用五种 IO 模型如何提升服务器的并发能…

Ubuntu 基本操作-嵌入式 Linux 入门

在 Ubuntu 基本操作 里面基本就分为两部分&#xff1a; 安装 VMware 运行 Ubuntu熟悉 Ubuntu 的各种操作、命令 如果你对 Ubuntu 比较熟悉的话&#xff0c;安装完 VMware 运行 Ubuntu 之后就可以来学习下一章节了。 1. 安装 VMware 运行 Ubuntu 我们首先来看看怎么去安装 V…

2.4_4 死锁的检测和解除

文章目录 2.4_4 死锁的检测和解除&#xff08;一&#xff09;死锁的检测&#xff08;二&#xff09;死锁的解除 总结 2.4_4 死锁的检测和解除 如果系统中既不采取预防死锁的措施&#xff0c;也不采取避免死锁的措施&#xff0c;系统就很可能发生死锁。在这种情况下&#xff0c;…

通过Annotation将用户操作记录到数据库表功能实现

一、背景 在用户对我们所开发的系统访问的时候&#xff0c;需要我们的系统具有强大的健壮性&#xff0c;使得给与用户的体验感十足。在业务开发的过程中&#xff0c;我们通过将几个相关的操作绑定成一个事件&#xff0c;使得安全性以及数据的前后一致性得到提高。但是在溯源方面…

Linux第74步_“设备树”下的LED驱动

使用新字符设备驱动的一般模板&#xff0c;以及设备树&#xff0c;驱动LED。 1、添加“stm32mp1_led”节点 打开虚拟机上“VSCode”&#xff0c;点击“文件”&#xff0c;点击“打开文件夹”&#xff0c;点击“zgq”&#xff0c;点击“linux”&#xff0c;点击“atk-mp1”&am…

三角形费马点及深入拓展

三角形费马点及深入拓展 一、费马点的定义 三角形内部满足到三个顶点距离之和最小的点&#xff0c;称为费马点。 二、费马点的证明 比较麻烦的一件事情是&#xff0c;当我们考虑一个三角形的费马点时&#xff0c;我们需要将三角形分为两类: ①三个内角均小于120的三角形 ②有…

【SQL】185. 部门工资前三高的所有员工(窗口函数dense_rank();区分rank()、row_number())

前述 推荐阅读&#xff1a;通俗易懂的学会&#xff1a;SQL窗口函数 题目描述 leetcode题目 185. 部门工资前三高的所有员工 思路 先按照departmentId分组&#xff0c;再按照salary排序 >窗口函数dense_rank() over() select B.name as Department,A.name as Employee,A…

Python 初步了解urllib库:网络请求的利器

目录 urllib库简介 request模块 parse模块 error模块 response模块 读取响应内容 获取响应状态码 获取响应头部信息 处理重定向 关闭响应 总结 在Python的众多库中&#xff0c;urllib库是一个专门用于处理网络请求的强大工具。urllib库提供了多种方法来打开和读取UR…

试用期自我总结报告10篇

试用期自我总结报告&#xff08;篇1&#xff09; 一转眼试用期的时间飞快就过去了&#xff0c;在这段时间里我学习到了很多&#xff0c;也把自己在过去学习的东西得已融会贯通。能够来到幼儿园里成为一名老师是我一直以来的目标&#xff0c;而我也终于完成了自己的目标&#x…

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

演示视频&#xff1a; Springbootvue的医院药品管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…

如何在RTMP推送端和RTMP播放端支持Enhanced RTMP H.265(HEVC)

技术背景 时隔多年&#xff0c;在Enhancing RTMP, FLV With Additional Video Codecs And HDR Support&#xff08;2023年7月31号正式发布&#xff09;官方规范出来之前&#xff0c;如果RTMP要支持H.265&#xff0c;大家约定俗成的做法是扩展flv协议&#xff0c;CDN厂商携手给…

React-Mock数据

1.概念 说明&#xff1a;React中使用Mock数据主要是为了模拟后端接口和数据&#xff0c;以便前端开发可以在没有实际后端支持的情况下进行。 2.实现步骤 2.1安装 npm i -D json-server 2.2准备json文件 {"list":[{"name":"李四","age&q…
最新文章