Linux--进程间通信

1.进程间通信

进程间通信的背景:

进程之间是相互独立的,进程由内核数据结构和它所对应的代码和数据,通信成本比较高。

进程间通信目的:

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程间通信本质:

进程间通信的前提就是让不同的进程看到相同的一份“内存”,这块“内存”不属于任何一个进程,属于操作系统。

2.进程间通信的方式

1.管道 (匿名管道 命名管道)

2.System V通信 (多进程 单机通信)

3.POSIX 通信 (多线程 网络结构)(在这里不讲)

3.管道讲解

1.管道分类:匿名管道,命名管道。

2.什么是管道

        管道是一种古老的传输资源的方式,是UNIX中过来的传输方式,是从一个进程传递到另一个进程的方法。管道是单向通信的,传输的都是资源,不能同时完成双向通信。

3.实现原理:

匿名管道:

  如何做到不同进程看到相同的内存呢?

fork()函数让具有血缘关系的进程进行进程间通信,常用于父子进程。

创建管道文件,int pipe(int pipefd[2]);

具体实现看代码:

#include <iostream>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>


using namespace std;

int main()
{
    int pipefd[2]={0}; pipefd[0(嘴巴,读书)]: 读端 , pipefd[1(钢笔,写)]: 写端
    int n = pipe(pipefd);
    assert(n != -1); // debug assert, release assert
    (void)n;
    #ifdef DEBUG
        cout << "pipefd[0]: " << pipefd[0] << endl; // 3
        cout << "pipefd[1]: " << pipefd[1] << endl; // 4
    #endif

    pid_t id=fork();
    if(id==0)
    {
        close(pipefd[1]);
        char buff[1024*8];
        while(true)
        {
            ssize_t s = read(pipefd[0], buff, sizeof(buff) - 1);
            if(s>0)
            {
                buff[s] = 0;
                cout << "child get a message[" << getpid() << "] Father# " << buff << endl;
            }
            else
            {
                cout << "writer quit(father), me quit!!!" << endl;
                break;
            }
        }
        close(pipefd[0]);//关闭文件,可以不用
        exit(0);
        //return 0;
    }

    else if(id>0)
    {
        close(pipefd[0]);
        string message = "我是父进程,我正在给你发消息\n";
        int count = 0;
        char send_buffer[1024 * 8];

        while(true)
        {
            //构建一个变化的字符串
            snprintf(send_buffer, sizeof(send_buffer), "%s[%d] : %d",
                 message.c_str(), getpid(), count++);//写到一个字符串
           write(pipefd[1], send_buffer, strlen(send_buffer));

           if(count==5)
           {
                cout<<count<<endl;
                break;
           }
        }

        close(pipefd[1]);
        //进程等待
        //int status;
        pid_t ret = waitpid(id,NULL,0);
        cout << "id : " << id << " ret: " << ret <<endl;
        assert(ret > 0); 
        (void)ret;

    }
    return 0;
}

结论:

  • 管道是用来进行具有血缘关系的·进程实现进程间通信--常用于父子进程。
  • 具有让进程间协同通信,提供了访问控制。
  • 提供面向流的听信服务,面向字节流的服务。
  • 管道是基于文件的,文件的生命周期是基于进程的,所以管道的生命周期是基于进程的。
  • 管道是单向通信的,就是半双工通信的一种特殊形式。

如果写得快,读得慢,则写满管道之后不再写入。

如果写的慢,读得快,则管道没有数据是,则停下来等待。

如果写入端关闭,则读到文件末尾结束

关闭读,则OS会关闭写进程。

命名管道:

  • 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
  • 命名管道是一种特殊类型的文件。

命名管道的创建:

直接在命令行上创建:mkfifo filename

也可以在程序中创建:int mkfifo(const char *filename,mode_t mode);

第一个参数为文件名,第二个为权值

创建命名管道:

int main(int argc, char *argv[])
{
    mkfifo("p2", 0644);
    return 0;
}

匿名管道与命名管道之间的区别:

  • 匿名管道由pipe函数创建并打开。
  • 命名管道由mkfifo函数创建,打开用open。
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完。
  • 成之后,它们具有相同的语义。

