网络编程5之poll、epoll、超时检测

2023-11-13

1.poll机制

poll的实现和select非常相似,只是文件描述符fd集合的方式不同。

poll使用struct pollfd结构而不是select的fd_set结构,其他的都差不多。

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:poll机制

参数:
    fds:struct pollfd类型的数组
    nfds:准备的文件描述符的个数
    timeout:-1 阻塞,直到文件描述符准备好

返回值:
     成功返回准备好的文件描述符的个数,失败返回-1
            
        truct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
              };
                 fd:文件描述符;
                 event:请求的事件(读、写、异常)
                 revents:对请求事件的反馈(读、写、异常)
          POLLIN:读事件
          POLLOUT:写事件
          
        eg:
            

struct pollfd fds[3];

    memset(fds,0,sizeof(fds));
    fds[0].fd=fd1;
    fds[0].events=POLLIN;

eg: tcpserver_poll.c

/*===============================================
*   文件名称:tcpserver_select.c
*   创 建 者:     
*   创建日期:2022年08月19日
*   描    述:
================================================*/
/*===============================================
*   文件名称:clinet_unix_udp.c
*   创 建 者:     
*   创建日期:2022年08月18日
*   描    述:
================================================*/
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{ 
    
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        return -1;
    }
	
	//端口复用
	int on =1;
	int k = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	if(k<0)
	{
		perror("setsockopt");
		return -1;
	}
	
	struct sockaddr_in server;
	memset(&server,0,sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(8888);
	server.sin_addr.s_addr=inet_addr("0");
	
	int len = sizeof(server);
	
	int ret = bind(sockfd,(struct sockaddr *)&server,len);
	if(ret<0)
	{
		perror("bind");
		return -1;
	} 
	
	ret =listen(sockfd , 5);
	if(ret<0)
	{
		perror("listen");
		return -1;
	}

	//1.创建结构体数组
	struct pollfd fds[100];
	//2.清空数组
	memset(&fds,0,sizeof(fds));
	
	//3.添加第一个元素
	fds[0].fd=sockfd;
	fds[0].event=POLLIN;
	
	int m = 1;//结构体数组的长度
	int n = 1;//结构体数组的下标
	int i;
	
	char buf[64] ={0};
		
	while(1)
	{
		
		
		ret = poll(fds,m,-1);//阻塞,直到有文件描述符准备好
		if(ret<0)
		{
			perror("select");
			return -1;
		}
		
		for(i=0;i<m;i++)//检测谁准备好
		{
			if(fds[i].revents & POLLIN )//i准备好
			{
				int fd = fds[i].fd;
				if(fd==sockfd)	//处理sockfd,建立连接
				{
					int connfd = accept(i,NULL,NULL);
					if(connfd<0)
					{
						perror("accept");
						return -1;
					}
					printf("%d is link\n",connfd);
					
					n=connfd-sockfd;
					fds[n].fd=connfd;
					fds[n].event=POLLIN;
					if(m<connfd-2)	//m代表下标的最大值
					{
						m=connfd-2;	
					}
				}
				else//connfd准备好
				{
					ret = recv(fd,buf,sizeof(buf),0);
					if(ret<0)
					{
						perror("recv");
						return -1;
					}
					else if(ret==0)
					{
						printf("%d is unlink\n",fd);
						memset(&fds[i],0,sizeof(fds[i]));//删除队列
						
					}
					else
					{
						printf("%d :message =%s\n",i,buf);
						memset(buf,0,sizeof(buf));
					}
				}
				
			}
		}
	}
	

   close(sockfd);
    
    return 0;
} 

2.epoll机制

1.epoll使用红黑树来管理所有的文件描述符集合,不受大小限制,更新集合时,不需 要重新拷贝整个集合,直接更新红黑树即可

2.利用call back来知道文件描述符是否就绪,只关心已经就绪的文件描述符,不需要遍 历所有的文件描述符。

1.epoll_create

#include <sys/epoll.h>

int epoll_create(int size);

功能:创建一棵树
    
参数:
    size:树的节点
返回值:
    成功返回准备好的文件描述符epfd,失败返回-1

2.epoll_ctl

#include <sys/epoll.h>

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能:控制epoll

参数:
    epfd:epoll_create的返回值
    op:
        EPOLL_CTL_ADD:添加文件描述符
        EPOLL_CTL_DEL:删除文件描述符
    fd:准备好的文件描述符
    event:指定的结构体(一个)
    
