套接字服务器线程

C++ - Thread for socket server

本文关键字:线程 服务器 套接字      更新时间:2023-10-16

我正在尝试实现一个服务器,它在自己的线程中运行。稍后,服务器应该与另一个线程一起工作。这可能吗?

我当前尝试实现这个:

主要

#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: %sn", 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 bindn");
        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 %sn", 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
    }
}

你的线程作为main()的子线程运行。当你从main返回时,它的子线程也会被杀死。

main必须执行自己的等待操作,而不是返回,因此只有当所有子线程都完成时,它才会干净地退出。