首页 > 系统相关 >【Linux网络编程-6】IO复用

【Linux网络编程-6】IO复用

时间:2024-07-15 17:52:13浏览次数:16  
标签:return addr int 复用 server IO Linux sockfd include

select模型

//selectServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <errno.h>
#include <vector>

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    std::vector<int> clientfds;

    fd_set readfdset;
    FD_ZERO(&readfdset);
    FD_SET(listenfd,&readfdset);
    int maxfd;
    maxfd=listenfd;
    struct timeval sttime;
    sttime.tv_sec=30;
    while(true)
    {
        fd_set readfdsetTmp=readfdset;
        int infds=select(maxfd+1,&readfdsetTmp,NULL,NULL,NULL);
        if(infds<0)
        {   
            printf("select error..\n");
            perror("select failed: ");
            break;
        }
        else if(infds==0)
        {
            printf("timeout..\n");
            continue;
        }
        else
        {
            for(int eventfd=0;eventfd<=maxfd;eventfd++)
            {
                if(FD_ISSET(eventfd,&readfdsetTmp)<=0)
                    continue;
                if(eventfd==listenfd) 
                {
                    //发生listen事件,有client连接
                    struct sockaddr_in client_addr;
                    socklen_t client_addr_size=sizeof(client_addr);
                    int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,(socklen_t*)&client_addr_size);
                    
                    printf("client(%d) connectd..\n",clientfd);
                    FD_SET(clientfd,&readfdset);
                    //添加描述符,更新maxfd
                    if(maxfd<clientfd) 
                        maxfd=clientfd;
                    clientfds.push_back(clientfd);
                    continue;
                }
                else
                {
                    //有数据可读事件,或对端断开事件
                    char buf[1024];
                    memset(buf,0,sizeof(buf));
                    size_t isize = recv(eventfd,buf,sizeof(buf),0);	//clientfd是会变的,要传eventfd进recv和send
                    if(isize<0)
                    {
                        //断开连接
                        printf("client(%d) disconneted..\n",eventfd);
                        close(eventfd);	//关闭连接
                        for(auto iter=clientfds.begin();iter!=clientfds.end();iter++)
                        {
                            if(*iter==eventfd)
                                clientfd.erase(iter);
                        }
                        FD_CLR(eventfd,&readfdset);	//该bit位置0
                        if(eventfd==maxfd)	//只有当移除的eventfd是maxfd时,才需要更新maxfd
                        {
                            for(int i=maxfd;i>=0;i--)	//找到新的最大的还是1的eventfd
                            {
                                if(FD_ISSET(eventfd,&readfdset))
                                {
                                 	maxfd=eventfd;
                                    break;
                                }
                            }
                        }
                        continue;
                    }
					
                    //接收数据
                    printf("recv(%d):%s,size=%d\n",eventfd,buf,isize) ;
                    send(eventfd,buf,strlen(buf),0);

                }

            }
        }

    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}
//selectClient.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/select.h>
#include <netdb.h>


bool ConnectServer(int* sockfd, const char* ip, int port);

int main(int argc,char** argv)
{
    int serverfd=-1;
    if(ConnectServer(&serverfd,"127.0.0.1",atoi(argv[1]))==false)
    {
        printf("connect failed..\n");
        return -1;
    }
    printf("connected..\n");

    char buf[1024];
    while(true)
    {
        memset(buf,0,sizeof(buf));
        printf("enter input:\n");
        scanf("%s",buf);

        if(send(serverfd,buf,strlen(buf),0)==false)
        {
            printf("send error..\n");
            return -1;
        }
        printf("send:%s\n",buf);
        
        memset(buf,0,sizeof(buf));
        if(recv(serverfd,buf,sizeof(buf),0)==false)
        {
            printf("recv error..\n");
            return -1;
        }
        printf("recv:%s\n",buf);
    }

    return 0;
}

