1、使用多路复用或者异步I/O模型,这本是服务器段常用的技术,但在P2P应用,每台机器既是服务器,又是客户端,共享了一个十分受欢迎的文件,可能会有很多希望连接者,或者你下载一个受欢迎文件时,可能搜索到数百上千的Peer,此时就很有必要采用多路复用或者异步I/O技术,降低应用程序所占用的资源。

2、支持传统的协议,包括HTTP和FTP,其实这两种技术能够和P2P网络集成,其中一种办法就是,在提供下载地址的同时提供一个种子文件下载,例如服务器中提供了ABC.rar文件,同时提供一个ABC.rar.md5文件允许下载,这样P2P下载工具下载时,通过md5在P2P网络中搜索更多的资源,这样客户能够获得更好的速度,服务器端也可能降低下载的网络流量。

3、流行的P2P网络协议支持,包括BT和emule,这两种都是公开协议了,都有开源的实现,可以参考并重写,要支持并不困难。

4、健壮性。如同emule一样,将文件分块(piece)的同时,把每一块摘要一个piece_ID,将所有的piece_ID再摘要成一个总的ID,成为AICH。其实这也是一种很简单的技术,实现起来并不困难,做法可以多种多样。

5、对大型局域网有特别支持。现实中,存在很多大型的局域网,局域网之间的拥有高速的带宽。对局域网的特别支持办法也有很多的,例如,类似BT那样,在局域网里建立一个Tracker Server。若是基于JXTA,可以在局域网里部署聚合点(Rendezvous)

6、支持P2P目录共享,现在流行的P2P下载工具,都不支持以目录为单位实现P2P共享和下载。其实支持P2P目录共享也不困难,在提供共享时,提供一个目录结构信息就可以了。目录结构信息dir_info可以这样记录:子文件或子目录路径 偏移量 长度。当然把目录压缩然后提供下载也是可以的,不过这样会浪费共享者的磁盘空间。目录共享,要考虑共享之后文件进行修改,添加新文件等事情,使用dir_info能够更好解决这种问题。

7、关于通告。一个P2P共享资源(包括文件和目录),应该包括三个ID:content_id、aich_id、dir_info_id。其中content_id是整个资源的摘要,aich_id是每块id进行摘要产生的id,dir_info_id是dir_info的摘要id。
content_id可用资源搜索,建议采用MD5摘要产生,因为现在很多网上提供下载的文件,都提供一个.md5后缀的校验文件。
aich_id用于校验和智能恢复
dir_info_id。如果计算content_id时,dir_info独立计算,则需要提供dir_info_id,用于校验dir_info。理论上dir_info可以作为content的一部分,但是我觉得dir_info独立计算会带来很多好处。

8、关于传输。资源的传输,应该包括三部分,hashset的传输、dir_info的传输、内容数据的传输。内容传输是分块传输的,我觉得采用BT的默认值256K一块挺好的。每一块(piece)摘要计算一个piece_id,所有的piece_id放在一起,就是一个hashset,hashset这个名字不大好,不直观,但既然emule协议是这样会说,我也这样说好了。dir_info是可选的,文件共享不带dir_info。

9、P2P下载技术的应用范围应该扩展,程序的安装更新都应该加入P2P的支持,将会大大提高程序的用户体验。

10、P2P的平台应该具备良好的扩展性。当我们构建起一个庞大的P2P平台时,不单单只是在其上共享文件,有很多应用可以部署在其上,包括现在很流行的P2P视频,分布式计算等等。即时通讯也是可以构建在P2P网络上的。面对众多的应用需求,我们需要一个具备良好扩展性的协议,不应该像BT和emule那样,除了下载,别无它用。可能基于JXTA是一种较好的选择。

11、安全。P2P网络应该支持安全特性,一些团体,一些企业,需要限定范围内共享资源。例如NASA的卫星数据共享项目SAXTA,采用JXTA,就是因为JXTA支持安全特性。我想很多的P2P应用场景,都需要安全,例如,企业只希望内部员工之间实现P2P资源共享等等。



