【发布时间】:2014-10-01 04:09:15
【问题描述】:
我只是想知道即时通讯工具和在线游戏如何能够如此快速地接受和传递消息。 (使用套接字进行网络编程)
我了解到这是通过 非阻塞套接字 完成的。
我尝试了 blocking sockets 使用 pthreads(每个客户端都有自己的线程)和 nonblocking sockets 使用kqueue。然后我用一个建立 99 个连接的程序(每个一个线程中的连接),然后向它写入一些垃圾(睡眠时间为 1 秒)。当所有线程都设置好后,我在主线程中测量了从服务器获得连接所需的时间(带有挂钟时间)(当“99 个用户”正在写入时)。
threads (avg): 0.000350 // only small difference to kqueue
kqueue (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 个连接后,服务器“卡住”了?)。当太多用户在写东西时,服务器无法打开新连接。 (kqueue 服务器代码来自http://eradman.com/posts/kqueue-tcp.html)
【问题讨论】:
-
你的问题真的是“如何编写高性能 TCP 服务器代码?”
-
@DavidSchwartz 是的。确实。
-
阅读选择。阅读有关 unix 网络编程的经典书籍
标签: c multithreading sockets network-programming