返回值:
    成功返回0,失败返回-1;

    typedef union epoll_data {
               void        *ptr;
               int          fd;
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;

           struct epoll_event {
               uint32_t     events;      /* Epoll events */
               epoll_data_t data;        /* User data variable */
           };
            events:
                EPOLLIN:读事件
                EPOLLOUT:写事件
           
    eg:
        struct epoll_event ev;
        ev.events=;//事件
        ev.data.fd;//

3.epoll_wait

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

功能:
    等待文件描述符就绪
    
参数:
    epfd:epoll_creat的返回值
    events:指定的结构体数组;
        struct epoll_event evs[size];//结构体数组
    maxevents:[size]
    time_out:超时检测,-1阻塞,等待文件描述符就绪    

返回值:
    成功,返回准备好的文件描述符,没有准备好的返回0;
    失败返回-1;

/*===============================================
*   文件名称:tcpserver_select.c
*   创 建 者:     
*   创建日期:2022年08月19日
*   描    述:
================================================*/
/*===============================================
*   文件名称:clinet_unix_udp.c
*   创 建 者:     
*   创建日期:2022年08月18日
*   描    述:
================================================*/
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>


int main(int argc, char *argv[])
{ 
    
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        return -1;
    }
	
	//端口复用
	int on =1;
	int k = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	if(k<0)
	{
		perror("setsockopt");
		return -1;
	}
	
	struct sockaddr_in server;
	memset(&server,0,sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(8888);
	server.sin_addr.s_addr=inet_addr("0");
	
	int len = sizeof(server);
	
	int ret = bind(sockfd,(struct sockaddr *)&server,len);
	if(ret<0)
	{
		perror("bind");
		return -1;
	} 
	
	ret =listen(sockfd , 5);
	if(ret<0)
	{
		perror("listen");
		return -1;
	}

	//1.创建一课树
	int epfd = epoll_create(1003);
	if(epfd<0)
	{
		perror("epoll_create");
		return -1;
	}
	//2.添加到树中
	struct epoll_event ev,evs[100];//ev用于修改evs
	ev.events = EPOLLIN;	//设置为增加
	ev.data.fd = sockfd;	
	epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);//通过epfd把ev加到树中
	
	int m,i;//m用于接收epoll_wait的返回值,准备就绪的文件描述符
		//i用于循环
	
	char buf[64] ={0};
			
	while(1)
	{
		m = epoll_wait(epfd,evs,100,-1);
		if(m==-1)
		{
			perror("epoll_wait");
			return -1;
		}
		for(i=0;i<m;i++)
		{
			if(evs[i].events & EPOLLIN)//事件是可读的
			{
				int fd = evs[i].data.fd;
				if(fd==sockfd)//处理sockfd,建立连接
				{
					int connfd = accept(fd,NULL,NULL);
					printf("%d is link\n",connfd);
					
					ev.events = EPOLLIN;
					ev.data.fd = connfd;
					epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);//把connfd添加到树中
				}
				else//处理connfd
				{
					ret = recv(fd,buf,sizeof(buf),0);
					if(ret<0)
					{
						perror("recv");
					}
					else if(ret == 0)
					{
						printf("%d is unlink\n",fd);
						epoll_ctl(epfd,EPOLL_CTL_DEL,fd,&ev);//从树中删除fd
						close(fd);
					}
					else
					{
						printf("%d message=%s\n",fd,buf);
						memset(buf,0,sizeof(buf));	
					}
				}
			}
		}		
	}
	

   close(sockfd);
    
    return 0;
} 

3.超时检测

方法1:设置套接字属性,设置超时值

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>

int tcpserver_init(int port);
int recv_data(int connfd);

int main(int argc, const char *argv[])
{

	int sockfd = tcpserver_init(6666);

	struct sockaddr_in clientaddr;
	
	int m = sizeof(clientaddr);

	while(1)
	{
		printf("wait a client.............\n");

		//connfd 进行数据的收发
		int connfd = accept(sockfd,  (struct sockaddr *)&clientaddr , &m );
		if(connfd < 0)
		{
			perror("accept");
			return -1;
		}

		printf("client ip: %s client port: %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

		struct  timeval tv = {5,0}; 

		setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

		recv_data(connfd);
	}

	close(sockfd);

	return 0;
}



int tcpserver_init(int port)
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("sockfd");
		return -1;
	}

	printf("sockfd = %d\n", sockfd);

	//端口复用函数:解决端口号被系统占用的情况
	int on = 1;
	int k = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	if(k == -1)
	{
		perror("setsockopt");
		return -1;
	}

	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0 ,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(port);
	serveraddr.sin_addr.s_addr = inet_addr("0"); //自动路由,寻找IP地址

	int len = sizeof(serveraddr);

	int ret = bind(sockfd, (struct sockaddr *)&serveraddr, len);
	if(ret == -1)
	{
		perror("bind");
		return -1;
	}


	ret = listen(sockfd, 5);
	if(ret == -1)
	{
		perror("listen");
		return -1;
	}

	return sockfd;
}

