当前位置: 首页 > news >正文

比较好的政府网站/营销型网站制作建设

比较好的政府网站,营销型网站制作建设,天津网站建设方案咨询,民权做网站文章目录前言一、TCP Socket API1. socket2. bind3. listen4. accept5. connect二、封装TCPSocket三、服务端的实现1. 封装TCP通用服务器2. 封装任务对象3. 实现转换功能的服务器四、客户端的实现1. 封装TCP通用客户端2. 实现转换功能的客户端五、结果演示六、多进程版服务器七…

文章目录

  • 前言
  • 一、TCP Socket API
    • 1. socket
    • 2. bind
    • 3. listen
    • 4. accept
    • 5. connect
  • 二、封装TCPSocket
  • 三、服务端的实现
    • 1. 封装TCP通用服务器
    • 2. 封装任务对象
    • 3. 实现转换功能的服务器
  • 四、客户端的实现
    • 1. 封装TCP通用客户端
    • 2. 实现转换功能的客户端
  • 五、结果演示
  • 六、多进程版服务器
  • 七、线程池版服务器


前言

TCP和UDP都是工作在传输层,用于程序之间传输数据。二者之间的区别是TCP是面向连接的,而UDP是面向数据报的。那就意味着,TCP能够进行可靠的数据传输,而UDP进行不可靠的数据传输。关于TCP协议和UDP协议的详细内容可见博主的后续文章,本文的主要内容是关于TCP socket的网络编程。

接下来我们将基于TCP网络编程实现一个将小写字母转换成大写字母的网络服务器。

一、TCP Socket API

以下是关于使用TCP协议用到的socket API,这些函数都包含在头文件sys/socket.h中。

1. socket

函数定义:

NAME//socket - create an endpoint for communication
SYNOPSIS#include <sys/socket.h>int socket(int domain, int type, int protocol);

功能:
socket()会打开一个网络通信端口,如果打开成功,则像open()函数一样返回一个文件描述符,如果失败则返回 -1。这样网络应用程序就可以像读写文件那样使用read/write在网络上读取和发送数据。

参数详解:

  1. 第一个参数domain用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族。对于IPv4,domain参数指定为AF_INET,而IPv6则是AF_INET6。并且AF_INETPFINET的值是一致的。

  2. 第二个参数type用于设置通信协议的族,这些族也在文件sys/socket.h中定义,包含如下表所示的值。

类型说明
SOCK_STREAM用于TCP连接,提供序列化、可靠的、双向连接的字节流
SOCK_DGRAM用于UDP连接(无连接状态的消息)
SOCK_SEQPACKET序列化包,提供一个序列化的、可靠的、双向的基于连接的数据传输通道,数据长度定长。每次调用读系统调用时数据需要将全部数据读出
SOCK_RAWRAW类型,提供原始网络协议访问
SOCK_RDM提供可靠的数据报文,不过可能数据会有乱序
SOCK_PACKET这是一个专用类型,不能在通用程序中使用,用于直接从设备驱动接收数据

【补充说明】

  • 类型为SOCK_STREAM的套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用connet()函数进行。一旦连接,可以使用read/write函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收,当数据在一段时间内仍然没有接收完毕,可以将这个连接认为已经断开。
  • SOCK_DGRAMSOCK_RAW这两种套接字可以使用函数sendto()来发送数据,使用recvfrom()函数接收数据,recvfrom()接收来自指定IP地址的发送方的数据。
  1. 第三个参数protocol用于指定某个协议的特定类型,即type类型中的某个类型。通常某个协议中只有一种特定类型,这样protocol参数仅能设置为0,但是有些协议有多种类型,就需要设置这个参数来选择特定的类型。

2. bind

函数定义:

NAME//bind - bind a name to a socketSYNOPSIS#include <sys/socket.h>int bind(int socket, const struct sockaddr *address, socklen_t address_len);

因为服务器程序所监听的网络地址和端口号通常都是固定不变的,客户端得知了服务器程序的地址和端口号后就可以向服务器发起连接,而服务器需要绑定一个固定的网络地址和端口号。因此bind()的作用是将参数sockfdmyaddr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听sockaddr所描述的地址和端口号。绑定成功返回0,失败则返回-1。

