我只是想知道Instant Messenger和在线游戏如何如此快速地接受和传递消息。 (带套接字的网络编程)

我读到这是通过非阻塞套接字完成的。
我尝试使用pthreads阻塞套接字(每个客户端都有自己的线程),并使用kqueue阻塞套接字,然后我使用一个程序对两个服务器进行了配置,该程序建立了99个连接(每个连接在一个线程中),然后向其中写入一些垃圾(使用1秒钟的睡眠)。设置完所有线程后,我在主线程中测量了从服务器获得连接所需的时间(带有挂钟时间)(“ 99个用户”正在写入该消息)。

threads (avg): 0.000350 // only small difference to kqueuekqueue (avg): 0.000300 // and this is not even stable (client side)

问题是,在使用kqueue进行测试时,多次出现SIGPIPE错误(客户端)。 (由于超时usleep(50)的问题,此错误已修复)。我认为这真的很糟糕,因为服务器应该能够处理数千个连接。 (或者这是我在客户端的错?)关于此的疯狂的事情是臭名昭著的pthread方法很好(有和没有超时)。

所以我的问题是:如何在C中构建稳定的套接字服务器,该服务器可以“异步”处理数千个客户端?我只将线程方法看作是一件好事,但这被认为是不好的做法。

问候

编辑:

我的测试代码:


double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .000001;
}

#define NTHREADS    100

volatile unsigned n_threads = 0;
volatile unsigned n_writes  = 0;

pthread_mutex_t main_ready;
pthread_mutex_t stop_mtx;
volatile bool running = true;

void stop(void)
{
    pthread_mutex_lock(&stop_mtx);
    running = false;
    pthread_mutex_unlock(&stop_mtx);
}

bool shouldRun(void)
{
    bool copy;

    pthread_mutex_lock(&stop_mtx);
    copy = running;
    pthread_mutex_unlock(&stop_mtx);

    return copy;
}

#define TARGET_HOST "localhost"
#define TARGET_PORT "1336"

void *thread(void *args)
{
    char tmp = 0x01;

    if (__sync_add_and_fetch(&n_threads, 1) == NTHREADS) {
        pthread_mutex_unlock(&main_ready);

        fprintf(stderr, "All %u Threads are ready...\n", (unsigned)n_threads);
    }

    int fd = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);

    if (connect(fd, res->ai_addr, res->ai_addrlen) != 0) {
        socket_close(fd);

        fd = -1;
    }

    if (fd <= 0) {
        fprintf(stderr, "socket_create failed\n");
    }

    if (write(fd, &tmp, 1) <= 0) {
        fprintf(stderr, "pre-write failed\n");
    }

    do {
        /* Write some garbage */
        if (write(fd, &tmp, 1) <= 0) {
            fprintf(stderr, "in-write failed\n");

            break;
        }

        __sync_add_and_fetch(&n_writes, 1);

        /* Wait some time */
        usleep(500);
    } while (shouldRun());

    socket_close(fd);

    return NULL;
}

int main(int argc, const char * argv[])
{
    pthread_t threads[NTHREADS];

    pthread_mutex_init(&main_ready, NULL);
    pthread_mutex_lock(&main_ready);
    pthread_mutex_init(&stop_mtx, NULL);

    bzero((char *)&hint, sizeof(hint));
    hint.ai_socktype    = SOCK_STREAM;
    hint.ai_family      = AF_INET;

    if (getaddrinfo(TARGET_HOST, TARGET_PORT, &hint, &res) != 0) {
        return -1;
    }

    for (int i = 0; i < NTHREADS; ++i) {
        pthread_create(&threads[i], NULL, thread, NULL);
    }

    /* wait for all threads to be set up */
    pthread_mutex_lock(&main_ready);

    fprintf(stderr, "Main thread is ready...\n");

    {
        double start, end;
        int fd;

        start = get_wall_time();

        fd = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);

        if (connect(fd, res->ai_addr, res->ai_addrlen) != 0) {
            socket_close(fd);

            fd = -1;
        }

        end = get_wall_time();

        if (fd > 0) {
            fprintf(stderr, "Took %f ms\n", (end - start) * 1000);

            socket_close(fd);
        }
    }

    /* Stop all running threads */
    stop();
    /* Waiting for termination */
    for (int i = 0; i < NTHREADS; ++i) {
        pthread_join(threads[i], NULL);
    }

    fprintf(stderr, "Performed %u successfull writes\n", (unsigned)n_writes);

    /* Lol.. */
    freeaddrinfo(res);

    return 0;
}


当我尝试连接到SIGPIPE服务器时,出现kqueue(建立10个连接后,服务器“卡住”了吗?)。而且,当有太多用户在写东西时,服务器将无法打开新连接。 (来自http://eradman.com/posts/kqueue-tcp.htmlkqueue服务器代码)

最佳答案

SIGPIPE表示您正在尝试写入另一端已经关闭的套接字(或管道)(因此没有人可以读取它)。如果您对此不关心,则可以忽略SIGPIPE信号(调用signal(SIGPIPE, SIG_IGN)),并且信号不会有问题。当然,套接字上的write(或send)调用仍然会失败(使用EPIPE),因此您需要使代码足够健壮以应对这种情况。

SIGPIPE通常会终止进程的原因是,编写太容易忽略write / send调用中的错误并以100%的CPU时间运行amok的程序太容易了。只要您始终仔细检查错误并进行处理,就可以放心地忽略SIGPIPE

关于c - socket 性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25190617/

10-11 00:27