温少 2007-03-25 05:47 发表评论
posted @ 2007-03-25 05:47 温少的日志 阅读(205) | 评论 (0)编辑 收藏
 
1、通用的唯一ID,使用MD5或者SHA1等摘要算法。
2、需要引入类似emule AICH机制,防止恶意客户端捣乱,或者用户修改数据之后,无意上传错误数据。
3、引入文件结构。描述文件在整个共享内容中的位置,整个共享项包括那些文件等等。
4、总共的ID应该包括:唯一ID、AICH_ID、文件结构摘要三个。如果使用JXTA的方式,需要在ContentAdv中包括这三个ID。
5、如果采用类似BT种子文件的方式,可以把三个ID、AICH_HashSet、FILE_LIST_INFO全部放在一起。

在做一个基于JXTA的实现,当然支持目录P2P共享的,已经实现的差不多了,自我感觉很酷!!



温少 2007-03-20 01:15 发表评论
posted @ 2007-03-20 01:15 温少的日志 阅读(319) | 评论 (1)编辑 收藏
 
jxta.org上也有一个资源共享的项目,jxta-cm,但是这个项目作的不够好。

我重新设计了传输协议,参考了BT的传输协议。

存储本地信息,不像jxta-cm那样简单,序列化一个本地磁盘文件,而是引入了Derby数据库。我本想用Berkeley DB的,我很喜欢Berkeley DB,但是由于版权协议的问题,不得不放弃了。

当然与jxta-cm还有其他很多地方不同,包括一边下载一边上传等等。

今天文件传输测试成功了,随后将会进行更多的测试,保证稳定。

希望4月1日能够出一个愚人节版本。


温少 2007-03-13 21:08 发表评论
posted @ 2007-03-13 21:08 温少的日志 阅读(1008) | 评论 (2)编辑 收藏
 

Java SE 6.0的改变包括了ClassFile格式的改变。

新的版本的ClassFile中major_version为0x0032,也就是50。
Java SE 6 : 0x0032   (用自己写的ClassFileParser分析过证实)
Java SE 5 : 0x0031  (用自己写的ClassFileParser分析过证实)
JDK 1.4   : (未经证实是0x0030) 
JDK 1.3   :  (未经证实是0x002F)
JDK 1.2   : 0x002E
JDK 1.1   : 0x002D  

每次JDK大版本升级,ClassFile格式都改变,然后版本加1。

6.0增加了StackMapTable的Attribute。

要提一下三个byte code处理库:
ObjectWeb ASM
Apache BCEL
sourceforge SERP

ASM目前版本为3.0。其2.1版本开始支持StackMapTableAttribute。
其中ASM 2.1支持StackMapTableAttribute,BCEL 5.2似乎只支持JDK 1.3,SERP 1.12只支持JDK 5.0。

Aapche BCEL支持JDK 1.3,是从代码中猜测的,没有从文档中看到,但其中5.2版本的ClassParser的确是不支持StackMapTable Attribute,其代码中的StackMap和Java SE 6.0的StackMapTable Attribute没有任何关系。BCEL中的对象和ClassFile中的各项对应,用于学习分析方便。

ASM号称更小,速度更快。现在流行的Eclipse插件bytecode outline也是其中的子项目。

ASM可以直接cvs访问,提供的代码是一个Eclipse Project,十分方便,我很喜欢!
http://forge.objectweb.org/projects/asm/

在规范4.10.1中的这一段话有些疑问:
If the class file version number is 51.0 or above, then neither the jsr opcode or the jsr_w opcode may appear in the code array.
class file version number is 51.0 or above,什么意思?Java SE 6.0编译出俩的结果应该是50.x,这是怎么回事?

规范是一个186页的PDF,没有文档大纲,看晕了


posted @ 2006-11-26 02:54 温少的日志 阅读(1391) | 评论 (0)编辑 收藏
 

