写在前面
以前在学校的时候,老想着要出来工作锻炼一下自己,等到真的出来了,才发现校园生活是最宝贵的。
出来快一年了,感慨很多,但却不知道如何说起,如果非要说有什么不一样,那大概就是变丑了吧。。。。
工作虽然忙,但是陆陆续续也有看一些书,我觉得学了知识就要学会把它整理出来,防止过段时间自己就忘了。
阻塞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