【C/C++】实现Reactor高并发服务器 完整版

在这里插入图片描述
代码结构 文件介绍

InetAddress.h
InetAddress类 ip和端口设置

Socket.h
Socket类 设置fd

Epoll.h
epollfd 管理类

Channel.h
Channel类 管理epoll以及对应回调函数实现

EventLoop.h
EventLoop事件循环类

TcpServer.h
服务器类

tcpepoll.cpp 主函数

InetAddress.h

#ifndef _INETADDRESS_H
#define _INETADDRESS_H

#pragma on_INETADDRESS_He

#include <string>
#include <arpa/inet.h>
#include <netinet/in.h>


class InetAddress
{
private:
    sockaddr_in addr_;
public:
    InetAddress(const std::string &ip, uint16_t port);
    InetAddress(const sockaddr_in addr);
    InetAddress();
    ~InetAddress();
    const char *ip()const;
    uint16_t port()const;
    const sockaddr *addr()const;
    void setaddr(sockaddr_in clientaddr);
};

#endif // _INETADDRESS_H



InetAddress.cpp

#include "InetAddress.h"


InetAddress::InetAddress()
{

}

InetAddress::InetAddress(const std::string &ip, uint16_t port)
{
    addr_.sin_family = AF_INET;
    addr_.sin_addr.s_addr = inet_addr(ip.c_str());
    addr_.sin_port = htons(port);
}

InetAddress::InetAddress(const sockaddr_in addr):addr_(addr)
{
    
}

InetAddress::~InetAddress()
{

}

const char* InetAddress::ip()const
{
    return inet_ntoa(addr_.sin_addr);
}
uint16_t InetAddress::port()const
{
    return ntohs(addr_.sin_port);
}
const sockaddr* InetAddress::addr()const
{
    return (sockaddr*)&addr_;
}

void InetAddress::setaddr(sockaddr_in clientaddr)
{
    addr_ = clientaddr;
}

Socket.h

#ifndef SOCKET_H
#define SOCKET_H

#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>  // TCP_NODELAY

#include "InetAddress.h"

int createnonblocking();


class Socket
{
public:
    Socket(int fd);
    ~Socket();

    int fd() const;
    void setreuseaddr(bool on);
    void setreuseport(bool on);
    void settcpnodelay(bool on);
    void setkeepalive(bool on);
    void bind(const InetAddress &servaddr);
    void listen(int n=128);
    int accept(InetAddress &clientaddr);

private:
    const int fd_;
};

#endif // !SOCKET_H


Socket.cpp

#include "Socket.h"

int createnonblocking()
{
    int listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
    if(listenfd < 0)
    {
        perror("socket() failed"); exit(-1);
    }  
    return listenfd;
}

Socket::Socket(int fd)
    :fd_(fd)
{

}
Socket::~Socket()
{
    close(fd_);
}

int Socket::fd() const
{
    return fd_;
}
void Socket::setreuseaddr(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(fd_,  SOL_SOCKET, SO_REUSEADDR, &optval, static_cast<socklen_t>(sizeof(optval)));
}
void Socket::setreuseport(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(fd_,  SOL_SOCKET, SO_REUSEPORT, &optval, static_cast<socklen_t>(sizeof(optval)));
}
void Socket::settcpnodelay(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(fd_,  SOL_SOCKET, TCP_NODELAY, &optval, static_cast<socklen_t>(sizeof(optval)));    
}
void Socket::setkeepalive(bool on)
{
    int optval = on ? 1 : 0;
    setsockopt(fd_,  SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast<socklen_t>(sizeof(optval)));    
}
void Socket::bind(const InetAddress &servaddr)
{
    if(::bind(fd_, servaddr.addr(), sizeof(sockaddr)) < 0)
    {
        perror("bind() failed"); close(fd_); exit(-1);
    }
}
void Socket::listen(int n)
{
    if(::listen(fd_, n) != 0)
    {
        perror("listen() failed");
        close(fd_);
        exit(-1);
    }
}
int Socket::accept(InetAddress &clientaddr)
{
    struct sockaddr_in peeraddr;
    socklen_t len = sizeof(peeraddr);
    int clientfd = accept4(fd_, (struct sockaddr*)&clientaddr, &len, SOCK_NONBLOCK);
    clientaddr.setaddr(peeraddr);
    return clientfd;
}

Epoll.h

#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>  // TCP_NODELAY
#include <vector>
#include "Channel.h"

class Channel;

class Epoll
{
    private:
        static const int MaxEvents = 100;
        int epollfd_;
        epoll_event events_[MaxEvents];
    public:
        Epoll();
        ~Epoll();

