Servidor repetindo send() interminavelmente
Olá.
Estou iniciando agora em C++ (mesmo que nesse caso aqui, não tenha usado orientação a objeto; são apenas testes) mas já manejo bem a linguagem por ter familiaridade com PHP. Estou iniciando mesmo em sockets, os quais nunca usei.
Estava seguindo esse guia: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html
Consegui desenvolver um pequeno servidor que apenas envia um texto ao usuário usando o método dos processos filhos, o qual é bem defasado e obtive esse resultado funcional: http://pastebin.com/sXmErmiT. Aí chegou na parte do select() e fui tentar refazer esse servidor usando essa, para mim nova, técnica.
Obtive o seguinte:
#include <sys/types.h> //socklen_t and fd_set types
#include <sys/socket.h> //socket() bind() listen() accept()
#include <netdb.h> //structs
#include <cstdio> //perror() fprintf()
#include <string.h> //memset()
#include <unistd.h> //close()
#define PORT "19456"
#define MAX_CONNECTIONS 10
using namespace std;
int main() {
struct sockaddr_storage remote_addr;
socklen_t remote_addr_size;
struct addrinfo settings, *result_info, *info;
int srv_socket, conn_socket, gai_result, biggest_descriptor, i, yes = 1;
fd_set listening, write_set;
FD_ZERO(&listening); //Clear
FD_ZERO(&write_set); //the sets
memset(&settings, 0, sizeof settings); //Remove valores padrão da struct
settings.ai_family = AF_INET; //IPv4
settings.ai_socktype = SOCK_STREAM;
settings.ai_flags = AI_PASSIVE; //Usar IP's da própria máquina
if((gai_result = getaddrinfo(NULL, PORT, &settings, &result_info)) != 0) { //Obtém informações do endereço, salva em result_info e usa configs de settings
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_result));
return 1;
} //NULL no primeiro param faz usar AI_PASSIVE, e se a máquina tiver mais de um ipv4 no caso, vão haver vários addrinfo
for(info = result_info; info != NULL; info = info->ai_next) { //percorre cada addrinfo obtido e tenta bind em cada um
if((srv_socket = socket(info->ai_family, info->ai_socktype, info->ai_protocol)) == -1) {
perror("Error on socket()");
continue;
}
if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
close(srv_socket);
perror("Error on setsockopt()");
return 1;
}
if(bind(srv_socket, info->ai_addr, info->ai_addrlen) == -1) {
close(srv_socket);
perror("Error on bind()");
continue;
}
break; //não sei como, torna info acessível no escopo global
}
if(info == NULL) { //chegou ao último addrinfo (NULL) sem ter conseguido fazer o bind
fprintf(stderr, "Failed on all bind()");
return 1;
}
freeaddrinfo(result_info);
if(listen(srv_socket, MAX_CONNECTIONS) == -1) {
perror("Error on listen()"); //Envia para saída padrão de erros - stderr - "Error on listen(): mensagem de errno"
return 1;
}
FD_SET(srv_socket, &listening);
biggest_descriptor = srv_socket; //Maior (e no momento, único) descritor de arquivo
while(1) {
if(select(biggest_descriptor + 1, &listening, &write_set, NULL, NULL) == -1) {
close(srv_socket);
perror("Error on select()");
return 1;
}
if(FD_ISSET(srv_socket, &listening)) { //Verifica se há nova conexão
remote_addr_size = sizeof remote_addr;
if((conn_socket = accept(srv_socket, (struct sockaddr *) &remote_addr, &remote_addr_size)) == -1) { //Aceita a nova conexão
close(srv_socket);
perror("Error on accept()");
return 1;
}
if(conn_socket > biggest_descriptor) //Atualiza a variável do maior descritor
biggest_descriptor = conn_socket;
FD_SET(conn_socket, &write_set); //Adiciona o novo socket ao set de escrita
}
for(i = 0; i <= biggest_descriptor; i++) { //Percorre cada socket nos sets do select
if(FD_ISSET(i, &write_set)) //Verifica se o socket está aguardando por escrita
if(send(i, "Test", 4, 0) == -1) { //Caso esteja, envia o texto
close(i);
perror("Error on send()");
return 1;
}
}
}
return 0;
}
Não consegui entender o exemplo para *select()* no guia que eu estava seguindo e tentei fazer desse jeito aí, usando minha própria lógica. Também li um ou outro tutorial para ver se entendia. Achei mais fácil usar o *poll()*, mas quero entender esse método aí.
O servidor executa normalmente. O problema é que quando conecto-me a ele, algum problema na minha lógica fez com que ele ficasse me enviando "Test", no *send()*, sem parar, chegando a travar o computador. Acredito que o problema possa estar no *for* lá no final, acho que não entendi como percorrer todos os sockets que estão nos sets do *select()*, sei lá. Ainda ocorre que se eu fechar a conexão durante esse bombardeio de "Test", o servidor para de executar com a seguinte mensagem:
Error on send(): Connection reset by peer
Alguém pode ajudar?
Obrigado pela atenção; até mais.
Discussão (1)
Carregando comentários...