【Linux网络编程】网络编程套接字(1)

【Linux网络编程】网络编程套接字(1)

目录

  • 【Linux网络编程】网络编程套接字(1)
      • 源IP地址和目的IP地址
      • 端口号
        • 端口号和进程ID的关系
      • 网络通信
      • TCP协议
      • UDP协议
      • 网络字节序
      • socket编程接口
      • 简单的UDP网络程序

作者:爱写代码的刚子

时间:2024.1.29

前言:先提前写网络编程的博客,管道以及多线程的博客之后补上。

源IP地址和目的IP地址

IP数据包头部中,有两个IP地址,分别叫做源IP地址,和目的IP地址

  1. 源IP地址(Source IP Address):
    • 源IP地址是发送数据包的设备(或主机)的IP地址。
    • 在一个网络通信过程中,源IP地址标识了消息的来源。
    • 在IPv4中,源IP地址通常以四个十进制数字的形式表示,如 “192.168.0.1”。
    • 在IPv6中,源IP地址以一种更长的形式表示,如 “2001:0db8:85a3:0000:0000:8a2e:0370:7334”。
  2. 目的IP地址(Destination IP Address):
    • 目的IP地址是接收数据包的设备(或主机)的IP地址。
    • 在一个网络通信过程中,目的IP地址标识了消息的目标。
    • 同样,目的IP地址可以以IPv4或IPv6的形式表示。

端口号

端口号(port)是传输层协议的内容.

  • 端口号是一个2字节16位的整数;

  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;

  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;

  • 一个端口号只能被一个进程占用

端口号和进程ID的关系
  • 当网络服务启动时,它会监听一个特定的端口号,等待客户端连接。
  • 当客户端尝试连接到服务时,客户端和服务之间的通信将使用该端口号进行标识。
  • 当连接建立后,服务的进程ID与该连接相关联。这使得操作系统可以跟踪网络连接与哪个进程相关。

【问题】:我们之前在学习系统编程的时候, 学习了 pid 表示唯一一个进程; 此处我们的端口号也是唯一表示一个进程。那么这两者之间是怎样的关系?

  • 网络模块和进程管理模块进行解耦合。进程pid在技术上是可以标定当前主机上某一个唯一的进程,但是实际上不会用进程pid做,进程pid属于进程管理范畴,而端口号属于网络范畴。如果非要用进程pid做两用(既做调度进程管理,又在网络上标定主机的一个唯一进程),无疑是将进程管理和网络强耦合起来了。它可以但不合理。

  • 在我们的系统中,并不是所有的进程都要进行网络通信的。而端口号是一种数字,标定当前主机上某一个唯一的进程,它更加的是一种证明,证明对应的进程是要进行网络通信的。没有端口号,这个进程只是本地间跑某些业务。而有端口号,一定是要对外的。

【问题】:底层如何通过port找到对应进程的?

  • 实际底层采用哈希的方式建立了端口号和进程PID或PCB之间的映射关系,当底层拿到端口号时就可以直接执行对应的哈希算法,然后就能够找到该端口号对应的进程。

【问题】:一个进程可以绑定多个端口号吗?

  • 可以的。未来一个进程在进行网络通信的时候,它可能既和客户端A通信,也和客户端A的子模块通信,所以此进程就会绑定两个端口号。只要能够通过端口号找到同一个进程即可。但是一个端口号不能被多个进程绑定。因为端口号到进程具有唯一性。

网络通信

我们在网络通信的时候,只要让两台主机能够通信就可以了吗?

  • 实际上,在进行通信的时候,不仅仅要考虑两台主机间互相交互数据。

  • 本质上讲,进行数据交互的时候,是用户和用户在进行交互。用户的身份,通常是用程序体现的。程序一定是在运行中的 ---- 进程。

    所以主机间通信的目的本质是:在各自的主机上的两个进程在互相交互数据。IP地址可以完成主机和主机的通信,而主机上各自的通信进程,才是发送和接受数据的一方。