        //void addfd(int fd, uint32_t op);
        void updatechannel(Channel *ch);
        //std::vector<epoll_event> loop(int timeout=-1);
        std::vector<Channel*> loop(int timeout=-1);
};

Epoll.cpp

#include "Epoll.h"

/*
class Epoll
{
    private:
        static const int MaxEvents = 100;
        int epollfd;
        epoll_event events_[MaxEvents];
    public:
        Epoll();
        ~Epoll();

        void addfd(int fd, uint32_t op);
        std::vector<epoll_event> loop(int timeout=-1);
}
*/


Epoll::Epoll()
{
    if((epollfd_ = epoll_create(1)) == -1)
    {
        printf("epoll_create() failed(%d).\n", errno);
        exit(-1);
    }
}
Epoll::~Epoll()
{
    close(epollfd_);
}
/*
void Epoll::addfd(int fd, uint32_t op)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = op; //水平

    if(epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        printf("epoll_ctl() failed(%d).\n", errno);
        exit(-1);        
    }
}
*/

void Epoll::updatechannel(Channel *ch)
{
  epoll_event ev;
  ev.data.ptr = ch;
  ev.events = ch->events();
  if(ch->inpoll())
  {
        if(epoll_ctl(epollfd_, EPOLL_CTL_MOD, ch->fd(),&ev) == -1)
        {
            printf("epoll_ctl() failed(%d).\n", errno);
            exit(-1);  
        }
        printf("epoll_ctl() EPOLL_CTL_MOD success. %d\n", ch->fd());
  }
  else
  {
        if(epoll_ctl(epollfd_, EPOLL_CTL_ADD, ch->fd(),&ev) == -1)
        {
            printf("epoll_ctl() failed(%d).\n", errno);
            exit(-1);  
        }
        ch->setinepoll();
        printf("epoll_ctl() EPOLL_CTL_ADD success. %d\n", ch->fd());
  }  
}

/*
std::vector<epoll_event> Epoll::loop(int timeout)
{
    std::vector<epoll_event> evs;
    bzero(events_, sizeof(events_));
    int infds = epoll_wait(epollfd_, events_, MaxEvents, timeout);
    if(infds < 0)
    {
        perror("epoll_wait() failed "); exit(-1);
    }

    if(infds == 0)
    {
        perror("epoll_wait() timeout \n"); return evs;
    }

    for(int i = 0; i < infds; i++)
    {
        evs.push_back(events_[i]);
    }

    return evs;
}*/

std::vector<Channel*> Epoll::loop(int timeout)
{
    std::vector<Channel*> channles;
    bzero(events_, sizeof(events_));
    int infds = epoll_wait(epollfd_, events_, MaxEvents, timeout);
    if(infds < 0)
    {
        perror("epoll_wait() failed "); exit(-1);
    }

    if(infds == 0)
    {
        perror("epoll_wait() timeout \n"); return channles;
    }

    for(int i = 0; i < infds; i++)
    {
        Channel *ch = (Channel*)events_[i].data.ptr;    
        ch->setrevents(events_[i].events);
        channles.push_back(ch);
    }

    return channles;
}




Channel.h

#ifndef  CHANNEL_H
#define  CHANNEL_H


#pragma once
#include <sys/epoll.h>
#include <functional>

#include "Epoll.h"
#include "InetAddress.h"
#include "Socket.h"

class Epoll;

class Channel
{
    private:
        int fd_=-1;
        Epoll *ep_ = nullptr; //channle 对应的红黑树
        bool inepoll_=false; // epoll_ctl add mod
        uint32_t events_=0;  //fd_需要监视的事件
        uint32_t revents_=0; //fd 已发生的事件
        std::function<void()> readcallback_;

    public:
        Channel(Epoll *ep, int fd);
        ~Channel();
        int fd();
        void useet(); //采用边缘触发
        void enablereading(); //让epoll_wait()监视fd_的读事件
        void setinepoll();
        void setrevents(uint32_t ev);
        bool inpoll();
        uint32_t events();
        uint32_t revents(); //返回revents_成员

        void handleevent();

        void newconnection(Socket* servsock);
        void onmessage();

        void setreadcallback(std::function<void()> fn);
};

#endif // ! CHANNEL_H

Channel.cpp

#include "Channel.h"


/*
class Channel
{
    private:
        int fd_=-1;
        Epoll *ep_ = nullptr; //channle 对应的红黑树
        bool inepoll_=false; // epoll_ctl add mod
        uint32_t events_=0;  //fd_需要监视的事件
        uint32_t revents_0; //fd 已发生的事件
    public:
        Channel(Epoll *ep, intfd);
        ~Channel();
        int fd();
        void useet(); //采用边缘触发
        void enablereading(); //让epoll_wait()监视fd_的读事件
        void setinepoll();
        void setrevents(uint32_t ev);
        bool inpoll();
        uint32_t events();
        uint32_t revents(); //返回revents_成员
};*/


