Blcoking I/O & NonBlocking I/O

写在前面

以前在学校的时候,老想着要出来工作锻炼一下自己,等到真的出来了,才发现校园生活是最宝贵的。

出来快一年了,感慨很多,但却不知道如何说起,如果非要说有什么不一样,那大概就是变丑了吧。。。。

工作虽然忙,但是陆陆续续也有看一些书,我觉得学了知识就要学会把它整理出来,防止过段时间自己就忘了。

阻塞I/O (Blocking I/O)

什么是阻塞IO呢??我引用很经典的一张图:


通常应用程序去调用recvfrom接收数据后,会进入阻塞状态。然后kernel会开始准备数据,等待网络数据包的到来,然后将数据包从kernel space 拷贝到 user space(即copy到用户进程的buffer),然后返回。这个时候应用程序才会解除阻塞,继续往下执行。


非阻塞I/O (NonBlocking I/O)

非阻塞I/O,简单来说就是进程发出了一个IO请求后,不会阻塞,而是立即会返回一个结果。再引用一张图来说明:


当用户进程发出read/write操作时,如果kernel中的数据还没有准备好或者缓冲区满了没法写,那么它并不会block用户进程,而是立刻返回一个EAGAIN或者EWOULDBLOCK的错误。这个时候就需要不断的轮询,读就一直读到返回0,写就一直写到数据发送完。


阻塞IO编程示例


// Blocking_IO_Server.cpp

#include <stdio.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <string.h>  
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <unistd.h>  
  
int main()  
{  
    int sockfd, new_fd;  
    int sin_size, numbytes;  
    struct sockaddr_in addr, cliaddr;  
      
    //创建socket  
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
    {  
        perror("createSocket");  
        return -1;  
    }  
      
    //初始化socket结构  
    memset(&addr, 0, sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(8008);  
    addr.sin_addr.s_addr = htonl(INADDR_ANY);  
      
    //绑定套接口  
    if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr))==-1)  
    {  
        perror("bind");  
        return -1;  
    }  
      
    //创建监听套接口  
    if(listen(sockfd,10)==-1)  
    {  
        perror("listen");  
        return -1;  
    }  
      
      
    printf("server is running!\n");  
      
    char buff[1024];  
    //等待连接  
    while(1)   
    {  
        sin_size = sizeof(struct sockaddr_in);  
          
        //接受连接  
        if((new_fd = accept(sockfd, (struct sockaddr *)&cliaddr, (socklen_t*)&sin_size))==-1)  
        {  
            perror("accept");  
            return -1;  
        }  
          
        //生成一个子进程来完成和客户端的会话,父进程继续监听  
        if(!fork())  
        {  
            //读取客户端发来的信息  
            memset(buff,0,sizeof(buff));  
            if((numbytes = recv(new_fd,buff,sizeof(buff),0))==-1)  
            {  
                perror("recv");  
                return -1;  
            }  
            printf("buff=%s\n",buff);  
              
            //将从客户端接收到的信息再发回客户端  
            if(send(new_fd,buff,strlen(buff),0)==-1)  
            {  
                perror("send");  
            }  
      
            close(new_fd);  
            return 0;  
        }  
        //父进程关闭new_fd  
        close(new_fd);  
    }  
    close(sockfd);  
}  

// Blocking_IO_Client.cpp

#include <stdio.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <string.h>  
#include <netdb.h>  
#include <sys/types.h>  
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <unistd.h>  
  
int main(int argc,char *argv[])  
{  
    int sockfd,numbytes;  
    char buf[100] = "hello world";  
    struct hostent *he;  
    struct sockaddr_in their_addr;  
      
    //建立一个TCP套接口  
    if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)  
    {  
        perror("socket");  
        exit(1);  
    }  
      
    //初始化结构体  
    their_addr.sin_family = AF_INET;  
    their_addr.sin_port = htons(8008);  
    their_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    bzero(&(their_addr.sin_zero),8);  
      
    //和服务器建立连接  
    if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1)  
    {  
        perror("connect");  
        exit(1);  
    }  
      
    //向服务器发送字符串  
    if(send(sockfd,buf,strlen(buf),0)==-1)  
    {  
        perror("send");  
        exit(1);  
    }  
    memset(buf,0,sizeof(buf));  
      
    //接受从服务器返回的信息  
    if((numbytes = recv(sockfd,buf,100,0))==-1)  
    {  
        perror("recv");  
        exit(1);  
    }  
      
    close(sockfd);  
    return 0;  
}  
运行:
$ ./server 
server is running!
buff=hello world
buff=hello world

