Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <sys/types.h> //socklen_t type
- #include <sys/socket.h> //socket() bind() listen() accept()
- #include <sys/wait.h> //waitpid()
- #include <signal.h> //sigaction struct
- #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;
- void sigchld_handler(int x) { //handler recebe algum parâmetro inútil do sigaction()
- while(waitpid(-1, NULL, WNOHANG) > 0); //executa waitpid() repetidamente enquanto houver SIGCHLD dos processos filhos
- } //(pid do processo para aguardar "-1 quer dizer qualquer processo filho", onde salvar o resultado, opcoes "WNOHANG é para não suspender execução enquanto aguarda")
- int main() {
- struct sockaddr_storage remote_addr;
- socklen_t remote_addr_size;
- struct addrinfo settings, *result_info, *info;
- struct sigaction action;
- int srv_socket, conn_socket, gai_result, yes = 1;
- 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;
- }
- action.sa_handler = sigchld_handler;
- sigemptyset(&action.sa_mask); //Limpa lista de sinais bloqueados
- action.sa_flags = SA_RESTART; //Faz o handler reiniciar caso seja interrompido por SIGCHLD
- if(sigaction(SIGCHLD, &action, NULL) == -1) { //registra o action para sinais do tipo SIGCHLD
- perror("Error on sigaction()");
- return 1;
- }
- while(1) {
- remote_addr_size = sizeof remote_addr;
- if((conn_socket = accept(srv_socket, (struct sockaddr *) &remote_addr, &remote_addr_size)) == -1) {
- perror("Error on accept()");
- return 1;
- }
- if(!fork()) { //cria novo processo que executa a parir desse ponto
- close(srv_socket); //fecha socket copiado para não ficarem dois iguais abertos (nos dois processos)
- if(send(conn_socket, "Test", 4, 0) == -1)
- perror("Error on send()");
- close(conn_socket); //fecha a conexão no processo filho
- return 0; //fecha processo filho (ainda fica proceso zombie)
- //num_received_bytes = recv(conn_socket, &received, sizeof received, 0); -- Receive a data
- }
- close(conn_socket); //fecha a conexão no processo principal
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment