【Linux】基于UDP/TCP服务器与客户端的实现

news/2025/2/24 20:31:27

目录

一、UDP

(一)Server.hpp

(二)Server.cpp

(三)Client.hpp

(四)Client.cpp

(五)User.hpp

二、TCP

(一)多进程版本的服务器与客户端

1、Server.hpp

2、Server.cpp

3、Client.hpp

4、Client.cpp

5、log.hpp

(二)多线程版本的服务器与客户端

(三)线程池版本的服务器与客户端

1、Server.hpp

2、thread.hpp

3、pthreadpool.hpp

4、Task.hpp

(四)线程池版本+守护进程的服务器与客户端

1、daemon.hpp

2、Server.cpp


一、UDP

(一)Server.hpp

#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
using namespace std;
class Server
{
    typedef function<void(int, string, uint16_t, string)> func_t;

public:
    Server(const func_t func, const uint16_t &port, const string &ip = "0.0.0.0") : _func(func), _port(port), _ip(ip) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            cerr << "socket :" << strerror(errno) << endl;
            exit(1);
        }
        cerr << "socket succcess" << endl;

        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = inet_addr(_ip.c_str());
        int n = bind(_fd, (const sockaddr *)&addr, sizeof(addr));
        if (n != 0)
        {
            cerr << "bind error : " << strerror(errno) << endl;
            exit(2);
        }
        cerr << "bind success" << endl;
    }
    void start()
    {
        char buffer[1024];
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            size_t n = recvfrom(_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&addr, &len);
            if (n > 0)
            {
                buffer[n] = 0;
                uint16_t port = ntohs(addr.sin_port);
                string ip = inet_ntoa(addr.sin_addr);
                string messages = buffer;
                _func(_fd, ip, port, messages);
            }
        }
    }

private:
    func_t _func;
    int _fd;
    uint16_t _port;
    string _ip;
};

(二)Server.cpp

#include "Server.hpp"
#include "User.hpp"
#include <memory>

userManager m;
void handlerMessage(int sockfd, const string &ip, const uint16_t &port, const string &message)
{
    cout << "[" + ip + "]" + "[" + to_string(port) + "]: " + message << endl;
    if (message == "online")
        m.insert(ip, port);
    else if (message == "offline")
        m.erase(ip, port);
    else if (m.isOnline(ip, port))
        m.broadcast(sockfd, ip, port, message);
    else
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        addr.sin_port = htons(port);
        string response = "请先输入 online 上线";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
    }
}
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(3);
    }
    uint16_t port = atoi(argv[1]);
    unique_ptr<Server> usvr(new Server(handlerMessage, port));
    usvr->init();
    usvr->start();
    return 0;
}

(三)Client.hpp

#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

using namespace std;
class Client
{
public:
    Client(const uint16_t &Sport, const string &Sip) : _Sport(Sport), _Sip(Sip) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            cerr << "socket : " << strerror(errno) << endl;
            exit(1);
        }
        cout << "socket success" << endl;
    }
    static void *readMessage(void *arg)
    {
        int sockfd = *(static_cast<int *>(arg));
        while (true)
        {
            char buffer[1024];
            struct sockaddr_in temp;
            socklen_t temp_len = sizeof(temp);
            size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);
            if (n >= 0)
                buffer[n] = 0;
            cout << buffer << endl;
        }

        return nullptr;
    }
    void run()
    {
        pthread_create(&_read, nullptr, readMessage, (void *)&_fd);
        pthread_detach(_read);
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_Sport);
        addr.sin_addr.s_addr = inet_addr(_Sip.c_str());
        socklen_t len = sizeof(addr);
        while (1)
        {
            cerr << "Please input" << endl;
            string messages;
            cin >> messages;
            sendto(_fd, messages.c_str(), messages.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
        }
    }

private:
    int _fd;
    uint16_t _Sport;
    string _Sip;
    pthread_t _read;
};

(四)Client.cpp

#include "Client.hpp"
#include <memory>
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(3);
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    unique_ptr<Client> ucli(new Client(port, ip));
    ucli->init();
    ucli->run();
    return 0;
}

(五)User.hpp

