Linux网络编程之select模型

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

服务器select模型

/*
 *  @file           server_select.c
 *  @brief          TCP编程API的服务器select模型
 *  @version 1.1    无
 *  @author         北豼
 *  @date           2022年5月21日
 */

#include "net.h"

int main(void)
{

        int fd = -1;
        struct sockaddr_in sin;
        struct timeval tout;

        /*1.创建socket fd*/
        if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
                perror("socket");
                exit(1);
        }

        /*2.绑定*/
        /*2.1填充struct sockaddr_in结构体变量*/
        bzero(&sin, sizeof(sin));               //将struct sockaddr_in结构体变量清零
        sin.sin_family = AF_INET;
        sin.sin_port = htons(SERV_PORT);        //主机字节序的端口号转换为网络字节序的端口号
#if 0
        //主机字节序的IP转换为网络字节序的IP
        sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
        //主机字节序的IP转换为网络字节序的IP
        if (inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr) != 1)
        {
                perror("inet_pton");
                exit(1);
        }
#endif
        /*2.2绑定*/
        if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
                perror("bind");
                exit(1);
        }

        /*3.调用listen()把主动套接字变成被动套接字*/
        if ( listen(fd, BACKLOG) < 0)                   //BACKLOG = 5
        {
                perror("listen");
                exit(1);
        }

        /*4.多路复用*/
        fd_set rset;
        FD_ZERO(&rset);
        //依次把已经建立好连接的fd加入到集合中,记录下来最大的文件描述符maxfd
        FD_SET(fd, &rset);
        tout.tv_sec = 5;
        tout.tv_usec = 0;
        int maxfd = -1;
        maxfd = fd;
        int newfd = -1;

        /*5.读写*/
        /*和newfd进行数据读写*/
        int ret = -1;
        char buf[BUFSIZ];

        while (1)
        {
                fd_set tmp = rset;
                select(maxfd+1, &tmp, NULL, NULL, &tout);

                //判断是不是监听的fd
                if (FD_ISSET(fd, &tmp))
                {
                        newfd = accept(fd, NULL, NULL);                 //后面的两个参数可以接收客户端的属性信息
                        if (newfd < 0)
                        {
                                perror("accept");
                                exit(1);
                        }
                        FD_SET(newfd, &rset);
                        if (newfd > maxfd)
                        {
                                maxfd = newfd;
                        }

                        printf("accept sucessfully!\n");
                }

                for (int i = 0; i <= maxfd; ++i)
                {
                        if (i != fd && FD_ISSET(i, &tmp))
                        {
                                bzero(buf, BUFSIZ);
                                do
                                {
                                        ret =  read(i, buf, BUFSIZ-1);
                                }while (ret < 0 && EINTR == errno);             //如果读取的过程中遇到了中断,则再次从newfd中读取数据到buf中
                                if (ret < 0)
                                {
                                        perror("read");
                                        exit(1);
                                }
                                if (!ret)               //对方已经关闭
                                {
                                        printf("客户端已经断开连接...\n");
                                        FD_CLR(i, &rset);
                                        close(i);
                                        break;
                                }

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

                                if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)))      //用户输入了quit字符(忽略大小写)
                                {
                                        printf("Client is exiting!\n");
                                        break;
                                }

                        }
                }
        }
        close(fd);

}

客户端select模型

/*
 *  @file           client_select.c
 *  @brief          TCP编程API的客户端select模型
 *  @version 1.1
 *  @author         北豼
 *  @date           2022年5月14日
 */

#include "net.h"

int main(void)
{
        int fd = -1;
        struct sockaddr_in sin;

        /*1.创建socket fd*/
        if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
                perror("socket");
                exit(1);
        }

        /*2.连接服务器*/
        /*2.1填充struct sockaddr_in结构体变量*/
        bzero(&sin, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(SERV_PORT);        //网络字节序的端口号
#if 0
        sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
        if (inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr) != 1)
        {
                perror("inet_pton");
                exit(1);
        }
#endif

        if ((connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0))
        {
                perror("connect");
                exit(1);
        }

#if 0
        /*3.读写数据*/
        char buf[BUFSIZ];
        while (1)
        {
                bzero(buf, BUFSIZ);
                if (fgets(buf, BUFSIZ-1, stdin) == NULL)
                {
                        continue;
                }
                write(fd, buf, strlen(buf));

                if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)))      //用户输入了quit字符
                {
                        printf("Client is exiting!\n");
                        break;
                }

        }
#else
        int ret = -1;
        fd_set rset;
        int maxfd = -1;
        struct timeval tout;
        char buf[BUFSIZ];

        while (1)
        {
                FD_ZERO(&rset);
                FD_SET(0, &rset);
                FD_SET(fd, &rset);
                maxfd = fd;

                tout.tv_sec = 5;
                tout.tv_usec = 0;

                select(maxfd+1, &rset, NULL, NULL, &tout);
                /*如果标准键盘上有输入,读取键盘输入,发送到网络套接字fd*/
                if (FD_ISSET(0, &rset))
                {
                        bzero(buf, BUFSIZ);

                        do
                        {
                                ret = read(0, buf, BUFSIZ-1);
                        }while(ret < 0 && EINTR == errno);
                        if (ret < 0)
                        {
                                perror("read");
                                continue;
                        }
                        if (!ret)
                        {
                                continue;
                        }

                        if (write(fd, buf, strlen(buf)) < 0)
                        {
                                perror("write() to socket");
                                continue;
                        }

                        if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)))      //用户输入了quit字符
                        {
                                printf("Client is exiting!\n");
                                break;
                        }

                }

                /*如果服务器发送过来了数据,读取套接字数据,处理*/
                if (FD_ISSET(fd, &rset))
                {
                        bzero(buf, BUFSIZ);

                        do
                        {
                                ret = read(fd, buf, BUFSIZ-1);
                        }while(ret < 0 && EINTR == errno);
                        if (ret < 0)
                        {
                                perror("read from socket");
                                continue;
                        }
                        if (!ret)               //服务器关闭
                        {
                                break;
                        }

                        printf("server said: %s\n", buf);
                        if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR)))      //用户输入了quit字符
                        {
                                printf("Sender Client is exiting!\n");
                                break;
                        }

                }
        }
#endif
        /*4.关闭套接字*/
        close(fd);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是北豼不太皮吖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值