读写规则:

如果当前打开操作是为读而打开FIFO时:
        O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
        O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时:
        O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
        O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

代码实现:

#ifndef _COMM_H_
#define _COMM_H_
//公共文件
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "log.hpp"
using namespace std;

#define MODE 0666
#define SIZE 128

string ipcPath = "./fifo.ipc";


#endif
//日志文件

#include <iostream>
#include <ctime>
#include <string>

#define Debug   0
#define Notice  1
#define Warning 2
#define Error   3

//创建方法
const std::string msg[] = 
{
    "Debug",
    "Notice",
    "Warning",
    "Error"
};
//输出。日志。输出到屏幕中
std::ostream &Log(std::string message, int level)
{
    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;
    return std::cout;
}


#endif

//读文件
#include "comm.hpp"
#include "log.hpp"

static void getMessage(int fd)
{
    char buffer[SIZE];
    while(true)
    {
        memset(buffer,'\0',sizeof buffer);
        int s=read(fd,buffer,sizeof(buffer)-1);
        if(s>0)
        {
            cout <<"["  << getpid() << "] "<< "client say> " << buffer << endl;//还有文件
        }

        else if(s=0)
        {
            cerr <<"["  << getpid() << "] " << "read end of file, clien quit, server quit too!" << endl;//读到文件末尾
            break;
        }
        else if(s<0)
        {
            perror("read s");
            break;
        }
    }
}
int main()
{
    int id=mkfifo("textfifo.txt",0666);//创建命名管道文件
    if(id<0)//创建失败
    {
        perror("mkfifo id");
        return 0;
    }
    Log("创建管道文件成功", Debug) << " step 1" << endl;//打印日志

    int fd = open(ipcPath.c_str(), O_RDONLY);//打开文件,以读的方式
    if (fd < 0)
    {
        perror("open");
        exit(2);
    }
    Log("打开管道文件成功", Debug) << "step 2" << endl;

    int nums=3;
    for(int i=0;i<nums;i++)
    {
        pid_t id=fork();
        if(id==0)
        {
            getMessage(fd);
            exit(1);
        }
    }
    //父进程阻塞等待
    for(int i=0;i<nums;i++)
    {
        waitpid(-1, nullptr, 0);
    }
    close(id);//关闭文件
    Log("关闭文件",Debeg) << "step 3" << endl;
    unlink(ipcPath.c_str()); //删除文件
    Log("删除文件",Debeg) << "step 4" << endl;
    return 0;
}

//写文件
#include "comm.hpp"
#include "log.hpp"

int main()
{
    int id=open("ipcPath.c_str",O_WRONLY);//获取文件
    if(id<0)
    {
        perror("open file");
    }
    string buffer;
    while(true)
    {
        cout << "Please Enter Message Line :> ";
        std::getline(std::cin, buffer);//写文件
        write(id,buffer.c_str(),buffer.size());
    }
    close(id);//关闭
    //unlink(id);
    return 0;
}


结论:双方进程,可以看到同一份文件,,该文件一定在系统路径中,路径具有唯一性,管道文件可以被打开,但是不会将内存中的数据刷新到磁盘中。且有名字。

3.System V 通信

共享内存:共享内存区是最快的IPC形式。共享内存是在物理内存上申请一块空间,再让两个进程各自在页表建立虚拟地址和这块空间的映射关系。这样两个进程看到的就是同一份资源,这一份资源就叫做共享内存。

原理:

共享内存的提供者是操作系统,操作系统通过先描述再组织的方式管理共享内存。

共享内存=共享内存块+对应的共享内存的内核数据结构。

两个进程创建共享内存需要以下步骤:

  1. 创建共享内存
  2. 将两个进程关联到共享内存
  3. 取消两个进程和共享内存的关联
  4. 删除共享内存

注意: 前两个步骤是为了让两个进程实现通信,后面两个步骤是释放共享内存空间,要不然就会内存泄漏了。(与我们之前用的malloc是类似的)。

创建共享内存所需要的函数:

1.ftok——获取一个共享内存的唯一标识符

