C, программирование сокетов: подключение нескольких клиентов к серверу с помощью select()
Я пытаюсь создать сервер, к которому могут подключаться несколько клиентов. Вот мой код до сих пор:
Клиент:
int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
Сервер:
int main(int argc, char **argv) {
fd_set fds, readfds;
int i, clientaddrlen;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
struct sockaddr_in serveraddr, clientaddr;
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(6782);
if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,
sizeof(struct sockaddr_in)))
perror("Bind");
if (-1 == listen(serversock, SOMAXCONN))
perror("Listen");
FD_ZERO(&fds);
FD_SET(serversock, &fds);
while(1) {
readfds = fds;
rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (rc == -1) {
perror("Select");
break;
}
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &readfds)) {
if (i == serversock) {
if (numsocks < maxsocks) {
clientsock[numsocks] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
if (clientsock[numsocks] == -1) perror("Accept");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
} else {
printf("Ran out of socket space.\n");
}
} else {
int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
}
}
}
}
close(serversock);
return 0;
}
Как только клиент подключается и отправляет свое первое сообщение, сервер просто работает в бесконечном цикле и выплевывает мусор из массива сообщений. Кажется, что recv ничего не получает. Кто-нибудь может увидеть, где я иду не так?
5 ответов
Две проблемы в вашем коде:
Ты должен сделать
recv(i, ...)
вместоrecv(clientsock[i], ...)
После этого вы не проверяете,
recv()
не удалось, и, следовательно,printf()
распечатывает неинициализированный буферmessage
отсюда и мусор на выходе
В цикле while для сервера измените код на recv(i)
вместо recv(clientsocks[i])
, Я реализовал этот код, и он работает с этим изменением.
Вам нужно проверить ограничение <= 0 в цикле чтения, прежде чем вызывать read.
Я заменил остальное на ниже, и это работает
} else {
/* int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
memset ( &message[index] , 0, sizeof ( message [index] ) );
while ((in = recv(i, &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
*/
bzero(buf, sizeof(buf));
if ((rval = read(i, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
}
1) Хорошей практикой является использование PF_INET(семейство протоколов), а не
AF_INET(семейство адресов) при создании сокета.
2) в цикле while(1)
каждый раз желательно сделать ваши readfds пустыми, используя FD_ZERO(&readfds). в вызове recv () вы должны использовать i, а не clientocks[i], вы должны проверить, что возвращаемое значение recv отрицательно (что указывает на ошибку при чтении), если в этом случае вам не нужно печатать сообщение. во время печати сообщения убедитесь, что стандартный вывод / сервер готов к записи в него всего, что вы можете сделать с помощью writefds (третий аргумент выбора).