bool ConnectServer(int* sockfd, const char* ip, int port)
{
    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));
	server_addr.sin_family=AF_INET;

	server_addr.sin_addr.s_addr=inet_addr(ip);	
	server_addr.sin_port=htons(port);
	
    *sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(*sockfd==-1)
    {
        return false;
    }
 
	if(connect(*sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        close(*sockfd);
        *sockfd=-1;
        return false;
    }

    return true;
}

2.poll模型

//pollServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <vector>
#include <time.h>
#include <poll.h>
#include <fcntl.h>

#define MAXNFDS 1024

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    printf("listenfd=%d\n",listenfd);
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    //初始化数组
    int maxfd;
    struct pollfd fds[MAXNFDS];
    for(int i=0;i<MAXNFDS;i++)
    {
        fds[i].fd=-1;
    }
    //添加listenfd到数组
    fds[listenfd].fd=listenfd;
    fds[listenfd].events=POLLIN;	//监听读数据事件
    fds[listenfd].revents=0;
    maxfd=listenfd;

    while(1)
    {
        int infds=poll(fds,maxfd+1,-1);
        if(infds<0)
        {   
            printf("poll error..\n");
            perror("poll failed: ");
            break;
        }
		//超时返回0
        if(infds==0)
        {
            printf("timeout..\n");
            continue;
        }

        //遍历数组
        for(int eventfd=0;eventfd<=maxfd;eventfd++)
        {
            if(fds[eventfd].fd==-1) //-1表示不监视描述符
                continue;
			
            /*
            if(!(fds[eventfd].revents&POLLIN))   //发生的不是POLLIN数据可读事件
                continue;
            fds[eventfd].revents=0; //revents置0
            */
            
            //下面是数据可读事件
            if((eventfd==listenfd) && (fds[eventfd].revents&POLLIN)) 
            {
	                fds[eventfd].revents=0;
                    struct sockaddr_in client_addr;
                    socklen_t client_addr_size=sizeof(client_addr);
                    int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,&client_addr_size);
                    if(clientfd<0)
                        printf("accept failed..\n");
                    printf("%ld client(%d) connectd..\n",time(0),clientfd);
                    //close client which is more than MAXNFDS
                    if(clientfd>MAXNFDS)
                    {
                        printf("clientfd(%d) > MAXNFDS(%d), close client..\n",clientfd,MAXNFDS);
                        close(clientfd);
                        continue;
                    }

                    //把clientfd添加监视
                    fds[clientfd].fd=clientfd;
                    fds[clientfd].events=POLLIN;
                    fds[clientfd].revents=0;
                    //更新maxfd
                    if(maxfd<clientfd) 
                        maxfd=clientfd;
                    printf("maxfd=%d\n",maxfd);
                    continue;
            }
            else if(fds[eventfd].revents&POLLIN)
            {
                fds[eventfd].revents=0;
                char buf[1024];
                memset(buf,0,sizeof(buf));
                size_t isize = recv(eventfd,buf,sizeof(buf),0);
                if(isize<=0)
                {
                    printf("%ld client(%d) disconneted..\n",time(0),eventfd);
                    close(eventfd);
                        
                    //client断开,将clientfd移除监视
                    fds[eventfd].fd=-1;
                    if(eventfd==maxfd)	//更新maxfd
                    {
                        for(int i=maxfd;i>0;i--)
                        {
                            if(fds[i].fd!=-1)
                                maxfd=i;
                                break;
                        }
                        printf("maxfd=%d\n",maxfd);
                    }
                    continue;
                }
                //printf("recv(%d):%s,size=%d\n",eventfd,buf,isize) ;
                
                send(eventfd,buf,strlen(buf),0);
            }
        }
    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}

3.epoll模型

//epollServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <vector>
#include <time.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define MAXEVENTS 100

int InitServer(const unsigned int port);