这是6.0之前的poll模型。
solaris\native\sun\nio\ch\SocketChannelImpl.c
JNIEXPORT jint JNICALL
Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv 
*env, jobject this,
                           jobject fdo, jboolean block,
                                               jboolean ready)
{
    
int error = 0;
    
int n = sizeof(int);
    jint fd 
= fdval(env, fdo);
    
int result = 0;
    struct pollfd poller;

    poller.revents 
= 1;
    
if (!ready) {
        poller.fd 
= fd;
        poller.events 
= POLLOUT;
        poller.revents 
= 0;
        result 
= poll(&poller, 1, block ? -1 : 0);
        
if (result < 0) {
            JNU_ThrowIOExceptionWithLastError(env, 
"Poll failed");
            
return IOS_THROWN;
        }
    
if (!block && (result == 0))
        
return IOS_UNAVAILABLE;
    }

    
if (poller.revents) {
        errno 
= 0;
        result 
= getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
        
if (result < 0) {
            handleSocketError(env, errno);
            
return JNI_FALSE;
        } 
else if (error) {
            handleSocketError(env, error);
            
return JNI_FALSE;
        }
        
return 1;
    }
    
return 0;
}


6.0缺省的模型是使用epoll
E:\Java\jdk-6-rc-src\j2se\src\solaris\native\sun\nio\ch\EPollArrayWrapper.c

