2016-09-14 7 views
-1

私は自分のスレッドで動作するサーバーを実装しようとしています。 その後、サーバーは別のスレッドと一緒に作業する必要があります。 それも可能ですか?の子としてC++ - ソケットサーバーのスレッド

メイン

#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

あなたのスレッドが実行:これを実装する

私の現在の試みメイン()。あなたがメインから戻ると、その子スレッドも殺されます。

返されるのではなく、メインは独自の待機操作を実行する必要があるため、すべての子スレッドが完了したときに正常終了するようにします。

関連する問題