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

怎样才能制作网站/最简单的网页制作

怎样才能制作网站,最简单的网页制作,网站什么时候做SEO优化最合适,wordpress短信登录参考自游双《Linux高性能服务器编程》 背景 服务器同常需要定期处理非活动连接:给客户发一个重连请求,或关闭该连接,或者其他。我们可以通过使用升序定时器链表处理非活动连接,下面的代码利用alarm函数周期性的触发SIGALRM信号&a…

参考自游双《Linux高性能服务器编程》

背景

服务器同常需要定期处理非活动连接:给客户发一个重连请求,或关闭该连接,或者其他。我们可以通过使用升序定时器链表处理非活动连接,下面的代码利用alarm函数周期性的触发SIGALRM信号,该信号的处理函数利用管道通知主循环执行定时器链表上的定时任务—关闭非活动连接。

实现代码

升序定时器链表

定时器通常包含两个成员:超时时间和任务回调函数。

有时还会包含回调函数被执行时需要传入的参数。

下方代码实现了一个简单的升序定时器链表,按照超时时间做升序排列。

// lst_timer.h
// 升序定时器链表
#ifndef LST_TIMER
#define LST_TIMER#include <time.h>
#define BUFFER_SIZE 64
class util_timer;// 用户数据结构
struct client_data
{sockaddr_in address;   // 客户端socket地址int sockfd;            // socket 文件描述符char buf[BUFFER_SIZE]; // 读缓冲util_timer *timer;     // 链表
};// 定时器类
class util_timer
{
public:util_timer() : prev(NULL), next(NULL) {}public:time_t expire;                  // 任务的超时时间,绝对时间void (*cb_func)(client_data *); // 任务回调函数client_data *user_data;         // 回调函数处理的客户数据,由定时器执行者传递给回调函数util_timer *prev;util_timer *next;
};// 定时器链表,升序,双向,有头尾节点
class sort_timer_lst
{
public:sort_timer_lst() : head(NULL), tail(NULL){};// 删除所有定时器~sort_timer_lst(){util_timer *tmp = head;while (tmp){head = tmp->next;delete tmp;tmp = head;}}// 将定时器timer添加到链表中void add_timer(util_timer *timer){if (!timer){return;}if (!head) // 空链表{head = tail = timer;return;}// 若目标定时器超时时间小于当前链表中所有定时器的超时时间// 则把该定时器插入到头部,作为链表头节点// 否则就要插入合适的位置以保证升序if (timer->expire < head->expire){timer->next = head;head->prev = timer;head = timer;return;}add_timer(timer, head);}// 当某个定时任务发生变化时,调整对应的定时器的超时时间// 这个函数只考虑被调整的定时器的【超时时间的延长情况】,即该定时器要往链表尾部移动void adjust_timer(util_timer *timer){if (!timer){return;}util_timer *tmp = timer->next;// 被调整定时器在链表尾部,或该定时器超时时间仍小于下一个定时器的超时时间,则不用调整if (!tmp || (timer->expire < tmp->expire)){return;}// 若目标定时器时链表头节点,则将该定时器取出重新插入链表if (timer == head){head = head->next;head->prev = NULL;timer->next = NULL;add_timer(timer, head);}// 若目标定时器不是链表头节点,则将该定时器从链表中取出,然后插入原来所在位置之后的部分链表中else{timer->prev->next = timer->next;timer->next->prev = timer->prev;add_timer(timer, timer->next);}}void del_timer(util_timer *timer){if (!timer){return;}// 链表只剩待删除定时器if ((timer == head) && (timer == tail)){delete timer;head = NULL;tail = NULL;return;}if (timer == head){head = head->next;head->prev = NULL;delete timer;return;}if(timer == tail) {tail = tail->prev;tail->next = NULL;delete timer;return;}// 目标定时器位于链表中间timer->prev->next = timer->next;timer->next->prev = timer->prev;delete timer;}// SIGALARM信号每次触发就在其信号处理函数中执行一次tick函数// 来处理链表上到期的任务。void tick(){if(!head){return ;}printf("timer tick\n");time_t cur = time(NULL);util_timer *tmp = head;// 从头开始依次处理每个定时器,直到遇到一个尚未到期的定时器while(tmp){// 未来的时间比现在的时间大if(cur < tmp->expire){break;}tmp->cb_func(tmp->user_data);head = tmp->next;if(head){head->prev = NULL;}delete tmp;tmp = head;}}
private:// 重载的辅助函数// 被add_timer和adjust_timer调用// 功能:将目标定时器timer添加到lst_head之后的部分链表中void add_timer(util_timer *timer, util_timer *lst_head){util_timer *prev = lst_head;util_timer *tmp = prev->next; // 可能插入的位置while(tmp) {if(timer->expire < tmp->expire){prev->next = timer;timer->next = tmp;tmp->prev = timer;timer->prev = prev;break;}prev = tmp;tmp = tmp->next;}if(!tmp){prev->next = timer;timer->prev = prev;timer->next = NULL;tail = timer;}}
private:util_timer *head;util_timer *tail;
};
#endif