Channel::Channel(Epoll *ep, int fd)
    :ep_(ep),fd_(fd)
{
    
}

Channel::~Channel()
{
//在析构函数中,不要销毁ep_ 也不能关闭fd_ 不属于channel类
}


int Channel::fd()
{
    return fd_;
}
void Channel::useet()
{
    events_ = events_ | EPOLLET;
}
void Channel::enablereading()
{
    events_ |= EPOLLIN;
    ep_->updatechannel(this);
}
void Channel::setinepoll()
{
    inepoll_ = true;
}
void Channel::setrevents(uint32_t ev)
{
    revents_= ev;
}
bool Channel::inpoll()
{
    return inepoll_;
}
uint32_t Channel::events()
{
    return events_;
}
uint32_t Channel::revents()
{
    return revents_;
}


//事件处理函数, epoll_wait返回的时候执行它。
void Channel::handleevent()
{
    if(revents_ & EPOLLRDHUP)
    {
        printf("cilent fd =%d disconnection\n", fd_);
        close(fd_);
    } 
    else if (revents_ & EPOLLIN|EPOLLPRI)
    {
        readcallback_();
    }
    else if (revents_ & EPOLLOUT)
    {
    }
    else
    {
        printf("cilent fd =%d\n", fd_);
        close(fd_);
    }  
}


void Channel::newconnection(Socket* servsock)
{
    InetAddress clientaddr;
    Socket *clientsock = new Socket(servsock->accept(clientaddr));

    printf("FILE(%s)FUNCTION(%s)LINE(%d) accept client fd=%d, ip=%s,port=%d ok.\n",
        __FILE__, __func__, __LINE__,
    clientsock->fd(), clientaddr.ip(), clientaddr.port());
    Channel *clientchannel = new Channel(ep_, clientsock->fd());
    clientchannel->setreadcallback(std::bind(&Channel::onmessage, clientchannel));
    clientchannel->useet();
    clientchannel->enablereading();
}

void Channel::onmessage()
{
    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    size_t nread = recv(fd_, buffer, sizeof(buffer), 0);
    if(nread > 0)
    {
        printf("tcpepoll Recv:%s\n", buffer);
        send(fd_, buffer, strlen(buffer), 0);
    }else if (nread == -1 && errno == EINTR)
    {

    }else if(nread == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
    {
        
    }else if (nread == 0)
    {
        printf("clientfd:%d disconnected\n", fd_);
        close(fd_);
        
    }
}


//设置fd的回调函数
void Channel::setreadcallback(std::function<void()> fn)
{
    readcallback_ = fn;
}

EventLoop.h

#pragma once

#include "Epoll.h"

class EventLoop
{
private:
    Epoll *ep_;
public:
    EventLoop();
    ~EventLoop();

    void run();

    Epoll* ep();
};

EventLoop.cpp

#include "EventLoop.h"


/*
class EventLoop
{
private:
    Epoll *ep_;
public:
    EventLoop();
    ~EventLoop();

    void run();
};
*/

EventLoop::EventLoop():ep_(new Epoll)
{

}

EventLoop::~EventLoop()
{
    delete ep_;
}


void EventLoop::run()
{
    while(true)
    {
        std::vector<Channel*> channles = ep_->loop();
        for(auto &ch:channles)
        {
            ch->handleevent();
        }
    }
}


Epoll* EventLoop::ep()
{
    return ep_;
}

TcpServer.h

#pragma once

#include "EventLoop.h"
#include "Socket.h"
#include "Channel.h"


class TcpServer
{
private:
    EventLoop loop_;
public:
    TcpServer(const std::string &ip, const uint16_t port);
    ~TcpServer();

    void start();
};

TcpServer.cpp

#include "TcpServer.h"

/*
class TcpServer
{
private:
    EventLoop loop_;
public:
    TcpServer(const std::string &ip, const uint16_t port);
    ~TcpServer();
};
*/


TcpServer::TcpServer(const std::string &ip, const uint16_t port)
{
    Socket *servsock = new Socket(createnonblocking());
    InetAddress servaddr(ip, port);
    servsock->setreuseaddr(true);
    servsock->setreuseport(true);
    servsock->settcpnodelay(true);
    servsock->setkeepalive(true);
    servsock->bind(servaddr);
    servsock->listen();

    Channel *servchannel = new Channel(loop_.ep(), servsock->fd());
    servchannel->setreadcallback(std::bind(&Channel::newconnection, servchannel, servsock));
    servchannel->enablereading();
}

TcpServer::~TcpServer()
{

}

void TcpServer::start()
{
    loop_.run();
}

tcpepoll.cpp

#include "TcpServer.h"

int main(int argc, char *argv[])
{
    if(argc !=3)
    {
        printf("usage: ./tcpepoll ip port\n");
        printf("examples ./tcpepoll 127.0.0.1 6666\n");
        return -1;
    }

    TcpServer tcpserver(argv[1], atoi(argv[2]));
    tcpserver.start(); //运行事件循环

    return 0;
} 

client.cpp

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>  // TCP_NODELAY
#include <time.h>


int main(int argc, char *argv[])
{
    if(argc !=3)
    {
        printf("usage: ./client ip port");
        return -1;
    }

    int sockfd;
    struct sockaddr_in servaddr;
    char buf[1024];

    if((sockfd=socket(AF_INET,SOCK_STREAM, 0)) < 0)
    {
        return -1;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(argv[2]));

    if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))!=0)
    {
        return -1;
    }
    printf("connect ok\n");
    for(int i = 0; i < 200000; i++)
    {
        memset(buf, 0, sizeof(buf));
        printf("please input:");
        scanf("%s", buf);
        if(send(sockfd, buf, strlen(buf), 0) < 0)
        {
            close(sockfd);
            return -1;
        }
        memset(buf, 0, sizeof(buf));
        if(recv(sockfd, buf, sizeof(buf), 0) <= 0)
        {
            return -1;
        }
        printf("i:%d recv:%s\n", i, buf);
    }
    return 0;
}