$ ./client
$ ./client


非阻塞I/O编程示例


// NonBlocking_IO_Server.cpp

#include <stdio.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <string.h>  
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
int main()  
{  
    int sockfd, new_fd;  
    int sin_size;  
    struct sockaddr_in addr, cliaddr;  
      
    //创建socket  
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
    {  
        perror("createSocket");  
        return -1;  
    }  
      
    //初始化socket结构  
    memset(&addr, 0, sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(8008);  
    addr.sin_addr.s_addr = htonl(INADDR_ANY);  
      
    //绑定套接口  
    if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr))==-1)  
    {  
        perror("bind");  
        return -1;  
    }  
      
    //创建监听套接口  
    if(listen(sockfd,10)==-1)  
    {  
        perror("listen");  
        return -1;  
    }  
      
    printf("server is running!\n");  
      
    char buff[1024];  
    //等待连接  
    while(1)   
    {  
        sin_size = sizeof(struct sockaddr_in);  
          
        //接受连接  
        if((new_fd = accept(sockfd, (struct sockaddr *)&cliaddr, (socklen_t*)&sin_size))==-1)  
        {  
            perror("accept");  
            return -1;  
        }  
              
        //生成一个子进程来完成和客户端的会话,父进程继续监听  
        if(!fork())  
        {  
            //设置new_fd无阻塞属性  
            int flags;  
            if((flags=fcntl(new_fd, F_GETFL, 0))<0)    
            {  
                perror("fcntl F_GETFL");    
            }  
            flags |= O_NONBLOCK;    
            if(fcntl(new_fd, F_SETFL,flags)<0)    
            {  
                perror("fcntl F_SETFL");    
            }  
              
            //读取客户端发来的信息  
            memset(buff,0,sizeof(buff));  
            while(1)  
            {  
                if((recv(new_fd,buff,sizeof(buff),0)) < 0)  
                {  
                    if(errno==EWOULDBLOCK)  
                    {  
                        perror("recv error, wait....");  
                        sleep(1);  
                        continue;  
                    }  
                }  
                else  
                {  
                    printf("buff=%s\n",buff);  
                }     
                break;  
            }  
  
            //发送数据  
            while(1)  
            {  
                if(send(new_fd,buff,strlen(buff),0) < 0)  
                {  
                    if(errno==EWOULDBLOCK)  
                    {  
                        perror("send error, wait....");  
                        sleep(1);  
                        continue;  
                    }  
                }  
                else  
                {  
                    printf("buff=%s\n",buff);  
                }     
                break;  
            }  
      
            close(new_fd);  
            return 0;  
        }  
        //父进程关闭new_fd  
        close(new_fd);  
    }  
    close(sockfd);  
}  

// NonBlcoking_IO_Client.cpp

#include <stdio.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <string.h>  
#include <netdb.h>  
#include <sys/types.h>  
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <unistd.h>  
  
int main(int argc,char *argv[])  
{  
    if(argc!=3)  
    {  
        printf("%s: input IP & port\n",argv[0]);  
        return 1;  
    }  
    int sockfd,numbytes;  
    char buf[100] = "hello world";  
    struct hostent *he;  
    struct sockaddr_in their_addr;  
      
    //将基本名字和地址转换  
    he = gethostbyname(argv[1]);  
      
    //建立一个TCP套接口  
    if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)  
    {  
        perror("socket");  
        exit(1);  
    }  
      
    //初始化结构体  
    their_addr.sin_family = AF_INET;  
    their_addr.sin_port = htons(atoi(argv[2]));  
    their_addr.sin_addr = *((struct in_addr *)he->h_addr);  
    bzero(&(their_addr.sin_zero),8);  
      
    //和服务器建立连接  
    if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1)  
    {  
        perror("connect");  
        exit(1);  
    }  
  
    sleep(5);  
      
    //向服务器发送字符串  
    if(send(sockfd,buf,strlen(buf),0)==-1)  
    {  
        perror("send");  
        exit(1);  
    }  
    memset(buf,0,sizeof(buf));  
      
      
    sleep(5);  
      
    //接受从服务器返回的信息  
    if((numbytes = recv(sockfd,buf,100,0))==-1)  
    {  
        perror("recv");  
        exit(1);  
    }  
      
    close(sockfd);  
    return 0;  
}  
运行:
$ ./server 
server is running!
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
recv error, wait....: Resource temporarily unavailable
buff=hello world
buff=hello world

$ ./client 


引用:

https://segmentfault.com/a/1190000003063859

http://blog.csdn.net/yfkiss/article/details/7516589



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值