tsouzar

Socket Server

Apr 19th, 2013
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.46 KB | None | 0 0
  1. #include <sys/types.h> //socklen_t type
  2. #include <sys/socket.h> //socket() bind() listen() accept()
  3. #include <sys/wait.h> //waitpid()
  4. #include <signal.h> //sigaction struct
  5. #include <netdb.h> //structs
  6. #include <cstdio> //perror() fprintf()
  7. #include <string.h> //memset()
  8. #include <unistd.h> //close()
  9.  
  10. #define PORT "19456"
  11. #define MAX_CONNECTIONS 10
  12.  
  13. using namespace std;
  14.  
  15. void sigchld_handler(int x) { //handler recebe algum parâmetro inútil do sigaction()
  16.         while(waitpid(-1, NULL, WNOHANG) > 0); //executa waitpid() repetidamente enquanto houver SIGCHLD dos processos filhos
  17. } //(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")
  18.  
  19. int main() {
  20.  
  21.         struct sockaddr_storage remote_addr;
  22.         socklen_t remote_addr_size;
  23.         struct addrinfo settings, *result_info, *info;
  24.         struct sigaction action;
  25.         int srv_socket, conn_socket, gai_result, yes = 1;
  26.  
  27.         memset(&settings, 0, sizeof settings); //Remove valores padrão da struct
  28.         settings.ai_family = AF_INET; //IPv4
  29.         settings.ai_socktype = SOCK_STREAM;
  30.         settings.ai_flags = AI_PASSIVE; //Usar IP's da própria máquina
  31.  
  32.         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
  33.                 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_result));
  34.                 return 1;
  35.         } //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
  36.  
  37.         for(info = result_info; info != NULL; info = info->ai_next) { //percorre cada addrinfo obtido e tenta bind em cada um
  38.                 if((srv_socket = socket(info->ai_family, info->ai_socktype, info->ai_protocol)) == -1) {
  39.                         perror("Error on socket()");
  40.                         continue;
  41.                 }
  42.  
  43.                 if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
  44.                         close(srv_socket);
  45.                         perror("Error on setsockopt()");
  46.                         return 1;
  47.                 }
  48.  
  49.                 if(bind(srv_socket, info->ai_addr, info->ai_addrlen) == -1) {
  50.                         close(srv_socket);
  51.                         perror("Error on bind()");
  52.                         continue;
  53.                 }
  54.  
  55.                 break; //não sei como, torna info acessível no escopo global
  56.         }
  57.  
  58.         if(info == NULL) { //chegou ao último addrinfo (NULL) sem ter conseguido fazer o bind
  59.                 fprintf(stderr, "Failed on all bind()");
  60.                 return 1;
  61.         }
  62.  
  63.         freeaddrinfo(result_info);
  64.  
  65.         if(listen(srv_socket, MAX_CONNECTIONS) == -1) {
  66.                 perror("Error on listen()"); //Envia para saída padrão de erros - stderr - "Error on listen(): mensagem de errno"
  67.                 return 1;
  68.         }
  69.  
  70.         action.sa_handler = sigchld_handler;
  71.         sigemptyset(&action.sa_mask); //Limpa lista de sinais bloqueados
  72.         action.sa_flags = SA_RESTART; //Faz o handler reiniciar caso seja interrompido por SIGCHLD
  73.  
  74.         if(sigaction(SIGCHLD, &action, NULL) == -1) { //registra o action para sinais do tipo SIGCHLD
  75.                 perror("Error on sigaction()");
  76.                 return 1;
  77.         }
  78.  
  79.         while(1) {
  80.                 remote_addr_size = sizeof remote_addr;
  81.  
  82.                 if((conn_socket = accept(srv_socket, (struct sockaddr *) &remote_addr, &remote_addr_size)) == -1) {
  83.                         perror("Error on accept()");
  84.                         return 1;
  85.                 }
  86.  
  87.                 if(!fork()) { //cria novo processo que executa a parir desse ponto
  88.                         close(srv_socket); //fecha socket copiado para não ficarem dois iguais abertos (nos dois processos)
  89.                         if(send(conn_socket, "Test", 4, 0) == -1)
  90.                                 perror("Error on send()");
  91.                         close(conn_socket); //fecha a conexão no processo filho
  92.                         return 0; //fecha processo filho (ainda fica proceso zombie)
  93.                         //num_received_bytes = recv(conn_socket, &received, sizeof received, 0); -- Receive a data
  94.                 }
  95.  
  96.                 close(conn_socket); //fecha a conexão no processo principal
  97.         }
  98.  
  99.         return 0;
  100.  
  101. }
Advertisement
Add Comment
Please, Sign In to add comment