所以:

  • IP —— 确保主机的唯一性

  • 端口号(port)—— 确保该主机上的进程的唯一性

  • IP + PORT = 标识互联网中唯一的一个进程。—— socket

  • 网络通信的本质:也是进程间通信


    socket:

  • socket在英文上有“插座”的意思,插座上有不同规格的插孔,我们将插头插入到对应的插孔当中就能够实现电流的传输。

  • 在进行网络通信时,客户端就相当于插头,服务端就相当于一个插座,但服务端上可能会有多个不同的服务进程(多个插孔),因此当我们在访问服务时需要指明服务进程的端口号(对应规格的插孔),才能享受对应服务进程的服务。

TCP协议

先简单介绍一下,之后再详细介绍

  • 传输层协议
  • 有连接
  • 可靠传输
  • 面向字节流

UDP协议

先简单介绍一下,之后再详细介绍

  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏 移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

总结:由于我们不能保证通信双方存储数据的方式是一样的,因此网络当中传输的数据必须考虑大小端问题。因此TCP/IP协议规定如下:网络数据流采用大端字节序,即低地址高字节。无论是大端机还是小端机,都必须按照TCP/IP协议规定的网络字节序来发送和接收数据。

  • 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
  • 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。
  • 需要注意的是,所有的大小端的转化工作是由操作系统来完成的,因为该操作属于通信细节,不过也有部分的信息需要我们自行进行处理,比如端口号和IP地址。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络 字节序和主机字节序的转换。

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
  • 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。

  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。

  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;

  • 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。

socket编程接口

几个重要的函数接口

  • socket套接字

在这里插入图片描述

  • htons通常用于将主机字节顺序(host byte order)的16位整数转换为网络字节顺序(network byte order)

在这里插入图片描述

  • inet_addr 通常用于将点分十进制的 IPv4 地址转换为网络字节顺序的 32 位整数

在这里插入图片描述

  • sendto用于在UDP协议中发送数据的函数

在这里插入图片描述

  • recvfrom用于在UDP协议中接收数据的函数

在这里插入图片描述

  • socket常见API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器) int socket(int domain, int type, int protocol);

// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,
          socklen_t address_len);

// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);

// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,
          socklen_t* address_len);

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
					socklen_t addrlen);
  • sockaddr结构

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同。
在这里插入图片描述

  • IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.

  • IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址, 不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.

  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好 处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为 参数;

  • sockaddr结构

struct sockaddr
{
		_SOCKADDR_COMMON(sa_);/*Common data: address family and length. */
		char sa_data[14];  /*Address data*/
}
  • sockaddr_in结构
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
		_SOCKADDR_COMMON(sin_);
		in_port_t sin_port;		/* Port number. */
		struct in_addr sin_addr;	/* Internet address. */
		
		/* Pad to size of 'struct sockaddr.' */
		ussigned char sin_zero[sizeof(struct sockaddr) -
				__SOCKADDR_COMMON_SIZE - 
				sizeof(in_port_t) - 
				sizeof(struct in_addr)];
}
  • in_addr结构
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
		in_addr_t s_addr;
}

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数;

简洁版:

#include <netinet/in.h>

struct sockaddr_in {
    sa_family_t sin_family;     // 地址家族 AF_INET
    in_port_t sin_port;         // 16位端口号,网络字节顺序
    struct in_addr sin_addr;    // 32位IPv4地址,网络字节顺序
    char sin_zero[8];           // 不使用,填充0以使结构体大小与 struct sockaddr 相同
};

sockaddr_in 结构体包含以下字段:

  • sin_family: 地址家族,通常为 AF_INET,表示IPv4地址。
  • sin_port: 16位端口号,以网络字节顺序存储,即大端字节序。
  • sin_addr: 32位IPv4地址,以网络字节顺序存储,即大端字节序。它是一个结构体 struct in_addr,其中包含一个字段 s_addr,表示IPv4地址。
  • sin_zero: 用于填充,以使 sockaddr_in 的大小与通用地址结构 struct sockaddr 相同。

在网络编程中,当使用套接字 API 中的函数时,sockaddr_in 结构体通常需要进行类型转换,以便与通用的 struct sockaddr 结构体一起使用。这是因为套接字函数(如 bindconnectrecvfromsendto)通常使用通用地址结构 struct sockaddr 来表示地址信息。在使用时,可以使用类型强制转换sockaddr_in 转换为 struct sockaddr

套接字编程的种类:

  1. 域间套接字编程——同一个机器内
  2. 原始套接字编程——网络工具
  3. 网络套接字编程——用户间的网络通信

