Files
redkale/net.html
RedKale 1c1f5aba43
2016-02-18 09:15:23 +08:00

692 lines
83 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale - 全新的Java微服务框架</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale是一个全新的基于Java 8的微服务框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/github-light.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight.css" media="screen">
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?b4e05d7de8b5f3401dd93e3c6b35ffa5";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="articles.html" class="btn">技术文章</a>
<a href="code.html" class="btn">Java 源码</a>
</section>
<section class="main-content">
<h3><a id="net_intro" class="anchor" href="#" aria-hidden="true"></a>Net 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Net 组件是基于AIO(NIO.2)的一套TCP/UDP的网络框架且只提供异步接口。org.redkale.net 是所有网络协议服务的基础包。Redkale内置HTTP和远程模式Service依赖的SNCP(Service Node Communicate Protocol)协议的实现包。Redkale启动的<b>&lt;server&gt;</b>节点服务都是基于Net组件实现的协议。下面详细介绍 <a href="#net_http">HTTP服务</a><a href="#net_sncp">SNCP协议</a></p>
<h3><a id="net_http" class="anchor" href="#" aria-hidden="true"></a>HTTP 服务</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale自实现的HTTP服务接口并不遵循Java EE规范JSR 340(Servlet 3.1)Redkale提倡的是HTTP+JSON的服务接口方式因此没有实现JSP规范HTTP+JSON服务接口几乎适合所有类型的客户端(PC应用程序、PC Web、微信H5、移动APP、移动Web)开发。其与JSR 340(Servlet 3.1)的主要区别如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、内置参数的JSON反序列化和响应结果的序列化接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、对数值型的参数和header值提供简易接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、不支持JSP提倡的是HTTP+JSON接口方式。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、无HttpSession对象session可通过配置CacheSource实现。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、内置文件上传接口且可自实现断点续传。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、对响应结果内容可以进行短期缓存从而减少数据源操作的压力。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7、内置WebSocket的集群与组功能且提供伪WebSocket连接功能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8、HttpResponse只能异步输出。<br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, Redkale也提供了更友好的基类 org.redkale.net.http.BasedHttpServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类这样方便以后加入类似javax.servlet.Filter的功能。 <br/> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个典型的BaseSerlvet实现:
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">BaseSerlvet</span> <span class="kd">extends</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">http</span><span class="o">.</span><span class="na">BasedHttpServlet</span> <span class="o">{</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="n">Logger</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="n">fine</span> <span class="o">=</span> <span class="n">logger</span><span class="o">.</span><span class="na">isLoggable</span><span class="o">(</span><span class="n">Level</span><span class="o">.</span><span class="na">FINE</span><span class="o">);</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源] 进程的启动时间</span>
<span class="kd">protected</span> <span class="kt">long</span> <span class="n">serverCreateTime</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonFactory</span> <span class="n">jsonFactory</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前进程的根目录,字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;APP_HOME&quot;</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">home</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前Http Server的web页面的根目录字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;SERVER_ROOT&quot;</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">webroot</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//在调用authenticate之前调用 返回false表示请求不合法</span>
<span class="c1">//该方法可以用于判断请求源是否合法或加入一些全局的拦截操作</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">preExecute</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="kd">final</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">request</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">&quot;User-Agent&quot;</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">).</span><span class="na">contains</span><span class="o">(</span><span class="s">&quot;Redkale-Agent&quot;</span><span class="o">))</span> <span class="o">{</span> <span class="c1">//只用移动APP的接口可以判断User-Agent是否正确</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">&quot;retcode&quot;</span><span class="o">,</span> <span class="s">&quot;10001&quot;</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">&quot;retmessage&quot;</span><span class="o">,</span> <span class="s">&quot;User-Agent error&quot;</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">finish</span><span class="o">(</span><span class="mi">201</span><span class="o">,</span> <span class="s">&quot;{&#39;success&#39;:false, &#39;message&#39;:&#39;User-Agent error, must be Redkale-Agent&#39;}&quot;</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//可以加上一些统计操作</span>
<span class="k">if</span> <span class="o">(</span><span class="n">fine</span><span class="o">)</span> <span class="n">response</span><span class="o">.</span><span class="na">setRecycleListener</span><span class="o">((</span><span class="n">req</span><span class="o">,</span> <span class="n">resp</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="c1">//记录处理时间太长的请求操作</span>
<span class="kt">long</span> <span class="n">e</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">()</span> <span class="o">-</span> <span class="n">request</span><span class="o">.</span><span class="na">getCreatetime</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span> <span class="o">&gt;</span> <span class="mi">500</span><span class="o">)</span> <span class="n">logger</span><span class="o">.</span><span class="na">fine</span><span class="o">(</span><span class="s">&quot;耗时居然用了 &quot;</span> <span class="o">+</span> <span class="n">e</span> <span class="o">+</span> <span class="s">&quot; 毫秒. 请求为: &quot;</span> <span class="o">+</span> <span class="n">req</span><span class="o">);</span>
<span class="o">});</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//标记为@AuthIgnore 的方法将不会调用authenticate方法</span>
<span class="c1">//一般用于判断用户的登录态, 返回false表示鉴权失败</span>
<span class="c1">//moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@WebAction.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">authenticate</span><span class="o">(</span><span class="kt">int</span> <span class="n">moduleid</span><span class="o">,</span> <span class="kt">int</span> <span class="n">actionid</span><span class="o">,</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="o">(</span><span class="n">UserInfo</span><span class="o">)</span> <span class="n">request</span><span class="o">.</span><span class="na">getAttribute</span><span class="o">(</span><span class="s">&quot;_current_userinfo&quot;</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">user</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//已经判断过了</span>
<span class="n">String</span> <span class="n">sessionid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sessionid</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">//没有sessionid表示没有登录</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">sessionid</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">user</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">request</span><span class="o">.</span><span class="na">setAttribute</span><span class="o">(</span><span class="s">&quot;_current_userinfo&quot;</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="k">return</span> <span class="n">user</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">//存在用户表示登录态正常</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;继承BasedHttpServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能 一个典型的操作用户HttpServlet: </p>
<div class="highlight"><pre><span class="nd">@WebServlet</span><span class="o">({</span><span class="s">&quot;/user/*&quot;</span><span class="o">})</span> <span class="c1">//拦截所有 /user/ 开头的请求</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserServlet</span> <span class="kd">extends</span> <span class="n">BaseSerlvet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//登录操作 </span>
<span class="nd">@AuthIgnore</span> <span class="c1">//登录操作不要判断登录态,所以需要标记为@AuthIgnore不会调用 BaseSerlvet.authenticate 方法</span>
<span class="c1">//因为WebAction的判断规则用的是String.startsWith所以WebAction.url不能用正则表达式只能是getRequestURI的前缀</span>
<span class="c1">//且同一个HttpServlet类内的所有WebAction不能存在包含关系, 如 /user/myinfo 和 /user/myinforecord 不能存在同一HttpServlet中。</span>
<span class="nd">@WebAction</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/login&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">login</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">LoginBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">LoginBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">&quot;bean&quot;</span><span class="o">);</span> <span class="c1">//获取参数</span>
<span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">login</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span> <span class="c1">//登录操作, service内部判断bean的合法性</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">result</span><span class="o">);</span> <span class="c1">//输出结果</span>
<span class="o">}</span>
<span class="c1">//获取当前用户信息</span>
<span class="c1">//未登录的请求会被BaseSerlvet.authenticate方法拦截因此能进入该方法说明用户态存在</span>
<span class="nd">@WebAction</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/myinfo&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">myinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="c1">//或者使用 user = req.getAttribute(&quot;_current_userinfo&quot;); 因为BaseSerlvet.authenticate方法已经将UserInfo注入到_current_userinfo属性中</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//获取指定用户ID的用户信息, 请求如: /user/username/43565443</span>
<span class="nd">@AuthIgnore</span>
<span class="c1">// 默认缓存时间是15秒BasedHttpServlet会将每个进入该方法的请求的响应结果缓存15秒缓存命中时不会再进入该方法过期会清空。</span>
<span class="c1">// @HttpCacheable 必须配合 @AuthIgnore 使用, 因为跟当前用户有关的请求一般不适合所有用户请求。 </span>
<span class="c1">// 翻页查询想缓存就需要将翻页信息带进url: /user/query/page:2/size:50 。</span>
<span class="nd">@HttpCacheable</span><span class="o">(</span><span class="n">timeout</span> <span class="o">=</span> <span class="mi">30</span><span class="o">)</span> <span class="c1">//有效期30秒</span>
<span class="nd">@WebAction</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/userinfo/&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">userinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">()));</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//更新个人头像</span>
<span class="nd">@WebAction</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/updateface&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">updateface</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="k">for</span> <span class="o">(</span><span class="n">MultiPart</span> <span class="n">part</span> <span class="o">:</span> <span class="n">req</span><span class="o">.</span><span class="na">multiParts</span><span class="o">())</span> <span class="o">{</span> <span class="c1">//遍历上传文件列表 </span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">byts</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="na">getContentBytes</span><span class="o">(</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024L</span><span class="o">);</span> <span class="c1">//图片大小不能超过5M超过5M返回null</span>
<span class="k">if</span> <span class="o">(</span><span class="n">byts</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="nf">RetResult</span><span class="o">(</span><span class="mi">102</span><span class="o">,</span> <span class="s">&quot;上传的文件过大&quot;</span><span class="o">));</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">BufferedImage</span> <span class="n">img</span> <span class="o">=</span> <span class="n">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="k">new</span> <span class="nf">ByteArrayInputStream</span><span class="o">(</span><span class="n">byts</span><span class="o">));</span>
<span class="c1">//... 此处处理并存储头像图片</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetResult</span><span class="o">.</span><span class="na">SUCCESS</span><span class="o">);</span> <span class="c1">//输出成功信息</span>
<span class="o">}</span>
<span class="k">return</span><span class="o">;</span> <span class="c1">//头像图片仅会传一个, 只需要读取一个即可返回</span>
<span class="o">}</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="nf">RetResult</span><span class="o">(</span><span class="mi">103</span><span class="o">,</span> <span class="s">&quot;没有上传图片&quot;</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上,所有/user/前缀的请求都会进入UserServlet若没匹配的则返回505错误为了方便以后编写前方静动分离服务器转发规则比较好的习惯是将项目中所有动态Servlet加一个固定前缀<a href="redkale.html#redkale_confxml" target="_blank">application.xml</a> 里设置path即可。</p>
<div class="highlight"><pre><span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;servlets</span> <b><span class="na">path=</span><span class="s">&quot;/pipes&quot;</span></b> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上, 配置了/pipes 前缀后客户端发送Servlet请求需带上前缀请求当前用户信息的url就变成/pipes/user/myinfo 。</p>
<br/>
<p id="net_ws">&nbsp;&nbsp;<b> WebSokcet 服务</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebSokcet协议遵循<a href="http://tools.ietf.org/html/rfc645" target="_blank">IETF RFC 6455</a>其接口并不符合Java EE中的WebSocket的接口规范。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个WebSocket连接对应一个WebSocket实体即一个WebSocket会绑定一个TCP连接。且有两种模式:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1) 普通模式: 协议上符合HTML5规范, 其流程顺序如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1 onOpen &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.2 createGroupid &nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.3 onConnected &nbsp;&nbsp;&nbsp;&nbsp; WebSocket成功连接后在准备接收数据前回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.4 onMessage/onFragment+ &nbsp;&nbsp; WebSocket接收到消息后回调此消息类方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.5 onClose &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebSocket被关闭后回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此模式下 以上方法都应该被重载。<br/>
<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2) 原始二进制模式: 此模式有别于HTML5规范可以视为原始的TCP连接。通常用于音频视频通讯场景。其流程顺序如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1 onOpen &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果方法返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2 createGroupid &nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.3 onRead &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebSocket成功连接后回调此方法 由此方法处理原始的TCP连接 同时业务代码去控制WebSocket的关闭。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此模式下 以上方法都应该被重载。<br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现一个WebSocket服务需要继承 org.redkale.net.http.WebSocketServlet以下是一个简单的聊天范例</p>
<div class="highlight"><pre><span class="nd">@WebServlet</span><span class="o">(</span><span class="s">&quot;/ws/chat&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ChatWebSocketServlet</span> <span class="kd">extends</span> <span class="n">WebSocketServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&quot;本实例的WebSocketEngine: &quot;</span> <span class="o">+</span> <span class="kd">super</span><span class="o">.</span><span class="na">engine</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&quot;本实例的WebSocketNode: &quot;</span> <span class="o">+</span> <span class="kd">super</span><span class="o">.</span><span class="na">node</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">destroy</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&quot;关闭了ChatWebSocketServlet&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">WebSocket</span> <span class="nf">createWebSocket</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">WebSocket</span><span class="o">()</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">UserInfo</span> <span class="n">user</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">String</span> <span class="n">text</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// text 接收的格式: {&quot;receiveid&quot;:200000001, &quot;content&quot;:&quot;Hi Redkale!&quot;}</span>
<span class="kd">final</span> <span class="n">ChatMessage</span> <span class="n">message</span> <span class="o">=</span> <span class="n">jsonConvert</span><span class="o">.</span><span class="na">convertFrom</span><span class="o">(</span><span class="n">ChatMessage</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">text</span><span class="o">);</span> <span class="c1">//获取给对方的消息体信息</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendid</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">();</span> <span class="c1">//将当前用户设为消息的发送方</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendtime</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span> <span class="c1">//设置消息发送时间</span>
<span class="c1">//给接收方发送消息, 即使接收方在其他WebSocket进程节点上有链接Redkale也会自动发送到其他链接进程节点上。</span>
<span class="kd">super</span><span class="o">.</span><span class="na">sendEachMessage</span><span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">receiveid</span><span class="o">,</span> <span class="n">jsonConvert</span><span class="o">.</span><span class="na">convertTo</span><span class="o">(</span><span class="n">message</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">Serializable</span> <span class="nf">createGroupid</span><span class="o">()</span> <span class="o">{</span> <span class="c1">//以用户ID作为WebSocketGroup的groupid</span>
<span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">=</span> <span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="kd">super</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">()));</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">onOpen</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span> <span class="c1">//以request中的sessionid字符串作为WebSocket的sessionid</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">ChatMessage</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">sendid</span><span class="o">;</span> <span class="c1">//发送方用户ID</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">receiveid</span><span class="o">;</span> <span class="c1">//接收方用户ID </span>
<span class="kd">public</span> <span class="n">String</span> <span class="n">content</span><span class="o">;</span> <span class="c1">//文本消息内容</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="n">sendtime</span><span class="o">;</span> <span class="c1">//消息发送时间</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p id="net_httprequest">&nbsp;&nbsp;<b>. HttpRequest 对象</b> </p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpRequest</span> <span class="o">{</span>
<span class="c1">//获取请求方法 GET、POST等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getMethod</span><span class="o">();</span>
<span class="c1">//获取协议名 http、https、ws、wss等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getProtocol</span><span class="o">();</span>
<span class="c1">//获取Host的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHost</span><span class="o">();</span>
<span class="c1">//获取请求内容的长度, 为-1表示内容长度不确定</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//获取Content-Type的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//获取Connection的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getConnection</span><span class="o">();</span>
<span class="c1">//获取客户端地址IP</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端地址IP, 与getRemoteAddres() 的区别在于本方法优先取header中指定为RemoteAddress名的值没有则返回getRemoteAddres()。</span>
<span class="c1">//本方法适用于服务前端有如nginx的代理服务器进行中转通过getRemoteAddres()是获取不到客户端的真实IP。</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取请求内容指定的编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBody</span><span class="o">(</span><span class="n">Charset</span> <span class="n">charset</span><span class="o">);</span>
<span class="c1">//获取请求内容的UTF-8编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBodyUTF8</span><span class="o">();</span>
<span class="c1">//获取文件上传对象</span>
<span class="kd">public</span> <span class="n">MultiContext</span> <span class="nf">getMultiContext</span><span class="o">();</span>
<span class="c1">//获取文件上传信息列表 等价于 getMultiContext().parts();</span>
<span class="kd">public</span> <span class="n">Iterable</span><span class="o">&lt;</span><span class="n">MultiPart</span><span class="o">&gt;</span> <span class="nf">multiParts</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//获取sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getSessionid</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">autoCreate</span><span class="o">);</span>
<span class="c1">//更新sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">changeSessionid</span><span class="o">();</span>
<span class="c1">//使sessionid失效</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">invalidateSession</span><span class="o">();</span>
<span class="c1">//获取所有Cookie对象</span>
<span class="kd">public</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">HttpCookie</span><span class="o">[]</span> <span class="nf">getCookies</span><span class="o">();</span>
<span class="c1">//获取Cookie值 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取Cookie值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取请求的URL</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequestURI</span><span class="o">();</span>
<span class="c1">//截取getRequestURI最后的一个/后面的部分</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURILastPath</span><span class="o">();</span>
<span class="c1">//从prefix之后截取getRequestURI再对&quot;/&quot;进行分隔</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getRequstURIPaths</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">);</span>
<span class="c1">//获取请求URL分段中含prefix段的long值</span>
<span class="c1">// 例如请求URL /pipes/record/query/time:1453104341363/id:40</span>
<span class="c1">// 获取time参数: long time = request.getRequstURIPath(&quot;time:&quot;, 0L);</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取请求URL分段中含prefix段的int值</span>
<span class="c1">// 例如请求URL /pipes/record/query/page:2/size:50</span>
<span class="c1">// 获取page参数: int page = request.getRequstURIPath(&quot;page:&quot;, 1);</span>
<span class="c1">// 获取size参数: int size = request.getRequstURIPath(&quot;size:&quot;, 20);</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取请求URL分段中含prefix段的值</span>
<span class="c1">//例如请求URL /pipes/record/query/name:hello</span>
<span class="c1">//获取name参数: String name = request.getRequstURIPath(&quot;name:&quot;, &quot;none&quot;);</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的short值</span>
<span class="c1">// 例如请求URL /pipes/record/query/type:10</span>
<span class="c1">// 获取type参数: short type = request.getRequstURIPath(&quot;type:&quot;, (short)0);</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取所有的header名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getHeaderNames</span><span class="o">();</span>
<span class="c1">// 获取指定的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Class</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">clazz</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">Class</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">clazz</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取所有参数名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getParameterNames</span><span class="o">();</span>
<span class="c1">//获取指定的参数值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Class</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">clazz</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">Class</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">clazz</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取HTTP上下文对象</span>
<span class="kd">public</span> <span class="n">HttpContext</span> <span class="nf">getContext</span><span class="o">();</span>
<span class="c1">//获取所有属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="nf">getAttributes</span><span class="o">();</span>
<span class="c1">//获取指定属性值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//删除指定属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//设置属性值</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取request创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="o">}</span></pre></div>
<p id="net_httpresponse">&nbsp;&nbsp;<b>. HttpResponse 对象</b> </p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpResponse</span> <span class="o">{</span>
<span class="c1">//设置状态码</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setStatus</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">);</span>
<span class="c1">//获取状态码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getStatus</span><span class="o">();</span>
<span class="c1">//获取 ContentType</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//设置 ContentType</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setContentType</span><span class="o">(</span><span class="n">String</span> <span class="n">contentType</span><span class="o">);</span>
<span class="c1">//获取内容长度</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//设置内容长度</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setContentLength</span><span class="o">(</span><span class="kt">long</span> <span class="n">contentLength</span><span class="o">);</span>
<span class="c1">//设置Header值</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//添加Header值</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">addHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//跳过header的输出</span>
<span class="c1">//通常应用场景是调用者的输出内容里已经包含了HTTP的响应头信息因此需要调用此方法避免重复输出HTTP响应头信息。</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">skipHeader</span><span class="o">();</span>
<span class="c1">//增加Cookie值</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">addCookie</span><span class="o">(</span><span class="n">HttpCookie</span><span class="o">...</span> <span class="n">cookies</span><span class="o">);</span>
<span class="c1">//异步输出指定内容</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">sendBody</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">,</span> <span class="n">A</span> <span class="n">attachment</span><span class="o">,</span> <span class="n">CompletionHandler</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">A</span><span class="o">&gt;</span> <span class="n">handler</span><span class="o">);</span>
<span class="c1">//关闭HTTP连接如果是keep-alive则不强制关闭</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">();</span>
<span class="c1">//强制关闭HTTP连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span><span class="o">...</span> <span class="n">objs</span><span class="o">);</span>
<span class="c1">//将指定字符串以响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">String</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//以指定响应码附带内容输出, message 可以为null</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">,</span> <span class="n">String</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//以304状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish304</span><span class="o">();</span>
<span class="c1">//以404状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish404</span><span class="o">();</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定文件按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">File</span> <span class="n">file</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="o">}</span></pre></div>
<p id="net_websocket">&nbsp;&nbsp;<b>. WebSocket 对象</b> </p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">WebSocket</span> <span class="o">{</span>
<span class="c1">//发送消息体, 包含二进制/文本 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="n">WebSocketPacket</span> <span class="n">packet</span><span class="o">);</span>
<span class="c1">//发送单一的文本消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="n">String</span> <span class="n">text</span><span class="o">);</span>
<span class="c1">//发送文本消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//发送单一的二进制消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//发送单一的二进制消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//发送消息, 消息类型是String或byte[] 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">send</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下所有WebSocket节点发送文本消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendEachMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下所有WebSocket节点发送文本消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendEachMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下所有WebSocket节点发送二进制消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendEachMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下所有WebSocket节点发送二进制消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendEachMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendRecentMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendRecentMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送二进制消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendRecentMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送二进制消息</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendRecentMessage</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//发送PING消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendPing</span><span class="o">();</span>
<span class="c1">//发送PING消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//发送PONG消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">sendPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//移出当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//给当前WebSocket下的增加属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket所属的groupid</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">getGroupid</span><span class="o">();</span>
<span class="c1">//获取当前WebSocket的会话ID 不会为null</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">getSessionid</span><span class="o">();</span>
<span class="c1">//获取客户端直接地址, 当WebSocket连接是由代理服务器转发的则该值固定为代理服务器的IP地址</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端真实地址 同 HttpRequest.getRemoteAddr()</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取WebSocket创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="c1">//显式地关闭WebSocket</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">close</span><span class="o">();</span>
<span class="c1">//获取当前WebSocket所属的WebSocketGroup 不会为null</span>
<span class="kd">protected</span> <span class="n">WebSocketGroup</span> <span class="nf">getWebSocketGroup</span><span class="o">();</span>
<span class="c1">//获取指定groupid的WebSocketGroup, 没有返回null</span>
<span class="kd">protected</span> <span class="n">WebSocketGroup</span> <span class="nf">getWebSocketGroup</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">);</span>
<span class="c1">//获取当前进程节点所有在线的WebSocketGroup</span>
<span class="kd">protected</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">WebSocketGroup</span><span class="o">&gt;</span> <span class="nf">getWebSocketGroups</span><span class="o">();</span>
<span class="c1">//获取在线用户的节点地址列表</span>
<span class="kd">protected</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">&gt;</span> <span class="nf">getOnlineNodes</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">);</span>
<span class="c1">//获取在线用户的详细连接信息</span>
<span class="kd">protected</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;&gt;</span> <span class="nf">getOnlineRemoteAddress</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">groupid</span><span class="o">);</span>
<span class="c1">//返回sessionid, null表示连接不合法或异常,默认实现是request.getSessionid(false),通常需要重写该方法</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">onOpen</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">);</span>
<span class="c1">//创建groupid null表示异常 必须实现该方法, 通常为用户ID为groupid</span>
<span class="kd">protected</span> <span class="kd">abstract</span> <span class="n">Serializable</span> <span class="nf">createGroupid</span><span class="o">();</span>
<span class="c1">//标记为@WebSocketBinary才需要重写此方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onRead</span><span class="o">(</span><span class="n">AsyncConnection</span> <span class="n">channel</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onConnected</span><span class="o">()</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">String</span> <span class="n">text</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onFragment</span><span class="o">(</span><span class="n">String</span> <span class="n">text</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onFragment</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClose</span><span class="o">(</span><span class="kt">int</span> <span class="n">code</span><span class="o">,</span> <span class="n">String</span> <span class="n">reason</span><span class="o">)</span> <span class="o">{</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<h3><a id="net_sncp" class="anchor" href="#" aria-hidden="true"></a>SNCP 协议</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP(Service Node Communicate Protocol)协议是Redkale独有的一种传输协议用于进程之间的通信即请求方的<a href="service.html#service_remote" target="_blank">远程模式Service</a>与响应方的Service之间的通信。是RPC(远程过程调用协议)的同类型协议主要区别在于Redkale里SNCP几乎是透明的写一个普通的Service通过配置即可实现远程调用而不需要专门针对远程写接口。SNCP服务的配置与HTTP差不多只是SNCP不需要ServletSncpServlet是通过Service动态生成的。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP的数据包分包头和包体。包头描述请求的Service信息请求包的包体描述参数的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>,响应包的包体描述回调的参数对象和结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;包头固定长度为72字节其结构如下:
</p>
<table style="margin: auto;">
<tr><th>字 段</th><th>占用字节数</th><th>描 述</th></tr>
<tr><td>序列号</td><td style="text-align: center;">8</td><td>请求的唯一序列号</td></tr>
<tr><td>包头长度</td><td style="text-align: center;">2</td><td>值固定为72</td></tr>
<tr><td>Service类名hash值</td><td style="text-align: center;">16</td><td>Service类名class.getName()的MD5值</td></tr>
<tr><td>Service资源hash值</td><td style="text-align: center;">16</td><td>Service资源名@Resource.name()的MD5值</td></tr>
<tr><td>Service方法hash值</td><td style="text-align: center;">16</td><td>Service方法method.toString()的MD5值</td></tr>
<tr><td>发送方地址</td><td style="text-align: center;">6</td><td>前4字节为地址后2字节为端口号</td></tr>
<tr><td>包体长度</td><td style="text-align: center;">4</td><td>整个包体的长度</td></tr>
<tr><td>结果码</td><td style="text-align: center;">4</td><td>请求方的值固定为0响应方的值视为错误码为0表示成功非0为失败。</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;包体数据结构为 ([参数序号][参数BSON值])* N + [0][结果对象BSON]。 其中参数序号从1开始只有当Service的方法存在<a href="service.html#service_dyncall" target="_blank">@DynCall回调</a>才会有参数<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>序号为0表示为结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>。若方法为<font color="blue">void</font>返回类型,则不存在结果对象<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>
</p>
<h3><a id="net_diy" class="anchor" href="#" aria-hidden="true"></a>自定义协议</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议的网络框架包含五种对象: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context &nbsp;&nbsp;&nbsp;&nbsp;: 协议上下文对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Request &nbsp;&nbsp;&nbsp;: 服务请求对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response : 服务响应对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Servlet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务逻辑处理对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务监听对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常自定义协议需要继承上面五种对象类同时为了让Redkale能识别和加载自定义协议服务需要继承 <b>org.redkale.boot.NodeServer</b> 并指明 <b>@NodeProtocol</b>,实现可以参考 <a href="https://github.com/redkale/redkale-plugins/tree/master/src/org/redkale/net/socks" target="_blank" >基于SOCKS5协议的反向代理服务器</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
</body>
</html>