Linux网络 TCP socket

news2025/1/22 20:48:40

TCP简介

TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它位于OSI模型的第四层,主要为应用层提供数据传输服务。TCP通过三次握手建立连接,确保数据在发送和接收过程中的准确性和顺序性。

TCP的主要特点

  1. 可靠性:TCP通过序列号、确认应答、超时重传等机制保证数据可靠传输。
  2. 面向连接:通信双方在传输数据前需要建立连接,通信结束后释放连接。
  3. 流量控制:通过滑动窗口机制,TCP可以控制数据的发送速度,避免接收方缓冲区溢出。
  4. 拥塞控制:TCP可以根据网络状况调整发送速率,减少网络拥塞。
  5. 全双工通信:TCP连接允许数据在两个方向上同时传输。

TCP与UDP的比较

与TCP不同,用户数据报协议(UDP)是无连接的、不可靠的传输层协议。UDP适用于对实时性要求高、但可以容忍少量数据丢失的应用,如视频通话、在线游戏等。而TCP则适用于对数据完整性要求高的应用,如文件传输、电子邮件等。

函数介绍

socket()

int socket(int domain, int type, int protocol);
  • 功能:创建一个新的套接字。
  • 参数说明:
    • domain:指定协议族,如 AF_INET(IPv4)或 AF_INET6(IPv6)。
    • type:指定套接字类型,如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP),由于使用TCP协议,所以使用SOCK_STREAM,表示面向流的传输协议。
    • protocol:指定协议类型,通常为 0,表示使用默认协议。
  • 返回值:成功时返回一个新的套接字描述符,失败时返回 -1。该套接字描述符本质与文件描述符一样,应用程序可以像读写文件一样用 read/write 在网络上收发数据。

bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 功能:将套接字绑定到指定的地址和端口。服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接; 服务器需要调用 bind 绑定一个固定的网络地址和端口号,客户端无需手动绑定。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • addr:指向包含地址和端口信息的 sockaddr 结构的指针。
    • addrlensockaddr 结构的长度。由于struct sockaddr *是一个通用指针类型,addr 参数实际上可以接受多种协议的 sockaddr 结构体,而它们的长度各不相同,所以需要第三个参数 addrlen指定结构体的长度。
我们的程序中对 addr 参数是这样初始化的 :
struct sockaddr_in socket;
bzero(&socket,sizeof(socket)); //将整个结构体清零
socket.sin_family=AF_INET; //设置地址类型为 AF_INET
socket.sin_port=htons(SERVER_PORT); //设置端口号,如8080
socket.sin_addr.s_addr=inet_addr(SERVER_IP); //设置IP地址,
//如"127.0.0.1",如果地址为 INADDR_ANY, 这个宏表示本地的任意 IP
//地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个 IP 地址, 
//这样设置可以在所有的 IP 地址上监听, 直到与某个客户端建立了连接
//时才确定下来到底用哪个 IP 地址
  • 返回值:成功时返回 0,失败时返回 -1。

listen()

int listen(int sockfd, int backlog);
  • 功能:服务器开始监听连接请求。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • backlog:指定连接请求队列的最大长度,最多允许有 backlog 个客户端处于连接等待状态, 如果接收到更多的连接请求就忽略。
  • 返回值:成功时返回 0,失败时返回 -1。
int _listensockfd = socket(AF_INET, SOCK_STREAM, 0);// 创建socket
struct sockaddr_in socket;
bzero(&socket,sizeof(socket)); //将整个结构体清零
socket.sin_family=AF_INET; //设置地址类型为 AF_INET
socket.sin_port=htons(SERVER_PORT); //设置端口号,如8080
socket.sin_addr.s_addr=inet_addr(SERVER_IP); 
int ret = bind(_listensockfd, (struct sockaddr *)&socket, sizeof(socket));
ret = listen(_listensockfd, BACKLOG);// 将socket设置为监听状态

accept()

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 功能:接受客户端的连接请求。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • addr:指向用于存储客户端地址信息的 sockaddr 结构的指针,如果给 addr 参数传NULL,表示不关心客户端的地址。
    • addrlen:指向 sockaddr 结构长度的指针。
  • 返回值:成功时返回一个新的套接字描述符,代表与客户端的连接,之后服务器和客户端之间的交流就通过该返回值进行,失败时返回 -1。
 struct sockaddr_in peer;
 socklen_t peerlen = sizeof(peer);
 int sockfd = accept(_listensockfd, (struct sockaddr *)&peer, &peerlen);