函数:key_t ftok(const char *pathname, int proj_id);

功能:获取一个共享内存的唯一标识符 key

参数: pathname 文件名 ;proj_id 只有是一个非0的数都可以 .

返回值:成功返回key;失败返回 -1

2..shmget——创建共享内存

函数:int shmget(key_t key, size_t size, int shmflg);

key:传入ftok函数获取的共享内存唯一标识符
size:共享内存的大小(页(4kb)的整数倍)
shmflg:权限,由9个权限标准构成

这里介绍两个选项
IPC_CREAT: 如果底层存在这个标识符的共享内存空间,就打开返回,不存在就创建
IPC_EXCL: 如果底层存在这个标识符的共享内存空间,就出错返回
两个选项合起来用就可以穿甲一个权限的共享内存空间
返回值:
成功返回共享内存标识码值(给用户看的),失败返回-1.

3.shmat——将共享内存空间关联到进程地址空间

函数:void *shmat(int shmid, const void *shmaddr, int shmflg);

功能: 将共享内存空间关联到进程地址空间
参数:
shmid:共享内存标识符
shmaddr:指定连接地址。
shmfig:两个可能取值是SHM_RND和SHM_RDONLY
返回值: 成功返回一个指针(虚拟地址空间中共享内存的地址,是一个虚拟地址),失败返回-1
说明:
shmaddr为NULL,核心自动选择一个地址。
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整> 数倍。公式:shmaddr -(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存。

4.shmdt——取消关联

函数:int shmdt(const void *shmaddr);

功能: 取消共享内存空间和进程地址空间的关联
参数:
shmaddr:共享内存的起始地址(shmat获取的指针)
返回值: 成功返回0,失败返回-1

5.shmctl——控制共享内存

函数:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

功能: 控制共享内存
参数:
shmid:共享内存标识符
cmd:命令,有三个
IPC_STAT: 把shmid_ds结构中设置为共享内存当前关联值
IPC_SET: 把共享内存的当前关联值设置为shmid_ds数据结构中的值
IPC_RMID:删除共享内存段
buf:指向一个报错这共享内存的模式状态和访问权限的数据结构
返回值: 成功返回0,失败返回-1。

共享内存的特性:

对于共享内存来说,它与管道有不同的特性,导致共享内存不同的使用方法

1.管道需要使用系统接口来调用,但是共享内存可以不用经过系统调用,直接可以访,双方进程如果要进行通信,直接进行内存级的读和写即可。共享内存实在堆栈之间的区域的,堆栈相对而生,中间区域为共享内存,不用经过操作系统。

共享内存是最快的,为什么呢?

因为如果是管道,需要从键盘写入,然后再拷贝到自己定义的缓冲区中,然后再次拷贝到内存中,再从内存中拷贝到用户级缓冲区中,最后再拷贝到屏幕中,需要经历最少4词的拷贝过程。

共享内存直接面向用户,所以从键盘中输入的内容直接进入到内存中,然后经过内存到达显示器中,最少只有2次拷贝,所以他的速度是最快的。

对于共享内存的理解:

为了进行进程间通信,需要让不同的进程看到相同的一份资源,所以之前的管道,本质都是优先解决一个问题,让不同的进程看到同一份资源!!!

让不同的进程看到相同的内存,带来了有些时序问题,造成数据不一致问题。

结果:

我们把多个进程(执行流)看到的同一份资源称为临界资源。

我们把自己的进程,访问临界资源的代码,称为临界区。

为了更好地进行临界区的保护,可以让多执行流在任何时刻都只有一个进程进入临界区。即互斥!!!

原子性:要么不做,要么做完,没有中间状态,即为原子性!!

所以,多个执行流,互相运行的时候互相干扰,主要是我们不加保护的访问了相同的资源(临界资源),在非临界区多个执行流是互不干扰的。

代码演示:

#pragma once

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include "Log.hpp"

using namespace std; //不推荐

#define PATH_NAME "/home/SSS"//环境变量
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍 

#define FIFO_NAME "./fifo"
//创建一个管道,形成访问控制
class Init
{
public:
    Init()
    {
        umask(0);
        int n = mkfifo(FIFO_NAME, 0666);
        assert(n == 0);
        (void)n;
        Log("create fifo success",Notice) << "\n";
    }
    ~Init()
    {
        unlink(FIFO_NAME);
        Log("remove fifo success",Notice) << "\n";
    }
};

#define READ O_RDONLY
#define WRITE O_WRONLY

int OpenFIFO(std::string pathname, int flags)
{
    int fd = open(pathname.c_str(), flags);
    assert(fd >= 0);
    return fd;
}

void Wait(int fd)
{
    Log("等待中....", Notice) << "\n";
    uint32_t temp = 0;
    ssize_t s = read(fd, &temp, sizeof(uint32_t));
    assert(s == sizeof(uint32_t));
    (void)s;
}

void Signal(int fd)
{
    uint32_t temp = 1;
    ssize_t s = write(fd, &temp, sizeof(uint32_t));
    assert(s == sizeof(uint32_t));
    (void)s;
    Log("唤醒中....", Notice) << "\n";
}

void CloseFifo(int fd)
{
    close(fd);
}

#ifndef _LOG_H_
#define _LOG_H_

#include <iostream>
#include <ctime>

#define Debug   0
#define Notice  1
#define Warning 2
#define Error   3


const std::string msg[] = {
    "Debug",
    "Notice",
    "Warning",
    "Error"
};

std::ostream &Log(std::string message, int level)
{
    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;
    return std::cout;
}


#endif

#include "comm.hpp"
#include "log.hpp"


string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    key_t key=ftok(PATH_NAME,PROJ_ID);
    assert(key!=-1);
    Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;
    //创建共享内存
    int shmid=shmget(key,SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);
    assert(shmid!=-1);
    Log("create shm done", Debug) << " shmid : " << shmid << endl;

    sleep(10);
    // 3. 将指定的共享内存,挂接到自己的地址空间
    char *shmaddr = (char *)shmat(shmid, nullptr, 0);
    Log("attach shm done", Debug) << " shmid : " << shmid << endl;

    sleep(10);

   // 这里就是通信的逻辑了
    // 将共享内存当成一个大字符串
    // char buffer[SHM_SIZE];
    // 结论1: 只要是通信双方使用shm,一方直接向共享内存中写入数据,另一方,就可以立马看到对方写入的数据。
    //         共享内存是所有进程间通信(IPC),速度最快的!不需要过多的拷贝!!(不需要将数据给操作系统)
    // 结论2: 共享内存缺乏访问控制!会带来并发问题 【如果我想一定程度的访问控制呢? 能】
    
    int fd = OpenFIFO(FIFO_NAME, READ);
    for(;;)
    {
        Wait(fd);

        // 临界区
        printf("%s\n", shmaddr);
        if(strcmp(shmaddr, "quit") == 0) break;
        // sleep(1);
    }
    

    // 4. 将指定的共享内存,从自己的地址空间中取消关联
    int n = shmdt(shmaddr);
    assert(n != -1);
    (void)n;
    Log("detach shm done", Debug) << " shmid : " << shmid << endl;
    sleep(10);

    // 5. 删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存
    n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
    Log("delete shm done", Debug) << " shmid : " << shmid << endl;
    return 0;
}