JNIEXPORT void JNICALL
Java_sun_nio_ch_EPollArrayWrapper_init(JNIEnv 
*env, jclass this
{
    epoll_create_func 
= (epoll_create_t) dlsym(RTLD_DEFAULT, "epoll_create");
    epoll_ctl_func    
= (epoll_ctl_t)    dlsym(RTLD_DEFAULT, "epoll_ctl");
    epoll_wait_func   
= (epoll_wait_t)   dlsym(RTLD_DEFAULT, "epoll_wait");
                                                                                                   
    
if ((epoll_create_func == NULL) || (epoll_ctl_func == NULL) ||
        (epoll_wait_func 
== NULL)) {
        JNU_ThrowInternalError(env, 
"unable to get address of epoll functions, pre-2.6 kernel?");
    }
}


具体程序的流程我还是不够清楚,还有待进一步深入了解。
posted @ 2006-11-22 01:34 温少的日志 阅读(5455) | 评论 (2)编辑 收藏
 
java 1.4提供了nio,也就是之前我的一片博客中所说的multiplexed non-blocking I/O。这种模型比阻塞模型的并发性能要好一些,Java很多的网络应用都因此重写了底层模块,包括Tomcat、Jetty等等,也出现了基于nio的框架mina、国产的cindy等等。

java nio带来的影响是巨大的,得到了很多拥护和赞赏。

不过有一些是谣言,例如windows下的实现是Windows中并发性能最好的I/O模型IOCP,但事实上是这样么?

JDK 6.0 RC版提供了源码下载,下载路径:http://www.java.net/download/jdk6/jdk-6-rc-src-b104-jrl-01_nov_2006.jar

我们看最终Windows的实现:
j2se\src\windows\native\sun\nio\ch\WindowsSelectorImpl.c


82行开始:
    /* Call select */
    
if ((result = select(0 , &readfds, &writefds, &exceptfds, tv)) 
                                                             
== SOCKET_ERROR) {
        
/* Bad error - this should not happen frequently */
        
/* Iterate over sockets and call select() on each separately */
        FD_SET errreadfds, errwritefds, errexceptfds;
        readfds.fd_count 
= 0;
        writefds.fd_count 
= 0;
        exceptfds.fd_count 
= 0;
        
for (i = 0; i < numfds; i++{
            
/* prepare select structures for the i-th socket */
            errreadfds.fd_count 
= 0;
            errwritefds.fd_count 
= 0;
            
if (fds[i].events & POLLIN) {
               errreadfds.fd_array[
0= fds[i].fd;
               errreadfds.fd_count 
= 1;
            }

            
if (fds[i].events & (POLLOUT | POLLCONN)) {
                errwritefds.fd_array[
0= fds[i].fd;
                errwritefds.fd_count 
= 1;
            }

            errexceptfds.fd_array[
0= fds[i].fd;
            errexceptfds.fd_count 
= 1;

            
/* call select on the i-th socket */
            
if (select(0&errreadfds, &errwritefds, &errexceptfds, &zerotime) 
                                                             
== SOCKET_ERROR) {
                
/* This socket causes an error. Add it to exceptfds set */
                exceptfds.fd_array[exceptfds.fd_count] 
= fds[i].fd;
                exceptfds.fd_count
++;
            }
 else {
                
/* This socket does not cause an error. Process result */
                
if (errreadfds.fd_count == 1{
                    readfds.fd_array[readfds.fd_count] 
= fds[i].fd;
                    readfds.fd_count
++;
                }

                
if (errwritefds.fd_count == 1{
                    writefds.fd_array[writefds.fd_count] 
= fds[i].fd;
                    writefds.fd_count
++;
                }

                
if (errexceptfds.fd_count == 1{
                    exceptfds.fd_array[exceptfds.fd_count] 
= fds[i].fd;
                    exceptfds.fd_count
++;
                }

            }

        }

    }
            

这就是广泛应用在Winsock中使用的select模型,也众所周知,并发性能不是很好。而且FD_SETSIZE不能超过Windows下层提供者的限制,这个限制通常是1024。也就是说Windows下,JDK的nio模型,不能超过1024个连接,这个跟我之前做的测试结果相似。

而且,如果FD_SETSIZE很大的话,例如是1000,调用select之前,必须设置1000个socket,返回之后又必须检查这1000个socket。

也就说,Windows下使用SUN JDK java的nio,并不能提高很好的并发性能。
posted @ 2006-11-22 00:35 温少的日志 阅读(7863) | 评论 (1)编辑 收藏
 

回顾一下Unix的5种I/O模型


1、阻塞I/O
2、非阻塞I/O
3、I/O复用(select、poll、linux 2.6种改进的epoll)
4、信号驱动IO(SIGIO)
5、异步I/O(POSIX的aio_系列函数)


同步I/O和异步IO


POSIX把这两个术语定义如下:
同步I/O操作导致请求进程阻塞,直至操作完成
异步I/O操作不导致请求阻塞。

根据上述定义,前四种I/O模型都是同步I/O,第5种才是异步I/O。

select不允许多于一个的线程在同一个描述符集上等待。这使得反应式模型不适用于高性能应用,因为它没有有效地利用硬件的并行性。
异步I/O通常能够提高更好的性能,windows的iocp通过内核线程调度,也能提供很好的并发性能,但不是真正的异步。


Java nio和多路复用


java 1.4 nio提供的select,这是一种多路复用I/O(multiplexed non-blocking I/O)模型,底层是使用select或者poll。I/O复用就是,阻塞在select或者poll系统调用的某一个之上,而不是阻塞在真正的I/O系统调用之上。JDK 5.0 update 9和JDK 6.0在linux下支持使用epoll,可以提高并发idle connection的性能(http://blogs.sun.com/alanb/entry/epoll)。

以前看到有人猜测Windows下nio使用了IOCP,那应该是错的,毕竟IOCP不是多路复用I/O模型。从JavaOne 2006的幻灯片来看,aio才会使用IOCP来实现的。


Java aio和JSR 203


2003年,就有了JSR 203(http://jcp.org/en/jsr/detail?id=203),但是一直没有实现。

终于,JSR 203的spec lead说,将会在Java SE 7.0中完成JSR 203,Java SE 6.0已经是RC,很快正式版就会发布,然后就是Java SE 7.0,估计我们不需要等太久了。
http://blogs.sun.com/alanb/entry/what_is_happening_with_jsr


asynchronous I/O对于Java的影响,将不会低于当年JDK 1.4 nio引入multiplexed non-blocking I/O的影响,很多的Java应用都会重写。如同Linux 2.6支持AIO,DB2、Oracle数据库都会发布新版本,说支持使用AIO,性能提高多少多少云云(主要是AIO的文件操作部分)。

对asynchronous I/O的支持,Java程序就能够支撑大并发网络应用了,在IO模型方面,对于C/C++等语言不再存在“C/C++能做,但是Java不能做的事情”。

这个是Java One 2006上的幻灯片。
http://blogs.sun.com/roller/resources/alanb/bof0895.pdf
提到了:
需要新的channel types支持异步I/O模型
使用Native机制,例如Windows IO Completion ports。
posted @ 2006-11-21 00:34 温少的日志 阅读(6820) | 评论 (2)编辑 收藏
 

文章:
http://blogs.sun.com/alanb/entry/epoll

JDK 6.0 nio支持epoll,对并发idle connection会有大幅度的性能提升,这就是很多网络服务器应用程序需要的。

One of the updates in build 59 of Mustang (JavaTM SE 6) is that the New I/O Selector implementation will use the epoll event notification facility when running on the Linux 2.6 kernel.


JDK 5.0 update 9也支持了。

The epoll SelectorProvider will be included in 5.0 update 9. To enable it requires setting the system property java.nio.channels.spi.SelectorProvider to the value sun.nio.ch.EPollSelectorProvider.


5种IO模型:
阻塞IO
非阻塞IO
多路复用
信号驱动IO
异步IO

最好性能的还是异步IO,目前Java只能支持到多路复用一级,期待着以后Java 7.0/8.0支持异步IO,6.0是没有希望了。
posted @ 2006-11-20 02:17 温少的日志 阅读(6286) | 评论 (3)编辑 收藏
 
买了个新硬盘安装ubuntu,把所有的工作迁移到linux下进行。

没感到什么不方便的,毕竟最常用的工具是Eclipse、Firefox、UltraEdit。UltraEdit在linux下的替代品为vi和gedit,一切都好。

听音乐的播放器要比windows下要差一些,也没关系,将就着用。

字体有些难看,也能用,可以将就。

开发环境,在Ubuntu下配置ACE、boost等库的环境是在太方便的,比windows下方便多了。


唯一的缺陷就是系统不稳定,用linux作服务器是很稳定的,但是linux的桌面系统稳定性就比较差劲了,仿佛回到
windows 98的那种年代,系统经常死机。

总之,了系统不稳定之外,一切都好。






温少 2006-10-25 01:50 发表评论


文章来源:http://www.cnblogs.com/jobs/archive/2006/10/25/538989.html
posted @ 2006-11-20 02:08 温少的日志 阅读(195) | 评论 (0)编辑 收藏
 
一直以来,都是使用两种即时通讯工具QQ和MSN,最近越来越讨厌MSN,而觉得QQ越作越好。

1、MSN是明文传输数据,偷窥、监听都是极为简单的事情。查看别人MSN是某些网管的乐趣,而且是普遍的现象。
2、MSN任何时候的聊天数据都是明文经过服务器的,这个动机非常值得怀疑。明文传输而且通过服务器,为了使得海量监听更有效率?
3、MSN在贴图、群方面功能缺乏,聊天记录没有等等,不好用,不方便。
4、骚扰很多,一些交友网站的骚扰烦死人。
5、MSN的语音传输效果很差,而且经常建立不了连接。
6、文件传输很慢。

QQ虽然也不是极好,但比MSN还是强一些。
1、QQ聊天数据传输是使用TEA加密的,虽然并不是非常高强度的加密,但至少是经过加密的。
2、QQ聊天数据,双方都在线的时候,不经过服务器。如果对方不在线,聊天记录经过服务器,会受到监听审查。但比MSN要好一些。
3、QQ功能比MSN完备,使用方便。

这两种工具的官方版本都是广告一大堆,解决办法就是使用第三方的客户端。例如lumaQQ、gaim来替代他。

在中文世界中,越来越多人使用QQ,包括一些海外的朋友,终有一天在中文世界里,MSN就如ICQ一样,微不足道,这是一个可以预见的趋势,我也将很乐见看到这个结果。

因为还有一些朋友只使用MSN,现在只能是少用MSN,最终将会不再使用MSN。


温少 2006-11-08 08:51 发表评论


文章来源:http://www.cnblogs.com/jobs/archive/2006/11/08/553714.html
posted @ 2006-11-20 02:08 温少的日志 阅读(263) | 评论 (0)编辑 收藏
仅列出标题
共8页: 上一页 1 2 3 4 5 6 7 8 下一页