connect()

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
  • 功能:客户端连接到指定的服务器,connect bind 的参数形式一致, 区别在于 bind 的参数是自己的地址, connect 的参数是对方的地址。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • serv_addr:指向包含服务器地址信息的 sockaddr 结构的指针。
    • addrlensockaddr 结构的长度。
  • 返回值:成功时返回 0,失败时返回 -1。
// 填写网络信息
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());
// client 无需显示bind,connect连接时自动bind
int n = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

send()

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 功能:发送数据到已连接的套接字。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • buf:指向要发送数据的缓冲区的指针。
    • len:要发送的数据的长度。
    • flags:通常为 0,表示默认的发送行为。
  • 返回值:成功时返回发送的字节数,失败时返回 -1。

recv()

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 功能:从已连接的套接字接收数据。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
    • buf:指向用于接收数据的缓冲区的指针。
    • len:缓冲区的长度。
    • flags:通常为 0,表示默认的接收行为。
  • 返回值:成功时返回接收的字节数,失败时返回 -1。

close()

int close(int sockfd);
  • 功能:关闭套接字。
  • 参数说明:
    • sockfd:由 socket() 函数返回的套接字描述符。
  • 返回值:成功时返回 0,失败时返回 -1。

案例 多线程远程命令执行

makefile

all: server client
server:TcpServermain.cc
	g++ -o $@ $^ -std=c++17 -lpthread
client:TcpClient.cc
	g++ -o $@ $^ -std=c++17
.PHONY:clean
clean:
	rm -f server client

Mutex.hpp

#pragma once
#include <iostream>
#include <pthread.h>
using namespace std;

class Mutex
{
public:
    Mutex(const Mutex&)=delete;
    const Mutex& operator=(const Mutex&)=delete;
    Mutex()
    {
        pthread_mutex_init(&_lock,nullptr);
    }
    ~Mutex()
    {
        pthread_mutex_destroy(&_lock);
    }
    void Lock()
    {
        pthread_mutex_lock(&_lock);
    }
    pthread_mutex_t * LockPtr()
    {
        return &_lock;
    }
    void Unlock()
    {
        pthread_mutex_unlock(&_lock);
    }
private:
    pthread_mutex_t _lock;
};
class LockGuard
{
    public:
    LockGuard(Mutex& m)
    :_mutex(m)
    {
        _mutex.Lock();
    }
    ~LockGuard()
    {
        _mutex.Unlock();
    }
    private:
    Mutex& _mutex;
};

Cond.hpp

#pragma once
#include"Mutex.hpp"
class Cond
{
    public:
    Cond()
    {
        pthread_cond_init(&_cond,nullptr);
    }
    ~Cond()
    {
        pthread_cond_destroy(&_cond);
    }
    void Wait(Mutex& mutex)
    {
        pthread_cond_wait(&_cond,mutex.LockPtr());
    }
    void Notify()
    {
        pthread_cond_signal(&_cond);
    }
    void NotifyAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    private:
    pthread_cond_t _cond;
};

Thread.hpp

#pragma once
#include <pthread.h>
#include <iostream>
#include <functional>
#include <string>
#include <unistd.h>
using namespace std;
using func_t = function<void(string)>;
static int number = 1;
enum STATUS
{
    NEW,
    RUNNING,
    STOP
};
class Thread
{
private:
    static void *Routine(void *arg)
    {
        Thread *t = static_cast<Thread *>(arg);
        t->_func(t->_name);
        return nullptr;
    }

public:
    Thread(func_t func)
        : _func(func), _status(NEW), _joinable(true)
    {
        _name = "Thread-" + to_string(number++);
        _pid = getpid();
    }
    bool Start()
    {
        if (_status != RUNNING)
        {
            _status = RUNNING;
            int n = pthread_create(&_tid, nullptr, Routine, this);
            if (n != 0)
            {
                return false;
            }
            return true;
        }
        return false;
    }
    bool Stop()
    {
        if (_status == RUNNING)
        {
            _status = STOP;
            int n = pthread_cancel(_tid);
            if (n != 0)
            {
                return false;
            }
            return true;
        }
        return false;
    }
    bool Join()
    {
        if (_joinable)
        {
            _status = STOP;
            int n = pthread_join(_tid, nullptr);
            if (n != 0)
            {
                return false;
            }
            return true;
        }
        return false;
    }
    void Detach()
    {
        _joinable = false;
        pthread_detach(_tid);
    }
    string Name()
    {
        return _name;
    }
private:
    string _name;
    pthread_t _tid;
    pid_t _pid;
    STATUS _status;
    bool _joinable;
    func_t _func;
};