makefile



all: client tcpepoll

client: client.cpp
	g++ -g -o client client.cpp 

tcpepoll:tcpepoll.cpp InetAddress.cpp Socket.cpp Epoll.cpp Channel.cpp EventLoop.cpp TcpServer.cpp
	g++  -g -o tcpepoll tcpepoll.cpp InetAddress.cpp Socket.cpp Epoll.cpp Channel.cpp EventLoop.cpp TcpServer.cpp

 
clean:
	rm -f client tcpepoll

运行

服务器
在这里插入图片描述
客户端
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

腾讯云OSS文件上传功能

腾讯云COS介绍 腾讯云COS&#xff08;Cloud Object Storage&#xff09;是一种基于对象的存储服务&#xff0c;用于存储和管理海量的非结构化数据&#xff0c;如图片、音视频文件、备份数据等。它具有以下特点和优势&#xff1a; 高可靠性&#xff1a;采用分布式存储架构&…

什么是485远程水表?

485远程水表是一种利用RS485通信协议进行数据传输的智能水表&#xff0c;它具有远程读数、实时监控、数据存储等功能&#xff0c;为水资源管理和居民用水提供了便捷。在我国&#xff0c;随着物联网、大数据等技术的发展&#xff0c;485远程水表得到了广泛的应用&#xff0c;为智…

数据库索引面试的相关问题

查看索引的执行计划 索引失效的情况 1、索引列上做了计算&#xff0c;函数&#xff0c;类型转换等操作。索引失效是因为查询过程需要扫描整个索引并回表。代价高于直接全表扫描。 Like匹配使用了前缀匹配符“%abc” 字符串不加引号导致类型转换。 原因&#xff1a; 常见索…

Java Thread 线程安全问题 上锁 解锁

模拟问题 package com.zhong.thread.usethread;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;/*** ClassName : ThreadProject* Description : 线程安全问题小案例* Author : zhx* Date: 2024-02-19 13:21*/ public class ThreadPr…

postman也不行!IDEA接口调试插件

Postman是大家最常用的API调试工具&#xff0c;那么有没有一种方法可以不用手动写入接口到Postman&#xff0c;即可进行接口调试操作&#xff1f;今天给大家推荐一款IDEA插件&#xff1a;Apipost Helper&#xff0c;写完代码就可以调试接口并一键生成接口文档&#xff01;而且还…

树和堆的精讲

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

MySQL的基础架构

文章目录 前言MySQL的基础架构总结 前言 你使用 MySQL 开发&#xff0c;你知道 MySQL 的基础架构吗&#xff1f;本文带你来入门MySQL 的基础架构 MySQL的基础架构 MySQL 是我们经常使用到的数据库。它的基础架构分为 server 层与存储引擎层。 server 层&#xff1a;用于存储…

nacos 2.3.1-SNAPSHOT 源码springboot方式启动(详细)附改造工程地址

