2. 基于多路复用的服务端

在这里插入图片描述
当有客户端连接时再调用accept()接受连接
在这里插入图片描述
在这里插入图片描述
监视服务端文件描述符server_fd,有事件发生,连接:accept(),返回新的文件描述符:client_fd与客户端通信,监听这个描述符,监听的事件:数据是否到达,若发生了就调用read/recv函数处理数据。

在这里插入图片描述
理解:
文件描述符在[0,max]中,都会被监视。如果监视的文件描述符发生了事件,返回大于0的数值,进入if语句,遍历文件描述符,查找哪一个发生了。如果是服务端的事件,处理,接受客户端连接。不是服务端的事件,那就是客户端的事件:读数据。

在这里插入图片描述
在这里插入图片描述

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
//处理服务端的事件函数
int server_handler(int server)
{
    struct sockaddr_in addr = {0};
    socklen_t asize = sizeof(addr);

    return accept(server, (struct sockaddr*)&addr, &asize);
}
//处理客户端数据的事件
int client_handler(int client)
{
    char buf[32] = {0};
    int ret = read(client, buf, sizeof(buf)-1);

    if( ret > 0 )
    {
        buf[ret] = 0;

        printf("Receive: %s\n", buf);

        if( strcmp(buf, "quit") != 0 )
        {
            ret = write(client, buf, ret);
        }
        else
        {
            ret = -1;
        }
    }

    return ret;
}

int main()
{
    int server = 0;
    struct sockaddr_in saddr = {0};
    int max = 0;
    int num = 0;
    fd_set reads = {0};
    fd_set temps = {0};
    struct timeval timeout = {0};
    server = socket(PF_INET, SOCK_STREAM, 0);
    if( server == -1 )
    {
        printf("server socket error\n");
        return -1;
    }
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8888);
    if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
    {
        printf("server bind error\n");
        return -1;
    }
    if( listen(server, 1) == -1 )
    {
        printf("server listen error\n");
        return -1;
    }
    printf("server start success\n");
    FD_ZERO(&reads);//清空
    FD_SET(server, &reads);//标识,对serevr监听
    max = server;
    while( 1 )
    {
        temps = reads;	
		//设置超时值
        timeout.tv_sec = 0;
        timeout.tv_usec = 10000;
        num = select(max+1, &temps, 0, 0, &timeout);//最大值基础上+1
        if( num > 0 )//进入if语句说明有事件发生,接下来查找哪一个事件并处理
        {
            int i = 0;

            for(i=1; i<=max; i++)
            {
                if( FD_ISSET(i, &temps) )//当前是否为有事件发生的文件描述符
                {
                    if( i == server )//是否为server,说明有新客户端连接
                    {
                        int client = server_handler(server);

                        if( client > -1 )
                        {
                            FD_SET(client, &reads);

                            max = (client > max) ? client : max;

                            printf("accept client: %d\n", client); 
                        }
                    }
                    else//客户端,有数据需要处理
                    {
                        int r = client_handler(i);

                        if( r == -1 )
                        {
                            FD_CLR(i, &reads);

                            close(i);
                        }
                    }
                }
            }
        }
    }   
    close(server);

    return 0;
}

印证了Linux一切皆文件的说法!

是否还有优化空间,select是否可以优化?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值