int recv_data(int connfd)
{
		//接收和发送数据
		char buf[1024] = {0};

		while(1)
		{
			int n = recv(connfd, buf, sizeof(buf), 0);	
			if(n < 0)
			{
				printf("%d\n", errno);
				if(errno == 11)
				{
					printf("overtime\n");
					continue;
				}

				perror("read");
				return -1;
			}
			else if(n == 0) //客户端关闭了
			{
				close(connfd);
				break;	
			}

			printf("message:%s\n", buf);

			memset(buf, 0 , sizeof(buf));
		}

		return 0;
}

方法2:设置闹钟

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>

int tcpserver_init(int port);
int recv_data(int connfd);

void signal_handler(int sig)
{
	printf("overtime\n");
	//......
}

int main(int argc, const char *argv[])
{
	signal(SIGALRM, signal_handler);

	alarm(5);

	int sockfd = tcpserver_init(6666);

	struct sockaddr_in clientaddr;
	
	int m = sizeof(clientaddr);

	while(1)
	{
		printf("wait a client.............\n");

		//connfd 进行数据的收发
		int connfd = accept(sockfd,  (struct sockaddr *)&clientaddr , &m );
		if(connfd < 0)
		{
			perror("accept");
			return -1;
		}

		printf("client ip: %s client port: %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

		recv_data(connfd);
	}

	close(sockfd);

	return 0;
}



int tcpserver_init(int port)
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("sockfd");
		return -1;
	}

	printf("sockfd = %d\n", sockfd);

	//端口复用函数:解决端口号被系统占用的情况
	int on = 1;
	int k = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	if(k == -1)
	{
		perror("setsockopt");
		return -1;
	}

	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0 ,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(port);
	serveraddr.sin_addr.s_addr = inet_addr("0"); //自动路由,寻找IP地址

	int len = sizeof(serveraddr);

	int ret = bind(sockfd, (struct sockaddr *)&serveraddr, len);
	if(ret == -1)
	{
		perror("bind");
		return -1;
	}


	ret = listen(sockfd, 5);
	if(ret == -1)
	{
		perror("listen");
		return -1;
	}

	return sockfd;
}

int recv_data(int connfd)
{
		//接收和发送数据
		char buf[1024] = {0};

		while(1)
		{
			int n = recv(connfd, buf, sizeof(buf), 0);	
			if(n < 0)
			{
				perror("read");
				return -1;
			}
			else if(n == 0) //客户端关闭了
			{
				close(connfd);
				break;	
			}

			printf("message:%s\n", buf);

			memset(buf, 0 , sizeof(buf));
		}

		return 0;
}

方法3:在select函数 或poll函数中设置超时值

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

