Ich bin neu, Socket-Programmierung, aber ich habe gefolgt ibm Beispiel https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/poll.htm und einige Code geändert, um es besser zu machen, aber wenn ich den Server über Telnet-Port verbinden, und mach es echo messages funktioniert es für den ersten Client, der verbindet, aber zweitens nicht die Nachrichten Echo?poll() Socket-Programmierung tcp linux mehrere Verbindungen Problem
#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;
}
aber es funktioniert, wenn ich den ersten Client trenne und versuche, auf einem anderen zu senden? –
gefunden, was es verursacht es ist, weil ich Pause hinzugefügt habe; nach printf ("etwas anderes stimmt nicht mit accept() \ n"); aber jetzt, wenn ich eine Verbindung mit dem ersten Client sende msg es echo zurück, aber wenn ich eine Verbindung mit dem zweiten Client und senden msg und trennen von der ersten Client sendet es nur Echo zurück, wenn die erste Verbindung trennt? Wie man es so macht, dass es zur gleichen Zeit anstatt der Warteschlange sendet? –
Ich weiß, die Warteschlange ist wegen RC = listen (s, 32); aber wie man es nicht blockierend macht? –