#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;
class user
{
public:
    user(const string &ip, const uint16_t &port) : _ip(ip), _port(port) {}
    string &getIp()
    {
        return _ip;
    }
    uint16_t &getPort()
    {
        return _port;
    }

private:
    string _ip;
    uint16_t _port;
};

class userManager
{
public:
    void insert(const string &ip, const uint16_t &port)
    {
        string id = ip + "-" + to_string(port);
        _um.insert(make_pair(id, user(ip, port)));
    }
    void erase(const string &ip, const uint16_t &port)
    {
        string id = ip + "-" + to_string(port);
        _um.erase(id);
    }
    bool isOnline(const string &ip, const uint16_t &port)
    {
        string id = ip + "-" + to_string(port);
        return _um.find(id) == _um.end() ? false : true;
    }
    void broadcast(int sockfd, const string &ip, const uint16_t &port, const string &message)
    {
        for (auto &user : _um)
        {
            struct sockaddr_in addr;
            bzero(&addr, sizeof(addr));
            addr.sin_family = AF_INET;
            addr.sin_port = htons(user.second.getPort());
            addr.sin_addr.s_addr = inet_addr(user.second.getIp().c_str());
            string response = "[" + ip + "]" + "[" + to_string(port) + "]: " + message;
            sendto(sockfd, response.c_str(), response.size(), 0, (sockaddr *)&addr, sizeof(addr));
        }
    }

private:
    unordered_map<string, user> _um;
};

二、TCP

(一)多进程版本的服务器与客户端

1、Server.hpp

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
using namespace std;
class Server
{
public:
    Server(const uint16_t &port) : _fd(-1), _port(port) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_fd == -1)
        {
            cerr << strerror(errno) << endl;
            exit(1);
        }
        logMessage(NORMAL, "socket success");
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(_port);
        int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (n == -1)
        {
            logMessage(ERROR, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "bind success");

        n = listen(_fd, 5);
        if (n < 0)
        {
            cerr << strerror(errno) << endl;
            exit(2);
        }
        logMessage(NORMAL, "listen success");
    }
    // 进程版
    void start()
    {
        signal(SIGCHLD, SIG_IGN);
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            cout << "accept successs : " << socket << endl;
            if (socket == -1)
            {
                cerr << strerror(errno) << endl;
                continue;
            }
            pid_t id = fork();
            if (id == 0)
            {
                close(_fd);
                serviceIO(socket);
                close(socket);
                exit(0);
            }
            close(socket);
        }
    }
    void serviceIO(const int &fd)
    {
        while (1)
        {
            char buffer[1024];
            ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
            if (size > 0)
            {
                buffer[size] = 0;
                cout << "[Client] : " << buffer << endl;
                string messages = buffer;
                ssize_t ret = write(fd, messages.c_str(), messages.size());
                if (ret < 0)
                {
                    cerr << strerror(errno) << endl;
                }
            }
            else if (size == 0)
            {
                cerr << "Client quit" << endl;
                break;
            }
            else
            {
                cerr << strerror(errno) << endl;
                exit(3);
            }
        }
    }

    void start()
    {
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            if (socket == -1)
            {
                cerr << strerror(errno) << endl;
                continue;
            }
            logMessage(NORMAL, "accept successs : %d", socket);
        }
    }

    ~Server()
    {
        close(_fd);
    }

private:
    int _fd;
    uint16_t _port;
};

2、Server.cpp

#include "Server.hpp"
#include "daemon.hpp"
#include <memory>
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(3);
    }
    uint16_t port = atoi(argv[1]);
    unique_ptr<Server> usvr(new Server(port));
    usvr->init();
    usvr->start();
    return 0;
}

3、Client.hpp