#include "comm.hpp"

int main()
{
    key_t k = ftok(PATH_NAME, PROJ_ID);//创建key值
    if (k < 0)
    {
        Log("create key failed", Error) << " client key : " << k << endl;
        exit(1);
    }
    Log("create key done", Debug) << " client key : " << k << endl;

    // 获取共享内存
    int shmid = shmget(k, SHM_SIZE, 0);
    if(shmid < 0)
    {
        Log("create shm failed", Error) << " client key : " << k << endl;
        exit(2);
    }
    Log("create shm success", Error) << " client key : " << k << endl;

    sleep(10);

    char *shmaddr = (char *)shmat(shmid, nullptr, 0);//将共享内存关联到进程地址空间
    if(shmaddr == nullptr)
    {
        Log("attach shm failed", Error) << " client key : " << k << endl;
        exit(3);
    }
    Log("attach shm success", Error) << " client key : " << k << endl;
    sleep(10);

    int fd = OpenFIFO(FIFO_NAME, WRITE);
    //使用
    // client将共享内存看做一个char 类型的buffer
    while(true)
    {
        ssize_t s = read(0, shmaddr, SHM_SIZE-1);
        if(s > 0)
        {
            shmaddr[s-1] = 0;
            Signal(fd);
            if(strcmp(shmaddr,"quit") == 0) break;
        }
    }

    CloseFifo(fd)
    // 去关联
    int n = shmdt(shmaddr);//取消关联
    assert(n != -1);
    Log("detach shm success", Error) << " client key : " << k << endl;
    sleep(10);

    // client 要不要chmctl删除呢?不需要!!

    return 0;
}

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

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

