select
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int array_fds[
1024];
static void Usage(
const char *proc)
{
printf(
"Usage: %s [local_ip] [local_port]\n",proc);
}
int startup(
char *_ip,
int _port)
{
int sock = socket(AF_INET,SOCK_STREAM,
0);
if(sock <
0)
{
perror(
"sock");
exit(
2);
}
int flag =
1;
setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,&flag,
sizeof(flag));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = inet_addr(_ip);
if(bind(sock,(
struct sockaddr*)&local,
sizeof(local))<
0)
{
perror(
"bind");
exit(
3);
}
if(listen(sock,
10)<
0)
{
perror(
"listen");
exit(
4);
}
return sock;
}
int main(
int argc,
char* argv[])
{
if(argc !=
3)
{
Usage(argv[
0]);
return 0;
}
int listenSock = startup(argv[
1],atoi(argv[
2]));
int maxfd =
0;
fd_set rfds;
int array_size =
sizeof(array_fds)/
sizeof(array_fds[
0]);
array_fds[
0] = listenSock;
int i =
1;
for(;i < array_size;i++)
{
array_fds[i] = -
1;
}
while(
1){
struct timeval _timeout = {
0,
0};
FD_ZERO(&rfds);
maxfd = -
1;
for(i =
0;i<array_size;i++){
if(array_fds[i] >
0){
FD_SET(array_fds[i],&rfds);
if(array_fds[i] > maxfd){
maxfd = array_fds[i];
}
}
}
switch(select(maxfd+
1,&rfds,NULL,NULL,NULL)){
case 0:
printf(
"timeout...\n");
break;
case -
1:
perror(
"select");
break;
default:
{
int j =
0;
for(;j < array_size;j++){
if(array_fds[j]<
0){
continue;
}
if(j ==
0&&FD_ISSET(array_fds[j],&rfds)){
struct sockaddr_in client;
socklen_t len =
sizeof(client);
int new_fd = accept(array_fds[j],\
(
struct sockaddr*)&client,&len);
if(new_fd <
0){
perror(
"accept");
continue;
}
else{
printf(
"get a new client: (%s:%d)\n",\
inet_ntoa(client.sin_addr),\
ntohs(client.sin_port));
int k =
1;
for(;k < array_size;k++){
if(array_fds[k] <
0){
array_fds[k] = new_fd;
break;
}
}
if(k == array_size){
close(new_fd);
}
}
}
else if(j !=
0&&\
FD_ISSET(array_fds[j],&rfds))
{
char buf[
10240];
ssize_t s = read(array_fds[j],buf,
sizeof(buf)-
1);
if(s>
0)
{
buf[s] =
0;
printf(
"client say: %s\n",buf);
}
else if(s ==
0)
{
printf(
"client quit!\n");
close(array_fds[j]);
array_fds[j] = -
1;
}
else
{
perror(
"read");
close(array_fds[j]);
array_fds[j] = -
1;
}
}
else
{
}
}
}
break;
}
}
return 0;
}
client
#include<stdio.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/stat.h>
#include<unistd.h>
static void Usage(
char * proc)
{
printf(
"Usage : %s [ip] [port]\n");
}
int main(
int argc,
char* argv[])
{
if(argc !=
3)
{
Usage(argv[
0]);
return 1;
}
int sock = socket(AF_INET, SOCK_STREAM,
0);
struct sockaddr_in peer;
peer.sin_family = AF_INET;
peer.sin_port = htons(atoi(argv[
2]));
peer.sin_addr.s_addr = inet_addr(argv[
1]);
if(connect(sock, (
struct sockaddr*)&peer,
sizeof(peer)) <
0)
{
perror(
"connect");
return 2;
}
char buf[
10240];
while(
1)
{
printf(
"Please Enter : ");
fflush(stdout);
ssize_t s = read(
0, buf,
sizeof(buf)-
1);
int sfd = dup(STDOUT_FILENO);
if(s >
0)
{
buf[s-
1] =
0;
int new_fd = dup2(sock,
1);
if(new_fd == -
1)
{
perror(
"dup()");
return -
1;
}
printf(
"%s",buf);
fflush(stdout);
dup2(sfd, STDOUT_FILENO);
ssize_t _s = read(sock, buf,
sizeof(buf)-
1);
if(_s >
0)
{
buf[_s] =
0;
printf(
"sever # %s \n", buf);
}
}
}
close(sock);
return 0;
}
总结select服务器优缺点,与多进程/多线程服务器进行对比: 使用select注意事项: 1.要将sock_fd加入到maxfd+1中,要不就无法检测到网络连接,会一直阻塞在select语句 2.通过存储每次连接的描述符,设置FD_SET函数,在遍历的去判断FD_ISSET处理。 3.我们可以看到select每次有数据到来时,需要遍历的去寻找所有可用的描述符,来判断其是否满足处理的条件。 4.select的通知机制,轮询的去查看是否在maxfd+1内有满足条件的描述符 select优缺点: 与多进程/多线程服务器进行对比 它的优点在于: 1、不需要建立多个线程、进程就可以实现一对多的通信。 2、可以同时等待多个文件描述符,效率比起多进程多线程来说要高很多。 3、select()的可移植性更好,在某些Unix系统上不支持poll() 4、select() 对于超时值提供了更好的精度:微秒,而poll是毫秒
与多进程/多线程服务器进行对比 它的缺点在于: 1、每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 ,循环次数有点多; 2、同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 。 3、select支持的文件描述符数量太小了,默认是1024;