gpt4 book ai didi

c++ - poll() socket编程tcp linux多连接问题

转载 作者:太空宇宙 更新时间:2023-11-04 12:51:52 34 4
gpt4 key购买 nike

我是套接字编程的新手,但我已经在 https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/poll.htm 关注了 ibm 示例并更改了一些代码以使其更好,但是当我通过 telnet ip 端口连接到服务器并使其回显消息时,它适用于第一个连接的客户端,但在第二个客户端上它不回显消息?

#include <netinet/in.h> // sockaddr_in struct
#include <arpa/inet.h> //inet_addr()
#include <sys/socket.h>
#include <errno.h> //errors
#include <stdio.h> //perror()
#include <cstdlib> //EXIT_FAILURE
#include <sys/ioctl.h> //FIONBIO
#include <unistd.h> //close file descriptor
#include <fcntl.h> //make non blocking
#include <poll.h> //poll stuff
#include <string.h> //memset
int main()
{
int s = -1;
int rc;
int optval = 1;
int timeout;
bool end_server = false; //because we need to log if EWOULDBLOCK is true...

struct pollfd fds[200]; //initialize pollfd struct
int nfds = 1; // nfds_t really set to 1 else it will be 199 once we pass it to poll....

int current_size = 0;

int new_s = -1;

int close_conn;

char *buff;

int len;

bool compress_array;

s = socket(AF_INET, SOCK_STREAM, 0);

//make socket description reusable with SO_REUSEADDR
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&optval), sizeof(optval));
if(rc < 0){
perror("setsockopt()");
close(s);
exit(EXIT_FAILURE);
}

//make socket non-blocking
//rc = ioctl(s, FIONBIO, reinterpret_cast<char*>(&optval));
//if(rc < 0)
//{
// perror("ioctl()");
// close(s);
// exit(EXIT_FAILURE);
//}
fcntl(s, F_SETFL, O_NONBLOCK);

struct sockaddr_in saddr;
//initialize sockaddr_in struct
memset(&saddr, 0, sizeof(saddr));

saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

rc = bind(s, reinterpret_cast<struct sockaddr *>(&saddr), sizeof(saddr));

if(rc < 0){
perror("bind()");
exit(EXIT_FAILURE);
}

rc = listen(s, 32);
if(rc < 0){
perror("listen() failed");
close(s);
exit(EXIT_FAILURE);
}

//initialize fds struct
memset(&fds, 0, sizeof(fds));

fds[0].fd = s;
fds[0].events = POLLIN; //check if data to read

//initialize timeout value to 3 mins based on millisecs
//timeout = (3 * 60 * 1000); // because function will be like sleep() that uses millisecs
timeout = 10000;

do{
//call poll() and wait 3 mins to complete because of timeout
printf("Waiting on poll()...\n");
rc = poll(fds, nfds, timeout);

if(rc < 0){
perror("poll() failed");
exit(EXIT_FAILURE);
}

//check if 3 minutes timeout expired
if(rc == 0){
printf("poll() timed out ending program...\n");
exit(EXIT_FAILURE);
}

current_size = nfds;
for(int i = 0; i < current_size; i++)
{
//loop thru fds and check if revents returns POLLIN, means the fd have data to read...
if(fds[i].revents == 0)
continue;


//if revents is not POLLIN then exit program and log
if(fds[i].revents != POLLIN){
printf("revents != POLLIN, revents = %d\n", fds[i].revents);
//end_server = true;
//break;
//perror("revents unknown");
//exit(EXIT_FAILURE);
close(fds[i].fd);
fds[i].fd = -1;
break;
}

if(fds[i].fd == s){
printf("Listening socket available\n");

do{
//accept each new incoming connections
new_s = accept(s, NULL, NULL);
if(new_s < 0){
if(errno != EWOULDBLOCK){
perror("accept() failed because of socket would block");
end_server = true;
}
//printf("something else wrong with accept()\n");
break;
}

//add new incoming connection
printf("new incoming connection - nfds: %d\n", new_s);
fds[nfds].fd = new_s;
fds[nfds].events = POLLIN;
nfds++;
//continue;
//loop back up and accept another connection

} while(new_s != -1);
}
// file descriptor is readable because its now new_s instead of s
else {
printf("descriptor %d is readable\n", fds[i].fd);
close_conn = false;
//receive all data on this connection till we go back and poll again
do {

rc = recv(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0);
if(rc < 0){
if(errno != EWOULDBLOCK){
perror("recv() failed");
close_conn = true;
}
break;
}

//check if conn was closed by client
if(rc == 0){
printf("connection closed");
close_conn = true;
break;
}

//data was received
len = rc;
printf("%d bytes received", len);

//process stuff or echo data back to client
rc = send(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0);
if(rc < 0){
perror("send() failed");
close_conn = true;
break;
}
memset(&buff, 0, sizeof(buff));

} while (true);
if(close_conn){
close(fds[i].fd);
fds[i].fd = -1;
compress_array = true;
}

}


}
if(compress_array){
compress_array = false;
int i = 0;
for(i = 0; i < nfds; i++){
if(fds[i].fd == -1){
for(int j = i; j < nfds; j++){
fds[j].fd = fds[j+1].fd;
}
i--;
nfds--;
}
}
}

} while (end_server == false);

//clean all sockets that are open
for(int i = 0; i < nfds; i++){
if(fds[i].fd > 0){ // if already -1 don't need to close socket
close(fds[i].fd);
fds[i].fd = -1;
}
}



return 0;
}

最佳答案

啊这是因为我用 while(true) 循环所以它一直循环尝试接收数据而不是返回并向列表添加新连接。

关于c++ - poll() socket编程tcp linux多连接问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36950681/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com