相关文章

AI绘画 | stable-diffusion-web-ui的基本操作

前言 我们下载安装完成stable-diffusion-web-ui以后&#xff0c;下载对应风格的模型&#xff0c;就可以开始我们的绘画操作了。进行Ai绘画操作前&#xff0c;我们最好先弄清楚web ui界面上的参数按钮的含义。这样我们就能更轻松的绘画出我们想要stable-diffusion-web-ui创作出…

【C/PTA】循环结构进阶练习(二)

本文结合PTA专项练习带领读者掌握循环结构&#xff0c;刷题为主注释为辅&#xff0c;在代码中理解思路&#xff0c;其它不做过多叙述。 7-1 二分法求多项式单根 二分法求函数根的原理为&#xff1a;如果连续函数f(x)在区间[a,b]的两个端点取值异号&#xff0c;即f(a)f(b)<0…

AR眼镜硬件解决方案_AR/VR智能眼镜安卓主板芯片方案介绍

随着近两年来增强现实(AR)技术的逐渐成熟&#xff0c;采用MT8788芯片解决方案的AR眼镜已经问世。众所周知&#xff0c;AR技术可以帮助开发者打造一个既强大而又实用的混合现实世界&#xff0c;将虚拟与真实世界相结合。 据了解&#xff0c;MT8788芯片采用了多芯片分布式处理系统…

卡牌游戏类型定制开发微信卡牌小程序游戏

卡牌类型的游戏开发具有一些独特的特点和挑战&#xff0c;以下是一些主要的特点&#xff1a; 卡牌设计和平衡&#xff1a;卡牌游戏的核心是卡牌设计和平衡。开发团队需要设计各种卡牌&#xff0c;确保它们在游戏中相互平衡&#xff0c;以便提供有趣的游戏体验。卡牌的特性、效…

C语言,数据结构指针,结构构体操作符 •,->,*的区别,看这篇就够了

在朋友们学习指针和数据结构这一章的时候&#xff0c;对各种操作符云里雾里。当你看到这么文章之后你就会明白了。 一 • 和 ->运算符 • 运算符&#xff1a;是结构变量访问结构体成员时用的操作符 -> 运算符&#xff1a;这是结构体指针访问结构体成员时调用的运算符。 …

04-react基础知识-路由

一、react路由环境安装 使用指令&#xff1a;npm i --save react-router-dom type/react-router-dom进行react路由环境安装 二、引入路由 在main.jsx文件中引入该语句&#xff1a; import { createBrowserRouter, RouterProvider } from react-router-dom 定义一个变量rou…

借助 DevChat AI 之力,成就我之全栈梦想

何为 DevChat &#xff1f; DevChat 是集好多种 AI 大模型的智能编程工具,可以大大增加我们上班摸鱼的时间。 整合了如 ChatGPT、Codex等热门 AI 模型支持自然语言编程、代码生成与编写、代码补全等功能因其集成热门 AI 智能&#xff0c;相当于站在了巨人的肩膀上&#xff0c…

节省服务器资源、实现双向数据传输——深度解析WebSocket协议

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、W…

MinIO 分布式文件(对象)存储

简介 MinIO是高性能、可扩展、云原生支持、操作简单、开源的分布式对象存储产品。 在中国&#xff1a;阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品 官网地址&#xff1a;http://www.minio.org.cn/ 下载 官网下载(8.4.3版本)&#x…