#include <iostream>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
using namespace std;
class Client
{
public:
    Client(const string &ip, const uint16_t &port) : _fd(-1), _Sip(ip), _Sport(port) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_fd == -1)
        {
            cerr << strerror(errno) << endl;
            exit(1);
        }
        logMessage(NORMAL, "socket success");
    }
    void run()
    {
        struct sockaddr_in addr;
        bzero(&addr, 0);
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(_Sip.c_str());
        addr.sin_port = htons(_Sport);
        if (connect(_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
        {
            cerr << strerror(errno) << endl;
            exit(2);
        }
        else
        {
            while (true)
            {
                string messages;
                cout << " please input#";
                getline(cin, messages);
                write(_fd, messages.c_str(), messages.size());
                char buffer[1024];
                int n = read(_fd, buffer, sizeof(buffer) - 1);
                if (n > 0)
                {
                    buffer[n] = 0;
                    cout << "[Server] : " << buffer << endl;
                }
                else
                    break;
            }
        }
    }
    ~Client()
    {
        close(_fd);
    }

private:
    int _fd;
    string _Sip;
    uint16_t _Sport;
};

4、Client.cpp

#include "Client.hpp"
#include <memory>
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(3);
    }
    string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    unique_ptr<Client> ucli(new Client(ip, port));
    ucli->init();
    ucli->run();
    return 0;
}

5、log.hpp

#pragma once
#include <iostream>
#include <ctime>
#include <stdio.h>
#include <stdarg.h>
using namespace std;
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
#define NUM 1024
const char *getLevel(const int &level)
{
    switch (level)
    {
    case 0:
        return "DEBUG";
    case 1:
        return "NORMAL";
    case 2:
        return "WARNING";
    case 3:
        return "ERROR";
    case 4:
        return "FATAL";
    default:
        return nullptr;
    }
}
void logMessage(int level, const char *format, ...)
{
    char logprefix[NUM];
    sprintf(logprefix, "[%s][%ld]:", getLevel(level), time(nullptr));
    char logContext[NUM];
    va_list arg;
    va_start(arg, format);
    vsnprintf(logContext, sizeof(logContext), format, arg);
    cout << logprefix << logContext << endl;
}

(二)多线程版本的服务器与客户端

        多线程版本只有Server.hpp与多进程不同,其他文件相同。

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
using namespace std;
class Server
{
public:
    Server(const uint16_t &port) : _fd(-1), _port(port) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_fd == -1)
        {
            cerr << strerror(errno) << endl;
            exit(1);
        }
        logMessage(NORMAL, "socket success");
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(_port);
        int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (n == -1)
        {
            logMessage(ERROR, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "bind success");

        n = listen(_fd, 5);
        if (n < 0)
        {
            cerr << strerror(errno) << endl;
            exit(2);
        }
        logMessage(NORMAL, "listen success");
    }
   // 线程版
    void start()
    {
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            cout << "accept successs : " << socket << endl;
            if (socket == -1)
            {
                cerr << strerror(errno) << endl;
                continue;
            }
            pthread_t t;
            pthread_create(&t, nullptr, serviceIO, (void *)&socket);
            pthread_detach(t);
        }
    }
    static void *serviceIO(void *arg)
    {
        int fd = *(static_cast<int *>(arg));
        while (1)
        {
            char buffer[1024];
            ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
            if (size > 0)
            {
                buffer[size] = 0;
                cout << "[Client] : " << buffer << endl;
                string messages = buffer;
                ssize_t ret = write(fd, messages.c_str(), messages.size());
                if (ret < 0)
                {
                    cerr << strerror(errno) << endl;
                }
            }
            else if (size == 0)
            {
                cerr << "Client quit" << endl;
                break;
            }
            else
            {
                cerr << strerror(errno) << endl;
                exit(3);
            }
        }
        close(fd);
        return nullptr;
    }
    void start()
    {
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            if (socket == -1)
            {
                cerr << strerror(errno) << endl;
                continue;
            }
            logMessage(NORMAL, "accept successs : %d", socket);
        }
    }

    ~Server()
    {
        close(_fd);
    }

private:
    int _fd;
    uint16_t _port;
};

(三)线程池版本的服务器与客户端

        其他文件与多进程版本相同。

