Оригинальный вопрос: я написал некоторый клиентский код, который контролирует нажатия клавиш и sockfd, на который сервер отправляет сообщения. Проблема в том, что после первого сообщения с сервера epoll больше не вызывается сообщениями с сервера. Кроме того, каждый раз, когда я нажимаю клавишу около 10 раз, для sockfd запускается epoll и читается одна пачка символов (даже если сервер уже отправил много сообщений). Что еще больше усложняет мою путаницу, так это то, что если я отправляю только одного персонажа за раз, epoll может правильно реагировать. Все, что больше одного, будет иметь тот же результат, что и раньше (epoll не реагирует).
Редактировать: я понимаю, что если я установлю STDIN_FILENO на неблокирующую, я получу сообщения от сервера в соответствующее время. Тем не менее, программа также войдет в бесконечный цикл с STDIN_IN, который всегда запускается. Наверное, теперь вопрос в том, как правильно использовать epoll с ncurses, чтобы мы не были в бесконечном цикле.
Вот мой код:
Как использовать:
- clang ++ client.cpp -lncurses -o cli
- clang ++ server.cpp -o ser
- . / Ser 8080
- открыть другой терминал
- . / cli 127.0.0.1 8080
Я новичок в epoll, поэтому боюсь, что-то пропустил. Пожалуйста, дайте мне знать, что не так с моим кодом!
server.cpp:
#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;
}
client.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ncurses.h>
#include <sys/epoll.h>
#include <sys/fcntl.h>
#define FROM_SER_BUF_SIZE 32
#define TO_SER_BUF_SIZE 8
int main(int argc, char **argv){
int sockfd, portno, n;
socklen_t serverlen;
struct sockaddr_in serveraddr;
struct hostent *server;
char *hostname;
char toServerBuf[TO_SER_BUF_SIZE];
char fromServerBuf[FROM_SER_BUF_SIZE];
if (argc != 3) {
perror("usage: filename <hostname> <port>\n");
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("ERROR: opening sockets\n");
exit(0);
}
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(0);
}
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
serverlen = sizeof(serveraddr);
bzero(toServerBuf, TO_SER_BUF_SIZE);
n = sendto(sockfd, toServerBuf, TO_SER_BUF_SIZE, 0, ( struct sockaddr *) &serveraddr, serverlen);
if (n < 0){
perror("ERROR: sendto");
exit(0);
}
if(connect(sockfd, (struct sockaddr *)&serveraddr, serverlen) < 0) {
printf("\n Error : Connect Failed \n");
exit(0);
}
fcntl(sockfd, F_SETFL, O_NONBLOCK);
nodelay(stdscr, true);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
initscr();
noecho();
int keyboardtick = 0;
int servertick = 0;
int ep = epoll_create1(0);
struct epoll_event e1,e2, e[2]; // e1 for serverfd, e2 for stdin
memset(&e1, 0, sizeof(struct epoll_event));
e1.events = EPOLLIN;
e1.data.fd = sockfd;
epoll_ctl(ep, EPOLL_CTL_ADD, sockfd, &e1);
memset(&e2, 0, sizeof(struct epoll_event));
e2.events = EPOLLIN;
e2.data.fd = STDIN_FILENO;
epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &e2);
mvprintw(0,0,"ticks from server: %d",servertick);
mvprintw(2,0,"ticks from keyboard: %d",keyboardtick);
while (1){
int n = epoll_wait(ep, e, 2, -1);
for(int i = 0; i < n; i++){
if (e[i].data.fd == sockfd) { // from server
//
bzero(fromServerBuf, FROM_SER_BUF_SIZE);
n = recvfrom(sockfd, fromServerBuf, FROM_SER_BUF_SIZE, 0,( struct sockaddr *) &serveraddr, &serverlen);
if(n < 0) {
perror("ERROR in recv");
exit(1);
}
servertick+=n;
mvprintw(0,0,"ticks from server: %d",servertick);
}else if(e[i].data.fd == STDIN_FILENO){
char c = getch();
keyboardtick++;
mvprintw(2,0,"ticks from keyboard: %d",keyboardtick);
}
}
refresh();
}
endwin();
return 0;
}