#include <string.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#define SERV_PORT 8080
#define MAXLINE 100
#define MAXSIZE 1024
void sys_error(const char *fun_str,int exitno)
{
perror(fun_str);
exit(exitno);
}
int main(void)
{
//nready记录select就绪的文件描述符个数 maxfd用于记录最大描述符 maxi用于记录客户端的数组下标
//rset用于记录监听描述符中可读文件的描述符集合 allset用于记录要监听的文件描述符集合
int ret=0,i=0,nready;
int maxfd,maxi=-1;
int client[MAXSIZE];
fd_set rset,allset;
int sockfd,connfd,cli_fd;
int cli_len;
struct sockaddr_in serv_addr,cli_addr;
char buf[MAXSIZE];
char addr[MAXLINE];
int len;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
sys_error("socket",-1);
}
bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(-1 == ret)
{
sys_error("bind",-2);
}
//listen 中backlog的值为两个连接队列的和 已完成连接队列 和正处于三次握手的待连接队列
ret = listen(sockfd,20);
if(-1 == ret)
{
sys_error("listen",-3);
}
printf("waiting for connnect\n");
for(i=0; i<MAXSIZE; i++)
{
client[i]=-1;
}
maxfd = sockfd;
FD_ZERO(&allset);
FD_ZERO(&rset);
FD_SET(sockfd,&allset);
while(1)
{
rset = allset;
//rset位一个传入传出参数 作为传入参数时为要监听的文件描述符的集合 作为传出参数时为就绪的文件描述符会被置位
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if(nready<0)
{
sys_error("select",-4);
}
//有新的客户端发起连接请求
if(FD_ISSET(sockfd,&rset))
{
cli_len = sizeof(cli_addr);
connfd = accept(sockfd,(struct sockaddr*)&cli_addr, &cli_len);
printf("receive from ip %s port %d\n",
inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, buf, sizeof(buf)),ntohs(cli_addr.sin_port));
if(connfd == -1)
{
sys_error("accept",-5);
}
//将对应的文件描述符加入到client的数组中
for(i=0; i<MAXSIZE; i++)
{
if(client[i]<0)
{
client[i] = connfd;
break;
}
}
if(i == MAXSIZE)
{
perror("too many client\n");
exit(1);
}
//将已经建立连接的文件描述符添加到要监听的集合中
FD_SET(connfd, &allset);
if(i>maxi)
{
maxi = i;
}
if(connfd > maxfd)
{
maxfd = connfd;
}
//说明已经处理完客户端的请求连接,继续阻塞于select
if(--nready == 0)
continue;
//说明在已经建立连接的描述符有数据
}
//有数据可读
for(i=0; i<=maxi; i++)
{
cli_fd = client[i];
if(FD_ISSET(cli_fd,&rset))
{
//处理请求
len = read(cli_fd, buf, sizeof(buf));
if(len<0)
{
sys_error("read",-6);
}
ret = write(cli_fd, buf, len);
if(ret < 0)
{
sys_error("write",-7);
}
if(-- nready == 0)
{
break;
}
}
}
}
close(sockfd);
return 0;
}