1、Server.hpp

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <pthread.h>
#include "pthreadpool.hpp"
#include "Task.hpp"
#include "log.hpp"
using namespace std;
class Server
{
public:
    Server(const uint16_t &port) : _fd(-1), _port(port) {}
    void init()
    {
        _fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_fd == -1)
        {
            cerr << strerror(errno) << endl;
            exit(1);
        }
        logMessage(NORMAL, "socket success");
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(_port);
        int n = bind(_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (n == -1)
        {
            logMessage(ERROR, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "bind success");

        n = listen(_fd, 5);
        if (n < 0)
        {
            cerr << strerror(errno) << endl;
            exit(2);
        }
        logMessage(NORMAL, "listen success");
    }
    void start()
    {
        pthreadPool<Task>::getInstance()->run();
        while (1)
        {
            struct sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int socket = accept(_fd, (struct sockaddr *)&addr, &len);
            if (socket == -1)
            {
                cerr << strerror(errno) << endl;
                continue;
            }
            logMessage(NORMAL, "accept successs : %d", socket);
            pthreadPool<Task>::getInstance()->push(Task(socket, serviceIO));
        }
    }

    ~Server()
    {
        close(_fd);
    }

private:
    int _fd;
    uint16_t _port;
};

2、thread.hpp

#include <iostream>
#include <pthread.h>
#include <functional>
#include <string>
using namespace std;
class Thread
{
    typedef std::function<void *(void *)> func_t;

private:
    static void *start_routine(void *arg)
    {
        Thread *th = static_cast<Thread *>(arg);
        th->callback(th->_arg);
    }
    void *callback(void *arg)
    {
        return _func(arg);
    }

public:
    void start(func_t func, void *arg = nullptr)
    {
        _func = func;
        _arg = arg;
        pthread_create(&_tid, nullptr, start_routine, this);
    }
    void join()
    {
        pthread_join(_tid, nullptr);
    }
    ~Thread()
    {
        join();
    }

private:
    func_t _func;
    pthread_t _tid;
    void *_arg;
};

3、pthreadpool.hpp

#include <vector>
#include <queue>
#include "thread.hpp"
#include "Task.hpp"
template <class T>
class pthreadPool
{
private:
    void pop(T &date)
    {
        date = _tasks.front();
        _tasks.pop();
    }

    static void *handlerTask(void *arg)
    {
        pthreadPool *th = static_cast<pthreadPool *>(arg);
        while (1)
        {
            pthread_mutex_lock(&(th->_mutex));
            while (th->_tasks.empty())
                pthread_cond_wait(&(th->_cond), &(th->_mutex));
            T task;
            th->pop(task);
            pthread_mutex_unlock(&(th->_mutex));
            task();
        }
        return nullptr;
    }

public:
    pthreadPool(int num = 10) : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; ++i)
        {
            _threads.push_back(new Thread());
        }
    }
    ~pthreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (int i = 0; i < _num; ++i)
        {
            delete _threads[i];
        }
    }
    void run()
    {
        for (int i = 0; i < _num; ++i)
        {
            _threads[i]->start(handlerTask, this);
        }
    }
    void push(const T &date)
    {
        pthread_mutex_lock(&_mutex);
        _tasks.push(date);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }
    static pthreadPool<T> *getInstance()
    {
        if (_tp == nullptr)
        {
            pthread_mutex_lock(&_sin);
            if (_tp == nullptr)
            {
                _tp = new pthreadPool();
            }
            pthread_mutex_unlock(&_sin);
        }
        return _tp;
    }
    pthreadPool(const pthreadPool<T> &tp) = delete;
    pthreadPool<T> operator=(pthreadPool<T>) = delete;

private:
    int _num;
    vector<Thread *> _threads;
    queue<T> _tasks;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static pthreadPool<T> *_tp;
    static pthread_mutex_t _sin;
};
template <class T>
pthreadPool<T> *pthreadPool<T>::_tp = nullptr;

template <class T>
pthread_mutex_t pthreadPool<T>::_sin = PTHREAD_MUTEX_INITIALIZER;

4、Task.hpp

#pragma once
#include <iostream>
#include <functional>
#include "log.hpp"
using namespace std;
void serviceIO(const int &fd)
{
    while (1)
    {
        char buffer[1024];
        ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
        if (size > 0)
        {
            buffer[size] = 0;
            cout << "[Client] : " << buffer << endl;
            string messages = buffer;
            ssize_t ret = write(fd, messages.c_str(), messages.size());
            if (ret < 0)
            {
                cerr << strerror(errno) << endl;
            }
        }
        else if (size == 0)
        {
            logMessage(NORMAL, "Client quit");
            break;
        }
        else
        {
            cerr << strerror(errno) << endl;
            exit(3);
        }
    }
    close(fd);
}
class Task
{
    typedef function<void(int)> func_t;

public:
    Task() {}
    Task(const int &socket, func_t func) : _fd(socket), _func(func)
    {
    }
    void operator()()
    {
        _func(_fd);
    }

private:
    int _fd;
    func_t _func;
};