处理非活动连接

// 11_3_closeUnactiveConnections.cpp
// 利用alarm函数周期性触发 SIGALRM信号
// 该信号的信号处理函数利用管道通知主循环执行定时器链表上的定时任务即关闭非活动链接
// 一个用户对应一个连接fd、一个定时器检测是否活跃
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include "lst_timer.h"#define FD_LIMIT 65535  
#define MAX_EVENT_NUMBER 1024
#define TIMESLOT 5static int pipefd[2]; // 管道传输信号
// 利用升序链表管理定时器
static sort_timer_lst timer_lst;
static int epollfd = 0;int setnonblocking(int fd)
{int old_option = fcntl(fd, F_GETFL);int new_option = old_option | O_NONBLOCK;fcntl(fd, F_SETFL, new_option);return old_option;
}void addfd(int epollfd, int fd)
{epoll_event event;event.data.fd = fd;event.events = EPOLLIN | EPOLLET; // 注册可读事件epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);setnonblocking(fd);
}void sig_handler(int sig)
{int save_errno = errno;int msg = sig;send(pipefd[1], (char *)&msg, 1, 0);errno = save_errno;
}void addsig(int sig)
{struct sigaction sa;memset(&sa, '\0', sizeof(sa));sa.sa_handler = sig_handler;sa.sa_flags |= SA_RESTART;sigfillset(&sa.sa_mask); // 设置所有信号// 为信号注册处理函数assert(sigaction(sig, &sa, NULL) != -1);
}void timer_handler()
{// 定时处理任务,检查有没有到时的定时器,执行其对应任务timer_lst.tick();// 重新定时alarm(TIMESLOT); // 到时会发出SIGALARM信号
}// 定时器回调函数,删除非活动连接socket上的注册事件,并关闭之
void cb_func(client_data *user_data)
{epoll_ctl(epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0);assert(user_data);close(user_data->sockfd);printf("close fd %d\n", user_data->sockfd);
}int main(int argc, char *argv[])
{if (argc <= 2){printf("usage: %s ip_address port_num\n", basename(argv[0]));return 1;}const char *ip = argv[1];int port = atoi(argv[2]);int ret = 0;struct sockaddr_in addr;bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;inet_pton(AF_INET, ip, &addr.sin_addr);addr.sin_port = htons(port);// 创建TCP socket,并将其绑定到端口port上int listenfd = socket(PF_INET, SOCK_STREAM, 0);assert(listenfd >= 0);// 设置端口复用int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));ret = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));assert(ret != -1);ret = listen(listenfd, 5);assert(ret != -1);epoll_event events[MAX_EVENT_NUMBER];int epollfd = epoll_create(5);assert(epollfd != -1);addfd(epollfd, listenfd);// 管道ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd);assert(ret != -1);setnonblocking(pipefd[1]); // 设置写端非阻塞addfd(epollfd, pipefd[0]); // 将读端加入epoll树中进行监视// 设置信号处理函数addsig(SIGALRM); // SIGALRM 到来往管道写端发送信号的数值addsig(SIGTERM);bool stop_server = false;client_data *users = new client_data[FD_LIMIT]; // 客户端数组bool timeout = false;alarm(TIMESLOT);while(!stop_server) {int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);if((number < 0) && (errno != EINTR)){printf("epoll failure\n");break;}for(int i = 0; i < number; ++i){int sockfd = events[i].data.fd;if(sockfd == listenfd){struct sockaddr_in client_address;socklen_t client_addrlength = sizeof(client_address);int connfd = accept(listenfd, (sockaddr*)&client_address, &client_addrlength);addfd(epollfd, connfd); // users[connfd].address = client_address;users[connfd].sockfd = connfd;// 创建定时器,设置其回调函数与超时时间,然后绑定定时器与用户数据// 最后将定时器添加到链表 timer_lst中util_timer *timer = new util_timer;timer->user_data = &users[connfd];timer->cb_func = cb_func;time_t cur = time(NULL);// 设置过期时间,当前时间超过该时间就要回收该定时器绑定的connfdtimer->expire = cur + 3 * TIMESLOT;users[connfd].timer = timer;timer_lst.add_timer(timer);}// 处理信号else if((sockfd == pipefd[0]) && (events[i].events & EPOLLIN)){int sig;char signals[1024];// 管道读端接受数据// send是在SIGARLRM和SIGTERM信号被触发时,通过sig_handler函数来调用的ret = recv(pipefd[0], signals, sizeof(signals), 0);if(ret == -1){continue; // 处理下一个到来的事件}else if(ret == 0){continue;}else{for(int i = 0; i < ret; ++i){switch(signals[i]){case SIGALRM:{// timeout标志有定时任务要处理// 但不立即处理,因为通常定时任务优先级不高timeout = true;break;}case SIGTERM:{stop_server = true;}}}}}// 处理客户连接上收到的数据else if(events[i].events & EPOLLIN){memset(users[sockfd].buf, BUFFER_SIZE - 1, 0);ret = recv(sockfd, users[sockfd].buf, BUFFER_SIZE - 1, 0);printf("get %d bytes of client data %s from %d \n", ret, users[sockfd].buf, sockfd);util_timer *timer = users[sockfd].timer;if(ret < 0){if(errno != EAGAIN){cb_func(&users[sockfd]); // 回收connfdif(timer){timer_lst.del_timer(timer);}}}else if(ret == 0){// 若对方关闭连接,则我们也关闭连接并删除定时器cb_func(&users[sockfd]);if(timer){timer_lst.del_timer(timer);}}else{// 若某个客户的连接上有数据可读// 则要调整对应的定时器的过期时间(通过users数组找到定时器)if(timer){time_t cur = time(NULL);timer->expire = cur + 3 * TIMESLOT;printf("adjust timer once\n");timer_lst.adjust_timer(timer);}else{// other}}}}// 最后处理定时事件,因为通常IO事件有更高的优先级// 但这样导致定时任务不能精确的执行if(timeout){timer_handler(); // 检查是否有到时(太久没有使用)的定时器(对应一个用户的connfd),有就回收fd删除定时器timeout = false;}}close(listenfd);close(pipefd[1]);close(pipefd[2]);delete []users;return 0;
}