博主的上一篇文章【网络套接字编程】中提到过,struct sockaddr *是一个通用指针类型,myaddr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。

在程序中myaddr的定义及初始化如下:

struct sockaddr_in myaddr;
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERV_PORT);
  1. 定义myaddr
  2. 使用bzero函数将整个结构体清零
  3. 设置网络通信的域为AF_INET
  4. 将网络地址设置为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP 地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP 地址
  5. 最后填充端口号

虽然bind()中的第二个参数类型是sockaddr,但是我们真正填充信息使用的数据结构是sockaddr_in,这个结构里主要有三部分信息:地址类型、端口号、IP地址。最后在进行函数传参的时候只需要将sockaddr_in*强制类型转换成sockaddr即可。

3. listen

函数定义:

NAME//listen - listen for socket connections and limit the queue of incoming connectionsSYNOPSIS#include <sys/socket.h>int listen(int socket, int backlog);

listen()函数用于声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略。(详细内容可见博主的后续文章【TCP协议】)。listen()函数调用成功返回0,调用失败则返回 -1。

4. accept

函数定义:

NAMEaccept - accept a new connection on a socketSYNOPSIS#include <sys/socket.h>int accept(int socket, struct sockaddr *restrict_address, socklen_t *restrict_address_len);

accept()函数的作用是,当客户端与服务端的三次握手完成后,服务器调用accept()函数接受连接。如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端请求连接。
返回值:

  • 调用成功则返回客户端socket()返回的文件描述符,调用失败则返回 -1。

参数:

  • 第一个参数socket即是调用socket()函数返回的文件描述符。
  • 第二个参数restrict_address是输出型参数,用于获取客户端的网络地址和端口号,如果该参数为空,则表示当前服务端不关心客户端的地址。
  • 第三个参数restrict_address_len也是输出型参数,它表示的是缓冲区restrict_address的长度,以避免缓冲区溢出问题,最后传出客户端地址结构体的实际长度。

accept()函数在服务器程序中的使用结构如下:

while (true)
{sockaddr_in peer_addr;socklen_t len = sizeof(peer_addr);int peer_sock = accept(_fd, (sockaddr *)&peer_addr, &len);ssize_t read_size = read(peer_sock, buf, sizeof(buf));. . .close(peer_sock);
}

5. connect

函数定义:

NAME//connect - connect a socketSYNOPSIS#include <sys/socket.h>int connect(int socket, const struct sockaddr *address, socklen_t address_len);

作用与参数说明:
connect函数用于客户端连接服务器。其参数与bind()函数的参数一致,区别在于bind()函数绑定的参数是自己的地址,而connect()函数的连接是服务器的地址。
返回值:

  • 调用成功返回0,调用失败则返回 -1。

