я пишу сервер для клиента чата, который я делаю
проблема заключается в следующем
Select только снимает свой блок, если подключается сетевой клиент
и если последний подключенный клиент пишет.
пример:
у меня подключено 4 клиента
сервер будет продолжать блокировать, пока клиент не 4 пишет
если клиент 1-3 пишет, он продолжает блокировать
Что я делаю неправильно?
для анализа вот мой код может содержать уродливый и бесполезный код
но это только анализирует его поведение
Server.c ++
#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 <boost/thread/thread.hpp>
#include <sys/time.h>
#include <sys/ioctl.h>
using namespace std;
void error(char *msg, int socket) {
perror(msg);
close(socket);
exit(1);
}
int main(int argc, char** argv) {
int sockfd, newsockfd, portno, n, highsock;
socklen_t clilen;
fd_set readfds;
list<int> CliSocks;
FD_ZERO(&readfds);
/*
* Sockfd, newsockfd contain values returned by the socket
* portno stores the port number on which the server accepts connections
* clilen stores the size of the address of the client
* n contains the amount of character written of read
*/
char buffer[256];
/* buffer contains the characters read from the socket*/
struct sockaddr_in serv_addr, cli_addr;
/*
* sockaddr_in contains an internet address
* serv_addr contains the servers address
* cli addr contains the clients address
*/
if (argc < 2) {
fprintf(stderr, "ERROR no port provided");
exit(1);
}
/*
* error if no argument
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
highsock = sockfd;
FD_SET(sockfd, &readfds);
int opt = 1;
ioctl(sockfd, FIONBIO, &opt);
if (sockfd < 0) {
error("ERROR opening socket", sockfd);
}
/*
* socket() creates a new socket
* argument 1 contains the address domain
* argument 2 contains the socket type
* argument 3 contains the protocol should be 0
* socket() returns a reference for itself
*/
bzero((char*) &serv_addr, sizeof (serv_addr));
/* empty the serv_addr variable*/
portno = atoi(argv[1]);
/*converts the port argument from string to int*/
serv_addr.sin_family = AF_INET;
/*set the code for the address family*/
serv_addr.sin_port = htons(portno);
/*htons converts the portno to network bytes and gives it to the server address*/
serv_addr.sin_addr.s_addr = INADDR_ANY;
/*set the server ip to the ip of the running machine*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR on binding", sockfd);
/*
* bind() binds a socket to an address, in this case the
* addess of the current host
*/
listen(sockfd, 5);
/*the listen system call allows the process to listen on the socket for connections*/while (1) {
int sockcount = select(highsock + 1, &readfds, NULL, NULL, NULL);
clilen = sizeof (cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
/*
* accept() lets the system wait until a client connects to the server
*/
if (newsockfd > 0) {
ioctl(newsockfd, FIONBIO, &opt);
FD_SET(newsockfd, &readfds);
highsock = newsockfd;
CliSocks.push_back(newsockfd);
}for (list<int>::iterator it = CliSocks.begin(); it != CliSocks.end(); it++) {
bzero(buffer, 256);
n = read(*it, buffer, 255);
if(buffer[0] != 0){
printf("Here is the message: %s", buffer);
/*
* bzero empties the buffer
* read obviously reads data from the new socket descriptor
*/
n = write(*it, "I got your message", 18);
if (n < 0) error("ERROR writing to socket", sockfd);
}
}
}
close(sockfd);
return 0;
}
Проблема в том, что вы должны сбросить readfds
каждый раз в цикле перед вызовом select
, Это потому, что призыв к select
модифицирует его параметры.
while (1) {
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
highsock = sockfd;
for (list<int>::iterator it = CliSocks.begin(); it != CliSocks.end(); it++) {
FD_SET(*it, &readfds);
highsock = *it > highsock ? *it : highsock;
}
int sockcount = select(highsock + 1, &readfds, NULL, NULL, NULL);
...
}
Других решений пока нет …