测试

目录结构

.
├── 11_3_closeUnactiveConnections.cpp
├── build
├── CMakeLists.txt
└── lst_timer.h

输入编译指令

g++ -o closeConnection 11_3_closeUnactiveConnections.cpp -I ./

也可以使用CMake

cmake_minimum_required (VERSION 2.8)
PROJECT(closeConnection)
# 手动加入文件
SET(SRC_LIST 11_3_closeUnactiveConnections.cpp)#INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/dir1")
# 相对路径的方式
INCLUDE_DIRECTORIES(.)# 用SRC_LIST所存的名字的源文件来生成可执行文件 darren
ADD_EXECUTABLE(closeConnection ${SRC_LIST} )

执行程序

在本机任意地址的6666端口监听,同一个机器上不同会话使用客户端程序连接服务器

情况1

当客户端连接上服务器后,若socket在三次tick时间里没有IO操作,第四次tick时就回收socket。

服务器

在这里插入图片描述

客户端

在这里插入图片描述

情况2

当客户端连接上服务器后,若socket在三次tick时间里有IO操作,就会续上3次tick的时间( 3 * TIMESLOT)。

如下在第二次tick后,客户端向服务器发送了一条数据 hello

服务器

在这里插入图片描述

客户端

在这里插入图片描述

