天天看点

Linux下套接字详解(九)---poll模式下的IO多路复用服务器 poll多路复用 poll编程模型 示例

poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。

poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。

Linux下套接字详解(九)---poll模式下的IO多路复用服务器 poll多路复用 poll编程模型 示例

函数格式如下所示:

1

2

fds

是一个struct pollfd结构类型的数组,用于存放需要检测其状态的socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;

nfds

nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;

timeout

是poll函数调用阻塞的时间,单位:毫秒;

和 select 一样,最后一个参数 timeout 指定 poll() 将在超时前等待一个事件多长事件。这里有 3 种情况:

timeout 为 -1

这会造成 poll 永远等待。poll() 只有在一个描述符就绪时返回,或者在调用进程捕捉到信号时返回(在这里,poll 返回 -1),并且设置 errno 值为 eintr 。-1 可以用宏定义常量 inftim 来代替(在 pth.h 中有定义) 。

timeout 等于0

在这种情况下,测试所有的描述符,并且 poll() 立刻返回。这允许在 poll 中没有阻塞的情况下找出多个文件描述符的状态。

time > 0

这将以毫秒为单位指定 timeout 的超时周期。poll() 只有在超时到期时返回,除非一个描述符变为就绪,在这种情况下,它立刻返回。如果超时周期到齐,poll() 返回 0。这里也可能会因为某个信号而中断该等待。

和 select 一样,文件描述符是否阻塞对 poll 是否阻塞没有任何影响。

成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1

>0

数组fds中准备好读、写或出错状态的那些socket描述符的总数量;

==0

数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==inftim,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;

-1

poll函数调用失败,同时会自动设置全局变量errno为下列值之一

errno

描述

ebadf

一个或多个结构体中指定的文件描述符无效

efaultfds

指针指向的地址超出进程的地址空间

eintr

请求的事件之前产生一个信号,调用可以重新发起

einvalnfds

参数超出plimit_nofile值

enomem

可用内存不足,无法完成请求

3

4

5

6

fd 成员表示感兴趣的,且打开了的文件描述符;

events 成员是位掩码,用于指定针对这个文件描述符感兴趣的事件;

revents 成员是位掩码,用于指定当 poll 返回时,在该文件描述符上已经发生了哪些事情。

每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。

在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果pollin事件被设置,则文件描述符可以被读取而不阻塞。

如果pollout被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读取和写入操作都会正常返回而不阻塞。

timeout参数指定等待的毫秒数,无论i/o是否准备好,poll都会返回。timeout指定为负数值表示无限超时,使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好i/o的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。

每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。

revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域。

events域中请求的任何事件都可能在revents域中返回。

例如fds[0].events = pollin; /将测试条件设置成普通或优先级带数据可读/ 然后 int pollresult = poll(fds,xx,xx); //这样就可以监听fds里面文件描述符了,当满足特定条件就返回,并将结果保存在revents中。

合法的事件如下:

事件

pollin

有数据可读

pollrdnorm

有普通数据可读

pollrdband

有优先数据可读。

pollpri

有紧迫数据可读。

pollout

写数据不会导致阻塞

pollwrnorm

写普通数据不会导致阻塞

pollwrband

写优先数据不会导致阻塞

pollmsgsigpoll

消息可用。

此外,revents域中还可能返回下列事件:

poller

指定的文件描述符发生错误

pollhup

指定的文件描述符挂起事件

pollnval

指定的文件描述符非法

这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。

events 中使用该宏常数,能够在折本文件的可读情况下,结束 poll() 函数。相反,revents 上使用该宏常数,在检查 poll() 函数结束后,可依此判断设备文件是否处于可读状态(即使消息长度是 0)。

在 events 域中使用该宏常数,能够在设备文件的高优先级数据读取状态下,结束 poll() 函数。相反,revents 上使用该宏常数,在检查 poll() 函数结束后,可依此判断设备文件是否处于可读高优先级数据的状态(即使消息长度是 0)。该宏常数用于处理网络信息包(packet) 的数据传递。

在 events 域中使用该宏常数,能够在设备文件的写入状态下,结束 poll() 函数。相反,revents 域上使用该宏常数,在检查 poll() 结束后,可依此判断设备文件是否处于可写状态。

pollerr

在 events 域中使用该宏常数,能够在设备文件上发生错误时,结束 poll() 函数。相反,revents 域上使用该宏函数,在检查 poll() 函数结束后,可依此判断设备文件是否出错。

在 events域中使用该宏常数,能够在设备文件中发生 hungup 时,结束 poll() 函数 。相反,在检查 poll() 结束后,可依此判断设备文件是否发生 hungup 。

在 events 域中使用该宏函数,能够在文件描述符的值无效时,结束 poll() 。相反,在 revents 域上使用该宏函数时,在检查 poll() 函数后,文件描述符是否有效。可用于处理网络信息时,检查 socket handler 是否已经无效。

使用poll()和select()不一样,你不需要显式地请求异常情况报告。

pollin | pollpri等价于select()的读事件,

pollout |pollwrband等价于select()的写事件。

pollin等价于pollrdnorm |pollrdband,

而pollout则等价于pollwrnorm。

例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events为pollin |pollout。

poll的本质是轮训,就是监听我们所有的文件描述符的所注册的事件,当有事件请求时,poll返回,然后我们轮询所有的描述符,找到有时间请求的那个即可

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

转自:http://blog.csdn.net/gatieme/article/details/50978320

继续阅读