网络接口统一抽象化:参数的类型必须是统一的。

在这里插入图片描述

简单的UDP网络程序

Log.hpp

#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define SIZE 1024

#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

#define Screen 1
#define Onefile 2
#define Classfile 3

#define LogFile "log.txt"

class Log
{
public:
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }
    void Enable(int method)
    {
        printMethod = method;
    }
    std::string levelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "None";
        }
    }

    
    void printLog(int level, const std::string &logtxt)
    {
        switch (printMethod)
        {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            printClassFile(level, logtxt);
            break;
        default:
            break;
        }
    }
    void printOneFile(const std::string &logname, const std::string &logtxt)
    {
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"
        if (fd < 0)
            return;
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }
    void printClassFile(int level, const std::string &logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"
        printOneFile(filename, logtxt);
    }

    ~Log()
    {
    }
    void operator()(int level, const char *format, ...)
    {
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
                 ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        // 格式:默认部分+自定义部分
        char logtxt[SIZE * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

        // printf("%s", logtxt); // 暂时打印
        printLog(level, logtxt);
    }

private:
    int printMethod;
    std::string path;
};

Main.cc

#include "UdpServer.hpp"
#include <memory>
#include <cstdio>

void Usage(std::string proc)
{
    std::cout << "\n\rUsage: "<< proc << " port[1024+]\n" << std::endl;
}

std::string Handler(const std::string &str)
{
    std::string res = "Server get a message: ";
    res += str;
    std::cout << res << std::endl;

    return res;
}
std::string ExcuteCommand(const std::string &cmd)
{
    //SafeCheck(cmd);
    FILE *fp = popen(cmd.c_str(),"r");//文件中存放命令的执行结果
    if(nullptr == fp)
    {
        perror("popen");
        return "error";
    }
    std::string result;
    char buffer[4096];
    while(true)
    {
        char* p = fgets(buffer,sizeof(buffer),fp);
        if(p == nullptr)break;
        result += buffer;
    }
    pclose(fp);
    return result;
}

//运行时的指令 ./udpserver port
int main(int argc,char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(0);
    }

    uint16_t port = std::stoi(argv[1]);

    std::unique_ptr<UdpServer> svr(new UdpServer(port));

    svr->Init();
    svr->Run(ExcuteCommand);//传递一个func指针;

    return 0;

}

Makefile

.PHONY:all
all:udpserver udpclient

udpserver:Main.cc
	g++ -o $@ $^ -std=c++11

udpclient:UdpClient.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f udpserver udpclient

UdpClient.cc

#include <iostream>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>


using namespace std;

void Usage(std::string proc)
{
    std::cout << "\n\rUsage: "<< proc << " serverip serverport\n"<<std::endl;
}
int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(0);
    }

    std::string server_ip = argv[1];
    uint16_t server_port = std::stoi(argv[2]);

    struct sockaddr_in server;
    bzero(&server,sizeof(server));
    server.sin_family= AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());

    socklen_t len = sizeof(server);
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);

    if(sockfd < 0)
    {
        cout<< "socker error!!!" <<endl;
        return 1;
    }

    // client 也要bind,只不过不需要用户显示的bind!一般有OS自由随机选择!
    // 一个端口号只能被一个进程bind,对server是如此,对于client,也是如此!
    // 其实client的port是多少,其实不重要,只要能保证主机上的唯一性就可以!
    // 系统什么时候给我bind呢?首次发送数据的时候

    string message;
    char buffer[1024];
    while(true)
    {
        cout<<"Please Enter@";
        getline(cin, message);

        //给某某发数据
        sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr *)&server,len);

        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);

        size_t s = recvfrom(sockfd,buffer,1023,0,(struct sockaddr*)&temp,&len);
        if(s > 0)
        {
            buffer[s] = 0;
            cout<<buffer<<endl;
        }
    }

    close(sockfd);
    return 0;
}

UdpServer.hpp

#pragma once

#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"

//以下两种写法都可以
// using func_t = std::function<std::string(const std::string&)>;
typedef std::function<std::string(const std::string&)> func_t;

Log lg;

enum{
    SOCKET_ERR=1,
    BIND_ERR
};

uint16_t defaultport = 8080;
std::string default_ip = "0.0.0.0";
const int size = 1024;