相关文章:

利用升序定时器链表处理非活动连接

参考自游双《Linux高性能服务器编程》 背景 服务器同常需要定期处理非活动连接&#xff1a;给客户发一个重连请求&#xff0c;或关闭该连接&#xff0c;或者其他。我们可以通过使用升序定时器链表处理非活动连接&#xff0c;下面的代码利用alarm函数周期性的触发SIGALRM信号&a…...

MySQL 开发规范

一、数据库命名规范所有数据对象名称必须小写 :​​db_user​​禁止使用MySQL 保留关键字&#xff0c;若是则引用 临时表以​​tmp_​​​ 开头&#xff0c;备份表以​​bak_​​ 开头并以时间戳结尾所有存储相同数据的列名和列类型必须一致二、数据库基本设计规范​​1、MySQL…...

【C语言进阶】预处理与程序环境

目录一.详解编译与链接1.前言2.翻译环境3.剖析编译过程4.运行环境二.预处理详解1.预定义符号2.剖析#define(1).定义标识符(2).定义宏(3).替换规则(4).#和##(5).宏与函数的对比(6).#undef3.条件编译4.文件包含(1).头文件包含的方式(2).嵌套文件包含一.详解编译与链接 1.前言 在…...

【Docker知识】将环境变量传递到容器

一、说明 程序通常通过与软件捆绑在一起的配置来控制操作&#xff0c;环境变量允许用户在运行时设置它们。但是&#xff0c;在 Docker 容器中运行进程会使事情变得复杂&#xff0c;那么如何将环境变量传递给容器呢&#xff1f;下面介绍若干个传递办法。 二、环境变量有何用途 环…...

Allegro如何更改铜皮显示密度操作指导

Allegro如何更改铜皮显示密度操作指导 用Allegro做PCB设计的时候,铜皮正常显示模式如下图 铜皮的密度是基本填充满的,Allegro支持更改铜皮的显示密度 如下图 如何更改密度,具体操作如下 点击setup...

ThinkPHP5酒店预订管理系统

有需要请私信或看评论链接哦 可远程调试 ThinkPHP5酒店预订管理系统一 介绍 此酒店预订管理系统基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;采用了ueditor富文本编辑器。系统角色分为用户&#xff0c;员工和管理员。用户可注册登录并预订酒店和评论等&#xff…...

