select服务器设计

select工作原理:
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
函数说明:
maxfdp:表示要监听的最大个数,
readfds:表示监听可读
writefds:监听可写
errorfds:监听异常错误
timeout: 监听超时时间,NULL表示阻塞

 对监听集合的操作:
   void FD_CLR(int fd, fd_set *set);//把某fd文件描述符从集合清除
   int  FD_ISSET(int fd, fd_set *set);//判断某fd文件描述是否留在集合里--->即发出信号是否为该fd
   void FD_SET(int fd, fd_set *set);//设置某fd文件描述到监听集合里
   void FD_ZERO(fd_set *set);//清除集合里的文件描述符

 
    原理:
    select里面有个监听集合,把需要监听的文件描述符写进集合用FD_SET();
    当有某文件描述符发出信号,就会自动把其他文件描述符删除掉,只留下该文件描述符
    所以我们需要提前把集合里的文件描述符提前保留下来,通过循环找到文件描述符
    
    
    并发服务器设计:
    1.把socket写进监听集合FD_SET(int fd, fd_set *set)
    2.如果监听到的是socket文件描述符发来信号 FD_ISSET(int fd, fd_set *set),表示有新的客户端连接
        接受该客户端连接accept(),把通信文件描述符写入监听集合,
    3.如果监听到的是通信文件描述符,我们还需通过循环判断该文件描述符是哪个客户端的,确定下文件描述符后
        就可以通过该文件描述符通信
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include <pthread.h>
//#include"node.h"
//#include"list.h"
//#include<json/json.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>


//客户端处理函数
int main()
{
    int sockfd,confd[1024]={0};
    struct sockaddr_in serveraddr_in,clientaddr_in;

    //1.创建套接字
    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1)
    {perror("socket");exit(1);
    }
//2.绑定
    memset(&serveraddr_in,0,sizeof(serveraddr_in));
    serveraddr_in.sin_family=AF_INET;
    serveraddr_in.sin_port=htons(6868);
    serveraddr_in.sin_addr.s_addr=inet_addr("172.18.125.34");
    int ret=bind(sockfd,(struct sockaddr *)&serveraddr_in,sizeof(serveraddr_in));
    if(ret==-1)
    {perror("bind");exit(1);
    }
//3.监听
    ret=listen(sockfd,10);
    if(ret==-1)
    {perror("listen");exit(1);
    }

    int length=sizeof(clientaddr_in);
    fd_set readfd,tmpfd;    //监听集合
    FD_ZERO(&readfd);       //清空集合
    FD_SET(sockfd,&readfd); //设置集合
    int maxfd=sockfd; //设置监听个数
    char buf[128]={0};
 while(1)
    {
    ┊   tmpfd=readfd;//保存集合,因为当有文件有可读或写异常时,会把其他文件描述符删掉,留下可用的文件描述符int ret=select(maxfd+1,&tmpfd,NULL,NULL,NULL);//监听有可读文件描述符if(ret==-1){
    ┊   ┊   perror("select");
    ┊   ┊   exit(1);}if(FD_ISSET(sockfd,&tmpfd))//1.判断是否为sockfd{
    ┊   ┊   int i;
    ┊   ┊   for( i=0;i<1024;i++)//2.判断哪个通信fd是没用过的,因为当客户端退出后,那个位置就为0
    ┊   ┊   {
    ┊   ┊   ┊   if(confd[i]==0)
    ┊   ┊   ┊   {
    ┊   ┊   ┊   ┊   break;
    ┊   ┊   ┊   }
    ┊   ┊   }<F9>
    ┊   ┊ //3.接受链接
    ┊   ┊   confd[i]=accept(sockfd,(struct sockaddr*)&clientaddr_in,(socklen_t *)&length);
    ┊   ┊   if(confd[i]==-1)
    ┊   ┊   {
    ┊   ┊   ┊   perror("accept");
    ┊   ┊   ┊   exit(1);
    ┊   ┊   }//打印连接的客户端IP
    ┊   ┊   printf("客户端%s连接成功 fd=%d\n",inet_ntoa(clientaddr_in.sin_addr),confd[i]);
    ┊   ┊   FD_SET(confd[i],&readfd);//4.把上线的客户端的文件描述符写入集合
    ┊   ┊   if(confd[i]>maxfd)//5.修改监听的最大个数
    ┊   ┊   {
    ┊   ┊   ┊   maxfd=confd[i];
    ┊   ┊   }}else//1.表示是通信描述符的{
    ┊   ┊   memset(buf,0,sizeof(buf));//清除Buf
    ┊   ┊   for(int i=0;i<1024;i++)//2.判断是哪个通信文件描述符
    ┊   ┊   {
    ┊   ┊   ┊   if(FD_ISSET(confd[i],&tmpfd))
    ┊   ┊   ┊   {
    ┊   ┊   ┊   ┊   int ret=recv(confd[i],buf,sizeof(buf),0);//3.接收来自客户端信息
    ┊   ┊   ┊   ┊   if(ret==-1)
    ┊   ┊   ┊   ┊   {
    ┊   ┊   ┊   ┊   ┊   perror("recv");
    ┊   ┊   ┊   ┊   ┊
    ┊   ┊   ┊   ┊   }
    ┊   ┊   ┊   ┊   if(ret==0)//判断是否为退出
    ┊   ┊   ┊   ┊   {
    ┊   ┊   ┊   ┊   ┊   perror("客户端退出");
    ┊   ┊   ┊   ┊   ┊   close(confd[i]);//关闭通信文件描述符
    ┊   ┊   ┊   ┊   ┊   FD_CLR(confd[i],&readfd);//从监听集合中清除通信文件符
    ┊   ┊   ┊   ┊   ┊   confd[i]=0;//文件描述符置0
    ┊   ┊   ┊   ┊   }
    ┊   ┊   ┊   ┊   else
    ┊   ┊   ┊   ┊   {
    ┊   ┊   ┊   ┊   ┊   printf("收到客户%d的信息:%s\n",confd[i],buf);//打印信息
    ┊   ┊   ┊   ┊   }
    ┊   ┊   ┊   ┊   break;
    ┊   ┊   ┊   }
    ┊   ┊   }}
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知道起个啥名“”

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值