class UdpServer{
public:
    UdpServer(const uint16_t &port = defaultport, const std::string &ip = default_ip):sockfd_(0), port_(port), ip_(ip),isrunning_(false)
    {}
    void Init()
    {
        // 第一步 创建udp socket
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0); // PF_INET
        if(sockfd_ < 0)
        {
            lg(Fatal, "socket create error, sockfd: %d", sockfd_);
            exit(SOCKET_ERR);
        }
        lg(Info, "socket create success, sockfd: %d", sockfd_);
        
        
        // 第二步 bind socket
        struct sockaddr_in local;

        bzero(&local, sizeof(local));//Linux里面的函数
        local.sin_family = AF_INET;
        local.sin_port = htons(port_); //需要保证我的端口号是网络字节序列,因为该端口号是要给对方发送的,htons函数用于将主机字节序(host byte order)的16位整数转换为网络字节序(network byte order)
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); //1. string -> uint32_t 2. uint32_t必须是网络序列的 
        //local.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0)//bind函数用于将一个套接字(socket)与特定的地址(IP地址和端口号)关联起来
        {
            lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));
    }
    void Run(func_t func) // 对代码进行分层
    {
        isrunning_ = true;
        char inbuffer[size];
        while(isrunning_)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);//recvfrom是一个用于从网络套接字接收数据的函数
            if(n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[n] = 0;
            std::string info = inbuffer;
            std::string echo_string = func(info);//func为处理函数
            sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);
        }
    }
    ~UdpServer()
    {
        if(sockfd_>0) close(sockfd_);
    }
private:
    int sockfd_;     // 网路文件描述符
    std::string ip_; // 任意地址bind 0
    uint16_t port_;  // 表明服务器进程的端口号
    bool isrunning_;
};

运行结果:

在这里插入图片描述

(不能使用设置了别名的命令)

window下网络编程套接字代码与Linux类似,添加对应的头文件,更改部分代码,比如:bzero函数要换成memset函数。

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

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

相关文章

SV-7101T网络音频终端 网络对讲终端

SV-7101是一款IP网络广播终端&#xff0c;主要作为网络播放器使用&#xff0c;其接收网络的音频数据&#xff0c;提供音频输出。SV-7101与服务器主控软件、有源音箱配套使用可实现主控室对HG7101终端进行定时打铃、实时语音广播和紧急广播等功能。 淘宝速购&#xff1a; SV-701…

Android中属性property_get和property_set的详细用法介绍

1&#xff0c;property_get和property_set的作用说明 在Android操作系统中&#xff0c;property_get和property_set是用于获取和设置系统属性的函数。这些属性通常用于存储和读取配置信息&#xff0c;例如设备配置、网络设置、系统参数等。 property_get函数用于获取指定属性…

websocket 通信协议

websocket是什么 答: 它是一种网络通信协议&#xff0c;是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 意思就是服务器可以主动向客户端推送信息&#xff0c;客户端也可以主动向服务器发送信息 属于服务器推送技术的一种. 为什么需要websocket? 疑问?…

(五)MySQL的备份及恢复

1、MySQL日志管理 在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这样情况下&#xff0c;我们必须保证数据的安全性和完整性&#xff0c;就需要使用日志来查看或者恢复数据了 数据库中数据丢失或被破坏可能原因&#xff1a; 误删除数据…

MySQL原理(二)存储引擎(3)InnoDB

目录 一、概况&#xff1a; 1、介绍&#xff1a; 2、特点&#xff1a; 二、体系架构 1、后台线程 2、内存池&#xff08;缓冲池&#xff09; 三、物理结构 1、数据文件&#xff08;表数据和索引数据&#xff09; 1.1、作用&#xff1a; 1.2、共享表空间与独立表空间 …

【C/C++ 05】快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序算法&#xff0c;其基本思想是&#xff1a;任取待排序序列中的某元素作为基准值&#xff0c;按照该基准值将待排序集合分割成两个子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子序列中所有元素均大于…

MySQL原理(二)存储引擎(1)概述

一、存储引擎介绍 1、概念&#xff1a; &#xff08;1&#xff09;MySQL中的数据用各种不下同的技术存储在文件中&#xff0c;每一种技术都使用不同的存储机制、索引技巧、锁定水平并最终提供不同的功能和能力&#xff0c;这些不同的技术以及配套的功能在MySQL中称为存储引擎…