二、封装TCPSocket

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <cassert>#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define CHECK_RET(exp) \if (!(exp))        \{                  \return false;  \}class TcpSocket
{
public:TcpSocket() : _fd(-1) {}~TcpSocket() {}public:bool Socket(){_fd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET表示采用IPv4, SOCK_STREAM表示采用tcp协议if (_fd < 0){std::cerr << "create socket error!" << std::endl;return false;}return true;}bool Close(){close(_fd);return true;}bool Bind(const std::string &ip, uint16_t port){sockaddr_in addr;// 填充addr信息addr.sin_family = AF_INET;addr.sin_port = htons(port);// addr.sin_addr.s_addr = ip.empty() ? htonl(INADDR_ANY) : inet_addr(ip.c_str());ip.empty() ? (addr.sin_addr.s_addr = INADDR_ANY) : inet_aton(ip.c_str(), &addr.sin_addr);if (bind(_fd, (const sockaddr *)&addr, sizeof(addr)) < 0){std::cerr << "bind error!" << std::endl;return false;}return true;}bool Listen(int num){if (listen(_fd, num) < 0){std::cerr << "listen error!" << std::endl;return false;}return true;}bool Accept(TcpSocket *peer, std::string *ip = nullptr, std::uint16_t *port = nullptr){sockaddr_in peer_addr;socklen_t len = sizeof(peer_addr);int peer_sock = accept(_fd, (sockaddr *)&peer_addr, &len);if (peer_sock < 0){std::cerr << "accept error!" << std::endl;return false;}peer->_fd = peer_sock;if (ip != nullptr){*ip = inet_ntoa(peer_addr.sin_addr);}if (port != nullptr){*port = ntohs(peer_addr.sin_port);}return true;}bool Recv(std::string *buf){buf->clear();char inbuf[1024 * 10] = {0};ssize_t read_size = recv(_fd, inbuf, sizeof(inbuf), 0);if (read_size < 0){std::cerr << "recv error!" << std::endl;return false;}if (read_size == 0){return false;}buf->assign(inbuf, read_size);return true;}bool Send(const std::string &buf){ssize_t write_size = send(_fd, buf.c_str(), buf.size(), 0);if (write_size < 0){std::cerr << "send error!" << std::endl;return false;}return true;}bool Connect(const std::string &ip, uint16_t port){sockaddr_in addr;// 填充addr信息addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = ip.empty() ? htonl(INADDR_ANY) : inet_addr(ip.c_str());if (connect(_fd, (sockaddr *)&addr, sizeof(addr)) < 0){std::cerr << "connect error!" << std::endl;return false;}return true;}int GetFd(){return _fd;}private:int _fd;
};

三、服务端的实现

1. 封装TCP通用服务器

#include "TcpSocket.hpp"
#include "Task.hpp"typedef std::function<void(TcpSocket, const std::string &, uint16_t)> Handler;// void transServer(TcpSocket sock, const std::string &ip, uint16_t port)
// {
//     std::string inbuf;//     while (true)
//     {
//         if (!sock.Recv(&inbuf))
//         {
//             // 如果读取失败,结束循环
//             printf("[client %s:%d] disconnect!\n", ip.c_str(), port);
//             break;
//         }//         if (strcasecmp(inbuf.c_str(), "quit") == 0)
//         {
//             printf("[client %s:%d] quit!\n", ip.c_str(), port);
//             break;
//         }//         printf("transform before: %s[%d]--> %s\n", ip.c_str(), port, inbuf.c_str());
//         fflush(stdout);//         for (int i = 0; i < inbuf.size(); ++i)
//         {
//             if (isalpha(inbuf[i]) && islower(inbuf[i]))
//             {
//                 inbuf[i] = toupper(inbuf[i]);
//             }
//         }//         printf("transform after: %s[%d]--> %s\n", ip.c_str(), port, inbuf.c_str());
//         fflush(stdout);//         sock.Send(inbuf);
//     }
//     sock.Close();
// }class TcpServer
{
public:TcpServer(int port, const std::string &ip = ""): _port(port), _ip(ip){_sock.Socket();}~TcpServer() {}public:bool Start(Handler handler){// 绑定IP和端口号CHECK_RET(_sock.Bind(_ip, _port));// 监听CHECK_RET(_sock.Listen(5));// 进入循环while (true){// 进行acceptTcpSocket peer_sock;std::string ip;uint16_t port = 0;if (!_sock.Accept(&peer_sock, &ip, &port)){continue;}printf("[client %s:%d] connect!\n", ip.c_str(), port);// 执行任务// TODOTask task(peer_sock, ip, port, handler);task();}}private:// tcp socket对象TcpSocket _sock;// 端口号uint16_t _port;// ip地址std::string _ip;
};

2. 封装任务对象

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>#include "TcpSocket.hpp"class Task
{typedef std::function<void(TcpSocket, const std::string &, uint16_t)> callback_t;public:Task(TcpSocket sock, const std::string &ip, uint16_t port, callback_t func):_sock(sock), _ip(ip), _port(port), _func(func) {}~Task() {}void operator()(){printf("线程ID[%p]处理client[%s:%d]的请求开始了...\n", pthread_self(), _ip.c_str(), _port);fflush(stdout);_func(_sock, _ip, _port);printf("线程ID[%p]处理client[%s:%d]的请求结束了...\n", pthread_self(), _ip.c_str(), _port);fflush(stdout);}
private:TcpSocket _sock;std::string _ip;uint16_t _port;callback_t _func; // 处理任务的回调函数
};

3. 实现转换功能的服务器

#include <iostream>
#include "TcpSocket.hpp"
#include "TcpServer.hpp"void transServer(TcpSocket sock, const std::string &ip, uint16_t port)
{std::string inbuf;while (true){if (!sock.Recv(&inbuf)){// 如果读取失败,结束循环printf("[client %s:%d] disconnect!\n", ip.c_str(), port);break;}if (strcasecmp(inbuf.c_str(), "quit") == 0){printf("[client %s:%d] quit!\n", ip.c_str(), port);break;}printf("transform before: %s[%d]--> %s\n", ip.c_str(), port, inbuf.c_str());fflush(stdout);for (int i = 0; i < inbuf.size(); ++i){if (isalpha(inbuf[i]) && islower(inbuf[i])){inbuf[i] = toupper(inbuf[i]);}}printf("transform after: %s[%d]--> %s\n", ip.c_str(), port, inbuf.c_str());fflush(stdout);sock.Send(inbuf);}sock.Close();
}static void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " ip port" << std::endl;std::cout << "example:\n\t" << proc << " 127.0.0.1 8080\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 2 && argc != 3){Usage(argv[0]);return 1;}std::string ip;if (argc == 3){ip = argv[1];}uint16_t port = atoi(argv[2]);TcpServer server(port, ip);server.Start(transServer);return 0;
}

四、客户端的实现

1. 封装TCP通用客户端

#include "TcpSocket.hpp"class TcpClient
{
public:TcpClient(const std::string& ip, uint16_t port):_ip(ip), _port(port) {_sock.Socket();}~TcpClient(){_sock.Close();}
public:bool Connect(){return _sock.Connect(_ip, _port);}bool Recv(std::string* buf){return _sock.Recv(buf);}bool Send(const std::string& buf){_sock.Send(buf);}int GetFd(){return _sock.GetFd();}
private:TcpSocket _sock;std::string _ip;uint16_t _port;
};

2. 实现转换功能的客户端

#include <iostream>
#include "TcpClient.hpp"volatile bool quit = false;static void Usage(std::string proc)
{std::cerr << "Usage:\n\t" << proc << " serverIp serverPort" << std::endl;std::cerr << "Example:\n\t" << proc << " 127.0.0.1 8080\n"<< std::endl;
}
// ./clientTcp serverIp serverPort
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);return 1;}std::string serverIp = argv[1];uint16_t serverPort = atoi(argv[2]);TcpClient client(serverIp, serverPort);// 建立连接if (!client.Connect()){std::cout << "connecte errer!" << std::endl;return 2;}std::cout << "connecte success! fd: " << client.GetFd() << std::endl;std::string message;while (!quit){message.clear();std::cout << "请输入您的内容# ";std::getline(std::cin, message);if (strcasecmp(message.c_str(), "quit") == 0){quit = true;}if (client.Send(message)){message.resize(message.size());if (client.Recv(&message)){std::cout << "Server Echo ---> " << message << std::endl;}}else{break;}}return 0;
}

