select的socket server多路复用模型
2009-04-22 10:16
567 查看
除了上文将的通过fork多进程socket server模型外, 另一种方法是使用select系统调用。当然,也可以对上文的fork进行修改,例如使用pthread创建线程来完成具体工作。
两种方法各有优缺点,都不是最优解决方案。但没种解决方案都不是绝对的,我们可以混合使用各种解决方案来完成,关键是能够理解socket,select,多线程,多进程的本质。相对于多进程fork的方式,我更喜欢使用pthread多线程,原因之一是pthread的代价更低,更重要的原因是多线程可以共享数据,省去了多进程之间通信的代价。
多进程socket server例程:http://www.9say.com/2009/01/multi-process-socket-server-demo-example/
以下是使用select多路复用的socket server模型的一个例子:
/**
* @brief: server.c
*
* A simplest tcp connection example of server side.
* use select to accept multi-client connections.
*
* guotie.9(at)gmail.com
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define TRANSFER_PORT 6688
#define MAX_LISTEN 12
int init_transfer();
void fini_transfer();
int recv_data(int sock, char *buf, int len);
int sig_handler(void);
void sig_handler_func(int sig);
int select_conns();
int transfer_sock;
int init_transfer()
{
int sock = -1;
struct sockaddr_in addr;
printf(”init transfer ……/n”);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock)
{
perror(”Failed to create socket./n”);
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(”0.0.0.0″);
addr.sin_port = htons(TRANSFER_PORT);
if(-1 == bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)))
{
perror(”Failed to bind socket./n”);
return -1;
}
if(-1 == listen(sock, MAX_LISTEN))
{
printf(”Failed to bind socket. errno: %d/n”, errno);
return -1;
}
transfer_sock = sock;
printf(” %s: init transfer socket %d …… success/n”, __FUNCTION__, sock);
return 0;
}
void fini_transfer()
{
int ret;
ret = shutdown(transfer_sock, SHUT_RDWR);
ret = close(transfer_sock);
if(ret < 0)
perror(”/nfini_transfer: “);
else
printf(”/n/n %s: success shutdown transfer socket!/n/n”, __FUNCTION__);
}
int recv_data(int sock, char *buf, int len)
{
int l = 0;
memset(buf, 0, len);
l = recv(sock, buf, len, 0);
if(0 > l)
{
perror(”recv error: “);
return -1;
}
else if (0 == l)
{
printf(”client shutdown the socket %d … /n”, sock);
return 0;
}
printf(”recv %d data./n”, l);
return l;
}
void sig_handler_func(int sig)
{
fini_transfer();
exit(0);
}
int sig_handler(void)
{
int ret = 0;
struct sigaction sact;
ret = sigemptyset(&sact.sa_mask);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGQUIT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGINT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGKILL, &sact, NULL);
if(0 > ret)
return ret;
return 0;
}
int main()
{
int i;
int s;
int ret = 0;
char buf[4096] = { 0 };
int len;
int client_fd[MAX_LISTEN];
int max_fd = 0;
fd_set client_conns;
struct sockaddr_in client_addr;
init_transfer();
sig_handler();
for(i = 0; i < MAX_LISTEN; i ++)
client_fd[i] = -1;
FD_ZERO(&client_conns);
max_fd = transfer_sock;
while(1)
{
/**
* 特别提醒,这里必须把所有正在listen的socket重新加入select队列,
* 和我之前理解的不同。如果不把该socket重新加入,则select无法
* 监听这个socket的状态变化,也就无法accept新的连接。
*/
FD_CLR(transfer_sock, &client_conns);
FD_SET(transfer_sock, &client_conns);
ret = select(max_fd + 1, &client_conns, NULL, NULL, (struct timeval *)0);
if (0 > ret)
{
perror(”select(): “);
exit(-1);
}
else if (0 == ret)
{
printf(” select timeout ……/n”);
continue;
}
printf(”select return something … /n”);
/**
* 有新的客户连接
*/
if(FD_ISSET(transfer_sock, &client_conns))
{
len = sizeof(struct sockaddr_in);
memset(&client_addr, 0, len);
s = accept(transfer_sock, (struct sockaddr *)&client_addr, &len );
if(-1 == s)
{
perror(”accept failed:”);
continue;
}
/**
* 把新连接加入select队列中
*/
for (i = 0; i < MAX_LISTEN; i ++)
{
if(-1 != client_fd[i])
continue;
client_fd[i] = s;
break;
}
FD_SET(s , &client_conns);
if(max_fd < s)
max_fd = s;
printf(”Add client socket connection %d to select/n”, s);
continue;
}
for(i = 0; i < MAX_LISTEN; i ++)
{
if(-1 == client_fd[i])
continue;
if(!FD_ISSET(client_fd[i], &client_conns))
continue;
ret = recv_data(client_fd[i], buf, sizeof(buf));
if(0 >= ret)
{
close(client_fd[i]);
FD_CLR(client_fd[i], &client_conns);
printf(”del socket %d from select pipe./n”, client_fd[i]);
client_fd[i] = -1;
}
}
max_fd = transfer_sock;
for(i = 0; i < MAX_LISTEN; i ++)
{
if(max_fd < client_fd[i])
{
max_fd = client_fd[i];
}
}
printf(”This cycle of select loop over, max_fd = %d…/n”, max_fd);
}
fini_transfer();
return 0;
}
Filed under: program
除了上文将的通过fork多进程socket server模型外, 另一种方法是使用select系统调用。当然,也可以对上文的fork进行修改,例如使用pthread创建线程来完成具体工作。
两种方法各有优缺点,都不是最优解决方案。但没种解决方案都不是绝对的,我们可以混合使用各种解决方案来完成,关键是能够理解socket,select,多线程,多进程的本质。相对于多进程fork的方式,我更喜欢使用pthread多线程,原因之一是pthread的代价更低,更重要的原因是多线程可以共享数据,省去了多进程之间通信的代价。
多进程socket server例程:http://www.9say.com/2009/01/multi-process-socket-server-demo-example/
以下是使用select多路复用的socket server模型的一个例子:
/**
* @brief: server.c
*
* A simplest tcp connection example of server side.
* use select to accept multi-client connections.
*
* guotie.9(at)gmail.com
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define TRANSFER_PORT 6688
#define MAX_LISTEN 12
int init_transfer();
void fini_transfer();
int recv_data(int sock, char *buf, int len);
int sig_handler(void);
void sig_handler_func(int sig);
int select_conns();
int transfer_sock;
int init_transfer()
{
int sock = -1;
struct sockaddr_in addr;
printf(”init transfer ……/n”);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock)
{
perror(”Failed to create socket./n”);
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(”0.0.0.0″);
addr.sin_port = htons(TRANSFER_PORT);
if(-1 == bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)))
{
perror(”Failed to bind socket./n”);
return -1;
}
if(-1 == listen(sock, MAX_LISTEN))
{
printf(”Failed to bind socket. errno: %d/n”, errno);
return -1;
}
transfer_sock = sock;
printf(” %s: init transfer socket %d …… success/n”, __FUNCTION__, sock);
return 0;
}
void fini_transfer()
{
int ret;
ret = shutdown(transfer_sock, SHUT_RDWR);
ret = close(transfer_sock);
if(ret < 0)
perror(”/nfini_transfer: “);
else
printf(”/n/n %s: success shutdown transfer socket!/n/n”, __FUNCTION__);
}
int recv_data(int sock, char *buf, int len)
{
int l = 0;
memset(buf, 0, len);
l = recv(sock, buf, len, 0);
if(0 > l)
{
perror(”recv error: “);
return -1;
}
else if (0 == l)
{
printf(”client shutdown the socket %d … /n”, sock);
return 0;
}
printf(”recv %d data./n”, l);
return l;
}
void sig_handler_func(int sig)
{
fini_transfer();
exit(0);
}
int sig_handler(void)
{
int ret = 0;
struct sigaction sact;
ret = sigemptyset(&sact.sa_mask);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGQUIT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGINT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGKILL, &sact, NULL);
if(0 > ret)
return ret;
return 0;
}
int main()
{
int i;
int s;
int ret = 0;
char buf[4096] = { 0 };
int len;
int client_fd[MAX_LISTEN];
int max_fd = 0;
fd_set client_conns;
struct sockaddr_in client_addr;
init_transfer();
sig_handler();
for(i = 0; i < MAX_LISTEN; i ++)
client_fd[i] = -1;
FD_ZERO(&client_conns);
max_fd = transfer_sock;
while(1)
{
/**
* 特别提醒,这里必须把所有正在listen的socket重新加入select队列,
* 和我之前理解的不同。如果不把该socket重新加入,则select无法
* 监听这个socket的状态变化,也就无法accept新的连接。
*/
FD_CLR(transfer_sock, &client_conns);
FD_SET(transfer_sock, &client_conns);
ret = select(max_fd + 1, &client_conns, NULL, NULL, (struct timeval *)0);
if (0 > ret)
{
perror(”select(): “);
exit(-1);
}
else if (0 == ret)
{
printf(” select timeout ……/n”);
continue;
}
printf(”select return something … /n”);
/**
* 有新的客户连接
*/
if(FD_ISSET(transfer_sock, &client_conns))
{
len = sizeof(struct sockaddr_in);
memset(&client_addr, 0, len);
s = accept(transfer_sock, (struct sockaddr *)&client_addr, &len );
if(-1 == s)
{
perror(”accept failed:”);
continue;
}
/**
* 把新连接加入select队列中
*/
for (i = 0; i < MAX_LISTEN; i ++)
{
if(-1 != client_fd[i])
continue;
client_fd[i] = s;
break;
}
FD_SET(s , &client_conns);
if(max_fd < s)
max_fd = s;
printf(”Add client socket connection %d to select/n”, s);
continue;
}
for(i = 0; i < MAX_LISTEN; i ++)
{
if(-1 == client_fd[i])
continue;
if(!FD_ISSET(client_fd[i], &client_conns))
continue;
ret = recv_data(client_fd[i], buf, sizeof(buf));
if(0 >= ret)
{
close(client_fd[i]);
FD_CLR(client_fd[i], &client_conns);
printf(”del socket %d from select pipe./n”, client_fd[i]);
client_fd[i] = -1;
}
}
max_fd = transfer_sock;
for(i = 0; i < MAX_LISTEN; i ++)
{
if(max_fd < client_fd[i])
{
max_fd = client_fd[i];
}
}
printf(”This cycle of select loop over, max_fd = %d…/n”, max_fd);
}
fini_transfer();
return 0;
}
两种方法各有优缺点,都不是最优解决方案。但没种解决方案都不是绝对的,我们可以混合使用各种解决方案来完成,关键是能够理解socket,select,多线程,多进程的本质。相对于多进程fork的方式,我更喜欢使用pthread多线程,原因之一是pthread的代价更低,更重要的原因是多线程可以共享数据,省去了多进程之间通信的代价。
多进程socket server例程:http://www.9say.com/2009/01/multi-process-socket-server-demo-example/
以下是使用select多路复用的socket server模型的一个例子:
/**
* @brief: server.c
*
* A simplest tcp connection example of server side.
* use select to accept multi-client connections.
*
* guotie.9(at)gmail.com
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define TRANSFER_PORT 6688
#define MAX_LISTEN 12
int init_transfer();
void fini_transfer();
int recv_data(int sock, char *buf, int len);
int sig_handler(void);
void sig_handler_func(int sig);
int select_conns();
int transfer_sock;
int init_transfer()
{
int sock = -1;
struct sockaddr_in addr;
printf(”init transfer ……/n”);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock)
{
perror(”Failed to create socket./n”);
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(”0.0.0.0″);
addr.sin_port = htons(TRANSFER_PORT);
if(-1 == bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)))
{
perror(”Failed to bind socket./n”);
return -1;
}
if(-1 == listen(sock, MAX_LISTEN))
{
printf(”Failed to bind socket. errno: %d/n”, errno);
return -1;
}
transfer_sock = sock;
printf(” %s: init transfer socket %d …… success/n”, __FUNCTION__, sock);
return 0;
}
void fini_transfer()
{
int ret;
ret = shutdown(transfer_sock, SHUT_RDWR);
ret = close(transfer_sock);
if(ret < 0)
perror(”/nfini_transfer: “);
else
printf(”/n/n %s: success shutdown transfer socket!/n/n”, __FUNCTION__);
}
int recv_data(int sock, char *buf, int len)
{
int l = 0;
memset(buf, 0, len);
l = recv(sock, buf, len, 0);
if(0 > l)
{
perror(”recv error: “);
return -1;
}
else if (0 == l)
{
printf(”client shutdown the socket %d … /n”, sock);
return 0;
}
printf(”recv %d data./n”, l);
return l;
}
void sig_handler_func(int sig)
{
fini_transfer();
exit(0);
}
int sig_handler(void)
{
int ret = 0;
struct sigaction sact;
ret = sigemptyset(&sact.sa_mask);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGQUIT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGINT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGKILL, &sact, NULL);
if(0 > ret)
return ret;
return 0;
}
int main()
{
int i;
int s;
int ret = 0;
char buf[4096] = { 0 };
int len;
int client_fd[MAX_LISTEN];
int max_fd = 0;
fd_set client_conns;
struct sockaddr_in client_addr;
init_transfer();
sig_handler();
for(i = 0; i < MAX_LISTEN; i ++)
client_fd[i] = -1;
FD_ZERO(&client_conns);
max_fd = transfer_sock;
while(1)
{
/**
* 特别提醒,这里必须把所有正在listen的socket重新加入select队列,
* 和我之前理解的不同。如果不把该socket重新加入,则select无法
* 监听这个socket的状态变化,也就无法accept新的连接。
*/
FD_CLR(transfer_sock, &client_conns);
FD_SET(transfer_sock, &client_conns);
ret = select(max_fd + 1, &client_conns, NULL, NULL, (struct timeval *)0);
if (0 > ret)
{
perror(”select(): “);
exit(-1);
}
else if (0 == ret)
{
printf(” select timeout ……/n”);
continue;
}
printf(”select return something … /n”);
/**
* 有新的客户连接
*/
if(FD_ISSET(transfer_sock, &client_conns))
{
len = sizeof(struct sockaddr_in);
memset(&client_addr, 0, len);
s = accept(transfer_sock, (struct sockaddr *)&client_addr, &len );
if(-1 == s)
{
perror(”accept failed:”);
continue;
}
/**
* 把新连接加入select队列中
*/
for (i = 0; i < MAX_LISTEN; i ++)
{
if(-1 != client_fd[i])
continue;
client_fd[i] = s;
break;
}
FD_SET(s , &client_conns);
if(max_fd < s)
max_fd = s;
printf(”Add client socket connection %d to select/n”, s);
continue;
}
for(i = 0; i < MAX_LISTEN; i ++)
{
if(-1 == client_fd[i])
continue;
if(!FD_ISSET(client_fd[i], &client_conns))
continue;
ret = recv_data(client_fd[i], buf, sizeof(buf));
if(0 >= ret)
{
close(client_fd[i]);
FD_CLR(client_fd[i], &client_conns);
printf(”del socket %d from select pipe./n”, client_fd[i]);
client_fd[i] = -1;
}
}
max_fd = transfer_sock;
for(i = 0; i < MAX_LISTEN; i ++)
{
if(max_fd < client_fd[i])
{
max_fd = client_fd[i];
}
}
printf(”This cycle of select loop over, max_fd = %d…/n”, max_fd);
}
fini_transfer();
return 0;
}
select的socket server多路复用模型
January 13, 2009 by admin · Leave a CommentFiled under: program
除了上文将的通过fork多进程socket server模型外, 另一种方法是使用select系统调用。当然,也可以对上文的fork进行修改,例如使用pthread创建线程来完成具体工作。
两种方法各有优缺点,都不是最优解决方案。但没种解决方案都不是绝对的,我们可以混合使用各种解决方案来完成,关键是能够理解socket,select,多线程,多进程的本质。相对于多进程fork的方式,我更喜欢使用pthread多线程,原因之一是pthread的代价更低,更重要的原因是多线程可以共享数据,省去了多进程之间通信的代价。
多进程socket server例程:http://www.9say.com/2009/01/multi-process-socket-server-demo-example/
以下是使用select多路复用的socket server模型的一个例子:
/**
* @brief: server.c
*
* A simplest tcp connection example of server side.
* use select to accept multi-client connections.
*
* guotie.9(at)gmail.com
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define TRANSFER_PORT 6688
#define MAX_LISTEN 12
int init_transfer();
void fini_transfer();
int recv_data(int sock, char *buf, int len);
int sig_handler(void);
void sig_handler_func(int sig);
int select_conns();
int transfer_sock;
int init_transfer()
{
int sock = -1;
struct sockaddr_in addr;
printf(”init transfer ……/n”);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock)
{
perror(”Failed to create socket./n”);
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(”0.0.0.0″);
addr.sin_port = htons(TRANSFER_PORT);
if(-1 == bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)))
{
perror(”Failed to bind socket./n”);
return -1;
}
if(-1 == listen(sock, MAX_LISTEN))
{
printf(”Failed to bind socket. errno: %d/n”, errno);
return -1;
}
transfer_sock = sock;
printf(” %s: init transfer socket %d …… success/n”, __FUNCTION__, sock);
return 0;
}
void fini_transfer()
{
int ret;
ret = shutdown(transfer_sock, SHUT_RDWR);
ret = close(transfer_sock);
if(ret < 0)
perror(”/nfini_transfer: “);
else
printf(”/n/n %s: success shutdown transfer socket!/n/n”, __FUNCTION__);
}
int recv_data(int sock, char *buf, int len)
{
int l = 0;
memset(buf, 0, len);
l = recv(sock, buf, len, 0);
if(0 > l)
{
perror(”recv error: “);
return -1;
}
else if (0 == l)
{
printf(”client shutdown the socket %d … /n”, sock);
return 0;
}
printf(”recv %d data./n”, l);
return l;
}
void sig_handler_func(int sig)
{
fini_transfer();
exit(0);
}
int sig_handler(void)
{
int ret = 0;
struct sigaction sact;
ret = sigemptyset(&sact.sa_mask);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGQUIT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGINT, &sact, NULL);
if(0 > ret)
return ret;
sact.sa_flags = 0;
sact.sa_handler = sig_handler_func;
ret = sigaction(SIGKILL, &sact, NULL);
if(0 > ret)
return ret;
return 0;
}
int main()
{
int i;
int s;
int ret = 0;
char buf[4096] = { 0 };
int len;
int client_fd[MAX_LISTEN];
int max_fd = 0;
fd_set client_conns;
struct sockaddr_in client_addr;
init_transfer();
sig_handler();
for(i = 0; i < MAX_LISTEN; i ++)
client_fd[i] = -1;
FD_ZERO(&client_conns);
max_fd = transfer_sock;
while(1)
{
/**
* 特别提醒,这里必须把所有正在listen的socket重新加入select队列,
* 和我之前理解的不同。如果不把该socket重新加入,则select无法
* 监听这个socket的状态变化,也就无法accept新的连接。
*/
FD_CLR(transfer_sock, &client_conns);
FD_SET(transfer_sock, &client_conns);
ret = select(max_fd + 1, &client_conns, NULL, NULL, (struct timeval *)0);
if (0 > ret)
{
perror(”select(): “);
exit(-1);
}
else if (0 == ret)
{
printf(” select timeout ……/n”);
continue;
}
printf(”select return something … /n”);
/**
* 有新的客户连接
*/
if(FD_ISSET(transfer_sock, &client_conns))
{
len = sizeof(struct sockaddr_in);
memset(&client_addr, 0, len);
s = accept(transfer_sock, (struct sockaddr *)&client_addr, &len );
if(-1 == s)
{
perror(”accept failed:”);
continue;
}
/**
* 把新连接加入select队列中
*/
for (i = 0; i < MAX_LISTEN; i ++)
{
if(-1 != client_fd[i])
continue;
client_fd[i] = s;
break;
}
FD_SET(s , &client_conns);
if(max_fd < s)
max_fd = s;
printf(”Add client socket connection %d to select/n”, s);
continue;
}
for(i = 0; i < MAX_LISTEN; i ++)
{
if(-1 == client_fd[i])
continue;
if(!FD_ISSET(client_fd[i], &client_conns))
continue;
ret = recv_data(client_fd[i], buf, sizeof(buf));
if(0 >= ret)
{
close(client_fd[i]);
FD_CLR(client_fd[i], &client_conns);
printf(”del socket %d from select pipe./n”, client_fd[i]);
client_fd[i] = -1;
}
}
max_fd = transfer_sock;
for(i = 0; i < MAX_LISTEN; i ++)
{
if(max_fd < client_fd[i])
{
max_fd = client_fd[i];
}
}
printf(”This cycle of select loop over, max_fd = %d…/n”, max_fd);
}
fini_transfer();
return 0;
}
相关文章推荐
- Linux下的socket编程实践(七) I/O多路复用技术之select模型
- Linux下的socket编程实践(七) I/O多路复用技术之select模型
- socket编程:多路复用I/O服务端客户端之select
- Unix Socket编程--I/O复用之select模型
- Unix Socket编程--I/O复用之select模型
- 多路复用I/O模型select() 模型 代码实现
- socket编程之select多路复用
- [Python]Socket高级 -- select I/O复用模型(二)
- C/S通信---服务器IO多路复用模型之select的使用
- 多路复用I/O模型之select
- socket编程:多路复用I/O服务端客户端之select
- I/O多路复用之select模型
- [Python]Socket高级 -- select I/O复用模型(一)
- 多路IO复用模型 select epoll 等
- 状态集合[Python]Socket高级 -- select I/O复用模型(二)
- 自动化运维Python系列之IO多路复用、SocketServer源码分析
- socket server select模型值得注意的地方
- 从零开始写select和epoll I/O多路复用网络模型
- linux下多路复用模型之Select模型
- Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)