首先先说一下,阻塞IO会在哪些地方阻塞住呢?输入操作read, 输出操作write,接受请求操作accept,发送请求操作connect,这四个地方阻塞进程。
非阻塞IO的模型图示在前面的章节有讲过,它和阻塞IO的最大区别就是:如果连接或者操作不能立即建立,那么连接的建立照样能发起,只是会返回一个错误信息。
同样,先说明几个用到的函数和操作:
1 fcntl函数
其全名为”file control“。顾名思义,fcntl可以执行各种操作符控制操作。
1
2
3
|
#include <fcntl.h>
int
fcntl(
int
fd,
int
cmd, ..
/* int arg */
)
|
第一个参数fd是文件描述符
第二个参数cmd是操作命令,比如设置套接字阻塞非阻塞的命令为F_SETFL, 设置套接字属主的命令为F_SETOWN
第三个参数以后,是操作命令的参数。比如设置非阻塞IO型的F_SETFL的参数为O_NONBLOCK
所以设置非阻塞IO的典型设置代码为:
flags = flags | O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
2 非阻塞IO返回的错误
对于不能满足的非阻塞IO操作,System V会返回EAGAIN错误,而源自Berkeley的实现返回EWOULDBLOCK。大多数当前系统把这两个错误码定义为相同的值。
对不能满足的非阻塞IO连接,系统会返回EINPROGRESS
按照非阻塞的定义,我们只需要将cli做下面修改:
3客户端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int
main(
int
argc,
char
* argv[])
{
int
socketfd, n;
socketfd = socket(AF_INET, SOCK_STREAM,
0
);
fcntl(socketfd, F_SETFL, O_NONBLOCK);
struct sockaddr_in serv_addr;
bzero((
char
*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(
7777
);
for
(;;) {
if
(n = connect(socketfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <
0
) {
if
(errno == EINPROGRESS) {
printf(
"EINPROGRESS\n"
);
}
}
else
{
break
;
}
}
write(socketfd,
"client message"
,
14
);
char
buffer[
256
];
bzero(buffer,
256
);
read(socketfd, buffer,
255
);
printf(
"server return message:%s\r\n"
, buffer);
return
0
;
}
|
1
|
|
运行方式:
1 server不启动
2 client启动,则会在connect这个地方进入无限循环。
好吧,是不是觉得有问题?
1 这种模型,客户端使用轮询不断调用IO操作,那么,CPU就会一直用于轮询,造成cpu的浪费。
2 这种模型,代码量比阻塞的模型大很多
所以这个模型实际上是很少使用的。
本文转自轩脉刃博客园博客,原文链接:http://www.cnblogs.com/yjf512/archive/2012/06/05/2536005.html,如需转载请自行联系原作者