int main(int argc,char** argv)
{
    int listenfd=InitServer(atoi(argv[1]));
    printf("listenfd=%d\n",listenfd);
    if(listenfd==-1)
    {
        printf("InitServer failed..\n");
        return -1;
    }

    //创建epoll句柄
    int epollfd=epoll_create(1);
    if(epollfd<0)   printf("epoll_create failed..\n");

    //epoll_event封装listenfd和监视类型为有数据可读(EPOLLIN)
    struct epoll_event ev;
    ev.data.fd=listenfd;
    ev.events=EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&ev);	//添加到epollfd

    while(true)
    {
        struct epoll_event events[MAXEVENTS];	//epoll_wait返回时保存发生的事件
        int infds=epoll_wait(epollfd,events,MAXEVENTS,-1);
        if(infds<0) 
        {
            printf("epoll_wait failed..\n");
            break;
        }
        if(infds==0)
        {
            printf("timeout..\n");
            break;
        }
        
        //发生的事件再events中从index=0依次保存
        for(int i=0;i<infds;i++) 
        {
            //listenfd上有数据可读事件发生
            if((events[i].data.fd==listenfd) && (events[i].events&EPOLLIN))
            {
                struct sockaddr_in client_addr;
                socklen_t client_addr_size=sizeof(client_addr);
                int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,&client_addr_size);
                if(clientfd<0)
                {
                    printf("accept failed..\n");
                    continue;
                }

                //连接上的客户端添加进监视
                memset(&ev,0,sizeof(struct epoll_event));	//清空ev
                
                ev.data.fd=clientfd;
                ev.events=EPOLLIN;
                epoll_ctl(epollfd,EPOLL_CTL_ADD,clientfd,&ev);
                printf("%ld client(%d) connectd..\n",time(0),clientfd);
                continue;
            }
            else if(events[i].events&EPOLLIN)	//有数据可读事件
            {
                char buf[1024];
                memset(buf,0,sizeof(buf));
                size_t isize = recv(events[i].data.fd,buf,sizeof(buf),0);

                if(isize<=0)
                {
                    //把客户端fd从监视中删除
                    memset(&ev,0,sizeof(struct epoll_event));
                    ev.data.fd=events[i].data.fd;
                    ev.events=EPOLLIN;
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);

                    close(events[i].data.fd);
                    printf("%ld client(%d) disconneted..\n",time(0),events[i].data.fd);
                    continue;
                }
 
                printf("client(%d)recv msg:%s,size=%d\n",events[i].data.fd,buf,isize);

                //send(events[i].data.fd,buf,strlen(buf),0);
                //判断sockfd是否可写
			   fd_set tmpfd;
			   FD_ZERO(tmpfd);
			   FD_SET(events[i].data.fd,&tmpfd);
			   if(select(events[i].data.fd+1,0,&tmpfd,0,0)<0)
			   {
			       printf("没有可写数据的fd\n");
			       return -1;
			   }
			   if(write(events[i].data.fd,buf,strlen(buf))<0)
			   {
			       printf("write failed..\n");
			       close(events[i].data.fd);
			       return -1;
			   }
                
            }
       }
    }
    return 0;
}

int InitServer(const unsigned int port)
{
    int sockfd=-1;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(sockfd == -1) return -1;

    int opt=1;
    unsigned int len=sizeof(opt);
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
	
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);	
    server_addr.sin_port=htons(port);

    if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }
    
    if(listen(sockfd, 5) == -1)
    {
        close(sockfd);
        sockfd=-1;
        return -1;
    }

    return sockfd;
}

标签:return,addr,int,复用,server,IO,Linux,sockfd,include
From: https://www.cnblogs.com/wk2522466153/p/18303668

