select() +socket 实现 socket服务器 -Linux

来源:互联网 发布:知商金融活动 编辑:程序博客网 时间:2024/05/20 10:11
#include<stdlib.h>#include<stdio.h>#include<unistd.h>#include<errno.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<string.h>#define PORT 1234 //服务器监听端口#define CLIENTSIZE 10 //最大连接数#define BUF_SIZE 200 //缓冲区大小int fd_Arr[CLIENTSIZE];//客户端文件描述符 数组int amount; //当前连接数量//显示当前连接的所有客户端void showClient(){int i;printf("Client amount:%d\n", amount);for (i = 0; i < CLIENTSIZE; i++){printf("[%d]:%d", i, fd_Arr[i]);}printf("\n");}int main(void){//服务器监听 fd,客户端新连接fdint sock_fd, client_fd; //服务器监听套接字地址信息struct sockaddr_in server_addr;//客户端套接字地址信息struct sockaddr_in client_addr;//socket长度socklen_t sin_size;int yes = 1;char buf[BUF_SIZE];//缓冲区大小int ret;// 返回值//初始化 服务器套接字if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket init Failure:");exit(1);} //if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){perror("setsockopt set NON-BLOCK failure:");exit(1);}memset(&server_addr, 0, sizeof(server_addr));// 主机字节序server_addr.sin_family = AF_INET;//主机字节序 转网络字节序server_addr.sin_port = htons(PORT);//设置所有ipserver_addr.sin_addr.s_addr = INADDR_ANY;//绑定端口if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){perror(" bind fail:");exit(1);}//监听端口if (listen(sock_fd, CLIENTSIZE) == -1){perror("listen fail!");exit(1);}//打印监听端口printf(" listen port %d .....\n", PORT);//待检查的 fd_set集合fd_set fdsr;int maxsock;//超时设置struct timeval tv;//给初始大小赋值amount = 0;sin_size = sizeof(client_addr);//select的最大数量maxsock = CLIENTSIZE;//每一次while循环 ,需要设置FD_SET,加入待检查的描述符,还要Select// 还需要 判断 FD_ISSET是否可以读/写while (1){//初始化集合FD_ZERO(&fdsr);//服务器监听套接字文件描述符加入setFD_SET(sock_fd, &fdsr);//超时设置tv.tv_sec = 30;tv.tv_usec = 0;//把所有客户端套接字添加进集合for (int i = 0; i < CLIENTSIZE; i++){if (fd_Arr[i] != 0){FD_SET(fd_Arr[i], &fdsr);}}//执行selectret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);//如果小于0 那么就是 select出错了if (ret < 0){perror("select failure:");break;} //如果等于0 就是 超时时间到了  continue继续else if (ret == 0){printf("timeout:");continue;}//检查是否是一个新连接的到来(就是server监听fd可读)if (FD_ISSET(sock_fd, &fdsr)){//获取客户端fdclient_fd = accept(sock_fd, (struct sockaddr*)&client_addr, &sin_size);//小于0 出错if (client_fd <= 0){perror("accept fail:");continue;}//总数量 小于 最大连接数 就可以添加if (amount < CLIENTSIZE){for(int i=0;i<CLIENTSIZE;i++){//查找一个空的位置if(fd_Arr[i]==0){fd_Arr[i] = client_fd;break;}}amount++;printf("new client connected!\n");showClient();//显示客户端}else{//连接已满printf("connection amount is more than max!");send(client_fd, "bye", 4, 0);close(client_fd);break;}}//检查每一个可读的fd,判断是否可读/写 for (int i = 0; i < CLIENTSIZE; i++){if (FD_ISSET(fd_Arr[i], &fdsr)){//接收数据 revcret = recv(fd_Arr[i], buf, sizeof(buf), 0);//如果客户端断开了 会发送一个FIN 0//这里就会返回0 并且 表示断开了if (ret <= 0){printf("client[%d] close\n", i);//关闭套接字close(fd_Arr[i]); //从集合中清除FD_CLR(fd_Arr[i], &fdsr);//重置fd_Arr[i] = 0;//连接数量减一--amount;showClient();//显示客户端}else {//正常接收//if (ret<BUF_SIZE)//memset(&buf[ret], '\0', 1);printf("recv data from client[%d]:%s\n", i, buf);}}}}exit(0);}

原创粉丝点击