(四)线程池版本+守护进程的服务器与客户端

        其他文件与线程池版本相同。

1、daemon.hpp

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#define DEV "/dev/null"
void daemonSelf(const char *currPath = nullptr)
{
    signal(SIGPIPE, SIG_IGN);
    
    if (fork() > 0)
        exit(0);
    pid_t id = setsid();
    assert(id != -1);
    int fd = open(DEV, O_RDWR);
    if (fd >= 0)
    {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
    }
    else
    {
        close(0);
        close(1);
        close(2);
    }
    if (currPath)
        chdir(currPath);
}

2、Server.cpp

#include "Server.hpp"
#include "daemon.hpp"
#include <memory>
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(3);
    }
    uint16_t port = atoi(argv[1]);
    unique_ptr<Server> usvr(new Server(port));
    usvr->init();
    daemonSelf();
    usvr->start();
    return 0;
}


http://www.niftyadmin.cn/n/5864796.html

相关文章

Leetcode 3464. Maximize the Distance Between Points on a Square

Leetcode 3464. Maximize the Distance Between Points on a Square 1. 解题思路2. 代码实现 题目链接&#xff1a;3464. Maximize the Distance Between Points on a Square 1. 解题思路 说来惭愧&#xff0c;这道题我也没有自力搞定&#xff0c;也是问了一下DeepSeek R1之…

模型思维 - 领域模型的应用与解析

文章目录 引言模型的核心作用与价值四大模型类型UML建模工具UML类图的核心价值类关系深度剖析企业级建模实践 领域模型&#xff08;推荐&#xff09; vs 数据模型&#xff08;不推荐&#xff09;区别联系错把领域模型当数据模型错误方案 vs 正确方案对比正确方案的实现1. 数据库…

苍穹外卖中的模块总结

本文总结苍穹外卖项目中可复用的通用设计 sky-common constant存放常量类&#xff0c;包括消息常量&#xff0c;状态常量 context是上下文对象&#xff0c;封装了threadlocal package com.sky.context;public class BaseContext {public static ThreadLocal<Long> thre…

毕业项目推荐:基于yolov8/yolov5/yolo11的番茄成熟度检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

k8s部署针对外部服务器的prometheus服务

在Kubernetes(K8s)集群中部署Prometheus以监控外部服务器&#xff0c;涉及到几个关键步骤&#xff1a;配置Prometheus以抓取远程目标、设置服务发现机制、以及确保网络可达性。下面是一个详细指南&#xff0c;指导您如何在Kubernetes中部署并配置Prometheus&#xff0c;以便有效…

Python的子线程与主线程之间的通信并通知主线程更新UI

新建PLC类 PLC.py import json import time from threading import Threadfrom HslCommunication import SiemensS7Net, SiemensPLCS from PySide6.QtCore import QThread, Signal, QObjectfrom tdm.MsgType import MSG_TYPE_LOG, MSG_TYPE_MSGBOX# 自定义信号类&#xff0c;用…

ElasticSearch查询指南:从青铜到王者的骚操作

ElasticSearch查询指南&#xff1a;从青铜到王者的骚操作 本文来源于笔者的CSDN原创&#xff0c;由于掘金>已经去掉了转载功能&#xff0c;所以只好重新上传&#xff0c;以下图片依然保持最初发布的水印&#xff08;如CSDN水印&#xff09;。&#xff08;以后属于本人原创均…

vue-fastapi-admin 部署心得

vue-fastapi-admin 部署心得 这两天需要搭建一个后台管理系统&#xff0c;找来找去 vue-fastapi-admin 这个开源后台管理框架刚好和我的技术栈所契合。于是就浅浅的研究了一下。 主要是记录如何基于原项目提供的Dockerfile进行调整&#xff0c;那项目文件放在容器外部&#xf…