相关文章

  • Linux获取进程cpu使用情况
    相关:{%post_linkshell/'Linux获取线程CPU使用情况'%}CPU使用率pidstat(推荐)pidstat-p进程PID-H-u间隔秒数|awk'{if(NR>3){print$1,$8}}'-H:Displaytimestampinsecondssincetheepoch.-u:ReportCPUutilization.NR>3:第四行开始才是有效输出。awk......
  • ArchLinux微信
    flatpak原生微信。flatpakinstallcom.tencent.WeChatflatpakruncom.tencent.WeChat也可以从系统的启动器里启动。{%post_linkApp/'flatpak教程'%}deepin-wine-wechatyay-Sdeepin-wine-wechat我尝试的版本:3.9.0.28-3如果是KDE的话,大概会报这个错:/opt/apps/com......
  • 数据库和对象存储_DuckDB 访问 Minio
    使用DuckDB访问Minio以对象存储为中心的世界的数据库数据库一直是基于SAN的块存储和基于NAS的文件存储的主要工作负载,OLAP数据库领域将在未来几年内转向对象存储优先的定位在DuckDB实例的生命周期内存储在内存中。持久密码以未加密的二进制格式存储在~/.duc......
  • Exchange邮箱用户发邮件失败,提示“ Client does not have permissions to send as thi
    原贴https://www.cnblogs.com/dreamer-fish/p/16876232.htmlExchange邮箱用户发邮件失败,提示“Clientdoesnothavepermissionstosendasthissender”Exchange用户发邮件提示“5505.7.60SMTP;Clientdoesnothavepermissionstosendasthissender”处理方法:......
  • Azure Function 时区设置
    一,引言AzureFunction上的默认使用UTC运行程序,我们在获取时间,或者通过时间执行某些逻辑时,返回UTC时间,导致业务数据不正常,由于AzureFunction是微软提供的IaaS托管服务,我们无法登录服务器来修改时区,那么我们今天将来实践操作,如何通过配置达到更改AzureFunction时区......
  • Linux 报错INFO: task blocked for more than 120 seconds
     一般情况下,Linux会把可用内存的40%的空间作为文件系统的缓存。 当缓存快满时,文件系统将缓存中的数据整体同步到磁盘中。但是系统对同步时间有最大120秒的限制。 如果文件系统不能在时间限制之内完成数据同步,则会发生上述的错误。 这通常发生在内存很大的系统上。系统......
  • linux 审核策略
    审计范围应覆盖到服务器和重要客户端上的每个操作系统用户和数据库用户;开启审核策略,若日后系统出现故障、安全事故则可以查看系统日志文件,排除故障、追查入侵者的信息等。查看rsyslog与auditd服务是否开启应保护审计记录,避免受到未预期的删除、修改或覆盖等。防止重要日志信息......
  • AI绘画Stable Diffusion 零基础入门 —AI 绘画原理与工具介绍,万字解析AI绘画的使用教
    大家好,我是设计师阿威想要入门AI绘画,首先需要了解它的原理是什么样的。其实很早就已经有人基于深度学习模型展开了对图像生成的研究了,但在那时,生成的图像分辨率和内容都非常抽象。直到近两年,AI产出的图像内容的质量变高、而且有一定的艺术价值,这时它才算正式拥有了理......
  • AI绘画Stable Diffusion教程,6种提示词角度!精准实现你的 stable diffusion 创作意图!
    1、引言本期内容的核心目标是向你展示构图、风格、媒介、画面清晰度、灯光效果以及颜色氛围等6大类别中的常用标签(tags),这些标签将为你提供更深入的理解,并帮助你更有效地编写提示词(prompt)。这些标签可以大大影响AI绘图模型生成的图片内容,掌握好它们的使用,将有助于你在AI绘......
  • 如何使用AI绘画工具stable diffusion填充画外内容?保姆级教程建议收藏!
    大家好,我是设计师阿威当我们尝试绘制高分辨率的图片时,传统的SD模型常常会遇到诸多问题,例如元素重复、显存不足和生成时间过长等。但如果只绘制低分辨率的图片,却很难生成丰富的画面元素和细节。我们可以借助outpaint来解决这个问题。Outpaint可以简单地理解为绘制画外内容,......