ThreadPool.hpp

#pragma once
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
using thread_t = shared_ptr<Thread>;
const static int defaultnum = 5;

template <class T>
class ThreadPool
{
private:
    bool IsEmpty() { return _taskq.empty(); }
    void HandlerTask(string name)
    {
        cout << "线程: " << name << ", 进入HandlerTask的逻辑" << endl;
        while (true)
        {
            // 1. 拿任务
            T t;
            {
                LockGuard lockguard(_lock);
                while (IsEmpty() && _isrunning)
                {
                    _wait_num++;
                    _cond.Wait(_lock);
                    _wait_num--;
                }
                // 2. 任务队列为空 && 线程池退出了
                if (IsEmpty() && !_isrunning)
                    break;
                t = _taskq.front();
                _taskq.pop();
            }
            // 2. 处理任务
            t(); // 规定,未来所有的任务处理,全部都是必须提供t()方法!
        }
        cout << "线程: " << name << " 退出";
    }
    ThreadPool(const ThreadPool<T> &) = delete;
    ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

    ThreadPool(int num = defaultnum) : _num(num), _wait_num(0), _isrunning(false)
    {
        for (int i = 0; i < _num; i++)
        {
            _threads.push_back(make_shared<Thread>(bind(&ThreadPool::HandlerTask, this, std::placeholders::_1)));
            cout << "构建线程" << _threads.back()->Name() << "对象 ... 成功" << endl;
        }
    }

public:
    static ThreadPool<T> *getInstance()
    {
        if (instance == NULL)
        {
            LockGuard lockguard(mutex);
            if (instance == NULL)
            {
                cout << "单例首次被执行,需要加载对象..." << endl;
                instance = new ThreadPool<T>();
                instance->Start();
            }
        }
        return instance;
    }

    void Equeue(T in)
    {
        LockGuard lockguard(_lock);
        if (!_isrunning)
            return;
        _taskq.push(in);
        if (_wait_num > 0)
            _cond.Notify();
    }
    void Start()
    {
        if (_isrunning)
            return;
        _isrunning = true;
        for (auto &thread_ptr : _threads)
        {
            cout << "启动线程" << thread_ptr->Name() << " ... 成功";
            thread_ptr->Start();
        }
    }
    void Wait()
    {
        for (auto &thread_ptr : _threads)
        {
            thread_ptr->Join();
            cout << "回收线程" << thread_ptr->Name() << " ... 成功";
        }
    }
    void Stop()
    {
        LockGuard lockguard(_lock);
        if (_isrunning)
        {
            _isrunning = false; // 不工作
            // 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了
            if (_wait_num > 0)
                _cond.NotifyAll();
        }
    }

private:
    vector<thread_t> _threads;
    int _num;
    int _wait_num;
    std::queue<T> _taskq; // 临界资源

    Mutex _lock;
    Cond _cond;

    bool _isrunning;

    static ThreadPool<T> *instance;
    static Mutex mutex; // 只用来保护单例
};

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = NULL;
template <class T>
Mutex ThreadPool<T>::mutex; // 只用来保护单例

InetAddr.hpp

