C++ 如何正确地为ncurses进行epoll
原始问题:我编写了一些客户端代码,用于监视键盘按下和服务器向其发送消息的sockfd。问题是,在服务器发出第一条消息后,服务器发出的消息不再触发epoll。此外,每次我输入大约10次按键,sockfd就会触发epoll并读取一组字符(即使服务器已经发送了很多消息)。更让我困惑的是,如果我一次只发送一个字符,epoll就能做出正确的反应。任何超过一个的,都将产生与以前相同的结果(epoll不反应) 编辑:我意识到如果我将STDIN_FILENO设置为非阻塞,我将在适当的时间从服务器获取消息。然而,该程序也将进入一个无限循环,而STDIN_总是被触发。我想现在的问题是如何正确地将epoll与ncurses结合使用,这样我们就不会处于无限循环中 这是我的密码: 如何使用:C++ 如何正确地为ncurses进行epoll,c++,sockets,udp,ncurses,epoll,C++,Sockets,Udp,Ncurses,Epoll,原始问题:我编写了一些客户端代码,用于监视键盘按下和服务器向其发送消息的sockfd。问题是,在服务器发出第一条消息后,服务器发出的消息不再触发epoll。此外,每次我输入大约10次按键,sockfd就会触发epoll并读取一组字符(即使服务器已经发送了很多消息)。更让我困惑的是,如果我一次只发送一个字符,epoll就能做出正确的反应。任何超过一个的,都将产生与以前相同的结果(epoll不反应) 编辑:我意识到如果我将STDIN_FILENO设置为非阻塞,我将在适当的时间从服务器获取消息。然而,
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <chrono>
#include <errno.h>
#include <ifaddrs.h>
#include <sys/epoll.h>
#define TO_CLI_BUF_SIZE 32
#define FROM_CLI_BUF_SIZE 8
int main(int argc, char ** argv){
//seed rand
srand(time(NULL));
int sockfd; // socket
int port; // my port to listen on
struct sockaddr_in serveraddr; // server's address
struct sockaddr_in clientaddr;
socklen_t clientlen;
int currentAddrMax = 0;
struct hostent * hostp; //host info
char * hostaddrp; // host adddr string
char toClientBuf[TO_CLI_BUF_SIZE];
char fromClientBuf[FROM_CLI_BUF_SIZE];
if(argc != 2){
perror("usage: file <port>");
exit(1);
}
port = atoi(argv[1]);
// create socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd<0){
perror("ERROR: opening socket.");
exit(1);
}
bzero((char*) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
perror("ERROR on bind");
exit(1);
}
bzero(fromClientBuf, FROM_CLI_BUF_SIZE);
clientlen = sizeof(clientaddr);
int n = recvfrom(sockfd, fromClientBuf,FROM_CLI_BUF_SIZE, 0, (struct sockaddr*) &clientaddr, &(clientlen));
while (1){
bzero(toClientBuf, TO_CLI_BUF_SIZE);
strcpy(toClientBuf, "alkjhkfqulw8fl128lh1oufo183hf1l\0"); // I want to send 32 TO_CLI_BUF_SIZE
int amountOfBytes = TO_CLI_BUF_SIZE; // anything greater than 1 will not work
int n = sendto(sockfd, toClientBuf, amountOfBytes, 0, (struct sockaddr *) &clientaddr, clientlen);
if(n < 0) {
perror("ERROR in sendto");
exit(1);
}
sleep(1); // sleep 1 sec
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义为大小32
#从大小8定义
int main(int argc,字符**argv){
//种子兰德
srand(时间(空));
int sockfd;//套接字
int-port;//要侦听的我的端口
serveraddr中的struct sockaddr\u;//服务器地址
clientaddr中的结构sockaddr_;
socklen_t clientlen;
int currentAddrMax=0;
结构hostent*hostp;//主机信息
char*hostaddrp;//主机adddr字符串
char-TO-clientbuf[TO_CLI_BUF_SIZE];
char fromClientBuf[来自CLI_BUF_SIZE];
如果(argc!=2){
perror(“用法:文件”);
出口(1);
}
端口=atoi(argv[1]);
//创建套接字
sockfd=插座(AF_INET,SOCK_DGRAM,0);
如果(sockfdh_地址,
(char*)&serveraddr.sin\u addr.s\u addr,server->h\u length);
serveraddr.sinu端口=htons(端口号);
serverlen=sizeof(serveraddr);
bzero(到服务器BUF,到服务器BUF大小);
n=sendto(sockfd,toServerBuf,TO_seru BUF_SIZE,0,(struct sockaddr*)和serveraddr,serverlen);
if(n<0){
perror(“错误:发送到”);
出口(0);
}
if(connect(sockfd,(struct sockaddr*)&serveraddr,serverlen)<0){
printf(“\n错误:连接失败\n”);
出口(0);
}
fcntl(sockfd、F_设置FL、O_非块);
节点延迟(stdscr,真);
fcntl(标准文件号、固定格式、非块);
initscr();
noecho();
int keyboardtick=0;
int servertick=0;
int ep=epoll_create1(0);
结构epoll_事件e1,e2,e[2];//e1用于serverfd,e2用于stdin
memset(&e1,0,sizeof(struct-epoll_事件));
e1.events=EPOLLIN;
e1.data.fd=sockfd;
epoll控制(ep、epoll控制添加、sockfd和e1);
memset(&e2,0,sizeof(struct-epoll_事件));
e2.2事件=依泊林;
e2.data.fd=标准数据文件号;
epoll控制(ep、epoll控制添加、标准文件号和e2);
mvprintw(0,0,“来自服务器的滴答声:%d”,服务器滴答声);
mvprintw(2,0,“来自键盘的滴答声:%d”,键盘滴答声);
而第(1)款{
int n=epoll_wait(ep,e,2,-1);
对于(int i=0;i
您已选择使用具有此设置的边缘触发的epoll
事件
epoll手册页面详细讨论了它的含义,以及如何正确使用边缘触发的epoll
事件。你应该回顾一下这个描述
让我们继续:
int n = epoll_wait(ep, e, 2, -1);
// ...
n = recvfrom(sockfd, fromServerBuf, FROM_SER_BUF_SIZE, 0,( struct sockaddr *) &serveraddr, &serverlen);
如果epoll
是由这个套接字从SER\u BUF\u SIZE接收的字节数超过而触发的,那么它只从SER\u BUF\u SIZE
字节中读取第一个——换句话说,发送方发送足够快的数据,这将从SER\u BUF\u SIZE
字节中读取第一个。当返回到epoll\u wait
()时,它将再次等待。即使套接字上有更多数据需要读取。这就是边缘触发的epoll
事件的工作方式。您正在以下描述边缘触发的epoll事件:
问题是在服务器发出第一条消息后,epoll是no
由来自服务器的消息触发的时间更长。还有,每次我进去
按键10次左右,sockfd和1的epoll被触发
读取字符包(即使服务器已发送)
大量信息)
对。您的epoll
被边缘触发。所示逻辑仅使用第一个数据报,并再次调用epoll
,即使套接字有更多未读数据报
更让我困惑的是,如果我一次只发送一个字符
随着时间的推移,epoll能够做出正确的反应。不止一个,威尔
结果与之前相同(epoll不起反应)
请再说一遍。如果只发送一条消息,它将按照显示的逻辑进行处理,然后epoll
再次等待
边缘触发的epoll将等待事件再次在套接字上发生。句号。故事结束了。如果事件已在套接字上发生,则边缘触发的epoll将等待而不是立即返回。TLDR:如果套接字有未读数据,epoll\u wait
ing forPOLLIN
将不会立即返回。它仅在获得更多数据后返回
e1.events = EPOLLIN|EPOLLET;
int n = epoll_wait(ep, e, 2, -1);
// ...
n = recvfrom(sockfd, fromServerBuf, FROM_SER_BUF_SIZE, 0,( struct sockaddr *) &serveraddr, &serverlen);