int main(int argc, const char *argv[])
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		perror("sockfd");
		return -1;
	}

	printf("sockfd = %d\n", sockfd);

	//端口复用函数:解决端口号被系统占用的情况
	int on = 1;
	int k = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	if(k == -1)
	{
		perror("setsockopt");
		return -1;
	}

	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0 ,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(8888);
	serveraddr.sin_addr.s_addr = inet_addr("0"); //自动路由,寻找IP地址

	int len = sizeof(serveraddr);

	int ret = bind(sockfd, (struct sockaddr *)&serveraddr, len);
	if(ret == -1)
	{
		perror("bind");
		return -1;
	}

	ret = listen(sockfd, 5);
	if(ret == -1)
	{
		perror("listen");
		return -1;
	}

	//select机制	
	fd_set readfds,tmpfds;

	FD_ZERO(&readfds);

	FD_SET(sockfd, &readfds);

	int maxfd = sockfd;

	tmpfds = readfds;

	char buf[64] = {0};

	int  i;

	struct timeval tv = {5, 0};

	while(1)
	{
		readfds = tmpfds;

		ret = select(maxfd+1, &readfds, NULL, NULL, &tv);
		if(ret == -1)
		{
			perror("select");
			exit(-1);
		}
		else if(ret == 0) //超时检测
		{
			printf("overtime\n");
			tv.tv_sec = 2;
			continue;
		}

		for(i=sockfd; i<maxfd+1; i++)
		{
			if(FD_ISSET(i, &readfds))
			{
				if(i== sockfd)
				{
					printf("%d 已经准备好了\n", i);

					//建立连接,用accept函数
					int connfd = accept(i, NULL, NULL);

					printf("%d is link\n", connfd);

					FD_SET(connfd, &tmpfds);

					if(maxfd < connfd)
					{
						maxfd = connfd;
					}
				}

				else{
					
					memset(buf, 0, sizeof(buf));

					//处理connfd
					ret = recv(i, buf, sizeof(buf), 0);
					if(ret == -1)
					{
						close(i);
						perror("recv");
						return -1;
					}
					else if(ret == 0) 
					{
						printf("%d is unlink\n", i);
						FD_CLR(i, &tmpfds);
						close(i);
						break;
					}
					else{

						printf("%d:message=%s\n", i,buf);

					}
				}
			}	

		}

	}

	close(sockfd);

	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络编程5之poll、epoll、超时检测 的相关文章

  • Java正则表达式验证电话号码

    在注册会员时 经常需要输入电话号码 电话号码是指手机号码或者固定电话 如果输入的内容不合法 则会向用户输出提示 本实例模拟实现电话号码的验证功能 接收用户在控制台输入的电话号码 然后进行判断 并将结果输出 在这里使用 Java正则表达式 一
  • 淘宝官方订单API接口,获取售出的商品订单列表(爬虫数据)

    淘宝 天猫获取售出的商品订单列表 API 返回值说明 seller order list 获取售出的商品订单列表 公共参数 名称 类型 必须 描述 key String 是 调用key 必须以GET方式拼接在URL中 获取Key和secre
  • Codeup(云效)手把手教部署SpringCloud项目到私有主机

    博主介绍 小黄鸭技术 擅长领域 Java 实用工具 运维 系列专栏 开发工具 Java之路 八股文之路 如果文章写作时有错误的地方 请各位大佬指正 一起进步 欢迎大家点赞 收藏 评论 支持博主 开通云效 上传代码仓库 配置SSH公钥或者是H
  • 并发编程概览

    由于内容较多 将会分成多篇文章详述 可移步查看 操作系统发展史 多道技术 进程理论 进程的并行与并发 进程的三状态 同步与异步 阻塞与非阻塞 同步异步与阻塞非阻塞 创建进程的多种方式 join方法 进程间数据默认隔离 进程间通信IPC机制
  • Java GUI编程——在线聊天室

    引言 综合应用Java的GUI编程和网络编程 实现一个能够支持多组用户同时使用的聊天室软件 该聊天室具有比较友好的GUI界面 并使用C S模式 支持多个用户同时使用 用户可以自己选择加入或者创建房间 和房间内的其他用户互发信息 文字和图片
  • 09 插件开发快速入门

    V5标准架构模型 V5平台基于三层模型开发 下面是相关架构图 建议认真阅读业务流向 入门 字符集 为了实现国际化编程 全局要求使用UTF 8的字符集编码 包括 数据库 参考安装维护手册配置字符集 文件 java properties jsp
  • 在JSP中弹出信息框

    下面我以登录界面的代码为例子 在LoginServlet中 判断验证码是否正确 忽略大小写 if attribute equalsIgnoreCase user getCheckCode User login new UserDao log
  • 进阶java大师之路,泛型在hashmap上的灵活运用

    由于 公司的试用的框架上 存在大量的hashmap的创建 产生大量的I O 以及内存的消耗 所以 抽了点时间 看书 effective java 这本书 同时 也从项目的作者 framework 上学习 吸取 最终写出了 符合生产的方案 存
  • Java代码判断当前操作系统是Windows或Linux或MacOS

    package com magic system public class SystemUtils 判断操作系统是否是 Windows return true 操作系统是 Windows false 其它操作系统 public static
  • JavaWeb05(删除&增加&修改功能实现&连接数据库)

    目录 一 实现删除功能 1 1 url如何传参 xx do 参数 参数值 参数名 参数值 1 2 servlet如何拿对应值 根据参数名拿到对应的参数值 String str req getParameter 参数名 1 3 如何询问 nc
  • DNS使用TCP与UDP

    DNS同时占用UDP和TCP端口53是公认的 这种单个应用协议同时使用两种传输协议的情况在TCP IP栈也算是个另类 但很少有人知道DNS分别在什么情况下使用这两种协议 先简单介绍下TCP与UDP TCP是一种面向连接的协议 提供可靠的数据
  • Servlet 和 Cookie-Session 学习笔记(基础)

    简单来说 是运行在服务器端的 Java 程序 它作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层 用处 使用 Servlet 您可以收集来自网页表单的用户输入 呈现来自数据库或者其他
  • STC仿真失败

    原因就是购买的下载工具不适合在烧写STC8H3K64S仿真固件后再将该下载工具作为USB转串口工具连接PC与目标板 推测是接入仿真时会重启目标板 不打算细究 换一个普通串口就好了
  • 外观设计模式

    外观设计模式 根据实际案例分析外观模式 Facade 示例 业务与设计模式落地案例 根据实际案例分析外观模式 Facade 案例 假设一个放电影功能 在播放电影时 需要放下窗帘 打开空调 打开播放机 打开音响 考虑用户观影时间较长时 提供暂
  • jsp+servlet+ajax实现登录

    该案列使用jsp servlet ajax实现登录 页面简洁大方 弹框都是封装的插件 整体案列采用三层的模式 链接数据库方面用的是dbcp的链接池 数据库时mysql 运行效果如下图 下载地址 jsp servlet ajax实现登录案例
  • Mybatis+Servlet+Mysql 整合的一个小项目:对初学者非常友好,有助于初学者很快的上手Java Web

    文章目录 前言 为何要写 目录结构 1 依赖配置 1 1 创建一个web项目 1 2 依赖需求分析 1 3 pom xml 2 配置Mybatis 2 1 mybatis config xml 2 2 UserMapper xml 2 3
  • this调用本类的其他构造器

    Student类 package Java project 1 public class Student private String name private String schoolName public Student public
  • 通过python程序调取摄像头画面

    目录 1 方法 2 演示代码 3 总结 1 方法 想要调取摄像头画面有这么几个前提 需要使用网络摄像头并且支持RTSP协议 摄像头要和你的电脑在同一个局域网下 需要知道摄像头的账号 密码 IP地址 RTSP协议是一种网络传输协议 不同的摄像
  • 泛型与反射机制在JDBC和Servlet编程中的实践

    写在前面 泛型与反射是java中的两种强大机制 可以很好的提高代码的灵活性和复用性 本篇文章向大家展现在JDBC和Servlet编程场景下反射和泛型技术的实践 通过灵活使用这两种机制打造 高度可复用的JDBC和Servlet代码 1 JDB
  • JavaWeb——第五章 Servlet

    第五章 Servlet 一 Servlet简介 1 1 动态资源和静态资源 1 2 Servlet简介 二 Servlet开发流程 2 1 目标 2 2 开发过程 三 Servlet注解方式配置