【数据结构与算法】7.详解队列的基本操作

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》|《数据结构与算法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢…

2024年最新 MySQL的下载、安装、启动与停止

一、MySQL的下载 MySQL最常用的2个版本&#xff1a; 社区版&#xff1a;免费开源&#xff0c;自由下载&#xff0c;不提供官方技术支持&#xff0c;大多数普通用户选择这个即可。企业版&#xff1a;需要付费&#xff0c;不能在线下载&#xff0c;可以使用30天&#xff0c;提供…

ctfshow web72

下载源码&#xff1a; 开启环境&#xff1a; 本题设置了 open_basedir()&#xff0c;将php所能打开的文件限制在指定的目录树中&#xff0c;包括文件本身。 因为 ini_set() 也被限制了&#xff0c;所以 open_basedir() 不能用 ini_set() 重新设置绕过。 使用 php 伪协议 glob:…

【网络】:网络套接字(UDP)

网络套接字 一.网络字节序二.端口号三.socket1.常见的API2.封装UdpSocket 四.地址转换函数 网络通信的本质就是进程间通信。 一.网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网…

数据结构----链表介绍、模拟实现链表、链表的使用

文章目录 1. ArrayList存在的问题2. 链表定义2.1 链表的概念及结构2.2 链表的组合类型 3. 链表的实现3.1 单向、不带头、非循环链表的实现3.2 双向、不带头节点、非循环链表的实现 4.LinkedList的使用4.1 什么是LinkedList4.2 LinkedList的使用4.2.1. LinkedList的构造4.2.2. L…

npm 淘宝镜像正式到期

由于node安装插件是从国外服务器下载&#xff0c;如果没有“特殊手法”&#xff0c;就可能会遇到下载速度慢、或其它异常问题。 所以如果npm的服务器在中国就好了&#xff0c;于是我们乐于分享的淘宝团队干了这事。你可以用此只读的淘宝服务代替官方版本&#xff0c;且同步频率…

Docker 数据管理、容器互联、网络与资源控制

一、docker数据管理 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷(Data volumes)和数据卷容器(Datavolumes containers)。 1、数据卷 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立…

seata 分布式

一、下载安装seata 已经下载好的朋友可以跳过这个步骤。这里下载的是seata1.6.1这个版本。 1、进入seata官网 地址&#xff1a; https://seata.io/zh-cn/index.html 2、进入下载 3、点击下载地址 下载地址&#xff1a; https://github.com/seata/seata 二、配置seata 进入c…

​ PaddleHub 首页图像 - 文字识别chinese_ocr_db_crnn_server​

PaddleHub 便捷地获取PaddlePaddle生态下的预训练模型&#xff0c;完成模型的管理和一键预测。配合使用Fine-tune API&#xff0c;可以基于大规模预训练模型快速完成迁移学习&#xff0c;让预训练模型能更好地服务于用户特定场景的应用 零基础快速开始WindowsLinuxMac Paddle…

MacOS安装反编译工具JD-GUI以及解决无法打开的问题

目录 一.下载地址 二.安装 三.问题 四.解决办法 1.显示包内容 2.找到Contents/MacOS/universalJavaApplicationStub.sh 3.修改sh文件 4.保存后再次打开即可 一.下载地址 Java Decompiler 二.安装 将下载下来的 jd-gui-osx-1.6.6.tar 解压&#xff0c;然后将 JD-GUI.a…

驾驭AI绘画:《AI魔法绘画》带你秒变顶级画手!

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二名&#xff0c;科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…

C++笔试强训选择题7

1.对于以下代码&#xff0c;说法正确的是&#xff08;&#xff09; char * p new char[100]&#xff1b;A p 和 new出来的内存都在栈上 B p 和 new出来的内存都在堆上 C p在栈上 new出来的在堆上 D p在堆上 new出来的在栈上 new默认情况下申请的空间在堆上 2. 类模板的使用…

微信小程序~上推加载更多组件

本组件使用的是TaroReact 实现的 &#xff0c;具体代码如下 一共分为tsx和less文件 //index.tsx /** RefreshLoading* description 上推加载更多组件* param loading boolean* param style* returns*/import { View } from "tarojs/components"; import React, { FC…