/
3c79e6b3.html
333 lines (303 loc) · 147 KB
/
3c79e6b3.html
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
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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<!DOCTYPE html><html class="theme-next gemini use-motion" lang="zh-Hans"><head><meta name="generator" content="Hexo 3.8.0"><meta name="google-site-verification" content="SJDgyqjBwkGnbvvQE_jdQKhgkQfRh7WhtS0-E3egoyk"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="theme-color" content="#222"><meta name="viewport" content="width=device-width"><script src="/lib/pace/pace.min.js?v=1.0.2"></script><link href="/lib/pace/pace-theme-minimal.min.css?v=1.0.2" rel="stylesheet"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css"><link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4"><link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222"><meta name="keywords" content="Java,并发编程,NIO,socket,channel,"><link rel="alternate" href="/atom.xml" title="从入门到放弃" type="application/atom+xml"><meta name="description" content="前言上篇【从入门到放弃-Java】并发编程-NIO使用简单介绍了nio的基础使用,本篇将深入源码分析nio中channel的实现。 简介channel即通道,可以用来读、写数据,它是全双工的可以同时用来读写操作。这也是它与stream流的最大区别。 channel需要与buffer配合使用,channel通道的一端是buffer,一端是数据源实体,如文件、socket等。在nio中,通过chann"><meta name="keywords" content="Java,并发编程,NIO,socket,channel"><meta property="og:type" content="article"><meta property="og:title" content="【从入门到放弃-Java】并发编程-NIO-Channel"><meta property="og:url" content="https://nc2era.com/3c79e6b3.html"><meta property="og:site_name" content="从入门到放弃"><meta property="og:description" content="前言上篇【从入门到放弃-Java】并发编程-NIO使用简单介绍了nio的基础使用,本篇将深入源码分析nio中channel的实现。 简介channel即通道,可以用来读、写数据,它是全双工的可以同时用来读写操作。这也是它与stream流的最大区别。 channel需要与buffer配合使用,channel通道的一端是buffer,一端是数据源实体,如文件、socket等。在nio中,通过chann"><meta property="og:locale" content="zh-Hans"><meta property="og:image" content="https://nc2era.com/3c79e6b3/1.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/2.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/3.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/4.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/5.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/6.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/7.jpg"><meta property="og:image" content="https://nc2era.com/3c79e6b3/8.jpg"><meta property="og:updated_time" content="2019-07-09T04:02:52.784Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="【从入门到放弃-Java】并发编程-NIO-Channel"><meta name="twitter:description" content="前言上篇【从入门到放弃-Java】并发编程-NIO使用简单介绍了nio的基础使用,本篇将深入源码分析nio中channel的实现。 简介channel即通道,可以用来读、写数据,它是全双工的可以同时用来读写操作。这也是它与stream流的最大区别。 channel需要与buffer配合使用,channel通道的一端是buffer,一端是数据源实体,如文件、socket等。在nio中,通过chann"><meta name="twitter:image" content="https://nc2era.com/3c79e6b3/1.jpg"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Gemini",version:"5.1.4",sidebar:{position:"left",display:"post",offset:12,b2t:!1,scrollpercent:!1,onmobile:!1},fancybox:!0,tabs:!0,motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"slideDownIn",post_body:"slideDownIn",coll_header:"slideLeftIn",sidebar:"slideUpIn"}},duoshuo:{userId:"0",author:"博主"},algolia:{applicationID:"",apiKey:"",indexName:"",hits:{per_page:10},labels:{input_placeholder:"Search for Posts",hits_empty:"We didn't find any results for the search: ${query}",hits_stats:"${hits} results found in ${time} ms"}}}</script><link rel="canonical" href="https://nc2era.com/3c79e6b3.html"><title>【从入门到放弃-Java】并发编程-NIO-Channel | 从入门到放弃</title><script type="text/javascript">var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="https://hm.baidu.com/hm.js?7f0f37da8af427b455867492ca709c92";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script></head><body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans"><div class="container sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title">从入门到放弃</span><span class="logo-line-after"><i></i></span></a></div><h1 class="site-subtitle" itemprop="description">从入门到放弃-程序员进阶之路</h1></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i><br> 首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> 标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> 分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> 归档</a></li><li class="menu-item menu-item-search"><a href="javascript:;" class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> 搜索</a></li></ul><div class="site-search"><div class="popup search-popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><div class="post-block"><link itemprop="mainEntityOfPage" href="https://nc2era.com/3c79e6b3.html"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="AloofJr"><meta itemprop="description" content><meta itemprop="image" content="/images/avatar.gif"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="从入门到放弃"></span><header class="post-header"><h2 class="post-title" itemprop="name headline">【从入门到放弃-Java】并发编程-NIO-Channel</h2><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">发表于</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-06-25T13:39:01+08:00">2019-06-25</time></span> <span class="post-comments-count"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-comment-o"></i></span><a href="/3c79e6b3.html#comments" itemprop="discussionUrl"><span class="post-comments-count valine-comment-count" data-xid="/3c79e6b3.html" itemprop="commentCount"></span></a></span> <span class="post-meta-divider">|</span><span class="page-pv"><i class="fa fa-file-o"></i> 浏览<span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span><div class="post-wordcount"><span class="post-meta-item-icon"><i class="fa fa-file-word-o"></i></span> <span class="post-meta-item-text">字数统计:</span> <span title="字数统计">4.6k</span> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-clock-o"></i></span> <span class="post-meta-item-text">阅读时长 ≈</span> <span title="阅读时长">23</span></div></div></header><div class="post-body" itemprop="articleBody"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>上篇<a href="https://nc2era.com/e57ab61.html">【从入门到放弃-Java】并发编程-NIO使用</a>简单介绍了nio的基础使用,本篇将深入源码分析nio中channel的实现。</p><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>channel即通道,可以用来读、写数据,它是全双工的可以同时用来读写操作。这也是它与stream流的最大区别。</p><p>channel需要与buffer配合使用,channel通道的一端是buffer,一端是数据源实体,如文件、socket等。在nio中,通过channel的不同实现来处理 不同实体与数据buffer中的数据传输。</p><p>channel接口:<br></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.nio.channels;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.Closeable;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A nexus for I/O operations.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> A channel represents an open connection to an entity such as a hardware</span></span><br><span class="line"><span class="comment"> * device, a file, a network socket, or a program component that is capable of</span></span><br><span class="line"><span class="comment"> * performing one or more distinct I/O operations, for example reading or</span></span><br><span class="line"><span class="comment"> * writing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> A channel is either open or closed. A channel is open upon creation,</span></span><br><span class="line"><span class="comment"> * and once closed it remains closed. Once a channel is closed, any attempt to</span></span><br><span class="line"><span class="comment"> * invoke an I/O operation upon it will cause a {<span class="doctag">@link</span> ClosedChannelException}</span></span><br><span class="line"><span class="comment"> * to be thrown. Whether or not a channel is open may be tested by invoking</span></span><br><span class="line"><span class="comment"> * its {<span class="doctag">@link</span> #isOpen isOpen} method.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> Channels are, in general, intended to be safe for multithreaded access</span></span><br><span class="line"><span class="comment"> * as described in the specifications of the interfaces and classes that extend</span></span><br><span class="line"><span class="comment"> * and implement this interface.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Mark Reinhold</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> JSR-51 Expert Group</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 1.4</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Channel</span> <span class="keyword">extends</span> <span class="title">Closeable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Tells whether or not this channel is open.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> <tt>true</tt> if, and only if, this channel is open</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isOpen</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Closes this channel.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> After a channel is closed, any further attempt to invoke I/O</span></span><br><span class="line"><span class="comment"> * operations upon it will cause a {<span class="doctag">@link</span> ClosedChannelException} to be</span></span><br><span class="line"><span class="comment"> * thrown.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> If this channel is already closed then invoking this method has no</span></span><br><span class="line"><span class="comment"> * effect.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> This method may be invoked at any time. If some other thread has</span></span><br><span class="line"><span class="comment"> * already invoked it, however, then another invocation will block until</span></span><br><span class="line"><span class="comment"> * the first invocation is complete, after which it will return without</span></span><br><span class="line"><span class="comment"> * effect. </p></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException If an I/O error occurs</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p><p>常见的channel实现有:</p><ul><li>FileChannel:文件读写数据通道</li><li>SocketChannel:TCP读写网络数据通道</li><li>ServerSocketChannel:服务端网络数据读写通道,可以监听TCP连接。对每一个新进来的连接都会创建一个SocketChannel。</li><li>DatagramChannel:UDP读写网络数据通道</li></ul><h2 id="FileChannel"><a href="#FileChannel" class="headerlink" title="FileChannel"></a>FileChannel</h2><img src="/3c79e6b3/1.jpg"> <img src="/3c79e6b3/2.jpg"><p>FileChannel是一个抽象类,它继承了AbstractInterruptibleChannel类,并实现了 SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel接口。<br>具体的实现类主要是sun.nio.ch.FileChannelImpl。下面详细分析下FileChannelImpl中每个方法的具体实现。</p><h3 id="open"><a href="#open" class="headerlink" title="open"></a>open</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">FileChannelImpl</span><span class="params">(FileDescriptor var1, String var2, <span class="keyword">boolean</span> var3, <span class="keyword">boolean</span> var4, <span class="keyword">boolean</span> var5, Object var6)</span> </span>{</span><br><span class="line"> <span class="comment">//主要记载操作系统维护的文件描述符</span></span><br><span class="line"> <span class="keyword">this</span>.fd = var1;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否可读</span></span><br><span class="line"> <span class="keyword">this</span>.readable = var3;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否可写</span></span><br><span class="line"> <span class="keyword">this</span>.writable = var4;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否以追加的方式打开</span></span><br><span class="line"> <span class="keyword">this</span>.append = var5;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">this</span>.parent = var6;</span><br><span class="line"> <span class="keyword">this</span>.path = var2;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//底层使用native的read和write来处理文件的</span></span><br><span class="line"> <span class="keyword">this</span>.nd = <span class="keyword">new</span> FileDispatcherImpl(var5);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//FileInputStream::getChannel 调用 FileChannelImpl.open(fd, path, true, false, this) 获取只读channel</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> FileChannel <span class="title">open</span><span class="params">(FileDescriptor var0, String var1, <span class="keyword">boolean</span> var2, <span class="keyword">boolean</span> var3, Object var4)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> FileChannelImpl(var0, var1, var2, var3, <span class="keyword">false</span>, var4);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//FileOutputStream::getChannel 调用 FileChannelImpl.open(fd, path, false, true, append, this) 获取只写channel</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> FileChannel <span class="title">open</span><span class="params">(FileDescriptor var0, String var1, <span class="keyword">boolean</span> var2, <span class="keyword">boolean</span> var3, <span class="keyword">boolean</span> var4, Object var5)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> FileChannelImpl(var0, var1, var2, var3, var4, var5);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">FileChannelImpl</span><span class="params">(FileDescriptor fd, String path, <span class="keyword">boolean</span> readable,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">boolean</span> writable, <span class="keyword">boolean</span> direct, Object parent)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">this</span>.fd = fd;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否可读</span></span><br><span class="line"> <span class="keyword">this</span>.readable = readable;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否可写</span></span><br><span class="line"> <span class="keyword">this</span>.writable = writable;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//对于从流创建的channel,在结束时要做不同的清理动作,(openJDK中才有,sun的jdk中没有)</span></span><br><span class="line"> <span class="keyword">this</span>.parent = parent;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//源文件的path</span></span><br><span class="line"> <span class="keyword">this</span>.path = path;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否使用DirectIO</span></span><br><span class="line"> <span class="keyword">this</span>.direct = direct;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">this</span>.nd = <span class="keyword">new</span> FileDispatcherImpl();</span><br><span class="line"> <span class="keyword">if</span> (direct) {</span><br><span class="line"> <span class="keyword">assert</span> path != <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">this</span>.alignment = nd.setDirectIO(fd, path);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>.alignment = -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//当parent不存在时,则注册一个cleaner,否则交由parent做清理动作。</span></span><br><span class="line"> <span class="comment">// Register a cleaning action if and only if there is no parent</span></span><br><span class="line"> <span class="comment">// as the parent will take care of closing the file descriptor.</span></span><br><span class="line"> <span class="comment">// FileChannel is used by the LambdaMetaFactory so a lambda cannot</span></span><br><span class="line"> <span class="comment">// be used here hence we use a nested class instead.</span></span><br><span class="line"> <span class="keyword">this</span>.closer = parent != <span class="keyword">null</span> ? <span class="keyword">null</span> :</span><br><span class="line"> CleanerFactory.cleaner().register(<span class="keyword">this</span>, <span class="keyword">new</span> Closer(fd));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Used by FileInputStream.getChannel(), FileOutputStream.getChannel</span></span><br><span class="line"><span class="comment">// and RandomAccessFile.getChannel()</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> FileChannel <span class="title">open</span><span class="params">(FileDescriptor fd, String path,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">boolean</span> readable, <span class="keyword">boolean</span> writable,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">boolean</span> direct, Object parent)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> FileChannelImpl(fd, path, readable, writable, direct, parent);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>open方法主要是返回一个新new的FileChannelImpl对象,初始化时设置fileDescriptor、readable、writable、append、parent、path等属性,看变量名很容易理解,在此不赘述变量含义。</li></ul><h3 id="read"><a href="#read" class="headerlink" title="read"></a>read</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现自SeekableByteChannel接口的方法,将文件中的内容读取到给定的byteBuffer中</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(ByteBuffer dst)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="comment">//保证读写时,channel处于开启状态</span></span><br><span class="line"> ensureOpen();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//判断是否可读</span></span><br><span class="line"> <span class="keyword">if</span> (!readable)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NonReadableChannelException();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">if</span> (direct)</span><br><span class="line"> Util.checkChannelPositionAligned(position(), alignment);</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//开始阻塞,并注册为Interruptible,可以被中断</span></span><br><span class="line"> beginBlocking();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//将当前线程添加到NativeThreadSet中,并返回索引,方便后续操作。</span></span><br><span class="line"> <span class="comment">//NativeThreadSet是一个线程安全的本地线程集合,方便管理,用来发送信号</span></span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//当未被系统中断(即读取完毕)或channel未被关闭,则一直读,将内容写入到byteBuffer(dst)中</span></span><br><span class="line"> n = IOUtil.read(fd, dst, -<span class="number">1</span>, direct, alignment, nd);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//把当前线程从set中移出</span></span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//结束,释放锁</span></span><br><span class="line"> endBlocking(n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现自ScatteringByteChannel接口的方法,将文件中的内容依次读取到给定的byteBuffer数组中。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">read</span><span class="params">(ByteBuffer[] dsts, <span class="keyword">int</span> offset, <span class="keyword">int</span> length)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ((offset < <span class="number">0</span>) || (length < <span class="number">0</span>) || (offset > dsts.length - length))</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfBoundsException();</span><br><span class="line"> <span class="comment">//保证读写时,channel处于开启状态</span></span><br><span class="line"> ensureOpen();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//判断是否可读</span></span><br><span class="line"> <span class="keyword">if</span> (!readable)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NonReadableChannelException();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">if</span> (direct)</span><br><span class="line"> Util.checkChannelPositionAligned(position(), alignment);</span><br><span class="line"> <span class="keyword">long</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//开始阻塞,并注册为Interruptible,可以被中断</span></span><br><span class="line"> beginBlocking();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//将当前线程添加到NativeThreadSet中,并返回索引,方便后续操作。</span></span><br><span class="line"> <span class="comment">//NativeThreadSet是一个线程安全的本地线程集合,方便管理,用来发送信号</span></span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//当未被系统中断(即读取完毕)或channel未被关闭,则一直读,将内容写入到byteBuffer(dst)中</span></span><br><span class="line"> n = IOUtil.read(fd, dsts, offset, length,</span><br><span class="line"> direct, alignment, nd);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//把当前线程从set中移出</span></span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//结束,释放锁</span></span><br><span class="line"> endBlocking(n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="write"><a href="#write" class="headerlink" title="write"></a>write</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现自SeekableByteChannel接口的方法,将byteBuffer中的内容写入到文件中</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">write</span><span class="params">(ByteBuffer src)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="comment">//保证写时,channel处于开启状态</span></span><br><span class="line"> ensureOpen();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//判断是否可写</span></span><br><span class="line"> <span class="keyword">if</span> (!writable)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NonWritableChannelException();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">if</span> (direct)</span><br><span class="line"> Util.checkChannelPositionAligned(position(), alignment);</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//开始阻塞,并注册为Interruptible,可以被中断</span></span><br><span class="line"> beginBlocking();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//将当前线程添加到NativeThreadSet中,并返回索引,方便后续操作。</span></span><br><span class="line"> <span class="comment">//NativeThreadSet是一个线程安全的本地线程集合,方便管理,用来发送信号</span></span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//当未被系统中断(即写入完毕)或channel未被关闭,则一直写,将内容写入到文件中</span></span><br><span class="line"> n = IOUtil.write(fd, src, -<span class="number">1</span>, direct, alignment, nd);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//把当前线程从set中移出</span></span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//结束,释放锁</span></span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现自GatheringByteChannel接口的方法,将byteBuffer数组中的内容依次写入到文件中</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">write</span><span class="params">(ByteBuffer[] srcs, <span class="keyword">int</span> offset, <span class="keyword">int</span> length)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ((offset < <span class="number">0</span>) || (length < <span class="number">0</span>) || (offset > srcs.length - length))</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfBoundsException();</span><br><span class="line"> <span class="comment">//保证写时,channel处于开启状态</span></span><br><span class="line"> ensureOpen();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//判断是否可写</span></span><br><span class="line"> <span class="keyword">if</span> (!writable)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NonWritableChannelException();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">if</span> (direct)</span><br><span class="line"> Util.checkChannelPositionAligned(position(), alignment);</span><br><span class="line"> <span class="keyword">long</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//开始阻塞,并注册为Interruptible,可以被中断</span></span><br><span class="line"> beginBlocking();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//将当前线程添加到NativeThreadSet中,并返回索引,方便后续操作。</span></span><br><span class="line"> <span class="comment">//NativeThreadSet是一个线程安全的本地线程集合,方便管理,用来发送信号</span></span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//当未被系统中断(即写入完毕)或channel未被关闭,则一直写,将内容写入到文件中</span></span><br><span class="line"> n = IOUtil.write(fd, srcs, offset, length,</span><br><span class="line"> direct, alignment, nd);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//把当前线程从set中移出</span></span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//结束,释放锁</span></span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="position"><a href="#position" class="headerlink" title="position"></a>position</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现自SeekableByteChannel接口的方法,获取当前channel的position</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">position</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> ensureOpen();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">long</span> p = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginBlocking();</span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">boolean</span> append = fdAccess.getAppend(fd);</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//append模式下,position在channel的末尾</span></span><br><span class="line"> <span class="comment">// in append-mode then position is advanced to end before writing</span></span><br><span class="line"> p = (append) ? nd.size(fd) : nd.seek(fd, -<span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">while</span> ((p == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(p);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> endBlocking(p > -<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(p);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现自SeekableByteChannel接口的方法,设置当前channel的position为newPosition</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> FileChannel <span class="title">position</span><span class="params">(<span class="keyword">long</span> newPosition)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> ensureOpen();</span><br><span class="line"> <span class="keyword">if</span> (newPosition < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">synchronized</span> (positionLock) {</span><br><span class="line"> <span class="keyword">long</span> p = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> ti = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginBlocking();</span><br><span class="line"> ti = threads.add();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//设置当前position为newPosition</span></span><br><span class="line"> p = nd.seek(fd, newPosition);</span><br><span class="line"> } <span class="keyword">while</span> ((p == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> threads.remove(ti);</span><br><span class="line"> endBlocking(p > -<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(p);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="size"><a href="#size" class="headerlink" title="size"></a>size</h3><p>实现自SeekableByteChannel接口的方法,返回当前实体(文件)的大小</p><h3 id="truncate"><a href="#truncate" class="headerlink" title="truncate"></a>truncate</h3><p>实现自SeekableByteChannel接口的方法,用来截取文件至newSize大小</p><h3 id="force"><a href="#force" class="headerlink" title="force"></a>force</h3><p>实现自SeekableByteChannel接口的方法,用来将channel中尚未写入磁盘的数据强制落盘</p><h3 id="transferTo"><a href="#transferTo" class="headerlink" title="transferTo"></a>transferTo</h3><p>将fileChannel中的数据传递至另一个channel</p><h3 id="transferFrom"><a href="#transferFrom" class="headerlink" title="transferFrom"></a>transferFrom</h3><p>从其它channel读取数据至fileChannel</p><h2 id="SocketChannel"><a href="#SocketChannel" class="headerlink" title="SocketChannel"></a>SocketChannel</h2><img src="/3c79e6b3/3.jpg"> <img src="/3c79e6b3/4.jpg"><h3 id="open-1"><a href="#open-1" class="headerlink" title="open"></a>open</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Opens a socket channel.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p> The new channel is created by invoking the {<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment"> * java.nio.channels.spi.SelectorProvider#openSocketChannel</span></span><br><span class="line"><span class="comment"> * openSocketChannel} method of the system-wide default {<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment"> * java.nio.channels.spi.SelectorProvider} object. </p></span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> A new socket channel</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> * If an I/O error occurs</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SocketChannel <span class="title">open</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">return</span> SelectorProvider.provider().openSocketChannel();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>open方法是调用SelectorProvider中实现了java.nio.channels.spi.SelectorProvider#openSocketChannel的方法,底层实际是new SocketChannelImpl,调用native方法创建socket</p><h3 id="connect"><a href="#connect" class="headerlink" title="connect"></a>connect</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">connect</span><span class="params">(SocketAddress sa)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="comment">//校验Address是否合法</span></span><br><span class="line"> InetSocketAddress isa = Net.checkAddress(sa);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获取系统安全管理器</span></span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (sm != <span class="keyword">null</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//校验IP和端口是否被允许连接</span></span><br><span class="line"> sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());</span><br><span class="line"></span><br><span class="line"> InetAddress ia = isa.getAddress();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//如果是本机地址,则获取本机的host</span></span><br><span class="line"> <span class="keyword">if</span> (ia.isAnyLocalAddress())</span><br><span class="line"> ia = InetAddress.getLocalHost();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//加读锁</span></span><br><span class="line"> readLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//加写锁</span></span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//是否阻塞</span></span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//开启connect前的校验并设置为ST_CONNECTIONPENDING,如果blocking是true 即阻塞模式,则记录当前线程的ID,以便接收信号处理。</span></span><br><span class="line"> beginConnect(blocking, isa);</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//调用native connect方法</span></span><br><span class="line"> n = Net.connect(fd, ia, isa.getPort());</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//结束连接</span></span><br><span class="line"> endConnect(blocking, (n > <span class="number">0</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> <span class="keyword">return</span> n > <span class="number">0</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//释放写锁</span></span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//释放读锁</span></span><br><span class="line"> readLock.unlock();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException ioe) {</span><br><span class="line"> <span class="comment">// connect failed, close the channel</span></span><br><span class="line"> close();</span><br><span class="line"> <span class="keyword">throw</span> SocketExceptions.of(ioe, isa);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="configureBlocking"><a href="#configureBlocking" class="headerlink" title="configureBlocking"></a>configureBlocking</h3><p>实现自SelectableChannel的接口方法,调用native方法设置socket的阻塞状态</p><h3 id="register"><a href="#register" class="headerlink" title="register"></a>register</h3><p>在AbstractSelectableChannel中定义,注册要监听的事件。<br></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> SelectionKey <span class="title">register</span><span class="params">(Selector sel, <span class="keyword">int</span> ops, Object att)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> ClosedChannelException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> ((ops & ~validOps()) != <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ClosedChannelException();</span><br><span class="line"> <span class="keyword">synchronized</span> (regLock) {</span><br><span class="line"> <span class="keyword">if</span> (isBlocking())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalBlockingModeException();</span><br><span class="line"> <span class="keyword">synchronized</span> (keyLock) {</span><br><span class="line"> <span class="comment">// re-check if channel has been closed</span></span><br><span class="line"> <span class="keyword">if</span> (!isOpen())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ClosedChannelException();</span><br><span class="line"> SelectionKey k = findKey(sel);</span><br><span class="line"> <span class="keyword">if</span> (k != <span class="keyword">null</span>) {</span><br><span class="line"> k.attach(att);</span><br><span class="line"> k.interestOps(ops);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 向Selector中注册事件</span></span><br><span class="line"> <span class="comment">// New registration</span></span><br><span class="line"> k = ((AbstractSelector)sel).register(<span class="keyword">this</span>, ops, att);</span><br><span class="line"> addKey(k);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> k;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p><h3 id="read-1"><a href="#read-1" class="headerlink" title="read"></a>read</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现自ReadableByteChannel接口的方法,从socket中读取数据至ByteBuffer</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(ByteBuffer buf)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> Objects.requireNonNull(buf);</span><br><span class="line"></span><br><span class="line"> readLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//检查channel是否开启并已经是connected的状态。如果blocking是true 即阻塞模式,则记录当前线程的ID,以便接收信号处理。</span></span><br><span class="line"> beginRead(blocking);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// check if input is shutdown</span></span><br><span class="line"> <span class="keyword">if</span> (isInputClosed)</span><br><span class="line"> <span class="keyword">return</span> IOStatus.EOF;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果是阻塞模式,则一直读取直到数据读取完毕;非阻塞模式则直接调用native方法不需要等待。</span></span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = IOUtil.read(fd, buf, -<span class="number">1</span>, nd);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> n = IOUtil.read(fd, buf, -<span class="number">1</span>, nd);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endRead(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span> && isInputClosed)</span><br><span class="line"> <span class="keyword">return</span> IOStatus.EOF;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> readLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现自ScatteringByteChannel接口的方法,从socket中依次读取数据至ByteBuffer数组</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">read</span><span class="params">(ByteBuffer[] dsts, <span class="keyword">int</span> offset, <span class="keyword">int</span> length)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> Objects.checkFromIndexSize(offset, length, dsts.length);</span><br><span class="line"></span><br><span class="line"> readLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">long</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginRead(blocking);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// check if input is shutdown</span></span><br><span class="line"> <span class="keyword">if</span> (isInputClosed)</span><br><span class="line"> <span class="keyword">return</span> IOStatus.EOF;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果是阻塞模式,则一直读取直到数据读取完毕;非阻塞模式则直接调用native方法不需要等待。</span></span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = IOUtil.read(fd, dsts, offset, length, nd);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> n = IOUtil.read(fd, dsts, offset, length, nd);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endRead(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span> && isInputClosed)</span><br><span class="line"> <span class="keyword">return</span> IOStatus.EOF;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> readLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="write-1"><a href="#write-1" class="headerlink" title="write"></a>write</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现自ReadableByteChannel接口的方法,将ByteBuffer中的数据写入socket</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">write</span><span class="params">(ByteBuffer buf)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> Objects.requireNonNull(buf);</span><br><span class="line"></span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginWrite(blocking);</span><br><span class="line"> <span class="comment">//如果是阻塞模式,则一直读取直到数据读取完毕;非阻塞模式则直接调用native方法不需要等待。</span></span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = IOUtil.write(fd, buf, -<span class="number">1</span>, nd);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> n = IOUtil.write(fd, buf, -<span class="number">1</span>, nd);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endWrite(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span> && isOutputClosed)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AsynchronousCloseException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">write</span><span class="params">(ByteBuffer[] srcs, <span class="keyword">int</span> offset, <span class="keyword">int</span> length)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> Objects.checkFromIndexSize(offset, length, srcs.length);</span><br><span class="line"></span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">long</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginWrite(blocking);</span><br><span class="line"> <span class="comment">//如果是阻塞模式,则一直等待直到数据写入完毕;非阻塞模式则直接调用native方法不需要等待。</span></span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = IOUtil.write(fd, srcs, offset, length, nd);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> n = IOUtil.write(fd, srcs, offset, length, nd);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endWrite(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span> && isOutputClosed)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AsynchronousCloseException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现自ReadableByteChannel接口的方法,将ByteBuffer数组中的数据依次写入socket</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Writes a byte of out of band data.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">sendOutOfBandData</span><span class="params">(<span class="keyword">byte</span> b)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> beginWrite(blocking);</span><br><span class="line"> <span class="comment">//如果是阻塞模式,则一直等待直到数据写入完毕;非阻塞模式则直接调用native方法不需要等待。</span></span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = sendOutOfBandData(fd, b);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> n = sendOutOfBandData(fd, b);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endWrite(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span> && isOutputClosed)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AsynchronousCloseException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="ServerSocketChannel"><a href="#ServerSocketChannel" class="headerlink" title="ServerSocketChannel"></a>ServerSocketChannel</h2><img src="/3c79e6b3/5.jpg"> <img src="/3c79e6b3/6.jpg"><h3 id="socket"><a href="#socket" class="headerlink" title="socket"></a>socket</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ServerSocket <span class="title">socket</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (stateLock) {</span><br><span class="line"> <span class="keyword">if</span> (socket == <span class="keyword">null</span>)</span><br><span class="line"> socket = ServerSocketAdaptor.create(<span class="keyword">this</span>);</span><br><span class="line"> <span class="keyword">return</span> socket;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="bind"><a href="#bind" class="headerlink" title="bind"></a>bind</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ServerSocketChannel <span class="title">bind</span><span class="params">(SocketAddress local, <span class="keyword">int</span> backlog)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (stateLock) {</span><br><span class="line"> ensureOpen();</span><br><span class="line"> <span class="keyword">if</span> (localAddress != <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AlreadyBoundException();</span><br><span class="line"> InetSocketAddress isa = (local == <span class="keyword">null</span>)</span><br><span class="line"> ? <span class="keyword">new</span> InetSocketAddress(<span class="number">0</span>)</span><br><span class="line"> : Net.checkAddress(local);</span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (sm != <span class="keyword">null</span>)</span><br><span class="line"> sm.checkListen(isa.getPort());</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//绑定前做一些前置处理,如将tcp socket文件描述符转换成SDP</span></span><br><span class="line"> NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//绑定IP和地址</span></span><br><span class="line"> Net.bind(fd, isa.getAddress(), isa.getPort());</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//开始监听,设置socket上最多可以挂起backlog个连接,若backlog小于1 则默认设置50个</span></span><br><span class="line"> Net.listen(fd, backlog < <span class="number">1</span> ? <span class="number">50</span> : backlog);</span><br><span class="line"> </span><br><span class="line"> localAddress = Net.localAddress(fd);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="accept"><a href="#accept" class="headerlink" title="accept"></a>accept</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> SocketChannel <span class="title">accept</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> acceptLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> FileDescriptor newfd = <span class="keyword">new</span> FileDescriptor();</span><br><span class="line"> InetSocketAddress[] isaa = <span class="keyword">new</span> InetSocketAddress[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> begin(blocking);</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="comment">//阻塞等待接收客户端链接</span></span><br><span class="line"> n = accept(<span class="keyword">this</span>.fd, newfd, isaa);</span><br><span class="line"> } <span class="keyword">while</span> (n == IOStatus.INTERRUPTED && isOpen());</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> end(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n < <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//新接收的socket初始设置为阻塞模式(因此非阻塞模式的每次需要显示设置)</span></span><br><span class="line"> <span class="comment">// newly accepted socket is initially in blocking mode</span></span><br><span class="line"> IOUtil.configureBlocking(newfd, <span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line"> InetSocketAddress isa = isaa[<span class="number">0</span>];</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//用新接收的socket创建SocketChannel</span></span><br><span class="line"> SocketChannel sc = <span class="keyword">new</span> SocketChannelImpl(provider(), newfd, isa);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// check permitted to accept connections from the remote address</span></span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (sm != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());</span><br><span class="line"> } <span class="keyword">catch</span> (SecurityException x) {</span><br><span class="line"> sc.close();</span><br><span class="line"> <span class="keyword">throw</span> x;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sc;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> acceptLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ServerSocketChannel并没有read和write方法,只是继承了AbstractSelectableChannel,以便在selector中使用</p><h2 id="DatagramChannel"><a href="#DatagramChannel" class="headerlink" title="DatagramChannel"></a>DatagramChannel</h2><img src="/3c79e6b3/7.jpg"> <img src="/3c79e6b3/8.jpg"><h3 id="open-2"><a href="#open-2" class="headerlink" title="open"></a>open</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">DatagramChannelImpl</span><span class="params">(SelectorProvider sp)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">super</span>(sp);</span><br><span class="line"> ResourceManager.beforeUdpCreate();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//如果不支持IPv6则使用IPv4</span></span><br><span class="line"> <span class="keyword">this</span>.family = Net.isIPv6Available()</span><br><span class="line"> ? StandardProtocolFamily.INET6</span><br><span class="line"> : StandardProtocolFamily.INET;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//设置非流式的socket(tcp是流模式协议,udp是数据报模式协议)</span></span><br><span class="line"> <span class="keyword">this</span>.fd = Net.socket(family, <span class="keyword">false</span>);</span><br><span class="line"> <span class="keyword">this</span>.fdVal = IOUtil.fdVal(fd);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException ioe) {</span><br><span class="line"> ResourceManager.afterUdpClose();</span><br><span class="line"> <span class="keyword">throw</span> ioe;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="receive"><a href="#receive" class="headerlink" title="receive"></a>receive</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> SocketAddress <span class="title">receive</span><span class="params">(ByteBuffer dst)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">if</span> (dst.isReadOnly())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Read-only buffer"</span>);</span><br><span class="line"></span><br><span class="line"> readLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> ByteBuffer bb = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> SocketAddress remote = beginRead(blocking, <span class="keyword">false</span>);</span><br><span class="line"> <span class="keyword">boolean</span> connected = (remote != <span class="keyword">null</span>);</span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (connected || (sm == <span class="keyword">null</span>)) {</span><br><span class="line"> <span class="comment">// connected or no security manager</span></span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = receive(fd, dst, connected);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">if</span> (n == IOStatus.UNAVAILABLE)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// Cannot receive into user's buffer when running with a</span></span><br><span class="line"> <span class="comment">// security manager and not connected</span></span><br><span class="line"> bb = Util.getTemporaryDirectBuffer(dst.remaining());</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = receive(fd, bb, connected);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> <span class="keyword">if</span> (n == IOStatus.UNAVAILABLE)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> InetSocketAddress isa = (InetSocketAddress)sender;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> sm.checkAccept(isa.getAddress().getHostAddress(),</span><br><span class="line"> isa.getPort());</span><br><span class="line"> } <span class="keyword">catch</span> (SecurityException se) {</span><br><span class="line"> <span class="comment">// Ignore packet</span></span><br><span class="line"> bb.clear();</span><br><span class="line"> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> bb.flip();</span><br><span class="line"> dst.put(bb);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//sender:发送方地址, Set by receive0 (## ugh)</span></span><br><span class="line"> <span class="keyword">assert</span> sender != <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> sender;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (bb != <span class="keyword">null</span>)</span><br><span class="line"> Util.releaseTemporaryDirectBuffer(bb);</span><br><span class="line"> endRead(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> readLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="send"><a href="#send" class="headerlink" title="send"></a>send</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">send</span><span class="params">(ByteBuffer src, SocketAddress target)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException</span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> Objects.requireNonNull(src);</span><br><span class="line"> InetSocketAddress isa = Net.checkAddress(target, family);</span><br><span class="line"></span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">int</span> n = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//当connect后,remote会设置为连接的地址</span></span><br><span class="line"> SocketAddress remote = beginWrite(blocking, <span class="keyword">false</span>);</span><br><span class="line"> <span class="keyword">if</span> (remote != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="comment">// connected</span></span><br><span class="line"> <span class="keyword">if</span> (!target.equals(remote)) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AlreadyConnectedException();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = IOUtil.write(fd, src, -<span class="number">1</span>, nd);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// not connected</span></span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (sm != <span class="keyword">null</span>) {</span><br><span class="line"> InetAddress ia = isa.getAddress();</span><br><span class="line"> <span class="keyword">if</span> (ia.isMulticastAddress()) {</span><br><span class="line"> sm.checkMulticast(ia);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> sm.checkConnect(ia.getHostAddress(), isa.getPort());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> n = send(fd, src, isa);</span><br><span class="line"> } <span class="keyword">while</span> ((n == IOStatus.INTERRUPTED) && isOpen());</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> endWrite(blocking, n > <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">assert</span> IOStatus.check(n);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> IOStatus.normalize(n);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="connect-1"><a href="#connect-1" class="headerlink" title="connect"></a>connect</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> DatagramChannel <span class="title">connect</span><span class="params">(SocketAddress sa)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> InetSocketAddress isa = Net.checkAddress(sa, family);</span><br><span class="line"> SecurityManager sm = System.getSecurityManager();</span><br><span class="line"> <span class="keyword">if</span> (sm != <span class="keyword">null</span>) {</span><br><span class="line"> InetAddress ia = isa.getAddress();</span><br><span class="line"> <span class="keyword">if</span> (ia.isMulticastAddress()) {</span><br><span class="line"> sm.checkMulticast(ia);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> sm.checkConnect(ia.getHostAddress(), isa.getPort());</span><br><span class="line"> sm.checkAccept(ia.getHostAddress(), isa.getPort());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> readLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> writeLock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">synchronized</span> (stateLock) {</span><br><span class="line"> ensureOpen();</span><br><span class="line"> <span class="keyword">if</span> (state == ST_CONNECTED)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> AlreadyConnectedException();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> n = Net.connect(family,</span><br><span class="line"> fd,</span><br><span class="line"> isa.getAddress(),</span><br><span class="line"> isa.getPort());</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(); <span class="comment">// Can't happen</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// connected</span></span><br><span class="line"> remoteAddress = isa;</span><br><span class="line"> state = ST_CONNECTED;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// refresh local address</span></span><br><span class="line"> localAddress = Net.localAddress(fd);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// flush any packets already received.</span></span><br><span class="line"> <span class="keyword">boolean</span> blocking = isBlocking();</span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> IOUtil.configureBlocking(fd, <span class="keyword">false</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ByteBuffer buf = ByteBuffer.allocate(<span class="number">100</span>);</span><br><span class="line"> <span class="keyword">while</span> (receive(buf) != <span class="keyword">null</span>) {</span><br><span class="line"> buf.clear();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (blocking) {</span><br><span class="line"> IOUtil.configureBlocking(fd, <span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> writeLock.unlock();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> readLock.unlock();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>udp是数据报模式的协议,是没有connect的。这里的connect实际上是在底层忽略了与其他地址的数据传输。<br>在connect后,就可以像socketChannel似得使用read和write了</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文学习了各种channel的实现,主要是对底层native方法的一些封装,针对不同属性的实体(文件、socket),使用对应的channel与byteBuffer传输数据。再通过byteBuffer与byte数据进行转换。<br>channel的实现中,封装了大量的native方法,重要的底层实现全在native中,后续可以深入学习下。</p><p>本文中出现的byteBuffer和selector将在接下来的文章中,单独分析。</p></div><footer class="post-footer"><div class="post-tags"> <a href="/tags/Java/" rel="tag"># Java</a> <a href="/tags/并发编程/" rel="tag"># 并发编程</a> <a href="/tags/NIO/" rel="tag"># NIO</a> <a href="/tags/socket/" rel="tag"># socket</a> <a href="/tags/channel/" rel="tag"># channel</a></div><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/e57ab61.html" rel="next" title="【从入门到放弃-Java】并发编程-NIO使用"><i class="fa fa-chevron-left"></i> 【从入门到放弃-Java】并发编程-NIO使用</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"> <a href="/d5a7a7f5.html" rel="prev" title="【从入门到放弃-Java】并发编程-NIO-Buffer">【从入门到放弃-Java】并发编程-NIO-Buffer<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-spread"></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> 文章目录</li><li class="sidebar-nav-overview" data-target="site-overview-wrap"> 站点概览</li></ul><section class="site-overview-wrap sidebar-panel"><div class="site-overview"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"><p class="site-author-name" itemprop="name">AloofJr</p><p class="site-description motion-element" itemprop="description"></p></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives/"><span class="site-state-item-count">47</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories/index.html"><span class="site-state-item-count">1</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags/index.html"><span class="site-state-item-count">50</span> <span class="site-state-item-name">标签</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="https://github.com/AloofJr" target="_blank" title="GitHub" rel="external nofollow noopener noreferrer"><i class="fa fa-fw fa-github"></i> GitHub</a></span></div></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#简介"><span class="nav-number">2.</span> <span class="nav-text">简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#FileChannel"><span class="nav-number">3.</span> <span class="nav-text">FileChannel</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#open"><span class="nav-number">3.1.</span> <span class="nav-text">open</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#read"><span class="nav-number">3.2.</span> <span class="nav-text">read</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#write"><span class="nav-number">3.3.</span> <span class="nav-text">write</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#position"><span class="nav-number">3.4.</span> <span class="nav-text">position</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#size"><span class="nav-number">3.5.</span> <span class="nav-text">size</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#truncate"><span class="nav-number">3.6.</span> <span class="nav-text">truncate</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#force"><span class="nav-number">3.7.</span> <span class="nav-text">force</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#transferTo"><span class="nav-number">3.8.</span> <span class="nav-text">transferTo</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#transferFrom"><span class="nav-number">3.9.</span> <span class="nav-text">transferFrom</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#SocketChannel"><span class="nav-number">4.</span> <span class="nav-text">SocketChannel</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#open-1"><span class="nav-number">4.1.</span> <span class="nav-text">open</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#connect"><span class="nav-number">4.2.</span> <span class="nav-text">connect</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#configureBlocking"><span class="nav-number">4.3.</span> <span class="nav-text">configureBlocking</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#register"><span class="nav-number">4.4.</span> <span class="nav-text">register</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#read-1"><span class="nav-number">4.5.</span> <span class="nav-text">read</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#write-1"><span class="nav-number">4.6.</span> <span class="nav-text">write</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ServerSocketChannel"><span class="nav-number">5.</span> <span class="nav-text">ServerSocketChannel</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#socket"><span class="nav-number">5.1.</span> <span class="nav-text">socket</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#bind"><span class="nav-number">5.2.</span> <span class="nav-text">bind</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#accept"><span class="nav-number">5.3.</span> <span class="nav-text">accept</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#DatagramChannel"><span class="nav-number">6.</span> <span class="nav-text">DatagramChannel</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#open-2"><span class="nav-number">6.1.</span> <span class="nav-text">open</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#receive"><span class="nav-number">6.2.</span> <span class="nav-text">receive</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#send"><span class="nav-number">6.3.</span> <span class="nav-text">send</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#connect-1"><span class="nav-number">6.4.</span> <span class="nav-text">connect</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#总结"><span class="nav-number">7.</span> <span class="nav-text">总结</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright">© <span itemprop="copyrightYear">2020</span><span class="with-love"><i class="fa fa-user"></i></span> <span class="author" itemprop="copyrightHolder">AloofJr</span> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-area-chart"></i></span> <span class="post-meta-item-text">Site words total count:</span> <span title="Site words total count">79.4k</span></div><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><div class="busuanzi-count"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span class="site-uv"><i class="fa fa-user"></i><span class="busuanzi-value" id="busuanzi_value_site_uv"></span></span><span class="site-pv"><i class="fa fa-eye"></i><span class="busuanzi-value" id="busuanzi_value_site_pv"></span></span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script><script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script><script src="//unpkg.com/valine/dist/Valine.min.js"></script><script type="text/javascript">
var GUEST = ['nick','mail','link'];
var guest = 'nick,mail';
guest = guest.split(',').filter(item=>{
return GUEST.indexOf(item)>-1;
});
new Valine({
el: '#comments' ,
verify: true,
notify: true,
appId: 'AtTFeTEomwo5ADIQTR8YFRcL-gzGzoHsz',
appKey: 'vKO8qLF0TzyALMhWTxgQ7GPh',
placeholder: '欢迎各路大神交流指正!',
avatar:'mm',
guest_info:guest,
pageSize:'10' || 10,
});
</script><script type="text/javascript">
// Popup Window;
var isfetched = false;
var isXml = true;
// Search DB path;
var search_path = "search.xml";
if (search_path.length === 0) {
search_path = "search.xml";
} else if (/json$/i.test(search_path)) {
isXml = false;
}
var path = "/" + search_path;
// monitor main search box;
var onPopupClose = function (e) {
$('.popup').hide();
$('#local-search-input').val('');
$('.search-result-list').remove();
$('#no-result').remove();
$(".local-search-pop-overlay").remove();
$('body').css('overflow', '');
}
function proceedsearch() {
$("body")
.append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
.css('overflow', 'hidden');
$('.search-popup-overlay').click(onPopupClose);
$('.popup').toggle();
var $localSearchInput = $('#local-search-input');
$localSearchInput.attr("autocapitalize", "none");
$localSearchInput.attr("autocorrect", "off");
$localSearchInput.focus();
}
// search function;
var searchFunc = function(path, search_id, content_id) {
'use strict';
// start loading animation
$("body")
.append('<div class="search-popup-overlay local-search-pop-overlay">' +
'<div id="search-loading-icon">' +
'<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
'</div>' +
'</div>')
.css('overflow', 'hidden');
$("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');
$.ajax({
url: path,
dataType: isXml ? "xml" : "json",
async: true,
success: function(res) {
// get the contents from search data
isfetched = true;
$('.popup').detach().appendTo('.header-inner');
var datas = isXml ? $("entry", res).map(function() {
return {
title: $("title", this).text(),
content: $("content",this).text(),
url: $("url" , this).text()
};
}).get() : res;
var input = document.getElementById(search_id);
var resultContent = document.getElementById(content_id);
var inputEventFunction = function() {
var searchText = input.value.trim().toLowerCase();
var keywords = searchText.split(/[\s\-]+/);
if (keywords.length > 1) {
keywords.push(searchText);
}
var resultItems = [];
if (searchText.length > 0) {
// perform local searching
datas.forEach(function(data) {
var isMatch = false;
var hitCount = 0;
var searchTextCount = 0;
var title = data.title.trim();
var titleInLowerCase = title.toLowerCase();
var content = data.content.trim().replace(/<[^>]+>/g,"");
var contentInLowerCase = content.toLowerCase();
var articleUrl = decodeURIComponent(data.url);
var indexOfTitle = [];
var indexOfContent = [];
// only match articles with not empty titles
if(title != '') {
keywords.forEach(function(keyword) {
function getIndexByWord(word, text, caseSensitive) {
var wordLen = word.length;
if (wordLen === 0) {
return [];
}
var startPosition = 0, position = [], index = [];
if (!caseSensitive) {
text = text.toLowerCase();
word = word.toLowerCase();
}
while ((position = text.indexOf(word, startPosition)) > -1) {
index.push({position: position, word: word});
startPosition = position + wordLen;
}
return index;
}
indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
});
if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
isMatch = true;
hitCount = indexOfTitle.length + indexOfContent.length;
}
}
// show search results
if (isMatch) {
// sort index by position of keyword
[indexOfTitle, indexOfContent].forEach(function (index) {
index.sort(function (itemLeft, itemRight) {
if (itemRight.position !== itemLeft.position) {
return itemRight.position - itemLeft.position;
} else {
return itemLeft.word.length - itemRight.word.length;
}
});
});
// merge hits into slices
function mergeIntoSlice(text, start, end, index) {
var item = index[index.length - 1];
var position = item.position;
var word = item.word;
var hits = [];
var searchTextCountInSlice = 0;
while (position + word.length <= end && index.length != 0) {
if (word === searchText) {
searchTextCountInSlice++;
}
hits.push({position: position, length: word.length});
var wordEnd = position + word.length;
// move to next position of hit
index.pop();
while (index.length != 0) {
item = index[index.length - 1];
position = item.position;
word = item.word;
if (wordEnd > position) {
index.pop();
} else {
break;
}
}
}
searchTextCount += searchTextCountInSlice;
return {
hits: hits,
start: start,
end: end,
searchTextCount: searchTextCountInSlice
};
}
var slicesOfTitle = [];
if (indexOfTitle.length != 0) {
slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
}
var slicesOfContent = [];
while (indexOfContent.length != 0) {
var item = indexOfContent[indexOfContent.length - 1];
var position = item.position;
var word = item.word;
// cut out 100 characters
var start = position - 20;
var end = position + 80;
if(start < 0){
start = 0;
}
if (end < position + word.length) {
end = position + word.length;
}
if(end > content.length){
end = content.length;
}
slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
}
// sort slices in content by search text's count and hits' count
slicesOfContent.sort(function (sliceLeft, sliceRight) {
if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
return sliceRight.searchTextCount - sliceLeft.searchTextCount;
} else if (sliceLeft.hits.length !== sliceRight.hits.length) {
return sliceRight.hits.length - sliceLeft.hits.length;
} else {
return sliceLeft.start - sliceRight.start;
}
});
// select top N slices in content
var upperBound = parseInt('1');
if (upperBound >= 0) {
slicesOfContent = slicesOfContent.slice(0, upperBound);
}
// highlight title and content
function highlightKeyword(text, slice) {
var result = '';
var prevEnd = slice.start;
slice.hits.forEach(function (hit) {
result += text.substring(prevEnd, hit.position);
var end = hit.position + hit.length;
result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
prevEnd = end;
});
result += text.substring(prevEnd, slice.end);
return result;
}
var resultItem = '';
if (slicesOfTitle.length != 0) {
resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
} else {
resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
}
slicesOfContent.forEach(function (slice) {
resultItem += "<a href='" + articleUrl + "'>" +
"<p class=\"search-result\">" + highlightKeyword(content, slice) +
"...</p>" + "</a>";
});
resultItem += "</li>";
resultItems.push({
item: resultItem,
searchTextCount: searchTextCount,
hitCount: hitCount,
id: resultItems.length
});
}
})
};
if (keywords.length === 1 && keywords[0] === "") {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
} else if (resultItems.length === 0) {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
} else {
resultItems.sort(function (resultLeft, resultRight) {
if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
return resultRight.searchTextCount - resultLeft.searchTextCount;
} else if (resultLeft.hitCount !== resultRight.hitCount) {
return resultRight.hitCount - resultLeft.hitCount;
} else {
return resultRight.id - resultLeft.id;
}
});
var searchResultList = '<ul class=\"search-result-list\">';
resultItems.forEach(function (result) {
searchResultList += result.item;
})
searchResultList += "</ul>";
resultContent.innerHTML = searchResultList;
}
}
if ('auto' === 'auto') {
input.addEventListener('input', inputEventFunction);
} else {
$('.search-icon').click(inputEventFunction);
input.addEventListener('keypress', function (event) {
if (event.keyCode === 13) {
inputEventFunction();
}
});
}
// remove loading animation
$(".local-search-pop-overlay").remove();
$('body').css('overflow', '');
proceedsearch();
}
});
}
// handle and trigger popup window;
$('.popup-trigger').click(function(e) {
e.stopPropagation();
if (isfetched === false) {
searchFunc(path, 'local-search-input', 'local-search-result');
} else {
proceedsearch();
};
});
$('.popup-btn-close').click(onPopupClose);
$('.popup').click(function(e){
e.stopPropagation();
});
$(document).on('keyup', function (event) {
var shouldDismissSearchPopup = event.which === 27 &&
$('.search-popup').is(':visible');
if (shouldDismissSearchPopup) {
onPopupClose();
}
});
</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script></body></html>