随机推荐

  • pandoc提取word中的图片

    pandoc提取word中的图片 pandoc i xxx docx o xxx tex extract media pathName 会将word中的图片提取到 pathName下的media中 如图所示 更多参数可以参考pandoc的用
  • vi编辑器的使用(2)

    接上篇vi编辑器的使用 1 1 4 光标移动 vi编辑器中的很多命令都是基于光标当前位置的 因此 如何移动光标定位到所需要的位置是一项十分重要的工作 下面进行详细介绍 如无特别说明 下面所讲的命令都是在普通模式下执行 1 向前移动字符 将光
  • [4G/5G/6G专题基础-150]: 6G总体愿景与潜在关键技术白皮书解读-5-缩略语释义

    目录 前言 附录 AI 人工智能 AR 增强现实 Augmented Reality 简称AR DT 数字孪生 MR 混合现实技术 MTP 头动响应 DOICT 数字 运营 信息 通信 FDD 频分双工 FTN 超奈奎斯特准则 IHR 智能
  • 2022跨年-跨年倒计时(烟花)

    前言 2022 HAPPY NEW YEAR 马上都是新的一年了 岁末已至 是结束也是开始 不管这一年好和坏 都将结束 愿来年有趣有盼 无灾无难 你我都要平安才好 善良勇敢 跨年倒计时制作步骤 步骤一 首先在电脑桌面新建txt文本文档 如下
  • 【案例】某物流集团:用数据驱动企业数字化转型

    数据猿导读 数据驱动的数字化转型是一个体系化工作 需要从理论体系 平台工具 数据 组织 机制五个方面 着手 建一个企业级的数据资产平台 梳理清晰整个集团的数据资产 并借助数据和智能的算法 在数据资产中发现新的业务价值点 创新产品和服务 从而
  • 什么是用户体验五要素

    这里是修真院pm小课堂 每篇分享文从 背景介绍 知识剖析 常见问题 解决方案 编码实战 扩展思考 更多讨论 参考文献 八个方面深度解析pm知识 技能 本篇分享的是 什么是用户体验五要素 背景介绍 用户体验五要素是以用户为中心的产品设计 本次
  • Git提交代码到新建的工程

    Git 全局设置 git config global user name luge git config global user email epi 163 com 创建 git 仓库 mkdir flink cd flink git in
  • ModelAndView 传值到 jsp页面 $ 不能取值的原因

    web xml 约束头配置有误 原来不可以的
  • 打开新窗口不用window.open的替代方法

    实现脚本如下
  • ubutnu vins_fisheye编译错误 hidden symbol“ “ in“ “ is referenced by DSO

    usr bin ld home mwy vins fisheye devel lib vins vins node hidden symbol ZN5ceres12CostFunctionD2Ev in usr local lib libc
  • docker centos6 ssh 自启动

    docker centos6 自启动ssh服务 前期准备 下载centos6 6版本镜像 启动容器完善容器环境 修改登录密码 更换yum源地址 推荐使用阿里源http mirrors aliyun com repo Centos 6 rep
  • Linux 磁盘管理,分区,文件系统

    目录 磁盘基本概念 磁盘在Linux中的表示 分区的概念 分区是软件概念 MBR GPT 使用fdisk进行磁盘管理 文件系统 mke2fs mkfs mke2fs mkfs dumpe2fs 日志 e2label fsck file sy
  • 开源学习组织:Datawhale

    这篇文章其实最早成立Datawhale的时候写的 那时候我们还是在读的学生 以下文字一直没有更新 一是希望提醒我们不要忘记初心 二是希望让大家知道 当Datawhale陪伴了学习者成长 做成了一些事 它的起源只是因为播下了一颗理想的种子 申
  • Android12 ---- Material You 应用

    背景 Google android S 新特性 当你更换壁纸 整个手机主题的颜色会根据壁纸的配色方案而改变 也就说 每当你更新壁纸 你的手机界面也会焕然一新 当用户在 Android 12 设备上更改壁纸时 系统会分析图像以选择一种颜色 并
  • Xcode 4 常用快捷键(和 Xcode 3 有些不一样了)

    Xcode 4 常用快捷键 和 Xcode 3 有些不一样了 2011 06 16 Unmi 把 Xcode 由 3 2 5 升级到 Xcode 4 0 2 之后 满以为快捷键总该不会变化太大吧 没想又要经历一个快捷键的适应过程 发现有些在
  • 思维能力的学习

    前言 在工作中 随着工作时间的增长 我们与他人的差异不是知识本身的差异 主要是思维方面的差异 所以我们需要培养自己的思维能力 思维能力的学习 思维是一个具备内在框架和逻辑的系统工程 思维覆盖了学习 认知 问题解决和复盘以及知识库多维度的内容
  • 华为出品Python入门教程:从零基础入门到精通,这一篇就够了

    前言 本文罗列了了python零基础入门到精通的详细教程 内容均以知识目录的形式展开 01 python由来与发展介绍 02 项目开发流程 第一章 markdown编辑器 01 markdown基本语法 02 Typora简介与安装 03
  • 在QT中使用日志系统

    当写好的软件发布出去后 用户遇到死机或一些其他的bug 我们该怎么追踪这些问题呢 这时候日志系统很好的帮助了我们 最近也是参照网络大牛的博客代码实现了log 下面看看代码吧 void outputMessage QtMsgType type
  • 爬虫篇(2.2)使用scrapy-jsonrpc简单教程

    首先安装scrapy jsonrpc pip install scrapy jsonrpc 打开你的爬虫项目中setting py文件 加入如下代码进行配置 EXTENSIONS scrapy jsonrpc webservice WebS
  • 网络编程5之poll、epoll、超时检测

    1 poll机制 poll的实现和select非常相似 只是文件描述符fd集合的方式不同 poll使用struct pollfd结构而不是select的fd set结构 其他的都差不多 include