#pragma once
#include <string>
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
using namespace std;
class InetAddr
{
public:
    InetAddr();
    InetAddr(int port, string ip = "")
        : _port(port), _ip(ip)
    {
        bzero(&_sockaddr, sizeof(_sockaddr));
        _sockaddr.sin_family = AF_INET;
        _sockaddr.sin_port = htons(_port);
        if (_ip.empty())
            _sockaddr.sin_addr.s_addr = INADDR_ANY;
        else
            _sockaddr.sin_addr.s_addr = inet_addr(_ip.c_str());
    }
    InetAddr(const struct sockaddr_in &sockaddr)
    {
        _port = ntohs(sockaddr.sin_port);
        char buf[64];
        _ip = inet_ntop(AF_INET, &sockaddr.sin_addr, buf, sizeof(buf));
    }
    bool operator==(const InetAddr &other)
    {
        return _ip == other._ip;
    }
    InetAddr operator=(const InetAddr &other)
    {
        _ip = other._ip;
        _port = other._port;
        _sockaddr = other._sockaddr;
        return *this;
    }
    struct sockaddr *getSockaddr()
    {
        return (struct sockaddr *)&_sockaddr;
    }
    int getSockaddrLen()
    {
        return sizeof(_sockaddr);
    }
    const string &getIp()
    {
        return _ip;
    }
    int getPort()
    {
        return _port;
    }

private:
    string _ip;
    int _port;
    struct sockaddr_in _sockaddr;
};

Common.hpp

enum
{
    SOCKET_ERROR=1,
    BIND_ERROR,
    LISTEN_ERROR,
    ACCEPT_ERROR,
    CONNECT_ERROR
};

TcpServer.hpp

#pragma once
#include <iostream>
#include <pthread.h>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <memory>
#include "Common.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
using namespace std;

#define BACKLOG 8
using handler_t = function<string(string)>;
static const uint16_t gport = 8080;

class TcpServer
{
    using task_t = function<void()>;
    struct ThreadData
    {
        int sockfd;
        TcpServer *self;
    };

public:
    TcpServer(handler_t handler, int port = gport)
        : _handler(handler), _port(port), _isrunning(false)
    {
    }
    void InitServer()
    {
        // 创建socket
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            cout << "socket error" << endl;
            exit(SOCKET_ERROR);
        }
        cout << "socket create success,sockfd is: " << _listensockfd << endl;
        // 填写IP端口
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        // bind
        int ret = bind(_listensockfd, (struct sockaddr *)&local, sizeof(local));
        if (ret < 0)
        {
            cout << "bind error" << endl;
            exit(BIND_ERROR);
        }
        cout << "bind success" << endl;
        // 将socket设置为监听状态
        ret = listen(_listensockfd, BACKLOG);
        if (ret < 0)
        {
            cout << "listen error" << endl;
            exit(LISTEN_ERROR);
        }
        cout << "listen success" << endl;
    }
    void HandleRequest(int sockfd) // TCP为全双工通信
    {
        char buffer[1024];
        while (true)
        {
            // int n = read(sockfd, buffer, sizeof(buffer) - 1);
            int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                cout << buffer << endl;
                string cmd_result = _handler(buffer);
                // write(sockfd, cmd_result.c_str(), cmd_result.size());
                send(sockfd, cmd_result.c_str(), sizeof(cmd_result), 0);
            }
            else if (n == 0)
            {
                // 如果读取的值为0,说明client退出
                cout << "client quit" << endl;
                break;
            }
            else
            {
                // 读取失败
                break;
            }
        }
        close(sockfd);
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            int sockfd = accept(_listensockfd, (struct sockaddr *)&peer, &peerlen);
            if (sockfd < 0)
            {
                cout << "accept error" << endl;
                exit(ACCEPT_ERROR);
            }
            cout << "accept success,sockfd is: " << sockfd << endl;
            InetAddr addr(peer);
            cout << "client info: " << addr.getIp() << ":" << addr.getPort() << endl;
            // 将任务交给线程池
            ThreadPool<task_t>::getInstance()->Equeue(
                [&]()
                {
                    this->HandleRequest(sockfd);
                });
        }
    }
    void Stop()
    {
        _isrunning = false;
    }

private:
    int _listensockfd; // 监听socket
    uint16_t _port;
    bool _isrunning;
    // 处理上层任务的入口
    handler_t _handler;
};

TcpServermain.cc

#include "TcpServer.hpp"
#include "CommandExec.hpp"
int main()
{
    Command cmd;
    unique_ptr<TcpServer> server = make_unique<TcpServer>([&](string cmdstr)
                                                          { return cmd.Execute(cmdstr); });
    server->InitServer();
    server->Start();
    return 0;
}