五、结果演示

启动服务端:

启动客户端:

客户端连接服务端成功,此时服务端状态:

测试样例:
客户端输入样例,发现转换成功。

存在的问题:
此时,启动又一个客户端连接服务器,在此输入时,我们会发现输入的内容会卡住显示屏上。

此时我们关闭第一个客户端后发现有得出转换后的结果。


原因在于当前的服务器是单进程版本的,只能够同时为一个客户端服务,所以再来一个客户端会阻塞等待服务器结束对上一个客户端的服务。以下的改进的多进程和多线程版本的服务器。

六、多进程版服务器

改进思想是,父进程为每个客户端的请求都创建一个子进程去处理任务,父进程不做任何工作,但要注意的是父进程中要关闭不断创建的客户端的peer_sock,避免内存泄漏。子进程执行客户端的请求,在请求结束后调用exit函数退出,但不必单独释放_sock对象,因为会自动调用其析构函数。同时设置signal函数,对SIGCHLD做忽略动作,使得父进程不必等待子进程,只处理自己的任务。

#pragma once#include "TcpSocket.hpp"
#include "Task.hpp"
#include <cassert>
#include <signal.h>
#include <unistd.h>typedef std::function<void(TcpSocket, const std::string &, uint16_t)> Handler;class TcpProcessServer
{
public:TcpProcessServer(int port, const std::string &ip = ""): _port(port), _ip(ip){_sock.Socket();signal(SIGCHLD, SIG_IGN);}~TcpProcessServer() {}public:bool Start(Handler handler){// 绑定IP和端口号CHECK_RET(_sock.Bind(_ip, _port));// 监听CHECK_RET(_sock.Listen(5));// 进入循环while (true){// 进行acceptTcpSocket peer_sock;std::string ip;uint16_t port = 0;if (!_sock.Accept(&peer_sock, &ip, &port)){continue;}printf("[client %s:%d] connect!\n", ip.c_str(), port);// 执行任务// 多进程 v1.0pid_t id = fork();if (id > 0){// 父进程,不需要做什么peer_sock.Close(); // 父进程中需要关闭}else if (id == 0){// 子进程// 子进程的 socket 的关闭在析构函数中进行Task task(peer_sock, ip, port, handler);task();// 处理任务结束,退出子进程exit(0);}else{// fork失败std::cerr << "fork error!" << std::endl;return false;}}return true;}private:// tcp socket对象TcpSocket _sock;// 端口号uint16_t _port;// ip地址std::string _ip;
};

结果:

此时服务器便可以为多个客户端同时进行服务。

七、线程池版服务器

实现线程池:

#pragma once#include <iostream>
#include <queue>
#include <cassert>
#include <pthread.h>const uint32_t gDefaultThreadNum = 5; // 默认线程池中线程数量template <class T>
class ThreadPool
{
public:ThreadPool(uint32_t threadNum = gDefaultThreadNum): _isStart(false), _ThreadNum(threadNum){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}public:// 启动线程池void start(){// 判断线程池是否启动assert(!_isStart); // 如果已经启动则失败for (int i = 0; i < _ThreadNum; ++i){pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, this);}// 线程池已经启动_isStart = true;}// 放入任务void push(const T &in){lockQueue();_taskQueue.push(in);handleTask();unlockQueue();}// 消费任务T pop(){T task = _taskQueue.front();_taskQueue.pop();return task;}private:static void *threadRoutine(void *args){ThreadPool<T> *ptp = static_cast<ThreadPool<T> *>(args);while (true){ptp->lockQueue();// 判断当前任务队列中有没有任务while (!ptp->hasTask()){// 没有任务,进行循环等待ptp->waitTask();}// 当前线程获取任务T t = ptp->pop();ptp->unlockQueue();// 当前线程处理任务t();}}void lockQueue(){pthread_mutex_lock(&_mutex);}void unlockQueue(){pthread_mutex_unlock(&_mutex);}void waitTask(){pthread_cond_wait(&_cond, &_mutex);}void handleTask(){pthread_cond_signal(&_cond);}bool hasTask(){return !_taskQueue.empty();}private:bool _isStart;            // 判断线程池是否开启uint32_t _ThreadNum;      // 线程池中的线程数量std::queue<T> _taskQueue; // 任务队列pthread_mutex_t _mutex;   // 保护任务队列的锁pthread_cond_t _cond;     // 线程池的条件变量
};

线程池版服务器:

#pragma once#include "TcpSocket.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"typedef std::function<void(TcpSocket, const std::string &, uint16_t)> Handler;class TcpThreadPoolServer
{
public:TcpThreadPoolServer(int port, const std::string &ip = ""): _port(port), _ip(ip){_sock.Socket();_tp.start();}~TcpThreadPoolServer() {}public:bool Start(Handler handler){// 绑定IP和端口号CHECK_RET(_sock.Bind(_ip, _port));// 监听CHECK_RET(_sock.Listen(5));// 进入循环while (true){// 进行acceptTcpSocket peer_sock;std::string ip;uint16_t port = 0;if (!_sock.Accept(&peer_sock, &ip, &port)){continue;}printf("[client %s:%d] connect!\n", ip.c_str(), port);// 执行任务// TODOTask task(peer_sock, ip, port, handler);_tp.push(task);}}private:// tcp socket对象TcpSocket _sock;// 端口号uint16_t _port;// ip地址std::string _ip;// 线程池ThreadPool<Task> _tp;
};

结果

相关文章:

【计算机网络】Linux环境中的TCP网络编程

文章目录前言一、TCP Socket API1. socket2. bind3. listen4. accept5. connect二、封装TCPSocket三、服务端的实现1. 封装TCP通用服务器2. 封装任务对象3. 实现转换功能的服务器四、客户端的实现1. 封装TCP通用客户端2. 实现转换功能的客户端五、结果演示六、多进程版服务器七…...

idekCTF 2022 比赛复现

Readme 首先 []byte 是 go 语言里面的一个索引&#xff0c;比如&#xff1a; package mainimport "fmt"func main() {var str string "hello"var randomData []byte []byte(str)fmt.Println(randomData[0:]) //[104 101 108 108 111] }上面这串代码会从…...

jvm的类加载过程

加载 通过一个类的全限定名获取定义此类的二进制字节流将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构在内存中生成一个代表这个类的java.lang.Class对象&#xff0c;作为方法区这个类的各种数据的访问入口链接 验证 验证内容的合法性准备 把方法区的静态变量初…...

VOC数据增强与调整大小

数据增强是针对数据集图像数量太少所采取的一种方法。 博主在实验过程中&#xff0c;使用自己的数据集时发现其数据量过少&#xff0c;只有280张&#xff0c;因此便想到使用数据增强的方式来获取更多的图像信息。对于图像数据&#xff0c;我们可以采用旋转等操作来获取更多的图…...

Linux 安装jenkins和jdk11

Linux 安装jenkins和jdk111. Install Jdk112. Jenkins Install2.1 Install Jenkins2.2 Start2.3 Error3.Awakening1.1 Big Data -- Postgres4. Awakening1. Install Jdk11 安装jdk11 sudo yum install fontconfig java-11-openjdk 2. Jenkins Install 2.1 Install Jenkins 下…...

Pandas——Series操作【建议收藏】

pandas——Series操作 作者&#xff1a;AOAIYI 创作不易&#xff0c;觉得文章不错或能帮助到你学习&#xff0c;可以点赞收藏评论哦 文章目录pandas——Series操作一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.创建Series2.从具体位置的Series中访问数据3.使…...

JUC并发编程Ⅰ -- Java中的线程

文章目录线程与进程并行与并发进程与线程应用应用之异步调用应用之提高效率线程的创建方法一&#xff1a;通过继承Thread类创建方法二&#xff1a;使用Runnable配合Thread方法三&#xff1a;使用FutureTask与Thread结合创建查看进程和线程的方法线程运行的原理栈与栈帧线程上下…...

基于vue-admin-element开发后台管理系统【技术点整理】

一、Vue点击跳转外部链接 点击重新打开一个页面窗口&#xff0c;不覆盖当前的页面 window.open(https://www.baidu.com,"_blank")"_blank" 新打开一个窗口"_self" 覆盖当前的窗口例如&#xff1a;导入用户模板下载 templateDownload() {wi…...

【C语言学习笔记】:通讯录管理系统

系统中需要实现的功能如下&#xff1a; ✿ 添加联系人&#xff1a;向通讯录中添加新人&#xff0c;信息包括&#xff08;姓名、性别、年龄、联系电话、家庭住址&#xff09;最多记录1000人 ✿ 显示联系人&#xff1a;显示通讯录中所有的联系人信息 ✿ 删除联系人&#xff1a;按…...

开关电源环路稳定性分析(10)——OPA和OTA型补偿器传递函数

大家好&#xff0c;这里是大话硬件。 在前面9讲的内容中将开关电源环路分析进行了梳理&#xff0c;我相信很多人即使都看完了&#xff0c;应该还是不会设计&#xff0c;而且还存在几个疑问。比如我随便举几个&#xff1a; 开关电源的带宽怎么设定&#xff1f;开关电源精度和什…...

2.11知识点整理(关于pycharm,python,pytorch,conda)

pycharm 设置anaconda环境&#xff1a; File -> Settings->选择左侧的project xxx再选择打开Project Interpreter页->选择add添加解释器->添加Anaconda中Python解释器&#xff08;Anaconda安装目录下的python.exe&#xff09; (选择existing environment &#xff…...

Linux服务器开发-2. Linux多进程开发

文章目录1. 进程概述1.1 程序概览1.2 进程概念1.3 单道、多道程序设计1.4 时间片1.5 并行与并发1.6 进程控制块&#xff08;PCB&#xff09;2. 进程的状态转换2.1 进程的状态2.2 进程相关命令查看进程实时显示进程动态杀死进程进程号和相关函数3. 进程的创建-fork函数3.1 进程创…...

Excel中缺失数据值的自动填充

目录简单方法示例1&#xff1a;数据满足线性趋势示例2&#xff1a;数据满足增长(指数)趋势参考实验做完处理数据&#xff0c;发现有一组数据因为设备中途出现问题缺失了&#xff0c;之前做过的数据也找不到&#xff0c;为了不影响后续处理&#xff0c;这里使用Excel插入缺失值。…...

路由器刷固件

前言 我希望可以远程访问我的电脑。但&#xff0c;我不希望电脑总是处于运行状态&#xff0c;因为那样比较费电。所以需要一个方案&#xff0c;能将睡眠/关机中的电脑唤醒。 方案一&#xff1a;选用智能插座&#xff0c;远程给电脑上电。电脑设置上电自启。但&#xff0c;这存…...

leetcode: Two Sum II - Input Array is Sorted

leetcode: Two Sum II - Input Array is Sorted1. 题目2. 解答3. 总结1. 题目 Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two number…...

STL——list

一、list介绍及使用 1. list文档介绍 &#xff08;1&#xff09;list是可以在常数范围内&#xff0c;在任意位置进行插入、删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 &#xff08;2&#xff09;list的底层是带头结点的双向循环链表&#xff0c;其中每个元素…...

实战打靶集锦-004-My-Cmsms

**写在前面&#xff1a;**记录一次艰难曲折的打靶经历。 目录1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 WEB服务探查4.1.1 浏览器访问4.1.2 目录枚举4.1.3 控制台探查4.1.4 其他目录探查4.2 阶段小结5. 公共EXP搜索5.1 CMS搜索5.2 Apache搜索5.3 PHP搜索5.4 MySQL搜索5…...

c++代码实现我的世界(14)

c代码实现我的世界14|生成地貌兼工作台1前言的前言~前言生成地貌函数结构体struct dimao根据比例生成地貌工作台函数准备的东西写在最后前言的前言~ 实在对不起大家&#xff0c;有挺长时间没更新了。 前言 今天我们将写生成地形的函数与工作台前传的代码&#xff1b; 注&…...

RMQ--区间最值问题(在更)

RMQ&#xff08;Range Minimum/Maximum Query&#xff09;RMQ解决的问题ST算法 O(nlogn)线段树例题数列区间最大值最敏捷的机器人天才的记忆Frequent values总结&#xff08;ST和线段树对比&#xff09;RMQ解决的问题 RMQ是一个解决多个区间最值查询的算法,即区间最值查询&…...

一篇文章搞懂Cookie

目录 1 什么是Cookie 2 创建Cookie 3 浏览器查看Cookie 3.1 浏览器查看Cookie的第一种方式 3.2 浏览器查看Cookie的第二种方式 4 获取Cookie 5 修改Cookie 6 Cookie编码与解码 6.1 创建带中文Cookie 6.2 读取带中文Cookie 6.3 获取中文Cookie请求效果 6.4 解决创建和…...

深入解读.NET MAUI音乐播放器项目(二):播放内核

播放控制服务 IMusicControlService: 播放控制类&#xff0c;用于当前平台播放器对象的操作&#xff0c;对当前所播放曲目的暂停/播放&#xff0c;下一首/上一首&#xff0c;快进快退&#xff08;寻迹&#xff09;&#xff0c;随机、单曲模式等功能的控制。 播放控制类包含一…...

4.SpringWeb

一、创建项目LomBok:辅助开发工具&#xff0c;减少代码编写Spring Web:带上Spring MVC,可以做Web开发了Thymleaf: Web开发末班引擎&#xff08;不常用&#xff09;创建好&#xff0c;如下&#xff1a;static/ 放置静态资源的根目录templates/ 放置模板文件的根目录 二、资源配置…...

C++中的枚举与位域

枚举在传统 C中&#xff0c;枚举类型并非类型安全&#xff0c;枚举类型会被视作整数&#xff0c;则会让两种完全不同的枚举类型可以进行直接的比较&#xff08;虽然编译器给出了检查&#xff0c;但并非所有&#xff09;&#xff0c;甚至同一个命名空间中的不同枚举类型的枚举值…...

第19章 MongoDB Limit与Skip方法教程

第19章 MongoDB Limit与Skip方法教程 MongoDB Limit() 方法 如果仁兄需要在MongoDB中读取指定数量的数据记录&#xff0c;可以使用MongoDB的Limit方法&#xff0c;limit()方法接受一个数字参数&#xff0c;该参数指定从MongoDB中读取的记录条数。 语法 limit()方法基本语法请…...

进程间通信——消息队列

多线程 进程间通信——消息队列 消息队列——发送 测试代码 #include <sys/types.h> #include <sys/msg.h> #include <sys/ipc.h>#include <stdlib.h> #include <stdio.h> #include <string.h>#define MAX_BUF_SIZE 255struct msgtype {…...

OpenMMLab 实战营打卡 - 第 7 课

OpenMMLab MMSegmentation内容概要MMSegmentation统一超参MMSegmentation 的项目结构分割模型的模块化设计分割模型的配置文件主干网络的配置ResNet v1c主解码头的配置辅助解码头的配置数据集配置数据处理流水线常用训练策略参考资料内容概要 • MMSegmentation 项目概述 • M…...

MAC Boook打印长图

有时老师给留的作业是一张长图&#xff0c;直接打印或者通过把图放入word打印都不能实现把长页分成多页进行打印。通过网上找到思路可以通过EXCEL实现将长图分成多页打印。 测试版本 macos&#xff1a;ventura 13.1 office 365 注&#xff1a;同样适用windows版本的excel 第…...

web3:区块链共识机制系列-POS(Proof of Stake)股权证明算法

web3相关学习一并收录至该博客&#xff1a;web3学习博客目录大全 前情衔接&#xff1a;web3:区块链常见的几大共识机制及优缺点 目录前言算法公式与原理算法公式运作原理以Peer Coin为例缺陷优点缺点特点分类发展历程casper协议1.什么是无成本利益关系问题2.引入casper协议解决…...

Linux fork()系统调用流程解析

1. fork()函数介绍&#xff08;百度百科&#xff09; fork系统调用用于创建一个新进程&#xff0c;称为子进程&#xff0c;它与进程&#xff08;称为系统调用fork的进程&#xff09;同时运行&#xff0c;此进程称为父进程。创建新的子进程后&#xff0c;两个进程将执行fork&…...

自定义软件帮助文档(qt assistant实现)

网上搜了一下&#xff0c;软件的帮助文档&#xff0c;三个都可以&#xff1a;https://github.com/zealdocs/zeal&#xff0c;https://zealdocs.org/&#xff0c;看看这个博客说的 https://blog.csdn.net/libaineu2004/article/details/125028913&#xff0c;这个也是开源的&…...