【MySQL】MyCat分库分表分片规则配置详解与实战(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建工设优化。文章内容兼具广度深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于知名金融公…...

OpenWrt路由器设置域名动态解析手把手教程

文章目录0、前言1、准备工作2、详细步骤2.1、OpenWrt路由器软件包安装2.2、防火墙放行入站数据&#xff08;修改为“接受”并保存应用&#xff09;2.3、域名解析服务商对域名的解析设置2.4、路由器中动态域名插件的设置0、前言 因为一直用着内网穿透&#xff08;zerotier或者是…...

java流浪动物救助系统(毕业设计)

项目类型&#xff1a;Java web项目/Java EE项目&#xff08;非开源&#xff09; 项目名称&#xff1a;基于JSPServlet的流浪动物救助网站[dwjz_web] 进行源码获取 用户类型&#xff1a;双角色&#xff08;爱心人士、管理员&#xff09; 项目架构&#xff1a;B/S架构 设计思…...

阿里代码规范插件中,Apache Beanutils为什么被禁止使用?

在实际的项目开发中&#xff0c;对象间赋值普遍存在&#xff0c;随着双十一、秒杀等电商过程愈加复杂&#xff0c;数据量也在不断攀升&#xff0c;效率问题&#xff0c;浮出水面。 问&#xff1a;如果是你来写对象间赋值的代码&#xff0c;你会怎么做&#xff1f; 答&#xf…...

NFC enable NFC使能流程

同学,别退出呀,我可是全网最牛逼的 WIFI/BT/GPS/NFC分析博主,我写了上百篇文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。 NFC enable NFC使能流程 认识nfc系统如何工作,最好的方法就是了解nfc的各个流程,…...

Redis实例绑定CPU物理核优化Redis性能

进入本次Redis性能调优之前&#xff0c;首先要知道CPU结构也会影响Redis的性能。接下来&#xff0c;具体了解一下&#xff01;为什么CPU结构也会影响Redis的性能&#xff1f;主流的 CPU 架构一个 CPU 处理器中一般有多个物理核&#xff0c;每个物理核都可以运行应用程序。每个物…...

STC15中断系统介绍

STC15中断系统介绍✨本篇参考来源于STC官方stc15系列手册:538页- 589页。&#xff08;文末提供该摘取部分的文档资料&#xff09; &#x1f389;在官方提供的手册资料中&#xff0c;一个系列一份手册&#xff0c;手册内容涵盖了数据手册和参考手册以及例程案例。对于学习着来说…...

力扣HOT100 11-15

11.盛水最多的容器 思路&#xff1a;最大水量 底边 * 高度。较短的一边控制最大水量&#xff0c;因此&#xff0c;采用双指针的方式&#xff0c;左、右指针指向开始和末尾&#xff0c;逐个向中间移动&#xff0c;判断左右指针所指向的高度哪个更低&#xff0c;它就向中间移动一…...

深入浅出单调栈与单调队列

目录一、单调栈情形一&#xff1a;寻找一个数左边第一个小于它的数情形二&#xff1a;寻找一个数左边第一个小于它的数的下标情形三&#xff1a;寻找一个数右边第一个大于它的数情形四&#xff1a;寻找一个数右边第一个大于它的数的下标二、单调栈的应用2.1 单调栈模板题I2.2 单…...

深入C语言——实现可变参数函数

文章目录初步示例函数解析最大值函数初步示例 stdarg.h提供了C语言对可变参数的支持&#xff0c;先举一个简短的例子 //testStdArg.c #include <stdarg.h> #include <stdio.h>void printIntList(int N, ...){va_list args; //存放...所代表的参数va_start(…...

41-Dockerfile-Dockerfile简介

Dockerfile简介前言Dockerfile 简介基础知识使用Dockerfile 构建镜像步骤Dockerfile 构建过程Dockerfile基本结构Dockerfile示例总结前言 本篇开始来学习下Dockerfile相关的用法 Dockerfile 简介 Dockerfile : 是用来构建 Docker 镜像的文本文件&#xff0c;是有一条条构建镜…...

【408】操作系统 - 刻骨铭心自测题1(上)

文章目录OS练习题第一部分&#xff1a;1&#xff1a;2&#xff1a;3&#xff1a;4&#xff1a;5&#xff1a;6&#xff1a;7&#xff1a;8&#xff1a;9&#xff1a;10&#xff1a;11&#xff1a;12&#xff1a;13&#xff1a;14&#xff1a;15&#xff1a;16&#xff1a;17&am…...

【老卫拆书】009期:Vue+Node肩挑全栈!《Node.js+Express+MongoDB+Vue.js全栈开发实战》开箱

今天刚拿到一本新书&#xff0c;叫做《Node.jsExpressMongoDBVue.js全栈开发实战》&#xff0c;做个开箱。 外观 先从外观上讲&#xff0c;这本是全新的未开封的&#xff0c;膜还在。 这本书介绍从技术原理到整合开发实战&#xff0c;以丰富的项目展现全栈开发的一个技巧。 …...

【LeetCode】动态规划总结

动态规划解决的问题 动态规划和贪心的区别&#xff1a; 动态规划是由前一个状态推导出来的&#xff1b; 贪心是局部直接选最优的。 动态规划解题步骤 状态定义&#xff1a;确定dp数组以及下标的含义状态转移方程&#xff1a;确定递推公式初始条件&#xff1a;dp如何初始化遍历…...

CAS详解.

CAS这个机制就给实现线程安全版本的代码&#xff0c;提供了一个新的思路&#xff0c;之前通过加锁&#xff0c;把多个指令打包成整体&#xff0c;来实现线程安全。现在就可以考虑直接基与CAS来实现一些修改操作&#xff0c;也能保证线程安全&#xff08;不需要加锁&#xff09;…...

Mock.js初步使用(浏览器端)

Mock.js&#xff1a;生成随机数据&#xff0c;拦截 Ajax 请求。官方地址&#xff1a;http://mockjs.com/第一个demodemo.html<!DOCTYPE html> <html> <head><meta charset"utf-8"><title>mockjs demo</title> </head> <…...

opencv保存图片

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…...

【c++】数据类型

文章目录整型实型科学计数法sizeof关键字字符型字符串类型转义字符bool布尔类型c规定在创建一个变量或者常量时&#xff0c;必须要指定出相应的数据类型&#xff0c;否则无法给变量分配内存。 整型 作用&#xff1a;整型变量表示的是整数类型的数据。 实型 float f3.14; //默…...

Elasticsearch的写的底层原理

前面有一篇文章讲解了Elasticsearch的读写搜索过程&#xff0c;有的人感觉不太理解&#xff0c;今天我们再来看看这些过程的原理 写数据底层原理 首先是将数据写入到内存buffer中&#xff0c;在这里的时候&#xff0c;数据是搜索不到。他同时会将数据写入到translog日志文件中…...

【网络编程】Java中的Socket

文章目录前言socket是什么&#xff1f;Java中的SocketJava实现网络上传文件前言 所谓Socket&#xff08;套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用…...

有趣的Hack-A-Sat黑掉卫星挑战赛——跟踪卫星

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加&#xff0c;太空已经成为国家赖以生存与发展的命脉之一&#xff0c;凝聚着巨大的国家利益&#xff0c;太空安全的重要性日益凸显[1]。而在信息化时代&#xff0c;太空安…...

Ubuntu安装配置Cuda和Pytorch gpu

前言 在Ubuntu中操作系统中,通过Anconda安装对应的虚拟环境以及软件包,一般都需要适配Cuda、Pytorch版本等 以下安装配置都是在Ubuntu操作系统下 1. 安装Cuda 通过Ubuntu操作系统查看cuda适配的版本:nvidia-smi 截图如下: 查看Ubuntu版本可如下方式 (1)cat /proc/ver…...

三、Java面向对象

1 . 方法 方法(method)是程序中最小的执行单元方法就是一些代码的打包 需要的时候可以直接调用方法之间是平级的关系 不能在方法里面定义方法方法不调用就不执行 方法的定义 // 方法的定义 /* [修饰符] 返回值类型 方法名称([参数 1],[参数 2]){语句A;return 返回值; } *///…...

pygame7 弹球游戏2

上节课我们做到当球静止下来后在第0号球上画一个球杆 本节课我们将会让这个球杆将球打出来 1、鼠标事件 pygame.mouse.get_pressed():返回鼠标左键&#xff0c;中间&#xff0c;右键的情况 2、键盘事件&#xff1a; pygame.key.get_pressed(): 返回所有键盘的情况 3、pyg…...