TcpClient.cc

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <cstring>
using namespace std;
#include "Common.hpp"
//./client server_ip server_port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "Usage:./client server_ip server_port" << endl;
        return 0;
    }
    string server_ip = argv[1];
    int server_port = stoi(argv[2]);
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        cout << "socket create error" << endl;
        exit(SOCKET_ERROR);
    }
    // 填写网络信息
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());
    // client 无需显示bind,connect连接时自动bind
    int n = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (n < 0)
    {
        cout << "connect error" << endl;
        exit(CONNECT_ERROR);
    }
    string message;
    while (true)
    {
        char buffer[1024];
        cout << "input message: ";
        getline(cin, message);
        n = send(sockfd, message.c_str(), message.size(), 0);
        if (n > 0)
        {
            int m = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (m > 0)
            {
                buffer[m] = 0;
                cout << buffer;
            }
            else
                break;
        }
        else
            break;
    }
    close(sockfd);
    return 0;
}

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

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

相关文章

AI News(1/21/2025):OpenAI 安全疏忽:ChatGPT漏洞引发DDoS风险/OpenAI 代理工具即将发布

1、OpenAI 的安全疏忽&#xff1a;ChatGPT API 漏洞引发DDoS风险 德国安全研究员 Benjamin Flesch 发现了一个严重的安全漏洞&#xff1a;攻击者可以通过向 ChatGPT API 发送一个 HTTP 请求&#xff0c;利用 ChatGPT 的爬虫对目标网站发起 DDoS 攻击。该漏洞源于 OpenAI 在处理…

windows下使用docker执行器并配置 hosts 解析

本篇目录 1. 问题背景2. 环境准备2.1 云上开通windows 2022 英文版机器2.1.1 安装 git2.1.2 安装 runner2.1.3 装docker2.1.4 注册runner并使用docker执行器 3. 项目信息3.1 编写window bat脚本3.2 项目.gitlab-ci.yml文件 4. 测试结论4.1 运行流水线 5. troubleshooting问题1&…

centos9编译安装opensips 二【进阶篇-定制目录+模块】推荐

环境&#xff1a;centos9 last opensips -V version: opensips 3.6.0-dev (x86_64/linux) flags: STATS: On, DISABLE_NAGLE, USE_MCAST, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, HP_MALLOC, DBG_MALLOC, CC_O0, FAST_LOCK-ADAPTIVE_WAIT ADAPTIVE_WAIT_LOOPS1024, MAX_RE…

靶机复现-pikachu靶机文件包含漏洞

本篇文章旨在为网络安全渗透测试靶机复现学习。通过阅读本文&#xff0c;读者将能够对渗透pikachu靶场文件包含漏洞复现有一定的了解 原文学习链接 CSDN博主&#xff1a;One_Blanks主页地址 靶机资源下载 PHPStudy pikachu 一、前言 文件包含漏洞是编程中的一种安全隐患&a…

【机器学习实战高阶】基于深度学习的图像分割

机器学习项目图像分割 你可能已经注意到&#xff0c;大脑如何快速高效地识别并分类眼睛感知到的事物。大脑以某种方式进行训练&#xff0c;以便能够从微观层面分析所有内容。这种能力有助于我们从一篮子橙子中分辨出一个苹果。 计算机视觉是计算机科学的一个领域&#xff0c;…

【Elasticsearch 】 聚合分析:桶聚合

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

Skyeye 云 VUE 版本 v3.15.5 发布

Skyeye 云智能制造&#xff0c;采用 Springboot winUI 的低代码平台、移动端采用 UNI-APP。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公告、问卷、报表…

TCP如何保证安全可靠?

TCP如何保证安全可靠&#xff1f; TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的传输层协议。为了保证数据传输的安全性和可靠性&#xff0c;TCP 采用了多种机制&#xff0c;包括确认和重传、数据校验、数据分片和排序、流量控制以及拥塞控制。 1. 确认和…

高等数学学习笔记 ☞ 定积分的积分方法

1. 定积分的换元积分法 1. 换元积分公式&#xff1a;设函数在闭区间上连续&#xff0c;令&#xff0c;若满足&#xff1a; ①&#xff1a;当时&#xff0c;&#xff1b;当时&#xff0c;。 此时的大小关系不一定&#xff0c;但与最好对应着写&#xff0c;否则就要留意变号的问…

Alluxio 联手 Solidigm 推出针对 AI 工作负载的高级缓存解决方案