文章时间是2024-2-18日&#xff0c;nacos默认develop分支&#xff0c;最新版是2.3.1-SNAPSHOT版本。 我们这里就以nacos最新版进行改造成springboot启动方式。 1. Clone 代码 nacos github地址&#xff1a;https://github.com/alibaba/nacos.git 根据上面git地址把源码克隆到…

oauth2 授权码模式 流程说明和接口整理

一、说明 oauth2 授权模式一共有四种&#xff0c;即隐式授权模式、授权码授权模式、密码授权模式和客户端授权模式。 这里仅对授权码授权模式所包含的流程和接口做说明和整理。 具体的概念和源码解读&#xff0c;资料有很多&#xff0c;可以自行去搜索学习。 二、流程说明 假…

OpenAI最新模型Sora到底有多强?眼见为实的真实世界即将成为过去!

文章目录 1. 写在前面2. 什么是Sora&#xff1f;3. Sora的技术原理 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感…

maptalks多边形区域和点位-vue组件

多边形 <!-- 地图组件 --> <template><div :id="id" class="container"></div> </template><script> import _ from "lodash"; import "maptalks/dist/maptalks.css"; import * as maptalks from…

Open CASCADE学习|用点分割边

在Open CASCADE Technology&#xff08;OCCT&#xff09;中&#xff0c;几何模型是由拓扑&#xff08;Topology&#xff09;和几何&#xff08;Geometry&#xff09;两部分组成的。拓扑部分描述了形状的拓扑结构&#xff0c;比如边、面、体等&#xff0c;而几何部分则定义了这些…

金蝶云星空——用递归SQL查询物料分组

应用场景&#xff1a; 金蝶物料分组为树形结构&#xff0c;需要根据SQL查询同步到第三方系统中。 技术实现 用递归CTE按照树状结构展开物料分组 with cte as( select 0 as 物料分组层级,t1.FID,case when isnull(t1.FFULLPARENTID,) then .CAST(t1.FID AS VARCHAR(…

裸辞5个月,面试了37家公司,终于找到理想工作了

上半年裁员&#xff0c;下半年裸辞&#xff0c;有不少人高呼裸辞后躺平真的好快乐&#xff01;但也有很多人&#xff0c;裸辞后的生活五味杂陈。 面试37次终于找到心仪工作 因为工作压力大、领导PUA等各种原因&#xff0c;今年2月下旬我从一家互联网小厂裸辞&#xff0c;没想…

LeetCode JS专栏刷题笔记(二)

一、前言 LeetCode - JavaScript 专栏刷题笔记第二篇。 第一篇刷题笔记详见&#xff1a;LeetCode JS专栏刷题笔记&#xff08;一&#xff09; 二、算法题目 1. 复合函数 LeetCode地址&#xff1a;2629. 复合函数 请你编写一个函数&#xff0c;它接收一个函数数组 [f1, f2, …

(2024,自级联扩散,关键点引导的噪声重新调度,时间感知特征上采样器)进行廉价的扩展:用于更高分辨率适应的自级联扩散模型

Make a Cheap Scaling: A Self-Cascade Diffusion Model for Higher-Resolution Adaptation 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 4. 自级联扩散模型 …

【数据结构与算法】手搓JDK底层ArrayList底层 - 动态数组

数组 在介绍数组之前&#xff0c;我们先来看一段chatGPT给出的对于数组描述&#xff1a; 数组&#xff08;Array&#xff09;是一种线性数据结构&#xff0c;它由一组连续的内存空间组成&#xff0c;用来存储相同类型的数据元素。数组具有固定的大小&#xff0c;一旦创建后&a…

【Docker】前后端分离项目 Gin+Vue 容器化部署 | docker-compose 部署 | 部署 nginx 通过域名访问

文章目录 前言前后端不完全独立docker 部署mysqlredisrbac docker compose 部署部署 nginx 前后端独立部署 前言 项目地址&#xff1a;https://gitee.com/Cauchy_AQ/rbac 项目前端使用 vue3 并且由 vite 构建&#xff0c;后端采用 gin 框架&#xff0c;搭建了一个简易的权限管…

计算机设计大赛 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

WildCard:一个因太好用而被迫暂停服务的虚拟信用卡平台,魅力何在?

如果你需要使用Wildcard开通GPT4、Midjourney或是Only方式的话&#xff0c;请点击&#xff1a;WildCard使用教程 参考文章链接&#xff1a;WildCard&#xff1a;一个因太好用而被迫暂停服务的虚拟信用卡平台&#xff0c;魅力何在&#xff1f; 1、Wildcard用户数量激增&#x…