2016-09-14 2 views
-1

Я пытаюсь реализовать сервер, который работает в своем потоке. Позже сервер должен работать вместе с другим потоком. Возможно ли это?C++ - Thread для сервера сокетов

Моей текущую попытки осуществить это:

главного

#include "EtherServer.h" 

int main(int argc, char *argv[]) 
{ 
    EtherServer* es = new EtherServer(); 
    es->init(); 
    return 0; 
} 

server.h

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/wait.h> 
#include <signal.h> 
#include <pthread.h> 

#ifndef ETHERSERVER_H_ 
#define ETHERSERVER_H_ 

class EtherServer 
{ 
    public: 
     bool init(); 
     static void* runServer(void *arg); 
     static void sigchld_handler(int s); 
     static void* get_in_addr(struct sockaddr *sa); 

     static int s_sockfd; 

    private: 

}; 

#endif /* ETHERSERVER_H_ */ 

server.cpp

#include "EtherServer.h" 

#define PORT "31107" // the port users will be connecting to 

#define BACKLOG 10  // how many pending connections queue will hold 

int EtherServer::s_sockfd = 0; 

void EtherServer::sigchld_handler(int s) 
{ 
    // waitpid() might overwrite errno, so we save and restore it: 
    int saved_errno = errno; 

    while(waitpid(-1, NULL, WNOHANG) > 0); 

    errno = saved_errno; 
} 


// get sockaddr, IPv4 or IPv6: 
void* EtherServer::get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

bool EtherServer::init() 
{ 
    int rv; 
    int yes=1; 
    struct addrinfo hints, *servinfo, *p; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 
    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
    } 

    // loop through all the results and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) 
    { 
     if ((EtherServer::s_sockfd = socket(p->ai_family, p->ai_socktype, 
       p->ai_protocol)) == -1) { 
      perror("server: socket"); 
      continue; 
     } 

     if (setsockopt(EtherServer::s_sockfd, SOL_SOCKET, SO_REUSEADDR, yes,      
      sizeof(int)) == -1) 
     { 
      perror("setsockopt"); 
      exit(1); 
     } 

     if (bind(EtherServer::s_sockfd, p->ai_addr, p->ai_addrlen) == -1) 
     { 
      close(EtherServer::s_sockfd); 
      perror("server: bind"); 
      continue; 
     } 

     break; 
    } 

    freeaddrinfo(servinfo); // all done with this structure 
    if (p == NULL) { 
     fprintf(stderr, "server: failed to bind\n"); 
     exit(1); 

    } 

    if (listen(EtherServer::s_sockfd, BACKLOG) == -1) { 
     perror("listen"); 
     exit(1); 
    } 

    struct sigaction sa; 

    sa.sa_handler = EtherServer::sigchld_handler; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = 0; 
    if (sigaction(SIGCHLD, &sa, NULL) == -1) { 
     perror("sigaction"); 
     exit(1); 
    } 

    pthread_attr_t attr_baseb; 
    (void)pthread_attr_init(&attr_baseb); 
    (void)pthread_attr_setdetachstate(&attr_baseb, PTHREAD_CREATE_DETACHED); 
    (void)pthread_create(NULL, &attr_baseb, &runServer, (void *)this); 
} 

void* EtherServer::runServer(void *arg) 
{ 
    int new_fd; // listen on sock_fd, new connection on new_fd 
    //struct addrinfo hints, *servinfo, *p; 
    struct sockaddr_storage their_addr; // connector's address information 
    socklen_t sin_size; 
    char s[INET6_ADDRSTRLEN]; 

    printf("server: waiting for connections...\n"); 

    while(1) { // main accept() loop 
     sin_size = sizeof their_addr; 
     sleep(1); 
     new_fd = accept(EtherServer::s_sockfd, (struct sockaddr *)&their_addr, &sin_size); 
     if (new_fd == -1) { 
      perror("accept"); 
      continue; 
     } 

     inet_ntop(their_addr.ss_family, EtherServer::get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); 
     printf("server: got connection from %s\n", s); 

     if (!fork()) { // this is the child process 
      int n; 
      char buffer[256]; 
      bzero(buffer, 256); 
      close(EtherServer::s_sockfd); // child doesn't need the listener 

      while (n = read(new_fd, buffer, 255) > 0) 
      { 

       if (send(new_fd, buffer, 255, 0) == -1) 
        perror("send"); 
      } 
      close(new_fd); 
      exit(0); 
      sleep(1); 
     } 
     close(new_fd); // parent doesn't need this 
    } 
} 
+0

Есть ли у вас конкретный вопрос? – Galik

+0

Я не знаю, почему это решение не работает. – Erik

+2

Вы должны уточнить, что именно не работает? – FrankS101

ответ

1

Вашего поток работает как ребенок главный(). Когда вы возвращаетесь из основного, его дочерние потоки также убиваются.

Вместо того, чтобы возвращать, основной должен будет выполнить некоторую операцию ожидания, так что он будет полностью выйти только после завершения всех дочерних потоков.

Смежные вопросы