作者&#xff1a;Wayne Gao, Yi Wang, Jie Chen, Sarika Mehta Alluxio 作为全球领先的 AI 缓存解决方案供应商&#xff0c; 提供针对 GPU 驱动 AI 负载的高速缓存。其可扩展架构支持数万个节点&#xff0c;能显著降低存储带宽的消耗。Alluxio 在解决 AI 存储挑战方面的前沿技…

Docker Load后存储的镜像及更改镜像存储目录的方法

Docker Load后存储的镜像及更改镜像存储目录的方法 Docker Load后存储的镜像更改镜像存储目录的方法脚本说明注意事项Docker作为一种开源的应用容器引擎,已经广泛应用于软件开发、测试和生产环境中。通过Docker,开发者可以将应用打包成镜像,轻松地进行分发和运行。而在某些场…

爬虫基础之爬取某站视频

目标网址:为了1/4螺口买小米SU7&#xff0c;开了一个月&#xff0c;它值吗&#xff1f;_哔哩哔哩_bilibili 本案例所使用到的模块 requests (发送HTTP请求)subprocess(执行系统命令)re (正则表达式操作)json (处理JSON数据) 需求分析: 视频的名称 F12 打开开发者工具 or 右击…

可视化-numpy实现线性回归和梯度下降法

代码如下&#xff1a; import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib.patches import Patch# 生成二维输入数据 np.random.seed(0) X1 2 * np.random.rand(100, 1) # 第一个特征 X2 3 * np.random.rand(10…

计算机网络 (53)互联网使用的安全协议

一、SSL/TLS协议 概述&#xff1a; SSL&#xff08;Secure Sockets Layer&#xff09;安全套接层和TLS&#xff08;Transport Layer Security&#xff09;传输层安全协议是工作在OSI模型应用层的安全协议。SSL由Netscape于1994年开发&#xff0c;广泛应用于基于万维网的各种网络…

在视频汇聚平台EasyNVR平台中使用RTSP拉流的具体步骤

之前有用户反馈&#xff0c;在EasyNVR平台中添加Pull时使用海康设备的RTSP流地址无法播放。经过研发的优化及一系列严谨的验证流程&#xff0c;我们已确认优化后的EasyNVR平台&#xff0c;通过Pull方式添加海康设备的RTSP流已经能够正常播放。以下是具体的操作步骤&#xff1a;…

在Linux环境中使用Qt访问USB摄像头的解决方法

一、Cheese方法 1、将虚拟机关机&#xff0c;点击左上角的虚拟机设置&#xff0c;将显示所有USB输入设备选上&#xff0c;点击确定。 2、 打开虚拟机&#xff0c;在终端输入以下命令安装所需的软件包&#xff1a; sudo apt update sudo apt install cheese v4l-utils 确保摄…

Qt——网络编程

和多线程类似, Qt 为了支持跨平台, 对网络编程的 API 也进行了重新封装。 在进行网络编程之前, 需要在项目中的 .pro 文件中添加 network 模块&#xff0c;添加之后运行一下&#xff0c;使其包含的头文件能够被加载进Qt Creator。 Qt本身是一个非常庞大&#xff0c;包罗万象的…

docker 安装 mysql 详解

在平常的开发工作中&#xff0c;我们经常需要用到 mysql 数据库。那么在docker容器中&#xff0c;应该怎么安装mysql数据库呢。简单来说&#xff0c;第一步&#xff1a;拉取镜像&#xff1b;第二步&#xff1a;创建挂载目录并设置 my.conf&#xff1b;第三步&#xff1a;启动容…

no persistent volumes available for this claim and no storage class is set

目录标题 问题1问题描述**问题原因****解决步骤****1. 检查 PVC 的配置****2. 设置 StorageClass****创建默认 StorageClass****修改 PVC 的 StorageClass** **3. 创建匹配的 PV****4. 验证 PVC 是否绑定成功** **最佳实践** 问题2问题描述**问题原因****解决方案****1. 删除现…

2024微短剧行业生态洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p39072 本报告合集洞察从多个维度全面解读微短剧行业。在行业发展层面&#xff0c;市场规模与用户规模双增长&#xff0c;创造大量高收入就业岗位并带动产业链升级。内容创作上&#xff0c;精品化、品牌化趋势凸显&#xff0c;题材走…