﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-聂永的博客-随笔分类-socket.io</title><link>http://www.blogjava.net/yongboy/category/54838.html</link><description>记录工作/学习的点点滴滴。</description><language>zh-cn</language><lastBuildDate>Mon, 01 Jun 2015 04:03:10 GMT</lastBuildDate><pubDate>Mon, 01 Jun 2015 04:03:10 GMT</pubDate><ttl>60</ttl><item><title>c_socket.io_server笔记之定义私有接口</title><link>http://www.blogjava.net/yongboy/archive/2013/03/29/397154.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 29 Mar 2013 09:18:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2013/03/29/397154.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/397154.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2013/03/29/397154.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/397154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/397154.html</trackback:ping><description><![CDATA[<h2>有些话说</h2><p>头文件可以作为接口定义，再加上static修饰符，就很容易定义私有的接口，每一个具体的实现，即所有包含所有私有接口的头文件，都必须要完整实现所有已声明但未实现的函数，否则gcc编译不过去。废话不多说，进入步骤吧。</p><h2>开始实施</h2><p>以毫无用处的blog为例，简单两个方法就行了，需要每一个实现暴露一个可以外部调用函数。</p><h3>定义一个结构，公用</h3><p><strong>blog.h</strong>:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;#ifndef&nbsp;_BLOG_H<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;_BLOG_H</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">init)(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">welcome)(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;blog_t;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">#endif</span></div><br /><p>这个头文件定义了一个对象。可以自由的被包含，包含之后自由使用blog_t结构。</p><h3>定义一个完全私有函数头文件</h3><p><strong>blog_impl.h</strong>:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#ifndef&nbsp;_BLOG_IMPL_H<br /></span><span style="color: #0000FF; ">#define</span><span style="color: #000000; ">&nbsp;_BLOG_IMPL_H</span><span style="color: #000000; "><br /><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">stdlib.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">stdio.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br /><br />#include&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog.h</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">继承blog.h文件</span><span style="color: #008000; "><br /></span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;welcome(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">);<br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;init(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">);<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">gen_default(</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">name)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">)malloc(</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(blog_t));<br />&nbsp;&nbsp;&nbsp;&nbsp;blog</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">name&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;strdup(name);<br />&nbsp;&nbsp;&nbsp;&nbsp;blog</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">init&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;init;<br />&nbsp;&nbsp;&nbsp;&nbsp;blog</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">welcome&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;welcome;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;blog;<br />}<br /><br /></span><span style="color: #0000FF; ">#endif</span></div><br /><p>这个文件声明定义了若干static属性的函数，因此，只要包含此头文件的C源文件，必须实现<strong>welcome</strong>与<strong>init</strong>函数，否则gcc编译不通过。需要注意此头文件私有。</p><h3>编写实现</h3><p><strong>blog1.c</strong>，仅仅一个实现:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog_impl.h</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">;<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;init(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">the&nbsp;blog&nbsp;owner&nbsp;is&nbsp;%s\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">name);<br />}<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;welcome(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">here&nbsp;is&nbsp;the&nbsp;%s&nbsp;haha&nbsp;!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">name);<br />}<br /><br />blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">gen_blog1_ptr(){<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_default(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;blog;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;blog;<br />}</span></div><br /><p>仅有一个对外入口：<code>gen_blog1_ptr</code>，也就是此实现对外唯一的交互方式。</p><p><strong>blog2.c</strong>，默认的实现:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog_impl.h</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;init(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Here&nbsp;is&nbsp;the&nbsp;default&nbsp;blog&nbsp;init&nbsp;action&nbsp;!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />}<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;welcome(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">The&nbsp;system's&nbsp;welcome&nbsp;action&nbsp;!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />}<br /><br />blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">gen_blog2_ptr(){<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_default(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">default</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;blog;<br />}</span></div><br /><p>此文件对外唯一入口为：<code>gen_blog2_ptr</code>。</p><p>其实两个实现已经可以了，但多一个说明接口单一，实现多样性，再说锦上添花也是人们喜欢做的事情。
<strong>blog3.c</strong>，添花版:</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog_impl.h</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">;<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;init(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Hi,&nbsp;%s\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">name);<br />}<br /><br /></span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;welcome(</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">you&nbsp;are&nbsp;welcome&nbsp;%s!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">name);<br />}<br /><br />blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">gen_blog3_ptr(){<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_default(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog3</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;blog;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;blog;<br />}</span></div><br /><p>一样可以看到类似约定好的对外函数名称<code>gen_blog3_ptr</code></p><h3>应用端实现</h3><p>我们以<em>app.c</em>作为应用入口：</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">stdio.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">stdlib.h</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br /><br />#include&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blog.h</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;main(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;argc,&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">const</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">argv[])&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog1&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_blog1_ptr();<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog2&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_blog2_ptr();<br />&nbsp;&nbsp;&nbsp;&nbsp;blog_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">blog3&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;gen_blog3_ptr();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">the&nbsp;blog1's&nbsp;actions&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;blog1</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">init();<br />&nbsp;&nbsp;&nbsp;&nbsp;blog1</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">welcome();<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">the&nbsp;blog2's&nbsp;actions&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;blog2</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">init();<br />&nbsp;&nbsp;&nbsp;&nbsp;blog2</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">welcome();<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">the&nbsp;blog3's&nbsp;actions&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;blog3</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">init();<br />&nbsp;&nbsp;&nbsp;&nbsp;blog3</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">welcome();<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />}</span></div><br /><p>这里分别调用<strong>blog1.c</strong>, <strong>blog2.c</strong>, <strong>blog3.c</strong>，唯一入口，执行简单的逻辑。</p><h2>编译运行</h2><p>编译命令行代码很简单：</p><blockquote><p>gcc -o app app.c blog1.c blog2.c blog3.c</p></blockquote><p>运行：</p><blockquote><p>./app</p></blockquote><p>运行效果:</p><blockquote><p>the blog1's actions ... <br />the blog owner is blog1 <br />here is the blog1 haha ! </p><p>the blog2's actions ...
Here is the default blog init action ! <br />The system's welcome action ! </p><p>the blog3's actions ... <br />Hi, blog3 <br />you are welcome blog3!</p></blockquote><h2>小结</h2><p>这里借助两个头文件，模拟了私有接口，公有结构体对象，三个具体子类实现。 <br />在<ahref="https: github.="" com="" yongboy=""  c_socket.io_server"=""><code>c_socket.io_server</code>项目中，作用于具体的实现，以及定义了传输通道模型和实现，互相不干扰。 <br />当然和JAVA相比，模拟对象程度稍低了一些，但够用了。这个世界不仅仅只有面向对象，还有面向并发的函数式Erlang，还有面向软件工程的大型语言Go。嗯，面向对象不过是这个世界其中一角，天生存在缺陷，也不是被所有人喜欢。组件公用、库的概念，倒是大部分语言都很自然的欣然接受。面向过程，面向对象，不过是大部分人给与的标签，怎么用才重要。</ahref="https:></p><img src ="http://www.blogjava.net/yongboy/aggbug/397154.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2013-03-29 17:18 <a href="http://www.blogjava.net/yongboy/archive/2013/03/29/397154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c_socket.io_server笔记之htmlfile块传输</title><link>http://www.blogjava.net/yongboy/archive/2013/03/28/397081.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 28 Mar 2013 00:41:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2013/03/28/397081.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/397081.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2013/03/28/397081.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/397081.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/397081.html</trackback:ping><description><![CDATA[<h2>关于htmlfile chunked传输</h2>
<p>Google天才工程师们使用一个称为&#8220;htmlfile&#8221;的 ActiveX 解决了在 IE 中的加载显示问题，具体是封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，但需要服务器端配合使用。 <br />
稍微熟悉一下有关Transfer-Encoding: chunked的同学，会感觉一点技术含量都没有。但那是他们的事情，笨鸟先飞，记录下来，以作备忘。 <br />
我们做一个时间显示，每隔一秒自动显示在页面上。那么做这件事情的顺序，就很简单。</p>
<h3>输出头部</h3>
<p>chunked块传输，需要浏览器支持，服务器需要提前告诉浏览器端：</p>
<pre><code>#define HTMLFILE_RESPONSE_HEADER \
"HTTP/1.1 200 OK\r\n" \
"Connection: keep-alive\r\n" \
"Content-Type: text/html; charset=utf-8\r\n" \
"Transfer-Encoding: chunked\r\n" \
"\r\n"......
write_ori(client, HTMLFILE_RESPONSE_HEADER);
</code></pre>
<p>在socket.io服务器中，数据量不大，传输内容无须gzip压缩，毕竟压缩算法要耗费一些CPU时间。</p>
<h3>传输部分HTML预备内容</h3>
<p>这部分不是必须的，为了调用客户端javascript方便，可以提前定义好调用函数。</p>
<pre><code>#define HTMLFILE_RESPONSE_FIRST \
</code>&nbsp;&nbsp;&nbsp; <code>"&lt;html&gt;&lt;head&gt;&lt;title&gt;htmlfile chunked example&lt;/title&gt;&lt;script&gt;var _ = function (msg) { document.getElementById('div').innerHTML = msg; };&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div id=\"div\"&gt;&lt;/div&gt;"......
char target_message[strlen(HTMLFILE_RESPONSE_FIRST) + 20];
sprintf(target_message, "%X\r\n%s\r\n", (int)strlen(HTMLFILE_RESPONSE_FIRST), HTMLFILE_RESPONSE_FIRST);
write_ori(client, target_message);
</code></pre>
<p>除了http header头部输出，剩下内容的输出，需要注意输出的简单格式：</p>
<blockquote>
<p>具体输出内容长度16进制数字表示\r\n具体输出内容\r\n </p>
</blockquote>
<p>如</p>
<blockquote>
<pre><code>2D
&lt;script&gt;_('now time is 1364040943');&lt;/script&gt;</code></pre>
</blockquote>
<p>掌握了格式要求之后，其它的，就没有什么难点。</p>
<h3>设置定时器，周期性循环</h3>
<pre><code>client-&gt;timeout.data = client;
ev_timer_init(&amp;client-&gt;timeout, timeout_cb, 1.0, 1.0);
ev_timer_start(loop, &amp;client-&gt;timeout);
</code></pre>
<p>时间触发函数timeout_cb每一秒会定时触发：</p>
<pre><code>static void timeout_cb(EV_P_ struct ev_timer *timer, int revents) {
if (EV_ERROR &amp; revents) {
</code>&nbsp;&nbsp;&nbsp; <code>fprintf(stderr, "error event in timer_beat\n");
</code>&nbsp;&nbsp;&nbsp; <code>return ;
}
if (timer == NULL) {
</code>&nbsp;&nbsp;&nbsp; <code>fprintf(stderr, "the timer is NULL now !\n");
}
client_t *client = timer-&gt;data;
if (client == NULL) {
</code>&nbsp;&nbsp;&nbsp;&nbsp;<code> fprintf(stderr, "Timeout the client is NULL !\n");
</code>&nbsp;&nbsp;&nbsp; <code>return;
}
char target_msg[50];
snprintf(target_msg, 50, "now time is %d", (int)ev_time());
write_body(client, target_msg);
}
</code></pre>
<p>OK，基本功能完毕。</p>
<h2>编译运行</h2>
<p>编译一下：</p>
<blockquote>
<p>gcc htmlfile.c -o htmlfile ../include/libev.a -lm</p>
</blockquote>
<p>运行它：</p>
<blockquote>
<p>./htmlfile </p>
</blockquote>
<p>打开浏览器，输入地址 <strong>http://192.168.190.150:8080/htmlfile</strong>，可以看到时间一点点的流逝，诸如：</p>
<blockquote>
<p>now time is 1364043695</p>
</blockquote>
<h2>完整代码</h2>
<script src="https://gist.github.com/yongboy/5259523.js"></script><img src ="http://www.blogjava.net/yongboy/aggbug/397081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2013-03-28 08:41 <a href="http://www.blogjava.net/yongboy/archive/2013/03/28/397081.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c_socket.io_server笔记之长轮询超时(timeout)处理</title><link>http://www.blogjava.net/yongboy/archive/2013/03/27/397031.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Wed, 27 Mar 2013 00:57:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2013/03/27/397031.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/397031.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2013/03/27/397031.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/397031.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/397031.html</trackback:ping><description><![CDATA[<h2>不吐不快</h2>
<p>当你习惯了现有WEB服务器，诸如nginx、apache，JAVA应用服务器Tomcat等，你就不能不注意HTTP请求的响应超时时间，需要小心，尤其是反向代理时。当你可以自由控制请求timeout超时时，那是怎样一个快意。 <br />
在libev中使用timeout，没有像java那样封装的完善，一切都很原始，但确实锋利多了。</p>
<h2>长轮询</h2>
<p>一般长轮询需要定义超时时间，一旦超时，服务器端会主动断开连接。无论是xhr形式的长轮询，还是jsonp长轮询，在服务器端处理没有多大差别，输出数据有异。
</p>
<h3>输出头部</h3>
<p>一般优先输出头部，告诉浏览器，需要保持长连接，当然，这需要浏览器支持http 1.1协议，并且明确的注明当前连接为一直保持着：keep-alive：</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;heaer_str[</span><span style="color: #000000; ">200</span><span style="color: #000000; ">]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">""</span><span style="color: #000000; ">;<br />
strcat(heaer_str,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">HTTP/1.1&nbsp;200&nbsp;OK\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
strcat(heaer_str,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Content-Type:&nbsp;text/plain;&nbsp;charset=UTF-8\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
strcat(heaer_str,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Connection:&nbsp;keep-alive\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
strcat(heaer_str,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\r\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
write_msg(client,&nbsp;heaer_str);</span></div>
<br />
<h3>定时器启动，等待</h3>
<p>连接什么时候关闭，需要在代码中手动控制，除非浏览器端在发出请求等待响应期间出现异常，无故断开了连接。设服务器端设定好连接持续时间为30秒，那么就应该启动一个定时器，除非所使用的语言层面提供了内置支持。</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">client</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">timeout.data&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;client;<br />
ev_timer_init(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">client</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">timeout,&nbsp;timeout_cb,&nbsp;</span><span style="color: #000000; ">30.0</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">);&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">30s</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">ev_timer_start(loop,&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">client</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">timeout);</span></div>
<br />
<p>定时器start之后，触发的函数timeout_cb：</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;timeout_cb(EV_P_&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;ev_timer&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">timer,&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;revents)&nbsp;{<br />
</span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(EV_ERROR&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">&nbsp;revents)&nbsp;{<br />
</span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">error&nbsp;event&nbsp;in&nbsp;timer_beat\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
</span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;;<br />
</span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(timer&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;NULL)&nbsp;{<br />
</span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">the&nbsp;timer&nbsp;is&nbsp;NULL&nbsp;now&nbsp;!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
</span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />
</span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client_t&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">client&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;timer</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">data;<br />
</span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(client&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;NULL)&nbsp;{<br />
</span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Timeout&nbsp;the&nbsp;client&nbsp;is&nbsp;NULL&nbsp;!\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />
</span><span style="color: #008080; ">16</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">;<br />
</span><span style="color: #008080; ">17</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span><span style="color: #008080; ">18</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write_msg(client,&nbsp;HTML_RESPONSE_ECHO);<br />
</span><span style="color: #008080; ">20</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free_res(loop,&nbsp;client);<br />
</span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p>可以看到，定时器触发之后，本例中将输出一串预先定义好的文字，然后关闭连接。 <br />
如何关闭触发器，则很简单：
</p>
<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;ev_timer&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">timer&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">client</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">timeout;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(timer&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;NULL&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;(timer</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">data&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;NULL))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ev_timer_stop(loop,&nbsp;timer);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<h2>编译运行</h2>
<p>编译一下：</p>
<blockquote>
<p>gcc long<em>polling.c -o long</em>polling ../include/libev.a ../include/http-parser/http_parser.o -lm </p>
</blockquote>
<p>运行它：</p>
<blockquote>
<p>./long_polling
</p>
</blockquote>
<p>然后测试：</p>
<blockquote>
<p>curl -i http://192.168.190.150:9000/long_polling
</p>
</blockquote>
<p>可以先看到头部：
</p>
<blockquote>
<p>HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Connection: keep-alive</p>
</blockquote>
<p>等到30秒后输出具体的文字内容：
</p>
<blockquote>
<p>The timeout(30s) had passed, you are welcome ~!</p>
</blockquote>
<h2>小结</h2>
<p>所演示的长轮询，没有什么难度，HTTP 1.1头部输出，定时器启动，然后等待输出。 <br />
libev内含的timer组件简单易用，控制方便，但不算是最佳实践，官方文档给出了若干种最佳实践方式。具体可参阅: <br />
<a href="http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_timer_code_relative_and_opti">http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code<em>ev</em>timer<em>code<em>relative</em>and</em>opti</a></p>
<h2>完整代码</h2>
<p>
<script src="https://gist.github.com/yongboy/5250640.js"></script></p><img src ="http://www.blogjava.net/yongboy/aggbug/397031.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2013-03-27 08:57 <a href="http://www.blogjava.net/yongboy/archive/2013/03/27/397031.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c_socket.io_server笔记之处理静态文件</title><link>http://www.blogjava.net/yongboy/archive/2013/03/25/396972.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 25 Mar 2013 08:46:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2013/03/25/396972.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/396972.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2013/03/25/396972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/396972.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/396972.html</trackback:ping><description><![CDATA[<h2>缘由</h2>
<p>在编 <ahref="https: github.="" com="" yongboy=""  c_socket.io_server"="">写纯C语言版socket.io服务器 时，选择了<ahref="http: libev.schmorp.="" de=""  "="">libev作为网络基础层代码，可以离epoll模型远一些，再说还可以避免单独使用Epoll，写出不易维护的多层嵌套代码，听说，有时Epoll出现一些&#8220;伪信号&#8221;小问题，没有那么空闲精力，绕过之，选择成熟度非常高的libev好了。 <br />
有关libev的文章，中文资料不多，英文资料也不多。这里推荐三篇： <br />
- <ahref="http: cnodejs.="" org="" topic=""  4f16442ccae1f4aa270010a3"="">libev 设计分析<br />
- <ahref="http: rdc.taobao.="" com="" blog="" cs=""  ?="" p="1604&quot;">libev ev_io源码分析<br />
- 官方文档<ahref="http: pod.tst.="" eu="" http:=""  cvs.schmorp.="" de="" libev=""  ev.pod"="">http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod，更为全面一些，阅读时可以获得较总体认知。 </ahref="http:></ahref="http:></ahref="http:></ahref="http:></ahref="https:></p>
<p>这里把在编写<ahref="https: github.="" com="" yongboy=""  c_socket.io_server"=""><code>c_socket.io_server</code>程中使用libev的一些地方做些笔记，记录下来，也方便以后查阅。</ahref="https:></p>
<h2>预备知识</h2>
<p>所有代码的编写、编译、测试和运行等，都在Ubuntu下进行，另外实例严重依赖libev和<ahref="https: github.="" com="" joyent=""  http-parser"="">http-parser HTTP解析库。 <br />
其它依赖，可以从<ahref="https: github.="" com="" yongboy=""  c_socket.io_server"="">https://github.com/yongboy/c<em>socket.io</em>server处下载。</ahref="https:></ahref="https:></p>
<h2>处理静态文件</h2>
<p>这里设计一个静态文件WEB服务器，非常简单，仅仅满足socket.io服务器最基本的需求，因此别苛求太多。但比网上很多大把类似文章多了一点写入管道时缓冲区已满问题的处理。 <br />
这里简单说一下处理静态文件的思路。</p>
<h3>计算静态文件路径以及扩展名和内容类型</h3>
<pre><code>char file_path[200]; <br />sprintf(file_path, "%s%s", static_folder, url_str);
</code></pre>
<h3>获取文件内容和以及优先输出响应头部</h3>
<pre><code><div>&nbsp;&nbsp;&nbsp;  char file_path[200];<br /> &nbsp;&nbsp;&nbsp;&nbsp;sprintf(file_path, "%s%s", static_folder, url_str);<br /> <br /> &nbsp;&nbsp;&nbsp;&nbsp;int file = open(file_path, O_RDONLY);<br /> &nbsp;&nbsp;&nbsp;&nbsp;struct stat info;<br /> &nbsp;&nbsp;&nbsp;&nbsp;if (fstat(file, &amp;info) == -1) {<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, "the file %s is NULL\n", file_path);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write(client-&gt;fd, RESPONSE_404, strlen(RESPONSE_404));<br /> <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(file);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free_res(loop, client);<br /> <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br /> &nbsp;&nbsp;&nbsp;&nbsp;}<br /> <br /> &nbsp;&nbsp;&nbsp;&nbsp;char file_ext[50];<br /> &nbsp;&nbsp;&nbsp;&nbsp;get_extension(file_path, file_ext);<br /> &nbsp;&nbsp;&nbsp;&nbsp;char content_type[50];<br /> &nbsp;&nbsp;&nbsp;&nbsp;get_content_type(file_ext, content_type);<br /> <br /> &nbsp;&nbsp;&nbsp;&nbsp;int file_len = info.st_size;<br /> &nbsp;&nbsp;&nbsp;&nbsp;char head_msg[200] = "";<br /> &nbsp;&nbsp;&nbsp;&nbsp;sprintf(head_msg, RESPONSE_TEMPLATE, content_type, file_len);<br /> &nbsp;&nbsp;&nbsp;&nbsp;write(client-&gt;fd, head_msg, strlen(head_msg));</div><br /></code></pre>
<p>很显然，这里引入fcntl.h头部文件，调用fstat初始化stat结构，可判断文件是否存在，以及文件大小等。 </p>
<h3>读取文件内容到缓冲区，循环写入</h3>
<pre><code><div>    int read_count;<br />    int buf_size = 8 * 1024;//8096;<br />    char buffer[buf_size + 1];<br />    while ((read_count = read(file, buffer, buf_size)) &gt; 0) {<br />        int bytes_left = read_count;<br />        char *ptr = buffer;<br />        int need_break = 0;<br />        while (bytes_left &gt; 0) {<br />            ssize_t write_len = write(client-&gt;fd, ptr, bytes_left);<br /><br />            if (write_len == -1) {<br />                fprintf(stderr, "write failed(errno = %d): %s\n", errno, strerror(errno));<br />                switch (errno) {<br />                case EAGAIN:<br />                case EINTR:<br />                case EINPROGRESS:<br />                    fprintf(stderr, "now sleep 0.2s\n");<br />                    ev_sleep(0.2);<br />                    break;<br />                default:<br />                    need_break = 1;<br />                    break;<br />                }<br />            } else if (write_len == 0) {<br />                need_break = 1;<br />                fprintf(stderr, "write_len is zero, and break now\n");<br />                break;<br />            } else if (write_len &lt; bytes_left) {<br />                bytes_left -= write_len;<br />                ptr += write_len;<br />                fprintf(stderr, "write client with something wrong wtih bytes_left = %d &amp; write_len = %d and write the left data !\n", (int)bytes_left, (int)write_len);<br />            } else {<br />                break;<br />            }<br />        }<br /><br />        if (need_break) {<br />            break;<br />        }<br />    }<br /><br />    close(file);
</div></code></pre>
<p>需要注意，构造的一个大约8K+1的缓冲区buffer，不是每次都可以正常完整输出到socket对端，write输出不完整，会返回-1，系统返回errno值，在errno = EAGAIN，EINTR，EINPROGRESS时，需要再次将缓冲区中尚未写入的剩下数据再次写入到请求端。这样可以避免常见的半包、包不完整问题。 </p>
<h3>关闭socket描述符,当前请求结束</h3>
<pre><code>free_res(loop, client);
</code></pre>
<p>请求完成，一定要记得关闭socket描述符，释放相应资源等。
这样一个较为完整的HTTP请求，静态文件就处理完毕了。 </p>
<h2>编译运行</h2>
<p>先编译：</p>
<blockquote>
<p>gcc static<em>server.c -o static</em>server ../include/libev.a ../include/http-parser/http_parser.o -lm</p>
</blockquote>
<p>运行之：</p>
<blockquote>
<p>./static_server ../static</p>
</blockquote>
<p>命令输入错误，如输入静态路径为空，会报错的，哈哈： </p>
<blockquote>
<p>Error: invald path parmeter</p>
<p>Usage:
./static_server <yourstaticpath></yourstaticpath></p>
<p>Example: <br />
./static<em>server ../static <br />
./static</em>server /home/yongboy/your<em>static</em>folder</p>
<p>Enjoy it~</p>
</blockquote>
<p>测试一下吧</p>
<blockquote>
<p>curl -i http://192.168.190.150:8000/index.html</p>
</blockquote>
<p>在浏览器内，测试一下，支持图片样式等，完好显示。</p>
<p>需要注意，要传入静态文件目录路径，相对的路径，或绝对的路径，都是可以接受的。
最后，附上完整代码：</p>
<script src="https://gist.github.com/yongboy/5235734.js"></script><img src ="http://www.blogjava.net/yongboy/aggbug/396972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2013-03-25 16:46 <a href="http://www.blogjava.net/yongboy/archive/2013/03/25/396972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>哈，又来一个纯C语言版本的socket.io服务器端实现~</title><link>http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 15 Mar 2013 08:02:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/396493.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/396493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/396493.html</trackback:ping><description><![CDATA[<h2>前言</h2>
<p>哈，这又是一个socket.io服务端实现，本意是，拿C练练手，加强对C和linux系统的理解，写着写着，就写成了一个socket.io服务器端实现了。以为半成品，那就正式托管在github站点上吧，以便记录一下，可让大家批评与指正，加强内功的修炼等。 <br />
项目地址为 <br />
<a href="https://github.com/yongboy/c_socket.io_server">yongboy/c<em>_socket.io_</em>server</a>
</p>
<p><em>以下部分文字，偷懒，摘录自项目的README.md文件</em></p>
<h2>说明</h2>
<p>这是一个纯C语言版本的socket.io服务器端实现，目前仅支持linux系统，严重依赖<a href="http://libev.schmorp.de/">libev</a> and <a href="https://developer.gnome.org/glib/2.34/">glib</a>等基础库。<br />
在运行socket.io_server之前，需要安装以下依赖：
</p>
<blockquote>
<p>sudo apt-get install uuid-dev<br />
sudo apt-get install libglib2.0-dev </p>
</blockquote>
<h2>如何运行</h2>
<ol>
     <li>编写实现代码（eg:chatroom.c），需要包含头文件 <strong>endpoint_impl.h</strong></li>
     <li>把实现代码(eg:chatroom.c)放入examples目录</li>
     <li>编写对应的html文件，放入static目录</li>
     <li>编辑<strong>Makefile</strong>文件</li>
     <li>终端下运行make命令</li>
     <li>然后敲入 ./socket.io_server 接口运行</li>
     <li>打开浏览器即可访问 (eg:http://localhost:8000/chatroom.html)</li>
</ol>
<h2>API说明</h2>
<p>对外的API，可以在头文件 <strong>endpoint_impl.h</strong> 看到其定义，其继承了另外一个公用的头文件 <strong>endpoint.h</strong>, 其完整定义为：
<script src="https://gist.github.com/yongboy/5168005.js"></script></p>
<p><a href="https://gist.github.com/yongboy/5168005">完整定义</a>. <br />
在example目录中，你可以看到聊天室演示 <a href="https://github.com/yongboy/c_socket.io_server/blob/master/example/chatroom.c">chatroom</a> 和在线白板示范 <a href="https://github.com/yongboy/c_socket.io_server/blob/master/example/whiteboard.c">whiteboard</a> .
<script src="https://gist.github.com/yongboy/5168163.js"></script>因为C语言中没有散列表，只好借助于成熟的glib库实现。</p>
<h2>其它</h2>
<p>项目不太成熟，期待大家的参与，您的建议、批评和指正，都是一种激励，再次表示感谢。</p><img src ="http://www.blogjava.net/yongboy/aggbug/396493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2013-03-15 16:02 <a href="http://www.blogjava.net/yongboy/archive/2013/03/15/396493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>刚出炉的，socket.io erlang server版本，有点小清新</title><link>http://www.blogjava.net/yongboy/archive/2012/10/15/389575.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 15 Oct 2012 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/10/15/389575.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/389575.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/10/15/389575.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/389575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/389575.html</trackback:ping><description><![CDATA[<h2><strong>絮言</strong></h2> <p>最近在学习<a href="http://zh.wikipedia.org/wiki/Erlang" target="_blank">Erlang</a>，顺便写了一个<a href="http://socket.io/" target="_blank">socket.io</a> server作为练练手，感受函数式/面向并发编程的好处。</p> <p>毫无疑问，同样兼容最新的<a href="https://github.com/LearnBoost/socket.io-spec" target="_blank">socket.io spec 1.0</a>。</p> <p>无论哪一种语言，从头开始构建HTTP协议支持，都是很痛苦的，站在巨人肩上，总是可以让你更专注于业务。Java社区可选择netty，Erlang社区可以选择非常轻量级的<a href="https://github.com/mochi/mochiweb" target="_blank">mochiweb</a>和<a href="https://github.com/extend/cowboy" target="_blank">cowboy</a>等，这里要感谢一下尤日华同学（<a title="http://www.cnblogs.com/yourihua/" href="http://www.cnblogs.com/yourihua/">http://www.cnblogs.com/yourihua/</a>），特别热心，一一给我们分析了以上两个http框架的源码，我等新手获益良多。就是在其文章的帮助下，开始构建一个socket.io erlang server。</p> <p><a href="https://github.com/mochi/mochiweb" target="_blank">mochiweb</a>，有些历史，已趋于稳定，但目前不支持websocket协议。</p> <p><a href="https://github.com/extend/cowboy" target="_blank">cowboy</a>，模块/协议自由替换，使用二进制传输基本保证了低内存占用和快速传输，内置非常赞的dispatch URL分发器，内置对长连接的支持，目前使用的是0.6.1版本。推荐使用！</p> <p>闲话少说，目前已经释出0.1版本，项目地址为：</p> <p><a title="https://code.google.com/p/erlang-scoketio/" href="https://code.google.com/p/erlang-scoketio/">https://code.google.com/p/erlang-scoketio/</a></p> <h2><strong>项目介绍</strong></h2> <p>Erlang 版本的socket.io服务器实现</p> <h4><a name="1._基于cowboy构建"></a>1. 基于cowboy构建</h4> <blockquote>检出地址： <a href="https://erlang-scoketio.googlecode.com/svn/socket.io_cowboy">https://erlang-scoketio.googlecode.com/svn/socket.io_cowboy</a><br />兼容 socket.io-spec(<a href="https://github.com/LearnBoost/socket.io-spec">https://github.com/LearnBoost/socket.io-spec</a>) 1.0<br />支持xhr-polling/jsonp-polling/htmlfile/websocket/flashsocket等通讯协议<br />支持CJK语言，UTF-8编码下很少出现乱码<br />现在可以作为0.1版本释出，具有一个chat示范</blockquote> <h4><a name="2._基于mochiweb构建"></a>2. 基于mochiweb构建</h4> <blockquote>检出地址: <a href="https://erlang-scoketio.googlecode.com/svn/socket.io_mochiweb">https://erlang-scoketio.googlecode.com/svn/socket.io_mochiweb</a><br />兼容 socket.io-spec(<a href="https://github.com/LearnBoost/socket.io-spec">https://github.com/LearnBoost/socket.io-spec</a>) 1.0<br />仅支持xhr-polling/jsonp-polling/htmlfile等通讯协议<br />暂时精力有限，停止更新，假若有需要，可以进一步有偿商谈</blockquote> <h4><a name="3._运行一个示范"></a>3. 运行一个示范</h4> <blockquote> <ul> <li>下载示范文件<a href="http://code.google.com/p/erlang-scoketio/downloads/detail?name=socket.io.zip">http://code.google.com/p/erlang-scoketio/downloads/detail?name=socket.io.zip</a>  </li><li>在Linux下解压  </li><li>#unzip socket*.zip  </li><li>#cd socket.io  </li><li>#make  </li><li>#sh start.sh  </li><li>打开浏览器，访问<a href="http://yourip:8080/index.html">http://yourip:8080/index.html</a></li></ul></blockquote> <h2><strong>一个实现</strong></h2> <p>这里介绍一个聊天示范，看代码，很简单，也很短，才80行。</p><script src="https://gist.github.com/3891124.js?file=chat_impl.erl"></script> <p>与Java相比，Erlang代码显得少多了。 </p> <h2><strong>其它</strong></h2> <p>刚入门，项目代码写的有些草；您若慷慨，希望给些指点，谢谢 ：))</p><img src ="http://www.blogjava.net/yongboy/aggbug/389575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-10-15 14:57 <a href="http://www.blogjava.net/yongboy/archive/2012/10/15/389575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Javascript EventBus(事件总线)模拟socket.io中事件处理</title><link>http://www.blogjava.net/yongboy/archive/2012/08/24/386239.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Fri, 24 Aug 2012 15:04:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/08/24/386239.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/386239.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/08/24/386239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/386239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/386239.html</trackback:ping><description><![CDATA[<p>socket.io客户端对事件处理相当优雅，和weboscket的有限的javascript接口差不多一致好看，但可以支持更多的自定义事件：</p><script src="https://gist.github.com/3451735.js"> </script> <p>使用了EventBus(事件总线)方式可以很好的处理事件订阅者/事件的发布者解耦，发布者不知道订阅者，订阅者只需要自身注册，等待通知便可。EventBus是一种简单，高效，优雅，良好的客户端架构方式。嗯，还好，javascritp本身支持函数作为参数进行传递，要不还是很麻烦的。</p> <p>构建一个最简单的EventBus javascript库，也不难：</p><script src="https://gist.github.com/3451632.js?file=yongboy.eventbus.js"></script> <p>简单不到40行代码，提供了事件订阅，事件取消，事件广播/发布等，虽简单，但已经满足最简单的页面端EventBus模型，可以一窥全貌了。</p> <p>客户端使用事件总线代码：</p><script src="https://gist.github.com/3451656.js?file=eventbus.html"></script> <p>看着和socket.io的客户端使用方式有所类似，但socket.io的处理方式复杂多了，并且多了一些内置的事件，这里不过是简化了很多。</p> <p>嗯，有空谈一谈JAVA是如何做到事件总线(EventBus)的。</p><img src ="http://www.blogjava.net/yongboy/aggbug/386239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-08-24 23:04 <a href="http://www.blogjava.net/yongboy/archive/2012/08/24/386239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Real-Time Web实时信息流推送培训文档</title><link>http://www.blogjava.net/yongboy/archive/2012/08/23/386061.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 23 Aug 2012 01:57:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/08/23/386061.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/386061.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/08/23/386061.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/386061.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/386061.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Real-Time Web实时信息流推送<br>培训演示文档，文档大纲：<br>推送实现技术/历程<br>客户端如何选择<br>Java支持现状<br>socket.io<br>Realtime Web概念和现状<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/yongboy/archive/2012/08/23/386061.html'>阅读全文</a><img src ="http://www.blogjava.net/yongboy/aggbug/386061.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-08-23 09:57 <a href="http://www.blogjava.net/yongboy/archive/2012/08/23/386061.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>构建实时Web的JAVA选择组合：socket.io client + socketio-netty server</title><link>http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 24 May 2012 01:10:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/378839.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/378839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/378839.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 很显然，实时Web，是一种技术趋势，将成为一种人们的默认技术选择，用以拉近和桌面应用的距离。<br>socket.io是一种数据实时推送、事件驱动模型的框架，支持事件订阅，简单易用。其价值目前看来，还未被完整的挖掘出来。<br><br>socket.io即提供了node.js服务器端（地址）又提供了客户端（地址）的整体解决方案，而socketio-netty则是基于JAVA服务器端，支持最新socket.io client最新版规范。对JAVA编程人员来讲，可以不用学习node.js，从而多了一个选择。&nbsp;&nbsp;<a href='http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html'>阅读全文</a><img src ="http://www.blogjava.net/yongboy/aggbug/378839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-05-24 09:10 <a href="http://www.blogjava.net/yongboy/archive/2012/05/24/378839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socketio-netty(socket.io 服务器端JAVA实现) 近期升级手记</title><link>http://www.blogjava.net/yongboy/archive/2012/05/21/378723.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 21 May 2012 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/05/21/378723.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/378723.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/05/21/378723.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/378723.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/378723.html</trackback:ping><description><![CDATA[<h3><strong>前言</strong></h3> <p>针对JAVA开发者，<a href="http://code.google.com/p/socketio-netty/">socketio-netty</a>是一个socket.io的服务器端选择，又是目前兼容最新0.9+ &#8211; 1.0的JAVA服务器端实现。</p> <p>从<a href="http://socket.io">http://socket.io</a>官网来看，最近版本升级趋于缓和，几乎是没修正一个Bug，小版本就增加一次。已经是非常稳定的版本了，可以真正使用了。</p> <p>貌似国内使用socket.io少之又少，可惜了，这么优秀的全功能型实时推送实现，小众范围内被知晓。</p> <p>嗯，就最近当前项目修改做一些简单记载。</p> <p>&nbsp;</p> <h3><strong>升级手记</strong></h3> <ol> <li>netty升级到3.4.5<br />3.4.5的QueueFactory类，增加对了JAVA SE 7引入的JUC并发类LinkedTransferQueue，若是本地使用JAVA SE 6，还想要保持高性能的阻塞队列，那就需要引入Doug Lea&#8217;s jsr166y.jar并发包(<a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166y.jar" target="_blank">下载地址</a>)，然后修改一下QueueFactory实现。我已经重新打包成jar包（这里是netty-3.4.5.Final-modify.jar）。<br />QueueFactory原始代码： <script src="https://gist.github.com/2760980.js?file=QueueFactory.java"></script><br />QueueFactory修改后代码： <script src="https://gist.github.com/2760990.js?file=QueueFactory-modify.java"></script><br /> </li><li><a href="http://socket.io" target="_blank">socket.io</a> client 升级到 0.9.6  </li><li>支持将HTML/CSS/JS等文件<br />socketio.properties 增加配置项static，指定静态资源的相对路径 ，默认是static<br />若浏览器请求：<a title="http://10.95.20.168:9000/style/chat.css" href="http://localhost:9000/style/chat.css">http://localhost:9000/style/chat.css</a>，则此文件相对路径为 static/style/chat.css，其它文件与此类似。<br />此属性便于打包，以及不再单独依赖Web容器<br />项目中，直接把网页文件拷贝到/source/static目录中，运行相应的JAVA文件（ChatServer.java）  </li><li>在Google Code 增加demo<br />下载<a href="http://code.google.com/p/socketio-netty/downloads/detail?name=chat_server.zip&amp;can=2&amp;q=#makechanges" target="_blank">聊天示范</a>，下载后解压，双击 start.bat或者start.sh，浏览　<a href="http://localhost:9000/">http://localhost:9000/</a>　即可。</li></ol> <p>有时间，会聊聊更具体的实时Web一些心得，以及更为具体的示范等。</p><img src ="http://www.blogjava.net/yongboy/aggbug/378723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-05-21 17:31 <a href="http://www.blogjava.net/yongboy/archive/2012/05/21/378723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为Phonegap Android平台增加websocket支持，使默认成为socket.io首选通道选择</title><link>http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Thu, 10 May 2012 06:10:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/377787.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/377787.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/377787.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 构建一个在市面上常见浏览器上都可以正常运行的聊天应用，保证在IE6+，Firefox，Chrome，Safari，Opear，IOS，Android等可以正常运转，根据具体环境自动选择最佳的通信通道。<br>嗯，既然是跨浏览器平台，那自然选择socket.io了。它也是本文的重心，最终目的也是让socket.io 客户端版本在Phonegap包装的Android Apk程序中可以使用Websocket协议。<br>同时也保证我们的示范应用尽可能的做到编写一次，到处运行。<br>还好，有了socket.io(客户端js) + socketio-netty（socket.io服务器端JAVA实现） + Phonegap, 构建各种交互的HTML应用，是个不错的选择。<br>另，本文项目为仅仅为演示其功能，不保证样式。&nbsp;&nbsp;<a href='http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html'>阅读全文</a><img src ="http://www.blogjava.net/yongboy/aggbug/377787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-05-10 14:10 <a href="http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>socketio-netty : 又一款socket.io服务器端实现，兼容0.9-1.0版本~</title><link>http://www.blogjava.net/yongboy/archive/2012/04/07/373552.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Sat, 07 Apr 2012 14:08:00 GMT</pubDate><guid>http://www.blogjava.net/yongboy/archive/2012/04/07/373552.html</guid><wfw:comment>http://www.blogjava.net/yongboy/comments/373552.html</wfw:comment><comments>http://www.blogjava.net/yongboy/archive/2012/04/07/373552.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/yongboy/comments/commentRss/373552.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yongboy/services/trackbacks/373552.html</trackback:ping><description><![CDATA[<h3>
缘起</h3>
<div style="text-indent: 2em;">
socket.io是一个跨浏览器的全平台反响AJAX实现，官网（http://socket.io）定义为：the cross-browser WebSocket for realtime apps.</div>
<div style="text-indent: 2em;">
个人认为这是一个跨浏览器的集大成者，支持桌面端和移动端浏览器（http://socket.io/#browser-support）：
<h4>
Desktop</h4>
<ul>
<li>Internet Explorer 5.5+</li>
<li>Safari 3+</li>
<li>Google Chrome 4+</li>
<li>Firefox 3+</li>
<li>Opera 10.61+ </li>
</ul>
<h3>
Mobile</h3>
<ul>
<li>iPhone Safari</li>
<li>iPad Safari</li>
<li>Android WebKit</li>
<li>WebOs WebKit</li>
</ul>
</div>
<div style="text-indent: 2em;">
为了支持众多浏览器，必然内置对若干协议的支持：
<ul>
<li>WebSocket</li>
<li>Adobe&#174; Flash&#174; Socket</li>
<li>AJAX long polling</li>
<li>AJAX multipart streaming</li>
<li>Forever Iframe</li>
<li>JSONP Polling</li>
</ul>
socket.io跨浏览器，根据浏览器自动适配最适合方案进行实时推送。</div>
<div style="text-indent: 2em;">
官方提供了各种语言的实现，见 https://github.com/learnboost/socket.io/wiki/，有java语言实现服务器端，但不支持最新的0.9版本，于是萌发了重写一个的想法。</div>
<h3>
概述</h3>
<div style="text-indent: 2em;">
这是一个Socket.IO服务器端实现，基于netty框架，适配socket.io 0.9-1.0版本（虽然socket.io 目前还处于 0.9版本，会支持到1.0） </div>
<div style="text-indent: 2em;">
项目地址：
http://code.google.com/p/socketio-netty/</div>
<div style="text-indent: 2em;">
采用流行的Apache License 2.0协议，svn作为源代码管理。</div>
<div style="text-indent: 2em;">
邮件讨论组为 
<a href="http://groups.google.com/group/socketio-netty" rel="nofollow">http://groups.google.com/group/socketio-netty</a>
<br />或者<br />&nbsp;<a href="https://groups.google.com/group/socketio-netty" rel="nofollow">https://groups.google.com/group/socketio-netty</a> <br />
期待您的加入。 </div>
<div style="text-indent: 2em;">
至于为什么没有采用tomcat/jetty支持的servlet3规范、sebsocket实现，个人认为，构建在其基础上较为容易，tomcat7最新版刚刚支持websocket，传说支持websocket的servlet 3.1还未出世，等等看吧。
而Netty这个异步IO框架，我们可以在它的基础上一站式搞定如此多的传输通道/协议。</div>
<div style="text-indent: 2em;">
socketio-netty支持：
<ul>
<li>WebSocket</li>
<li>Flash Socket</li>
<li>AJAX long polling</li>
<li>Forever Iframe</li>
<li>JSONP Polling</li>
</ul>
等传输通道协议。</div>
<h3>
示范</h3>
<div style="text-indent: 2em;">
本示范，参考 socket.io node.js 版本的聊天实现(chat)，客户端完全一致，服务器端完全换成了socketio-netty实现。其它的没有任何变化。嗯，可能看一个示范，可以让人更放心的使用。
客户端入口 chat.html (存放在tomcat/jetty/nginx/apache/iis相应位置，可以直接访问即可)：
<script src="https://gist.github.com/2329041.js?file=chat.html">
</script>
看一下，我们的服务器端如何实现，来一个启动入口：
<script src="https://gist.github.com/2329062.js?file=ChatServer.java">
</script>
然后需要一个DemoChatHandler处理器，这个是一个单列多线程模式：
<script src="https://gist.github.com/2329074.js?file=DemoChatHandler.java">
</script></div>
<div style="text-indent: 2em;">
以上就是整个的聊天室实现，虽然不算优雅，但很简单。</div>
<div style="text-indent: 2em;">
所有你所需要做的就是，检出代码，运行com.yongboy.socketio.test.ChatServer即可。</div><img src ="http://www.blogjava.net/yongboy/aggbug/373552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yongboy/" target="_blank">nieyong</a> 2012-04-07 22:08 <a href="http://www.blogjava.net/yongboy/archive/2012/04/07/373552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>