简述SVM

概述 SVM&#xff0c;即支持向量机&#xff08;Support Vector Machine&#xff09;&#xff0c;是一种常见的监督学习算法&#xff0c;用于分类和回归问题。它是一种基于统计学习理论和结构风险最小化原则的机器学习方法。 SVM的主要思想是在特征空间中找到一个最优的超平面…

网络的地址簿:Linux DNS服务的全面指南

1 dns 1.1 dns&#xff08;域名解析服务&#xff09;介绍 当访问 www.baidu.com 首先查询/etc/hosts&#xff0c;如果没有再去查询/etc/resolv.conf&#xff0c;还是没有就去查询域名服务器 关于客户端: /etc/resolv.conf ##dns指向文件 nameserver 172.25.254.20测试&…

C语言实现将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5

完整代码&#xff1a; // 将一个正整数分解质因数。例如&#xff1a;输入90,打印出902*3*3*5 #include<stdio.h> //定义全局变量&#xff0c;使i可以作用于函数的递归调用中 int i2;void func(int num){//递归结束条件&#xff0c;当这个数除以最后一个它的因子时&#…

Halcon如何使用SaperaLT库连接dalsa相机

halcon安装好的时候&#xff0c;没有带SaperaLT的采集库&#xff0c;需要额外在Halcon官网下载此库。 以下是halcon官网下载此库的链接。官网需要注册才可以下载。 https://www.mvtec.com/downloads/interfaces?tx_mvtecproduct_extensiondownloadlist%5Bfilter%5D%5B0%5Dma…

Linux认识协议

目录 TCP协议通信流程TCP三次握手数据传输过程四次挥手过程TCP 和 UDP 对比 认识协议协议的概念结构化数据的传输序列化和反序列化 网络版计算器服务端代码面向字节流 协议定制客户端代码编写代码测试守护进程守护进程创建 关于协议制定中使用现成方法实现 TCP协议通信流程 下…

【JVM】JDBC案例打破双亲委派机制

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 JVM 打破双亲委派机制&#xff08;JDBC案例…

开发直播带货系统源码的技术要点

直播带货系统是一个复杂的技术项目&#xff0c;通常包括前端应用、后端服务器、数据库、支付集成、实时通信以及直播流处理等多个关键组件。以下是开发直播带货系统源码的技术要点&#xff1a; 实时视频流处理 一个成功的直播带货系统需要支持实时视频流的传输和处理。可以使…

【云原生】使用nginx反向代理后台多服务器

背景 随着业务发展&#xff0c; 用户访问量激增&#xff0c;单台服务器已经无法满足现有的访问压力&#xff0c;研究后需要将后台服务从原来的单台升级为多台服务器&#xff0c;那么原来的访问方式无法满足&#xff0c;所以引入nginx来代理多台服务器&#xff0c;统一请求入口…

TCP编程及基础知识

一、端口号 为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理&#xff0c;使用端口号来区分TCP端口号与UDP端口号独立端口用两个字节来表示 2byte&#xff08;65535个&#xff09; 众所周知端口&#xff1a;1~1023&#xff08;1~255之间为众所周知端口&#xff…

Ubuntu网络IP地址一直显示127.0.0.1

问题描述&#xff1a; 终端输入ip a显示127.0.0.1&#xff0c;原来类似192.168.231.1的地址不见了。 ip a 点击网络配置&#xff08;ubuntu桌面版&#xff09;&#xff0c;发现无线网络模块看不见了 正常情况应该有wired 模块&#xff0c;就是下面标红的 解决方案&#xff1a…

学为贵雅思写作备考

准确通顺&#xff0c;言之有物 两次读不懂&#xff0c;6分以下&#xff0c; 6分没有印象&#xff0c;味同嚼蜡&#xff0c;但是没错&#xff08;书面语过关&#xff09; 英语比较过关 8-9分&#xff0c;很有见地 6-7单个的句子读得懂&#xff0c;前后是贯通的、逻辑是通顺…