本版本为Pro 5.06版。

 

 

===================================================================================

启动篇

===================================================================================

 

Q1-1 Windows下,如何启动UFO?  

1. 首先,您的计算机要安装JDK1.6.0以及以上版本的JDK! 低版本的JDK将无法运行UFO; 

2. 进入bin目录,Windows操作系统敲startup.bat, 回车。 

       

注意:如果您在Windows下运行startup.bat而不能启动UFO,则Notepad打开bin目录下的setclasspath.bat文件,4行是这样的: 

   

    rem set JAVA_HOME=D:\jdk1.8.0_72

 

把上面的那行的"rem "去掉,并且把"D:\jdk1.8.0_72"替换成您计算机里的JDK的安装目录(所谓安装目录就是含有bin的目录),然后重新运行startup.bat文件即可。

 

 

Q1-2 Linux (redhat/centOS/ubuntu)下,如何安装、启动UFO?  

(下面的操作是在redhat/centOS下进行的,ubuntu下类似) 

 

1. 从java.sun.com官方网站下载Linux平台的JDK: jdk-8u72-linux-i586.rpm; 

2. 从www.gm365.com官方网站下载Linux平台的UFO Pro版:UFO_Pro_5.06.tar.gz; 

3. 把上面2个文件上传到你的Linux服务器的/usr/local目录下; 

4. 安装JDK

   # cd /usr/local

   # rpm -ivh jdk-8u72-linux-i586.rpm 

5. 安装UFO Pro

   # cd /usr/local  

   # tar -zxvf UFO_Pro_5.06.tar.gz 

6. 配置环境变量 

   # vi /etc/profile 

  (1) 在这个文件末尾加上

      export JAVA_HOME=/usr/local/jdk1.8.0_72

      export CLASSPATH=.:$JAVA_HOME/lib/tools.jar

      export PATH=$PATH:$JAVA_HOME/bin

  (2) 利用下面命令使配置生效,并且查看JDK版本

      # source /etc/profile

     # java -version

7. 配置放火墙        

   # vi /etc/sysconfig/iptables

   添加如下代码

    -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

   重启iptables

     service iptables restart

   (注意:一些机房为了防止DDOS攻击,在机房本身还有一道放火墙,您要向机房申请对您的IP的80端口开通!)                                     

8. 对.sh添加执行权限

   # cd /usr/local/UFO_Pro/bin

   # chmod a+x ./*.sh

9. 启动UFO

   # cd /usr/local/UFO_Pro/bin

   # ./startup.sh

 

 

Q1-3 Linux (redhat/centOS/ubuntu)下,如何关掉UFO?

(条件同Q1-2

 

# cd /usr/local/UFO_Pro/bin

# ./shutdown.sh

 

 

Q1-4 Linux (redhat/centOS/ubuntu)下,如何开机启动UFO?

(条件同Q1-2

 

#vi /etc/rc.d/rc.local

添加以下内容:

  export JAVA_HOME=/usr/local/jdk1.8.0_72

  cd /usr/local/UFO_Pro/bin

  ./startup.sh

 

 

Q1-5 Windows下,如何关掉UFO?

进入UFO的bin目录,敲shutdown.bat, 回车。

 

 

Q1-6 如何把UFO注册成windows服务启动啊?

我不知道您怎么会有这样的需求。 

关于UFO作为windows service的所有东西都在UFO的win-service子目录里。

要把UFO作为windows service安装或启动,您所要做的唯一事情是修改wrapper.conf, 一共需要修改4个地方(这4个地方都用一对"# !!!!!!!!!!!!!!!!!!"行标记起来):

 

    1. wrapper.java.command=D:\jdk1.8.0_72\bin\java

       根据您计算机的JDK,把wrapper.java.command指向java.exe(注意:设置时可不带.exe).

 

    2. wrapper.java.classpath.3=D:\jdk1.8.0_72\lib\tools.jar

       根据您计算机的JDK,把wrapper.java.classpath.3指向lib\tools.jar

 

    3. wrapper.java.classpath.4=D:\UFO_Pro\lib\javax.zip

       wrapper.java.classpath.5=D:\UFO_Pro\lib\mysql-connector-java-5.1.18-bin.jar

       wrapper.java.classpath.6=D:\UFO_Pro\lib\UFO-db.zip

       wrapper.java.classpath.7=D:\UFO_Pro\lib\UFO-jdt.jar

       classpath指向UFO的lib目录里的.zip和.jar.

    

    4. wrapper.app.parameter.3=D:\UFO_Pro

       wrapper.app.parameter.3指向UFO的安装目录(所谓安装目录就是含有bin子目录的目录)。

 

在修改好wrapper.conf后,运行install_service.bat,安装成功后,再运行start_service.bat,

UFO就是作为windows service启动起来了。        

 

 

Q1-7 我能否不用理睬web.xmlserver.xmlUFO-users.xml(/conf目录下的)?我不想动脑筋去看那些麻烦的配置参数。

如果您的网站没有认证,您完全可以不用理睬UFO-users.xml;相反,如果您的网站有认证,您还不理解UFO-users.xml里那些配置的含义么。

如果您对mimeType没有特殊的约定,您完全不需要理睬所有的web.xml,甚至可以把所有的web.xml全部删除掉。在这些情况下(不修改或者删除),UFO采取默认的最新的mimeType,“最新”的含义是完全支持无线互联网的mimeType标准,搭建手机wap网站没有任何问题。

您也可以不理睬/conf/server.xml文件,甚至在启动UFO之前把它删掉,这两种情况下,您要记住一点:把html、jsp等文件和子目录都放在/webapps/ROOT/目录下就可以了。

 

 

Q1-8 Linux操作系统下,即使我以root身份登陆,在/bin目录下敲./startup.sh,被告之:权限不够。怎么办?

这其实不是UFO的问题,而是Linux操作系统的问题。解决办法如下:

 

    chmod a+x startup.sh

    chmod a+x UFO.sh

    chmod a+x setclasspath.sh

 

添加可执行权限即可。

 

 

Q1-9 startupW.batstartup.bat有什么区别?它启动的是UFO service吗?与它对应的reloadshutdownbat文件在哪里?

(在Windows下)用startup.bat启动的UFO进程,Dos窗口不能关掉,否则,UFO进程也随之被kill掉。如果要使Dos窗口关掉后,UFO进程仍然在(后台)运行,应该怎么办?这时就应该用startupW.bat来启动UFO进程。

 

startupW.bat启动的UFO进程,在计算机关机重启后,消失了,因此它所启动的不是UFO service.

 

startupW.bat启动的UFO进程,要关掉它,(也)运行shutdown.bat; 要对它reload,(也)运行reload.bat

 

 

 

===================================================================================

改动篇

===================================================================================

 

Q2-1 Pro 5.06UFO有何改动?

1. 5.06版调整了log.txt文件的目录位置,现放在显眼位置。

2. 5.06版实现了log的1级,开发者可采用此级,然后将log.txt文件发给我公司,我公司很快定位问题。

 

35.05版把各个文档、.bat、.conf里的jdk推荐版本从1.6.x修改成了1.8.y,以支持注解以及restlet等相关组件(经过测试,用jdk1.6.x以及以下版本jdk运行UFO,不能很好地支持注解)。

45.05版更换了javax-ufo.zip和更新了examples里的联网扫雷。

55.05版修改了收费规则,收费规则更成熟(见Q6-1至Q6-3)。 

6. 5.02版支持web.xml里的<error-page>标签以及其它情况下出错的友好提示。

7. 5.01版再次修改Filter以支持Struts2。

8. 5.00版更换了ClassLoader。

9. 5.00版修改了Filter。

10. 5.00版修改了Request.getPathInfo()和Request. getContextPath()。

11. 5.00版调整了javax.zip和javax-ufo.zip。

12. 4.63版支持负载均衡,参见Q3-34和Q3-35。

13. 4.62版对Connector标签增加了soRcvBuf和soSndBuf两个属性。

14. 4.61版修改WebSocket在download大文件时特别消耗CPU和内存的问题。

15. 4.60版修改WebSocket方面的WSProcessor里的WSEndpoint wsEndpoint的Bug。

16. 4.59版修改了内核哈希表的问题。

17. 4.59版再次修改了联网扫雷的断线标准的一行代码。

18. 4.59版修改了examples里所有含有Image的servlet、jsp的代码。

19. 4.58版提高了网络连接常阻塞时的文件下载速度。

20. 4.58版修改了联网扫雷的断线标准部分的代码。

21. 4.57版解决4.56版不稳定的问题,就是说4.56版也是不稳定版本。

22. 4.56版解决4.55版不稳定的问题。

23. 4.55版提高一种情况下的WebSocket性能。

24. 4.53版在conf/server.xml里增加了<Download>标签,以调节大体积文件下载时的性能。(见Q3-41) 

25. 4.53版对静态文件下载正确填写http头,以保证浏览器能断线续传。

26. 4.53版修改了CS模式的WebSocket例子,增加了"Host" http头(在Web Server有多于1个Host时起作用,见Q8-17)

27. 4.53版对"喀秋莎-联网扫雷"的RecordThread.java增加了boolean idle这个变量,请体会它的重要作用。

28. 4.52版修改了WebSocket的一个Bug。

29. 4.51版提高了UFO内核里的哈希表(查找)的性能。

30. 4.50版优化了WebSocket关于断线方面的性能。

31. 4.49版去掉了server.xml里的Connector标签的maxFormContentSize, maxFormContentKill,maxUpLoadContentSize, maxUpLoadContentSizeKill, maxOtherContentSize, maxOtherContentSizeKill, maxErrorContentSizeKill等7个属性,以简化配置。并把maxParameterNum这个属性改成了maxParameterSize, 增加了maxParameterSizeKill。

32. 4.48版确保在WebSocket的WSEndpoint.close(WSClient aclient)方法调后,WSProcessor不再出现这个aclient的onData()。

33. 4.47版对Bad Request在debug Mode="1"时开始在Dos窗口里显示原因。

34. 4.46版修改HttpServletRequest.getInputStream().read()方法的一个Bug。

35. 4.45版修改了“喀秋莎-联网扫雷”的源代码,主要是增加了MsgNo这个清理bkp消息的重要消息。

36. 4.45版对UFO启动不起来给出更详细的提示和log。

37. 4.44版修改websocket的一处内存泄漏问题。

38. 4.43版修改了ClassLoader,以试图根除同名类(但包名不同)所带来的麻烦。

39. 4.42版在examples开源给出一个基于CS模式的websocket开发的喀秋莎-联网扫雷网游1.00版。

40. 4.42版确保javax.ufo.ws.WSProcessor的onClose(WSClient client, String message)方法是在WSClient client对应的Socket被close之后调用。

41. 4.42版在javax.ufo.ws.WSEndpoint增加了getRemoteSocketAddress(WSClient aclient), setSoTimeout(WSClient aclient, int timeout)等常用的Socket方法。  

42. 4.41版在examples开源给出一个基于CS模式的websocket开发的喀秋莎-联网扫雷网游0.80版。

43. 4.40版在examples开源给出一个基于CS模式的websocket开发的TT简易聊天联网应用。

44. 4.40版去掉了websocket的UFO层的HeartBeat检测。 

45. 4.39版在UFO发布首页带上UFO Web Server论坛链接。

46. 4.39版不输出jsp的注释行。

47. 4.39版修改一个jsp编译方面的Bug。

48. 4.38版使第2次设置ServletResponse的CharacterEncoding无效,并打印出warnings信息。

49. 4.38版修改一个jsp编译方面的Bug。

50. 4.38版修改一个taglib方面的Bug。

51. 4.37版解决一些情况下的中文乱码问题。

52. 4.37版提供客户端方式的(而是不只是applet方式)的UFO Probe,运行probe目录下的UFOProbe.bat启动。 

53. 4.36版在/conf/server.xml增加了<System>标签,可以把System.out.print的内容输出到指定的文件,或干脆关掉System.out.print以试图解决Windows进程莫明其妙地噎住的问题,就是增加UFO在Windows下的稳定性。

54. 4.35版在/conf/server.xml增加了<FileCache>标签,用户可以自己配置File Cache的体积。  

55. 4.34版提高在网站含有较大的动态网页时网站输出网页的流畅度。

56. 4.33版在<Connector>的参数配小了出错时,给予友好提示。

57. 4.32版修改ClassLoader的一个错误。

58. 4.31版解决jsp规范中的FunctionMapper的麻烦。

59. 4.30版支持WebSocket功能。

60. 4.30版修改HttpServletRequest.getHeaders()的Bug。

61. 4.30版实现每个http连接占用内存2.0K。

62. 4.30版实现每个WebSocket连接占用内存1.0K。

63. 4.25版对错误提示更友好。

64. 4.24版把静态网页的MappedByteBuffer数从500降为5,以防止高并发时,UFO内存用光。

65. 4.23版在jsp里的EL表达式为null时不输出任何内容,而不是输出"null"。

66. 4.23版修改了在3.22版引入的一处可能不稳定的错误。

67. 4.22版提高输出网页的流畅度。

68. 4.21版再次修改ClassLoader以对付一个不常见的问题。

69. 4.20版修改在有filter时不能正确回应"304 NOT_MODIFIED"的问题。

70. 4.19版可以配置更改UFO Probe的admin目录。

71. 4.18版修改了ClassLoader、RequestDispatcher、filter等方面若干问题。

72. 4.17版修改一处从4.10版引入的不能输出网页的假死的Bug。

73. 4.16版修改jsp里含有java.sql的Statement时编译失败的问题。

74. 4.16版再次修改了welcome-file-list。

75. 4.15版再次修改ClassLoader。

76. 4.14版修改ClassLoader以加快Class装载速度,并解决第3方项目自带javax包中类的麻烦。

77. 4.13版修改welcome-file-list等Bug。

78. 4.12版修改https等若干Bug。

79. 4.11版在测试struts2/spring/hibernate/ZK/sitemesh的基础上,修改若干Bug.

80. 4.10版将https部分改用Nio实现。

81. 4.10版解决了session数据库不能保存attribute的问题。

82. 4.10版改正了HttpServletRequest的getSession()的一个Bug。

83. 4.10版记录了各个Context的_work目录下的jsp编译时的绝对路径,当发生项目copy迁移时,重新编译jsp(与UFO的编译机制有关)。

84. 4.10版最小化每个连接占用的内存,实现了每个http连接占用2.16K内存,每个https连接占用52K内存。

85. 4.10版支持web.xml里的<servlet-mapping>和<servlet>标签里的多个<url-pattern>属性写法。

86. 4.10版校对了HttpServletRequest的getServletPath()和getPathInfo()在各种情况的正确性。

87. 4.10版改正了HttpServletRequest的getRequestDispatcher(String path)在path以空格开始时不正确的问题。

88. 4.10版改正了HttpServletResponse的setLocale(Locale locale)在contentType为null时甩出Exception的问题。

89. 4.10版对<filter>和<web-resource-collection>标签里的<url-pattern>不再对"*"进行任意通配,而是只通配"/*", "x/*"和"*.x"等3种情况,这样可以减少CPU和内存,任意通配也并无实际需求意义。 

90. 4.02版去掉了javax.zip里不必要的子目录,以避免与Spring等第3方jar包内容重复。

91. 4.01版修改Http请求无"If-Match"头但有"If-Modified-Since"和"If-None-Match"时,永远也回不出"304 NOT_MODIFIED"的Bug。

92. 4.00版内置特制的数据库,以支持任意多(可多达几百亿)个Session。

93. 4.00版支持Servlet的异步处理。

94. 4.00版大大改变了Connector标签的属性,以增加UFO的稳定性、防Hacker和提高性能。

95. 4.00版改正了Form认证的Bug。

96. 4.00版对Form认证的<form-login-config>标签增加了form-max-login-num属性,以增加UFO的稳定性。

97. 4.00版实现了Servlet 3.0规范的HttpServletRequest的getPart()和getParts()方法,对文件上传提供一个另外的支持。

98. 4.00版对Servlet的SingleThreadModel进行了标准的实现。     

99. 4.00版支持web.xml里的<servlet>标签和<servlet-mapping>合并的写法。

100. 4.00版修改了Servlet和filter的url-pattern方面的一个Bug。

101. 4.00版支持IP屏蔽。

102. 4.00版修改了HttpServletRequest在getWriter()后而不setCharacterEncoding(),不能输出网页的Bug。

103. 4.00版大大修改了https部分的代码,以增加https模式下的稳定性和提高负载能力。

104. 4.00版在UFO线程满时,对UFO Probe用户启动新的线程为之服务。

105. 4.00版在Servlet(和jsp)的输出内容没超过8K缓存时,一定带上Content-Length的Http头。

106. 3.67版增强了一处的稳定性,预防一种Hacker攻击的可能。

107. 3.66版及时回收一种情况下的垃圾,保持运行内存最小。

108. 3.65版修改了conf/web.xml,增加了sis, cab, apk, ipa的mime-mapping配置,这样使用UFO可直接发布symbian, windows, android, iphone手机游戏。(不配置mime-mapping,手机端会把游戏包当网页打开,而不会安装) 

109. Pro 3.64版在server.xml里增加<Host-Match>标签,以屏蔽一些域名。

110. Pro 3.63版对server.xml里的Connector标签的各个属性从程序上进行了校对,更好地防Hacker。

111. Pro 3.62版对Post方法请求静态网页时给予输出。

112. Pro 3.61版改正UFO一种可能宕掉的Bug。

113. Pro 3.60版重做了UFO的windows service部分。

114. Pro 3.60版对各个.bat和.sh文件进行了校对,并调整了发布目录结构。

115. Pro 3.60版不再要求站在UFO的bin目录下发出startup/reload/shutdown命令。在Linux下,可以站在任何目录位置发出命令,例如:./startup.sh, ./bin/startup.sh, /usr/local/UFO_Pro/bin/startup.sh都是正确的。在Windows下,要求站在UFO的安装目录或bin目录下发出startup/reload/shutdown命令,例如:startup.bat, bin\startup.bat都是正确的,而UFO_Pro\bin\startup.bat则是不正确的。

116. Pro 3.60版在Linux下启动多个UFO进程时,用ps -efw命令查找进程PID时得到了很好的区分。

117. Pro 3.60版修改了reload的Bug.  

118. Pro 3.56版在程序内部检查UFO安装路径的正确性。

119. Pro 3.56版修改shutdown.sh有时不能kill UFO(尤其是在ubuntu操作系统下)的Bug。

120. Pro 3.54版修改UFO Web Server一种不能启动的情形。

121. Pro 3.53版支持Head方法(从而支持一些搜索引擎的蜘蛛爬虫)。

122. Pro 3.52版修改有关Post方法的一个Bug。(与Apache cxf项目,SOA有关)

123. Pro 3.51版修改pathInfo里含有"/"时,Request的getPathInfo(), getServletPath()返回值不对的Bug。(与Apache cxf项目有关)

124. Pro 3.51版修改RequestDispatcher.forward()后,Request的getQueryString()返回值不对的Bug。(与Apache cxf项目有关)

125. Pro 3.51版对web.xml里的<servlet-mapping>里的<url-pattern>的*通配符进行了标准实现。          

126. Pro 3.50版支持ETag, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since等Http头。(控制利用浏览器端缓存、节省带宽、提高负载、提高静态网页响应速度,So, 聪明的网站应采用静态网页做首页,并且能使用静态网页的地方决不使用动态网页)

127. Pro 3.50版支持If-Range, Range等Http头(断点续传)。 

128. Pro 3.48版修改了GET方法的URL含有"?"时,Request的getPathInfo(), getServletPath(), getPathTranslated(), getRequestURL()返回值不对的问题(与axis和struts项目有关)。

129. Pro 3.48版修改了"Last-Modified: " http头的值不对的问题。

130. Pro 3.46版修改这样一个ClassCastException的问题:以前版本如果一个jsp里import了WEB-INF\classes\里的类,先访问这个jsp,然后在不重启UFO的情况下,修改这个jsp,再访问,可能throw ClassCastException的Bug.

131. Pro 3.45版支持gzip压缩。

132. Pro 3.45版支持"chunked" Transfer-Encoding,但从Client向Server端"chunked" Transfer-Encoding暂不支持(无这样的例子或需求)。

133. Pro 3.45版修改jsp/servlet的"Server"和"Date" Header重复输出的问题。

134. Pro 3.45版修改RequestDispatcher的forward在"File Not Found"时,显示空白页的Bug。

135. Pro 3.45版将/lib/javax.zip里的UFO自己的javax.db目录分离出来,形成UFO-db.zip,以方便用户用JDT开发调试程序。

136. Pro 3.45版增加了Connector标签的keepAlive等多个属性。

137. Pro 3.45版在server.xml里增加了Probe标签和属性。

138. Pro 3.45版在server.xml里增加了Session标签和属性。

139. Pro 3.40版填写ServletContext.getResourcePaths()方法,以支持Spring。

140. Pro 3.40版修改了UFO.bat、UFO.sh、UFOW.bat以及发布目录结构,以防止Spring(试图)重复装载类。

141. Pro 3.38版修改Reponse.flushBuffer()的Bug。(主要与Struts项目有关) 

142. Pro 3.37版修改server.xml、web.xml等xml文件里有注释行时可能出错的Bug。

143. Pro 3.37版修改Request.getParameterMap().entrySet()不正确的Bug。(主要与Struts项目有关) 

144. Pro 3.36版支持web.xml里的<error-page>属性。

145. Pro 3.36版正确设置Request的javax.servlet.include.servlet_path的属性值(与Struts的include有关)。

146. Pro 3.36版修改ServletContext的getResource()方法的一个Bug。

147. Pro 3.35版修改一处较严重的内存泄漏的Bug。

148. Pro 3.32版改正未在server.xml里显式配置Context的Dir和war部署的web.xml里的welcome-file无效的Bug。

149. Pro 3.32版改正把"/*"的url映射成Struts的Filter时,当url不以"/"结尾并且不是文件名时,访问不到welcome-file的Bug。

150. Pro 3.32版修改以前部分版本中由于“笔误”,在有多个Context时,配置Filter时可能引起混乱的Bug。 

151. Pro 3.31版大大提高了ClassLoader从zip/jar包装载类的速度;

152. Pro 3.31版支持从zip/jar包装载Servlet类。

153. Pro 3.30版修改并优化了UFO的ClassLoader。

154. Pro 3.30版正确处理URL里含有"./"字符串的情形。

155. Pro 3.30版在conf/server.xml文件里<Debug mode="0" />时,当"File Not Found"时,以相对路径显示文件,这是为了防止向Hacker暴露Server采用何种操作系统。而在Debug mode为"1"等其它值时,当"File Not Found"时,以绝对路径显示文件。

156. Pro 3.30版的UFO Probe在UFO进程产生hs_err_pidxxx.log时,显示为要求重启的警告状态。

157. Pro 3.26版修改因CPU采点而使jsp/servlet编译变慢1s的问题。

158. Pro 3.25版修改web.xml里servlet标签和filter标签的init-param属性不起作用的Bug。

159. Pro 3.24版修改examples的数据库连接池的例子,并修改server.xml中一个注释行位置不对的问题,以免用户上帝纳闷。

160. Pro 3.23版UFO Probe正常显示CPU指标。

161. Pro 3.22版修改war部署时忘了处理web.xml文件的问题。

162. Pro 3.21版修改在Linux下敲./shutdown.sh有时不能Kill掉UFO进程的Bug。

163. Pro 3.20版修改UFO Probe的下行流量有时突然增大几十M(而实际上流量并没有增大)的问题。

164. Pro 3.19版修改Request.getParameterMap()相关的中文乱码问题。

165. Pro 3.18版增加struts的demo、EL表达式的demo。

166. Pro 3.17版修改把"/*"的url映射成Filter时,不能输出静态网页的Bug。本版本对支持struts进行了比较充分的测试。

167. Pro 3.16版针对支持struts,将UFO的两个对外接口规范化。 

168. Pro 3.15版关于RequestDispatcher的Bug。

169. Pro 3.14版修改关于Filter的Bug。 

170. Pro 3.13版对UFO Pro进程所使用的虚拟内存进行了很好的管理和调度,对虚拟内存的回收也进行了比较充分的测试。Pro 3.13版的性能评测指标与Pro 3.00版一样。而Pro 3.00-Pro 3.10是不稳定的版本。 

171. Pro 3.10版修改Pro 3.01版和Pro 3.00版的一个严重的不稳定的Bug,就是说,Pro 3.01版和Pro 3.00版是一个不稳定的版本,请不用使用Pro 3.00版和Pro 3.01版!

172. Pro 3.01版修正在一种情况下Servlet不能装载的Bug,就是Ajax的demo中ProgressBar、ToolTip、YahooSearch不能运行的问题,这个Bug是在2.60版中引入的。

173. Pro 3.00版大幅提高输出静态网页的能力,特别是对较大体积的网页(>100kb的)。

174. Pro 3.00版大幅提高输出动态网页的能力,特别是对较大体积的jsp(>50kb的)。

175. 2.60版大幅降低运行内存,特别是对有很多个Context和Host的大项目。

176. 2.60版在编译了jsp/servlet后,内存泄漏大为下降,这样在UFO编译了jsp/servlet不重启也问题不大。

177. 2.60版动态装载更新的servlet class,以前版本虽然能动态编译servlet却不能动态装载。

178. 2.60版动态更新类路径,在UFO类路径上的类jar包、zip包发生增加,UFO编译时立即生效,而不需要重新启动UFO(而jar包、zip包发生更新、删除时,则要求重启动UFO)。

179. 2.60版修改https状态下不能显示图片验证码的Bug。

180. 2.51版在每天休闲时候执行一次System.gc()对UFO进程进行垃圾回收。

181. 2.50版采用eclipse的JDT Java编译器作为UFO的默认编译器。

182. 2.38版修改RequestDispatcher的相对路径的Bug。

183. 2.37版支持Debug模式,可显示必要的信息。

184. 2.36版修改jsp:include和jsp:forward的路径中含有"../"时的Bug。

185. 2.35版修改taglib和EL表达式方面的Bug。

186. 2.32版将jsp文件中的<!--  -->等注释行全盘输出,因为它们可能在一些场合不表示注释行的意思。

187. 2.31版修改war部署的Bug。 

188. 2.30版修改Listener的一个Bug。

189. 2.30版就中文乱码问题对examples Context下的demo示例进行了校对。

190. 2.30版支持有图片验证码、download的jsp文件除了保存为编码方式为ANSI外,还可以保存为UTF-8、UTF-16LE、UTF-16BE等。

191. 2.30版支持server.xml文件里对<Connector>标签的URIEncoding属性。

192. 2.20版支持通过JNDI和DataSource来配置数据库连接池的做法(并在examples Context增加示例),从而实现对Tomcat等Web Server 100%的兼容。

193. 2.20版修改jsp, servlet实例池的UFO Probe监测数据略微异常的问题,使UFO的运行内存更小。

194. 2.20版对UFO进程结束时,进行更详细的写log文件。

195. 2.00版改正不能显示图片验证码的Bug,这个Bug是在1.90版中由于笔误引入的。

196. 2.00版支持动态编译servlet.java。

197. 1.99版修改当1500个点满时,UFO Probe显示紊乱的Bug。

198. 1.98版支持Servlet规范的Filter。

199. 1.98版支持Servlet规范的各种Listener。

200. 1.98版支持双向SSL认证。

201. 1.98版修改UFO probe的一个显示上的Bug。 

202. 1.91版修改1.90版中引入的轻微内存泄漏和keepAliveConns的UFO Probe监测指标异常的Bug。

203. 1.90版提供英文版:examples英文版、UFO probe英文版和Howto文档英文版。

204. 1.90版修改一个不稳定因素。由于在1.70版中对"keep-alive"进行了标准的实现,改动比较大,1.70-1.88版本并不能保证“永远不宕”。

205. 1.90版在UFO Probe中增加keepAlive Connection数的指标监测。

206. 1.88版对体积小(<30KB)的静态网页的输出吞吐量接近100% Pure Java所能达到的最大值。

207. 1.87版将Probe采点从3000个下降为1500个,并修改Probe Client的一个数组越界错误。

208. 1.87版在bin目录下增加reload.bat和reload.sh,运行它们,可以不重新启动UFO,而能使对任何.xml配置(port, ssport参数除外)的修改、增删生效。 

209. 1.85版修改不能读一些xml配置文件的Bug。

210. 1.85版对启动时的一些信息的提示更正确。

211. 1.85版在请求文件"Not Found"时,以绝对路径显示,查错更容易,UFO不用担心Hacker。 

212. 1.83版完全支持将docBase和appbase设置成绝对路径。当它们以"/"或者"D:"开头,UFO就把它们判定为绝对路径。关于appBase的意义:如果配置了path=""的Context,appBase的唯一意义是放置war包的目录。

213. 1.81版修改UFO Probe的若干小问题。

214. 1.80版内置UFO Probe,监测UFO Web Server的重要运行数据,及时报警。

215. 1.71版在bin/UFO.bat, UFO.sh, UFOW.bat三个文件中增加JAVA_OPTS变量,让您方便地修改这个变量的值,以控制UFO进程的堆内存大小。关于JVM的堆内存的概念请查网上的相关文章。

216. 1.70版的评测指标应有进一步的提高,负载能力和响应速度等应有明显提高。

217. 1.70版对Http头信息里的"Connection: keep-alive"进行了标准的实现,从而支持一些Ajax网页的运行正确。

218. 1.70版对Cookie进行了改变,不再支持将Cookie的Value等直接设置为中文,而需要先进行转化,参见本发布的相关例子。

219. 1.70版预防了一种Hacker攻击的可能。

220. 1.70版对出错提示更友好。

221. 1.70版在exmaples Context里增加了Ajax栏目例子。并在这些Ajax例子对UFO唯一根据URL里的"/servlet/"字符串识别servlet的用法进行了足够的demo。(那种每增加一个servlet都需要配置一番的做法太麻烦了!)

222. 1.59版由UFO Web Server主程亲自校对整理增删修改examples Context,向您demo UFO Web Server精彩强大的功能。

223. 1.56版修改当response的头信息"Content-disposition"为"attachment;filename=xxx"时,response.getWriter()的一个Bug。

224. 1.55版修改与response.getOutputStream()相关的一个较严重的Bug。

225. 1.50版按照Jsp规范和Servlet规范,进行了全面的仔细的校对,修改了若干个不常用的地方,保持与Tomcat兼容。

226. 1.50版增加bin/startupW.bat,提供另外一种保险的把UFO作为Windows service启动办法。

227. 1.45版支持jsp规范的pageEncoding属性。

228. 1.45版将servlet的destroy()方法调用规范化。

229. 1.45版解决request的setCharacterEncoding(String env)方法不起作用的Bug。

230. 1.30版完全兼容Tomcat在web.xml对servlet进行配置的做法。

231. 1.30版对错误提示更标准。从而解决一些含有错误url连接的网页显示不出来或"Not Found"的问题。

232. 1.20版解决一些浏览器不标准规范含有一些固有的名字为Cookie保留关键字或字符的Cookie时,语句"Cookie[] cookies=req.getCookies()"不能返回Cookie数组,而是throw了例外的问题。1.20版UFO修改成:当浏览器含有一些固有的名字为Cookie保留关键字或字符的Cookie时或用户设置了名字为Cookie保留关键字或字符的Cookie时,语句"Cookie[] cookies=req.getCookies()"         都返回Cookie数组,但不包含那些名字不规范的Cookie,只包含那些名字规范的Cookie,而不会throw例外。 

233. 1.19版更好地支持特大文件的上传(100M以上的)。

234. 1.18版支持文件上传,支持UFOUpload、jspSmartUpload和Apache组织的commons-fileupload包。也就是很好地支持RFC 1867规范(参见http://www.ietf.org/rfc/rfc1867.txt)。这是一个很实用的功能。

235. 1.17版修改了如果jsp中用到了第三方类,这个第三方类的类名与JDK中的类名一样,并且UFO在编译这个jsp时正好用到了这个类名,导致UFO编译jsp失败的问题。

236. 1.16版修改了以前版本UFO用来搭建wap网站时,由于一些地方的无线网关不标准,手机用户需要访问两次http://wap.xxx.com,才能出内容的问题。也就是说,用1.16版本的UFO搭建wap网站,即使一些地方的无线网关不标准,手机用户也可顺利访问wap网站。 

237. 1.15版修改了1.10版可能不能显示“验证码”图片的Bug;

238. 1.10版修改了以前版本中对新建的Context需要手工创建"_work"子目录的大Bug;

239. 1.10版修改了https状态下的多个Bug;

240. 1.05版修改了由于模糊打包导致1.00版中数据库连接池不能用的Bug;

241. 1.00版提供全新的demo的jsp和servlet示例,尤其对中文乱码问题的解决进行足够的demo;

242. 1.00版允许在一个UFO进程内配置多个DBConnectionPool,根据poolName访问;

243. 1.00版对servlet自动检查servlet.class是否更新,如果有更新,自动对UFO的servlet对象更新,而不需要重新启动UFO;

244. 0.999x版在测试150个jsp和servlet程序的基础上,修改了几个Bug,并提高各种“评测”指标;

245. 0.9985版在测试350个jsp和servlet程序的基础上,修改了几个Bug。 

 

 

 

===================================================================================

server.xml篇

===================================================================================

 

Q3-1 我现在可以启动UFO Web Server了,我现在要对UFO Web Server做进一步的了解。打开/conf/server/xml文件,UFO<Connector>标签是这样的:

   <Connector port="80" scheme="http"

     protocols="http, ws" connectionTimeout="5*1000" soTimeout="5*60*1000"

     soRcvBuf="8192" soSndBuf="8192"

     maxThreads="250" maxConnectionNum="30000"

     maxURISize="10*1024" maxURISizeKill="12*1024"

     maxHeaderSize="2*1024" maxHeaderSizeKill="4*1024"

     maxParameterSize="100*1024" maxParameterSizeKill="150*1024"

     contentReadTimeout="2*60*1000"

     compression="off" compressionMinSize="2048" />

 

    <Connector port="81" scheme="http"

     protocols="ws" connectionTimeout="5*1000" soTimeout="5*60*1000"

     soRcvBuf="8192" soSndBuf="8192"

     maxThreads="250" maxConnectionNum="30000"

     maxURISize="10*1024" maxURISizeKill="12*1024"

     maxHeaderSize="2*1024" maxHeaderSizeKill="4*1024"

     maxParameterSize="100*1024" maxParameterSizeKill="150*1024"

     contentReadTimeout="2*60*1000"

     compression="off" compressionMinSize="2048" />  

            

    <Connector port="443" scheme="https"

     protocols="https, wss" connectionTimeout="5*1000" soTimeout="5*60*1000"

     soRcvBuf="8192" soSndBuf="8192" 

     maxThreads="150" maxConnectionNum="1000"

     maxURISize="10*1024" maxURISizeKill="12*1024"

     maxHeaderSize="2*1024" maxHeaderSizeKill="4*1024" 

     maxParameterSize="100*1024" maxParameterSizeKill="150*1024"

     contentReadTimeout="2*60*1000"

     compression="off" compressionMinSize="2048" 

     clientAuth="false" keystoreFile="/conf/ufo.keystore" keystorePass="ufoufo" 

     truststoreFile="/conf/ufo.keystore" truststorePass="ufoufo" />

 

   请解释scheme属性的含义。

 

scheme为http时,UFO就启动一个普通的ServerSocket;当scheme为https时就启动一个https的ServerSocket。

scheme为https时,您最好指定keystoreFile的存放位置。关于如何制作keystoreFile文件请按照/docs/https_Howto.txt所说的来做。

UFO可以支持多个<Connector>标签。

 

 

Q3-2 接上面话题。请解释protocols的含义。

protocols里含有http或https时,表示本Connector处理http协议的连接。

protoclos里含有ws或wss时,表示本Connector支持websocket的连接。

protocols="ws"或procotols="wss"时,表示本Connector只支持websocket的连接,对http协议的连接,只处理websocket握手时的http连接,其它的http连接一律不接受。

 

 

Q3-3 接上面话题。请解释connectionTimeoutsoTimeoutsoRcvBufsoSndBuf属性的含义。

connectionTimeout: 单位ms, 是指UFO接收了连接请求到接收到至少一个byte数据的最大时间长度。

soTimeout: 单位ms, 当一个http连接处理了一次连接请求任务后,从输出数据完毕算起到下次接收到至少一个Byte数据的最大时间长度。soTimeout参数只对http连接有意义,对websocket连接无意义

 

如果上面2个情况下的“最大时间长度”超出,并不是立即将这个连接Kill掉,而是在UFO执行检查时进行清理(UFO有一个线程每隔20分钟会执行一次检查,另外如果连接数达到最大时,也立即执行检查)。

 

soRcvBuf:单位Byte,UFO的连接的Socket的SO_RCVBUF参数,也就是接收缓存的大小。如果soRcvBuf<=0,表示不设置,采用系统默认缓存大小;如果soRcvBuf<512且soRcvBuf>0,则UFO修改成512;如果soRcvBuf>128*1024,则UFO修改成128*1024。

 

soSndBuf:单位Byte,UFO的连接的Socket的SO_SNDBUF参数,也就是输出缓存的大小。如果soSndBuf<=0,表示不设置,采用系统默认缓存大小;如果soSndBuf<512且soSndBuf>0,则UFO修改成512;如果soSndBuf>128*1024,则UFO修改成128*1024。

 

soRcvBuf和soSndBuf这2个参数的作用请见Socket的setReceiveBufferSize(int size)和setSendBufferSize(int size),把它们设置得较大,可能会提高下载速度,提高网页输出的流畅度,但也消耗更多的内存,减小了UFO的负载能力。

 

 

Q3-4 接上面话题。看到maxThreads属性,请解释这个属性。

UFO Web Server启动时,先启动了几个必须的线程,然后为每个Connector各启动一个线程池(至多2个Connector,前面问题说过)。以后每个Connector的ServerSocket收到用户的连接或者任务请求时,就从这个线程池中取出一个线程来为之服务。

 

每个线程池在启动时会启动20个最小数目的线程,但是这个线程池的最大线程数是由"maxThreads"来规定的。

 

对于maxThreads属性有一点要特别强调的是:一个进程并不是工作线程数越多越好,线程的开销是昂贵的。线程池的maxThreads交给用户来配其实是一件很危险的事情,因为不懂的用户误以为maxThreads越大越好,其实大错。如果您的计算机CPU不行,线程数越多完成任务反而越慢(调度它们是有成本的),最大的危险是使进程内存用光直接死掉。

 

对于一般的PC Server而言,线程数应该不超过500。线程数超过1000后,就可能有问题了。

 

但是,对UFO Web Server而言,不让用户来配置maxThreads,而直接在程序里设置成500,那又会怎样呢?那样就会导致一些高性能CPU的服务器(例如双CPU)得不到充分利用,导致浪费。 So, 你应该把maxThreads设置成多少,应该根据你的服务器性能和你的运行观察来决定。

 

关于maxThreads的另外一个话题是:当Connector的线程池数目达到maxThreads并且无空闲线程可用,这时有任务要求使用线程,UFO该怎么办?

 

1. 对于protocols里含有http或https的Connector,则在当前线程(就是UFO监测本Connector的那个线程)回复"500 SC_INTERNAL_SERVER_ERROR, Thread pool is full. There is no enough thread. Please try later!"

 

2. 对于protocols="ws"或protocols="wss"的Connector,则在当前线程(就是UFO监测Connector的那个线程)为它服务。

 

但如果是UFO Probe连接,在线程数达到最大值时,则启动新的线程来为之服务。

 

很明显,如果你的这个Connector是用来做网游等要断线续连的应用的,那么你应该把这个Connector的protocols设置成:

 

    protocols="ws"或protocols="wss"

 

 

Q3-5 接上面话题。什么是https?

关于https方面的知识您可以到网上去查相关文章。我这里要告诉您的是,关于https方面的知识您可能不需要知道得太多,只要知道它是用来防止Web Server与浏览器之间的字节流在Internet上传输过程中,被截获后,被他人破译信息的。也就是,加密传输。  

 

 

Q3-6 接上面话题。看到maxConnectionNum属性,请解释这个属性。

maxConnectionNum: 本Connector所能保持的最大连接数。

maxConnectionNum与maxThreads是一回事吗?肯定不是。

maxConnectionNum主要是用来防止UFO的所带的连接数过多而用光内存而死掉的。(你知道,每个连接都要消耗不少内存的)。

UFO的Connector所带的连接数达到maxConnectionNum时,UFO是怎样处理的呢?

这时,如果本Connector的protocols="ws"或protocols="wss",则UFO不做任何处理,继续接受处理这个连接,因此,对于那些采用websocket做网游等应用的情况,应该在上层程序BWServlet或CWSServlet里清理控制连接数,以防止UFO内存用光。

所以,maxConnectionNum对只支持websocket的Connector无意义!

 

这时,如果本Connector的protocols里含有http或https,UFO会立即启动清理:

1. 检查所有的连接,把处于无任务状态下的不活动时间超过soTimeout的所有连接都立即kill掉。

2. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,则把所有处于无任务状态下的连接都立即kill掉。(就是完成一次任务后的keepalive无任务连接)

3. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,则把所有从接收到连接请求算起,超过connectionTimeout时间没有读到至少一个Byte的连接都立即kill掉。

4. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,这时如果配置connectionTimeout>500ms,则把所有从接收到连接请求算起,超过500ms没有读到至少一个Byte的连接都立即kill掉。

5. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,则把所有从读到第1个Byte算起,过了1000ms,http头还没有全部读完的连接都立即kill掉。

6. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,则把所有"POST"方法的读Content的时间超过30s,并且读Content的速度小于10K/s的连接都立即Kill掉。

7. 如果上面操作后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,则把websocket的活动时间超wsHeartBeat的连接都立即Kill掉。

    

经过以上的清理后,没有清理掉任何连接,连接数仍然达到maxConnectionNum,这时UFO该怎么办呢?

对普通的用户(非UFO Probe用户),在回复"500 SC_INTERNAL_SERVER_ERROR, Max Connections arrived. Please try later!"后,立即将新接收到连接kill掉。但无论如何,UFO Probe连接不会被Kill掉。

 

 

Q3-7 接上面话题。请解释maxURISize, maxURISizeKill; maxHeaderSize, maxHeaderSizeKill属性。

maxURISize: 单位Byte,最大的URI长度。

maxURISizeKill:单位Byte,URI长度超过它时,立即将连接Kill掉(而没有超过它但大于maxURISize时, 会回错误提示的)。

maxHeaderSize: 单位Byte,最大的Http头体积(总和)。

maxHeaderSizeKill:单位Byte,Http头体积(总和)超过它时,立即将连接Kill掉(而没有超过它但大于maxHeaderSize时, 会接收全部Data放在内存里并回错误提示的)。

 

 

Q3-8 接上面话题。请解释maxParameterSizemaxParameterSizeKill属性。

maxParameterSize: 单位Byte, POST方法并且content-type为application/x-www-form-urlencoded或multipart/form-data时,POST的内容体作为Parameter保存在内存中的最大值。

maxParameterSizeKill: 单位Byte, POST方法并且content-type为application/x-www-form-urlencoded或multipart/form-data时,POST的内容体作为Parameter保存在内存中的体积超过了此值,立即kill掉连接,而不回应任何提示。

 

 

Q3-9 接上面话题。请解释contentReadTimeout属性。

contentReadTimeout: 单位ms,POST方法的连接并且有Content并且不是表单递交时,从有Content时算起,上层Servlet或jsp程序的HttpServletRequest.getInputStream().read()方法的最大时间间隔。

 

进行一步解释:POST方法时,只有content-type为application/x-www-form-urlencoded时,全部的Content才都读入UFO的缓存中。其它情况下UFO的缓存中至多保存20K的Content,在这些情况下,要求上层Servlet或jsp程序尽快调用HttpServletRequest的getInputStream(),打开其InputStream,然后调用InputStream的read()方法把20K缓存的Content读出。

 

如果read()的时间间隔超过了contentReadTimeout并且缓存里的数据满了20K,就这个连接立即Kill掉(完全有理由认为它是Hacker或有问题的连接)。

 

请用户根据上层Servlet或jsp程序根据处理20K的Content时间设置contentReadTimeout值。

                        

 

Q3-10 打开/conf/server.xml文件,UFO<Session>标签是这样的:

    <Session maxInactiveInterval="30" maxMemNum="1000" maxNum="1000000000" />

 

    请解释其各自属性的含义。

 

maxInactiveInterval:单位分钟,Session的最大不活动时间,当一个Session的不活动时间超过此数时,就Kill掉。

maxMemNum:单位个,保存内存中的Session的最大个数,Session个数超过此数,把多出的Session保存进数据库。Session保存在内存里,可加快访问速度,但消耗内存。

maxNum:单位个Session的最大数,保存在数据库里的Session数和内存中的Session数的和超过此值将把数据库里最早保存的1万个Session删除。本参数是用来防止硬盘被用光的(当硬盘被用光时,UFO必宕)。1万个Session需要400K硬盘来保存,请用户根据你的服务器硬盘大小来设置maxNum。

 

 

Q3-11 接上面问题。Session保存进数据库?怎么扯到数据库上了,你莫搞笑。数据库在哪里?

一个UFO Web Server进程1s内可以处理1000个左右的请求,而Session的maxInactiveInterval一般为30分钟,做得好的网站一个UFO Web Server进程或许可以满足全世界几十亿人“同时在线”。

 

1万个Session保存在内存中,它们占用的内存是显著的;当几十万个Session保存在内存中时,UFO估计内存用光而要死掉了。所以,必须有把Session保存进硬盘的机制。

 

UFO为Session的保存和访问这个特殊的问题内置了一个十分精巧的数据库,它的数据库文件放在UFO安装目录下的sessionDB子目录里。  

    

由于这个数据库设计的精巧,即使UFO保存的Session数在几百亿,对UFO的性能几乎没有影响。

 

 

Q3-12 /conf/server.xml文件,有一个<Debug>标签,是这样的:

     <Debug mode="0" />

   

    请说明是什么意思。  

  

当你采用UFO Web Server做开发时,要在Dos窗口下显示必要的调试信息,可设置本标签,你可以把本标签设置成:

    <Debug mode="1" />

    <Debug mode="2" />

    <Debug mode="3" />

   

解释如下:

    mode为"0"时,是正常情况,不显示信息。

    mode为"1"时,显示UFO Web Server所接收到的所有连接请求的requestURI, queryString和method。

    mode为"2"时,除了显示mode为"1"时的信息外,还显示这个请求所对应的文件名以及它是否存在。

    mode为"3"时,除了显示mode为"2"时的信息外,还显示连接请求的所有的http头信息的内容。

 

 

Q3-13 /conf/server.xml文件,有一个<Log>标签,是这样的:

        <Log level="0" maxSize="200*1024" />

 

       请说明是什么意思。

 

这是设置UFO的运行log的。

maxSize: 单位KB,log文件的最大体积。当log文件的体积超过此值时,就停止写log。

level: 写log的级别。

level="0": 0级,log文件只记录引起宕机的致命原因。

level="1": 1级,log文件还记录开发诊断信息,开发者遇到开发上的问题时,可采用此级log,然后将logs/目录下的log.txt文件发到gm365365@sina.com,我公司技术支持看log.txt就能知道问题所在

level="2": 2级,暂时未实现。

level="3": 3级,暂时未实现。

 

注意:默认的log级别是0级!级别越高,写的信息就越多,牺牲的性能就越多,所以建议只在开发调试时采用1级或以上级!

 

 

Q3-14 接上面话题。UFOlog文件放在什么地方?

UFO的log文件名为rlog.txt,在webapps\admin\probe\logs\目录里。

UFO在启动时,都会把上次的rlog.txt copy成rlog_old.txt文件。

 

 

Q3-15 /conf/server.xml文件里,有几个<UFOThread>标签,是这样的:

    <UFOThread name="RegUser" queSize="100" />

    <UFOThread name="CChessUser" queSize="100" />

    <UFOThread name="TomFee" queSize="5" /> 

 

    请说明是什么意思。

 

这是配置Servlet异步处理的线程。关于异步处理方面的问题请阅读后面的<Servlet 3.0>的相关话题。

说明:如果你的网站没有用到Servlet的异步处理,请把这3个标签注释掉。否则,UFO启动时,会启动3个不用的线程,白白占用内存。

 

 

Q3-16 /conf/server.xml文件里,有一个<Compiler>标签,是这样的:

   <Compiler name="JDT" />

   <!--

   <Compiler name="Sun" /> 

   -->

 

   请说明是什么意思。

 

这是选择UFO的Java编译器。

     

<Compiler name="JDT" />表示UFO的Java编译器采用eclipse的JDT Java编译器。

<Compiler name="Sun" />表示UFO的Java编译器采用Sun公司的Java编译器。  

 

如果不设置Compiler标签,或者错误地配置Compiler标签的name属性,UFO都采用eclipse的JDT Java编译器。 

 

 

Q3-17 /conf/server.xml文件里,有一个<Probe>标签,是这样的:

    <Probe maxConnections="10" perTime="1200" clientSet="on" />

    

    请说明是什么意思。

 

这是配置UFO Probe.

maxConnections="10" 表示同时支持10个UFO Probe用户。

perTime="1200" 表示每隔1200秒采一个点。

clientSet="on" 表示UFO Probe可以通过Client随时设置UFO的perTime等参数。

 

 

Q3-18 /conf/server.xml文件里,有两个<Valve>标签,是这样的:

   <!--

   <Valve type="RemoteAddr" deny="127.0.0.1" />

   <Valve type="RemoteHost" allow="localhost" deny="www.*.net" />

   -->

 

   请说明是什么意思。

 

这是用来屏蔽一些用户(例如Hacker)访问网站的。

<Valve type="RemoteAddr" deny="127.0.0.1" />是根据用户的IP来屏蔽。

<Valve type="RemoteHost" allow="localhost" deny="www.*.net" />是根据用户的host来屏蔽。

这里deny意思好理解,就是拒绝后面用户访问。

allow的理解要注意,如果配置了allow,表示只允许后面的那些用户访问,其它用户都将被拒绝。

关于allow和deny在多个IP或host的写法要符合正则表达式规定。

 

 

Q3-19 接上面话题。既然UFO提供了屏蔽IP的功能,那我在哪里可以看到有哪些IP是有问题的?

将在未来版本的UFO Probe里提供异常IP分析功能。

 

 

Q3-20 接上面话题。UFO是否能屏蔽掉那些来自代理服务器的Hacker攻击就象TomcatRemoteIpValve

不能。

1. 当Hacker通过一个代理服务器攻击你的网站时,是代理服务器被攻击了,代理服务器应该封掉那些IP

2. 当Hacker通过一个代理服务器攻击你的网站时,站在你的网站上看到的RemoteAdrr或RemoteHost都是代理服务器的,Hacker可以写一个假冒的代理服务器程序,每次连接伪装成代理连接,自己可以随便填写"x-forwarded-for"等Http头的内容。就是通过Http头"x-forwarded-for"是没有办法提取到真正的Hacker的IP的。因此,你只有把代理服务器的IP封掉。      

 

 

Q3-21 /conf/server.xml文件里,有两个<Valve>标签,是这样的:

   <Valve type="Host" match="No" />

 

   请说明是什么意思。 

 

本标签是用来防止一些Hacker的。

match="Yes":要求用户的URL严格地匹配UFO配置的某个Host,才给予服务。

match="No":不要求用户的URL严格地匹配UFO配置的某个Host,当不匹配任何Host时,就认为他是访问默认的Host。

关于本话题,请阅读下一问题。

 

 

Q3-22 接上面话题。我如何屏蔽一些域名?

server.xml里有一个标签<Valve type="Host" match="No" />,当它的值match为"Yes"时,表示对虚拟主机进行严格匹配。就是,Host标签里未配的"host"都将得不到服务。

 

为了进一步理解这个问题的意义,在此啰嗦一下,国家有关部门规定:未备案的网站不得运行。这就带来了麻烦。为了明白这个规定是怎样带来麻烦的,让我给您讲个故事:

 

我公司的网站是www.gm365.com,它是备案了的,合法的,没有问题的。我公司的www.gm365.com网站运行在我公司托管的服务器上,服务器的IP是222.73.205.120,web server是UFO Web Server。

可是,有个无聊的Hacker注册一个域名xuoxing1.com,也指向了222.73.205.120,这样,当用户在浏览器里输入http://www.xuoxing1.com的时候,也访问到了www.gm365.com的主页。

但是,xuoxing1.com是一个未备案的网站,国家有关部门找麻烦来了,他们通过机房通知你,在你的服务器上运行着一个未备案的网站,你必须把它封掉,否则将如何如何。。。

于是,我公司立即将server.xml改成这样:

    ......

    <Valve type="Host" match="Yes" />

    <Host appBase="webapps" name="www.gm365.com">

       <Alias>gm365.com</Alias>     

       <Alias>222.73.205.120</Alias>     

       <Alias>localhost</Alias>     

       <Alias>127.0.0.1</Alias> 

 

       <welcome-file>index.html</welcome-file>

    

       <Context path="/examples" docBase="webapps/examples" > 

       </Context>

 

       <Context path="/struts2_demo" docBase="webapps/struts2_demo" > 

       </Context>

 

       <Context path="" docBase="webapps/ROOT" >

       </Context>

    </Host>       

 

    然后,再重启UFO Web Server。这样,gm365网站照样运行,而xuoxing1.com得到了屏蔽。

 

 

Q3-23 /conf/server.xml文件里,有几个<Host>标签,是这样的:

   <Host appBase="webapps" name="www.gm365.com">     

       <Alias>gm365.com</Alias>

       <Alias>222.73.205.120</Alias>     

       <Alias>localhost</Alias>

       <Alias>127.0.0.1</Alias>      

        

       <welcome-file>index.html</welcome-file>

    

       <Context path="/examples" docBase="webapps/examples" > 

       </Context>

 

       <Context path="/struts2_demo" docBase="webapps/struts2_demo" > 

       </Context>  

 

       <Context path="" docBase="webapps/ROOT" >

       </Context>

       

    </Host>     

 

  <!--

    <Host appBase="wapapps" name="wap.gm365.com">     

 

      <Context path="" docBase="wapapps/ROOT" >

      </Context> 

 

      <welcome-file>index.wml</welcome-file>

    </Host>

  -->

 

请解释它们的含义。

 

1个Host标签表示配置了一个名字为"www.gm365.com"的Host(虚拟主机),它有4个别名:

    gm365.com

    222.73.205.120     

    localhost

    127.0.0.1

 

用户在浏览器输入如下字符串开头的URL时,都将访问到这个Host(虚拟主机):

    http://www.gm365.com

    http://gm365.com

    http://222.73.205.120

    http://localhost

    http://127.0.0.1

    www.gm365.com

    gm365.com

    222.73.205.120

    localhost

    127.0.0.1      

 

这个Host(虚拟主机)的welcome file是index.html。它配置了3个Context。

 

2个Host标签表示配置了一个名字为"wap.gm365.com"的Host(虚拟主机)。

用户在浏览器输入如下字符串开头的URL时,都将访问到这个Host(虚拟主机):

    http://wap.gm365.com

    wap.gm365.com

 

这个Host(虚拟主机)的welcome file也是index.html。它配置了1个Context。

 

 

Q3-24 接上面话题。我配置了多个虚拟主机(Host),如何指定默认的虚拟主机?

server.xml里的<Valve type="Host" match="No" />,当它的值match="No"时,才可以有默认的虚拟主机。

第一个虚拟主机便是默认的虚拟主机。在/conf/server.wml中请您把要作为默认的虚拟主机放在最前面。“默认”的意思您明白吧,就是当一个URL找不到所属的虚拟主机的时候,就由默认的虚拟主机来处理。

 

 

Q3-25 接上面话题。我只需要UFO来运行一个同学录网站:www.3ren.com,没有虚拟主机,那不需要配置虚拟主机了吧?

这种情况下,您可以不必配置<Host>标签,把所有的html、jsp等所有的文件和子目录都要放在webapps/ROOT目录下。

如果您要灵活指定html等文件子目录存放位置,您就要在/conf/server.xml里配置<Host>标签,象下面这样:

    

    <Host appBase="webapps" name="www.3ren.com">     

 

       <Context path="" docBase="webapps/dir1" >

       </Context>

 

    </Host>

 

 

Q3-26 接上面话题。关于虚拟主机的另外一个问题:我对虚拟主机很感兴趣,我怎样在我计算机上演练?

如果您要在您的桌面计算机上练习UFO的虚拟主机功能,您可以这么做:

    

/conf/server.xml里配置了两个<Host>,一个Host的name="localhost",另外一个Host的name="127.0.0.1";然后成功启动了UFO;然后在浏览器里输入http://localhost或者http://127.0.0.1就可以了。

 

 

Q3-27 接上面话题。只需要配置一下就可以了,虚拟主机使用起来这么简单?在网页制作方面是否需要注意些什么?

是有需要注意的地方,就是UFO是根据URL的host参数来区分它属于哪个虚拟主机的。含义是:虽然localhost和127.0.0.1都指向了同一个地方,但是在网页制作里却不能随便替代。

什么是URL里的host参数?URL里以"http://"开始的位置到后面第一个"/"所夹着的字符串,为host。例如:

 

    http://www.gm365.com/index.html,      host为www.gm365.com

    http://www.gm365.com:81/wap/index.wml  host为www.gm365.com:81

    http://www.gm365.com                   host为www.gm365.com

    www.gm365.com/index.html               host为www.gm365.com

    group3.rnx.com                         host为group3.rnx.com

    http://localhost                       host为localhost

    127.0.0.1/index.wml                    host为127.0.0.1

 

 

Q3-28 接上面话题。大师,前面您给我回答的问题我基本明白了,但是有一个地方:不少问题回答都提到了"Context",什么是Context?

 

简单一点说Context就是让您灵活地设置文档的目录,您知道,在Apache里,文档的目录为htdocs目录,但是在UFO里,有了Context的概念后,文档的目录就可以任意指定。Context是一个比虚拟主机更重要的概念。从字面上看,Context是上下文环境的意思,显然,Context是一组含义。其中最重要的一个含义是Context的识别字符串。在/conf/server.xml里有对一个<Context>的配置:

   

   <Context path="/examples" docBase="webapps/examples" > 

   </Context> 

 

这个path的理解很重要,它将决定一个URL属于那个Context。UFO对所接收到URL并不是单纯地理解成:(路径)+(文件名),而是理解成:(虚拟主机)+(Context)+(路径)+(文件名)。举一个例子,在浏览里输入:

 

   http://www.gm365.com/examples/servlets/index.html

 

UFO如何理解这个URL呢?它首先根据www.gm365.com(也就是host,见前述),确定这是属于哪个虚拟主机的URL;接着,它把/examples理解成是这个虚拟主机下的一个Context;再接着,它把/servlets/index.html理解成这个Context下的servlets目录下的index.html文件。/servlets/index.html的父目录是什么呢?就是在/conf/server.xml里为/examples这个Context配置的docBase,也就是webapps/examples。

 

Context除了上面所说的识别字符串和docBase两个概念外,还有:可以配置Context的mime的extension与mime-type的对应关系,以及配置Context的welcome-file。

 

 

Q3-29 接上面话题。我配置了两个Context,它们是:

    <Context path="/examples" docBase="webapps/examples" > 

    </Context>

    <Context path="/examples/example" docBase="webapps/examples" > 

    </Context>

   

   然后,对URL:

 

   http://www.gm365.com/examples/example/test/index.html

 

   UFO是如何理解的?最后是输出webapps/examples/test/index.html还是输出了webapps/examples/example

   /test/index.html?

 

UFO是按照“最长匹配”来寻找Context的,对于上面的URL,UFO寻找Context的步骤如下:

第一步:把host部分去掉,得到一个字符串:/examples/example/test/index.html;

第二步:把文件名部分去掉,得到字符串:/examples/example/test,并寻找是否有path值等于这个字符串的Context,结果发现没有;

第三步:把上面字符串:/examples/example/test的最后一个目录名去掉,得到字符串:/examples/example,并寻找是否有path值等于这个字符串的Context,结果找到了!

因此,对您这个URL,UFO的理解是请求"/examples/example"这个Context下的/test/index.html文件。由于"/examples/example"这个Context的docBase是"webapps/examples",因此最后输出了webapps/examples/test/index.html。

 

 

Q3-30 接上面话题。照您这么说,把那个字符串去完了,还没有找到Context,那就坏了。因此,一个<Host>里一定要配置一个path为空的Context,就象这样:

       <Context path="" docBase="webapps/ROOT" >

       </Context>

 

    我的理解是否正确?

 

您的悟性真高。您迟早会成为用UFO做网站的高手的。不过,UFO从0.999版开始,如果发现您没有配置这样的一个Context,会在启动的时候,自动为您加上这样的一个Context。

 

 

Q3-31 接上面话题。我可否将ContextdocBase设置为绝对路径?例如,设置成:

        <Context path="" docBase="D:/test/Docs" >

        </Context>

 

UFO里,Context的docBase可以设置为绝对路径也可以为相对路径。

 

 

Q3-32 接上面话题。有关war部署的问题。我能否把war包放在UFO的任何目录下?

war包只能放在server.xml文件里Host标签的appBase所指定的目录下。例如:

 

    <Host appBase="webapps" name="www.gm365.com">

    .....

 

那么要求您把所有的war包都放在webapps目录下。   

 

 

Q3-33 接上面话题。请解释:appBase具体有哪些意义?

appBase的意义有两点:

  

1. 是放置war包的目录;

2. UFO在启动时,会检查appBase下的每个子目录,如果发现server.xml里没有一个配置的Context的path是"/"+目录名,那么UFO会自动加上这样一个Context,它的path是"/"+目录名,它的docBase指向这个子目录。但是有一个例外!就是UFO始终把ROOT子目录的所对应的Context的path设置成"/"。 

 

 

Q3-34 /conf/server.xml文件里,有一个<Balancer>标签,是这样的:

      <Balancer URI="/, index.html, index.htm" HostName="www.gm365.com">

       <Member redirect="http://222.73.205.120" loadfactor="2" />

      <Member redirect="http://www.gm365.com" loadfactor="1" />

      <Threshold thread="5" CPU="7" request5="1000" flow5="50*1024*1024" session="100000" keepalive="2000" memory="250*1024*1024" />

      </Balancer>

 

    请解释它们的含义。

 

本标签配置了一个负载均衡。本标签表示把Host name为"www.gm365.com"的虚拟主机的/或index.html或index.htm的请求在满足一定的阀值条件时按权重因子重定向到另外的服务器。

URI: 要重定向的URL里的http://(或https://)后的第1个/后面的部分。它可以是一个请求;也可以把多个请求放在一起而用","或", "分割。

HostName: Host的name。它可以是具体的一个Host的name;也可以是"*",表示任何Host。它不可以把多个Host的name放在一起。

Member: 定义了一个负载均衡的服务器。

redirect: 将重定向到的另外服务器的协议、IP和端口。

loadfactor: 权重。UFO将根据请求次数按权重把URI里规定的请求重新定向。

Threshold: 定义了重新定向的阀值,只有阀值条件满足时才进行重新定向,否则仍然由当前的服务器来服务。它有memory等7个属性,这7个属性之间是或的关系而不是与的关系,也就是说,任何一个属性条件满足时,都会发生重新定向。

thread: 在用线程数。当UFO进程的当前正在工作的线程数>=thread属性约定的值时就重新定向。注意:thread="-1",表示不考虑在用线程数因素!thread="0",表示无条件重新定向!   

CPU: 当前CPU,单位%。当UFO进程的当前占用的CPU>=CPU属性约定的值时就重新定向。注意:CPU="-1",表示不考虑当前CPU因素CPU="0",表示无条件重新定向!

request5: 最近5秒内的请求次数。当UFO进程的最近5秒处理的请求数>=request5属性约定的值时就重新定向。注意:request5="-1",              表示不考虑request5因素!request5="0",表示无条件重新定向!

flow5: 最近5秒内的流量(上行+下行),单位Byte。当UFO进程的最近5秒流量>=flow5属性约定的值时就重新定向。注意:             flow5="-1",表示不考虑流量因素!flow5="0",表示无条件重新定向!

session: 当前Session数。当UFO进程的当前的session数>=session属性约定的值时就重新定向。注意:session="-1",表示不考虑session数因素!session="0",表示无条件重新定向! 

keepalive: 当前keepalive连接数。当UFO进程的当前的keepalive连接数>=keepalive属性约定的值时就重新定向。注意: keepalive="-1",表示不考虑keepalive连接数因素!keepalive="0",表示无条件重新定向!   

memory: 在用内存,单位Byte。当UFO进程的当前使用内存>=memory属性约定的值时就重新定向。注意:memory="-1",表示不考虑在用内存因素!memory="0",表示无条件重新定向!

 

 

Q3-35 接上面话题。在/conf/server.xml文件里,有一个<Balancer>标签,是这样的:

      <Balancer URI="games/login.jsp" HostName="*">

      <Member redirect="http://127.0.0.1:8012" loadfactor="1" />

      <Threshold thread="-1" CPU="-1" request5="-1" flow5="-1" session="-1" keepalive="-1" memory="0" />     

      </Balancer>   

      

      请大体说说这个负载均衡。

 

UFO收到的任何虚拟主机的games/login.jsp的请求都无条件地重新定向到http://127.0.0.1:8012。

 

 

Q3-36 /conf/server.xml文件里,有一个<DBConnectionPool>标签,是这样的:

     <DBConnectionPool

      poolName="gm365DBSZJ" 

      driver="org.gjt.mm.mysql.Driver" 

      username="gm" 

      password="112358"

      URL="jdbc:mysql://61.151.252.98/gm365?user=gm&password=112358&useUnicode=true&characterEncoding=gb2312" 

      minOpen="1" 

      maxOpen="100"

      timeout="2000"

    />

  

   请解释它们的含义。

 

本标签配置了一个name为"gm365DBSZJ"的数据库连接池。

预先创建好数据库连接,可以提高jsp程序的响应速度;可以避免随意创建数据库连接而“打爆”数据库(数据库能带的连接数是有限的)。  

但是在你配置了这样的一个数据库连接池后,你怎么在servlet或jsp里使用它呢?

第一步,把相应的jdbc driver的.zip包或.jar包放到/lib目录下。(重启UFO,当然)

第二步,编写jsp程序,参见examples/jsp/DB/DBJsp.jsp程序:

    <%@ page contentType="text/html; charset=gb2312" %>

<%@ page import="java.sql.*"%>

<%@ page import="javax.db.DBConnectionPool"%>

<%@ page import="core.UFO"%>

<html>

<body>

以下是从MySQL数据库读取的数据:<hr>

<table border=1>

<tr><td>ID</td><td>书名</td><td>出版社</td><td>价格</td></tr>

 

<%

      DBConnectionPool dbConnPool=UFO.getDBConnectionPool("gm365DB");

      

      java.sql.Connection conn=null;

      java.sql.Statement stmt=null;

      java.sql.ResultSet rs=null;

   

      try{

          conn=dbConnPool.getConnection();

          stmt=conn.createStatement();

          rs=stmt.executeQuery("select * from book"); 

 

          while (rs.next()){

              out.println("<tr>");

              out.println("<td>"+rs.getString("bookId")+"</td>");

              out.println("<td>"+rs.getString("bookName")+"</td>");

              out.println("<td>"+rs.getString("publisher")+"</td>");

              out.println("<td>"+rs.getFloat("price")+"</td>");

              out.println("</tr>");

          }

      }

          catch (Throwable e){

          }

          if (rs!=null){ 

            try{

              rs.close();

            }

            catch (Throwable e){

            }

          }

          if (stmt!=null){

            try{

              stmt.close();

            }

            catch (Throwable e){

            }

          }

          dbConnPool.returnToPool(conn);

        %>

        </table>

        </body>

      </html>

 

 

Q3-37 接上面话题。<DBConnectionPool>标签内的属性都不难理解,但是有一个属性:timeout="2000",我有点含糊,能否解释一下? 

当到数据库连接池取连接时,如果没有空闲的连接,并且连接池打开的连接数已经达到了最大数,这时如果立即返回null,就有问题了,因为再过几ms就可能有一个连接返回池中;如果无限时间地等待下去,也有问题,因为有可能永远也没有连接返回池中,导致调用线程“吊死”。timeout属性就是用来解决这个问题的,等待timeout ms,若还没有连接可取,则throw Exception。

 

程序本身是最精确的文档,请参见DBConnectionPool.java

 

 

Q3-38 接上面话题。请对用到数据库连接池的jsp程序的写法给些指导?

如果您在/conf/server.xml配置正确的<DBConnectionPool>标签,并且数据库确实已经启动,当UFO启动时,就已经创建了数据库连接池。以后您只要在jsp程序里取出DBConnectionPool的引用就可以了,为此您需要:

   

    1. 在jsp程序的一开头写上:

      

       <%@ page import="javax.db.DBConnectionPool"%>

       <%@ page import="core.UFO"%>  

 

    2. 在jsp程序里取出UFO的DBConnectionPool的引用:

 

       DBConnectionPool dbConnPool=UFO.getDBConnectionPool("gm365DB");

 

       这里的"gm365DB"是poolName,要在配置文件里配置过的。

 

    3. 从数据库连接池中取连接:

 

       java.sql.Connection conn=dbConnPool.getConnection();

 

   以后的做法,都是正常的数据库的jdbc操作。

 

 

Q3-39 接上面话题。在examples/jsp/DB/DBJsp.jsp程序的后部分,有一个语句:

 

          dbConnPool.returnToPool(conn);

 

      请问这语句是否是必须的?

 

必须!从数据库连接池中取出连接后,用完后,一定要调用dbConnPool.returnToPool(conn)或dbConnPool.wipe(conn)中的一个,即使发现这个连接已死,也要这么做!否则,数据库连接池关于连接数的数据就不对了,导致您的网站宕掉!

 

请参见DBConnectionPool.java

 

 

Q3-40 接上面话题。数据库连接池可以在哪些文件里配置?如何配置多个数据库连接池?

<DBConnectionPool>标签可以在两种文件里配置:

    

1. 在/conf/server.xml文件里配置,可以配置多个<DBConnectionPool>标签,请不要将

       <DBConnectionPool>标签嵌在<Host>标签里面(目前不支持这种做法);

    2. 可以在各个Context里的web.xml里配置多个<DBConnectionPool>标签,但是不能在/conf/web.xml

       里配置<DBConnectionPool>标签。

 

    特别注意的是:无论在什么地方配置,配置多少个<DBConnectionPool>,请保持poolName属性的唯一性。 

 

 

Q3-41 接上面话题。我配置了<DBConnectionPool>标签,并且把JDBC Driver.zip包放到了/lib目录下,结果启动UFO,发现UFO消耗的内存多了好几M,启动速度也慢了不少,这令人很不舒服,正常否?

是这样的。这是因为UFO启动时装载JDBC Driver类的结果。因此,对于那些不用数据库连接的网站,请您在/conf/server.xml里把<DBConnectionPool>标签注释掉,就没有这个问题了。 

 

 

Q3-42 /conf/server.xml文件里,有一个<Resource>标签,是这样的:

    <GlobalNamingResources>

     <Resource

    name="jdbc/myDB"

     type="javax.sql.DataSource"

        driverClassName="org.gjt.mm.mysql.Driver"

     username="mars"

     password="234235"

     url="jdbc:mysql://61.151.252.98/gm365?useUnicode=true&characterEncoding=gb2312" 

     minOpen="1" 

        maxOpen="10"

     maxWait="2000"

     maxIdle="2"  

     maxActive="4" />

   </GlobalNamingResources>

 

   请解释它们的含义。

 

这是按照DataSource的相关规范配置了一个数据库连接池。这个数据库连接池按照DataSource的标准方式来访问。

 

UFO同时支持<DBConnectionPool>和<Resource>两种数据库连接池的配置方法。两种方法配置出来的数据库连接池在UFO Probe看来没有差别。

建议您采用<DBConnectionPool>配置方式,UFO支持<Resource>的配置方式主要是为了对Tomcat等其它Web Server的兼容。

有关数据库连接池、DataSource、JNDI部分的所有源代码在javax.ufo.db目录下。

 

 

Q3-43 conf/server.xml文件里,有<Download>标签,是这样的:

    <Download buffSize="40*1024" threshold="2*1024*1024" thread="MIN" /> 

 

    请说明是什么意思。

 

本标签是用来调节UFO输出较大体积文件或静态网页下载时的性能的。

 

buffSize="40*1024" 表示当文件或静态网页的体积大于或等于threshold时,UFO用于输出这个文件或静态网页的buff的size是40*1024。size大时,可能会使下载的速度快。如果配置的buffSize<8*1204, UFO在启动时,把buffSize设置成8*1204;如果配置的buffSize>64*1024,UFO在启动时,把buffSize设置成64*1024. 

 

threshold="2*1024*1024" 表示阀值,即当文件或静态网页的体积大于或等于2*1024*1024时,UFO用于输出这个文件或静态网页的buff size和线程优先级才采用本<Download>标签的配置;小于2*1024*1024时,仍然采用默认值。

 

thread="MIN" 表示当文件或静态网页的体积大于或等于threshold时,UFO用于输出这个文件或静态网页的线程的优先级是Thread.MIN_PRIORITY thread可有三种配置:"MAX", "NORM", "MIN"分别表示线程的优先级是Thread.MAX_PRIORITY, Thread.NORM_PRIORITY, Thread.MIN_PRIORITY.

 

作为提示参考:

    

    1. UFO默认的buff size是8*1024.

    2. UFO里所有线程的优先级是Thread.NORM_PRIORITY (对应配置thread="NORM").

    3. 是否应该把buffSize设置得较大,取决于您的服务器的内存是否富裕。    

 

 

 

===================================================================================

web.xml篇

===================================================================================

 

Q4-1 /conf/web.xml文件里,有一大堆<mime-mapping>标签,例如:

     <mime-mapping>

        <extension>abs</extension>

        <mime-type>audio/x-mpeg</mime-type>

     </mime-mapping>

 

    它们是么意思?

 

上面的例子标签的意思是,如果用户请求下载文件的扩展名是.abs,就将输出的Http头里的Content-Type填写为audio/x-mpeg。

 

这个mime-mapping功能在当今日新月异的互联网(尤其是无线互联网)比较重要。例如,对Android手机,如何发布游戏呢?

你需要在/conf/web.xml里加上如下标签:

    <mime-mapping>  

       <extension>apk</extension>  

       <mime-type>application/vnd.android.package-archive</mime-type>  

    </mime-mapping>

 

这样当android手机用户到你的网站来下载.apk游戏时,android手机得到了"application/vnd.android.package-archive"的Content-Type的Http头,手机知道了这是一个要安装的包。否则手机会把游戏包当网页显示成乱码了。

 

 

Q4-2 UFO/conf/目录下有一个web.xml,然后在各个Context/WEB-INF/目录下也有一个web.xml,这些web.xml都可以对mime-mapping配置,这是否有点混乱?

不混乱。你应该知道面向对象的“继承”和“重载”的关系吧。在/conf/web.xml里对mime的extension与mime-type对应关系进行配置,各个Context都拥有这些配置。但是,个别Context要对某一个mime的extension所对应的mime-type定义新的值,怎么办?可以在那个Context的/WEB-INF/目录下的web.xml对那个extension与那个mime-type重新对应。

  

  

Q4-3 welcome-file这个参数,在UFO里可以在/conf/web.xml/conf/server.xml和各个Context的     /WEB-INF/目录下的web.xml文件里都可以对它进行配置,是这样的吗?

是这样的。与mime参数相比,多了一个配置的地方:/conf/server.xml。

各个文件配置的welcome-file的“继承”和“重载”的关系是:/conf/web.xml配置的welcome参数在所有虚拟主机的各个Context下都得到“继承”;/conf/server.xml里配置的welcome参数对所在虚拟主机的各个Context的welcome参数进行“重载”;每个Context的/WEB-INF/目录下的web.xml文件对welcome参数的配置,对自己的welcome参数进行“重载”。

 

 

Q4-4 /webapps/examples/WEB-INF/web.xml文件里,有这样的标签:

     <servlet>

      <servlet-name>HelloServlet</servlet-name>

      <servlet-class>HelloUFO</servlet-class>

     </servlet>

     <servlet-mapping>

      <servlet-name>HelloServlet</servlet-name>

      <url-pattern>/HelloUFO</url-pattern>

     </servlet-mapping>

 

    请解释它们的含义。

 

这两个标签规定了一个Servlet,它们规定用户请求访问到本"examples"的Context的URL里"/HelloUFO"字符串看成是访问一个名为"HelloServlet"的Servlet,它的类是classes子目录下的HelloUFO.class.

 

 

Q4-5 /webapps/examples/WEB-INF/web.xml文件里,有这样的标签:

     <servlet>

      <servlet-name>RequestDetail</servlet-name>

      <servlet-class>RequestDetail</servlet-class>

      <url-pattern>/RequestDetail</url-pattern>

     </servlet>

  

    请问这种写法与Q4-4里的写法效果有不同吗? 

 

没有差别。在Q4-4里将同一个Servlet的规定放在2个标签里写,真是愚蠢的做法。那么多servlet要校对2次,真是费神的体力活,使人要疯掉了。

但是即使是Q4-5这种比较省力的写法,在UFO里也不提倡。因为这种servlet map的做法,会导致URL与一大堆"url-pattern"匹配,尤其是要做"*"通配符的配匹,白白浪费CPU!连普通的静态网页请求都要这么浪费CPU。另外,把这些servlet map的对象装进UFO,也是浪费内存。

UFO支持一种把URL里"/servlet/"字符串当成servlet标识符的做法,这个做法不浪费CPU,速度快,也不浪费内存。

 

 

Q4-6 接上面话题。我访问Q4-5里的RequestDetail这个Servlet,用"/servlet"字符串做标识符的写法,应该怎么写?假定Hostnamewww.gm365.com

 

http://www.gm365.com/examples/servlet/RequestDetail

 

 

Q4-7 接上面话题。在UFO中有两个URL:

 

      http://www.gm365.com/examples/servlets/servlet/HelloWorld

      http://www.gm365.com/examples/servlet/servlets/HelloWorld

 

     UFO对它们怎样解释?存放路径是否一样?

 

第一个URL,UFO对它的解释:请求examples这个Context的类路径下的servlets子目录下的HelloWorld这个servlet程序服务。因此在examples这个Context下的/WEB-INF/classes/servlets/目录下要有HelloWorld类,这个HelloWorld类没有包名。

 

第二个URL,UFO对它的解释:请求examples这个Context的类路径下的servlets.HelloWorld这个servlet程序服务。由于包名在路径解释上相当于子目录,因此在examples这个Context下的WEB-INF/classes/servlets/目录下要有HelloWorld类,这个HelloWorld类有包名servlets。

 

可见两个URL的servlet的类存放路径是一样的,但是类本身,一个无包名,另外一个则有包名。

 

 

Q4-8 接上面问题,假定www.gm365.com的运行Web ServerUFO,那么我要访问www.gm365.comexamples这个Context的类路径下(/WEB-INF/classes/)下的servlet子目录下的HelloWorld这个servlet服务,URL怎么写?

http://www.gm365.com/examples/servlet/servlet/HellWorld

 

 

Q4-9 接上面问题,我要访问www.gm365.comexamples这个Context的类路径下(/WEB-INF/classes/)下的servlet子目录下的HelloWorld这个servlet服务,但是这个HelloWorld类有包名servlet,这个URL怎么写?

 

由于UFO总是把URL路径中最后一个/servlet/作为servlet的识别字符串,因此包名为servlet的HelloWorld类是没有办法访问的。

请修改HelloWorld的包名,例如,改成servlets,当然,把它的存放目录也改成servlets,这样,URL就可以写成:

    

    http://www.gm365.com/examples/servlet/servlets/HellWorld 

 

 

Q4-10 /webapps/examples/WEB-INF/web.xml文件里,有这样的一些标签:

    <security-constraint>

      <display-name>Example Security Constraint</display-name>

      <web-resource-collection>

         <web-resource-name>Protected Area</web-resource-name>

 <!-- Define the context-relative URL(s) to be protected -->

         <url-pattern>/jsps/security/protected/*</url-pattern>

 <!-- If you list http methods, only those methods are protected -->

 <http-method>DELETE</http-method>

         <http-method>GET</http-method>

         <http-method>POST</http-method>

 <http-method>PUT</http-method>

      </web-resource-collection>

      <auth-constraint>

         <!-- Anyone with one of the listed roles may access this area -->

         <role-name>ufo</role-name>

 <role-name>role1</role-name>

      </auth-constraint>

    </security-constraint>

  

    <!-- Default login configuration uses form-based authentication -->

    <login-config>

      <auth-method>FORM</auth-method>

      <realm-name>Example Form-Based Authentication Area</realm-name>

      <form-login-config>

        <form-max-login-num>200</form-max-login-num>

        <form-login-page>/jsps/security/protected/login.jsp</form-login-page>

        <form-error-page>/jsps/security/protected/error.jsp</form-error-page>

      </form-login-config>

    </login-config>

        

    <!-- Security roles referenced by this web application -->

    <security-role>

      <role-name>role1</role-name>

    </security-role>

    <security-role>

      <role-name>ufo</role-name>

    </security-role>    

 

这组标签规定了一个认证。它们规定用户访问到examples这个Context的URL只要匹配"/jsps/security/protected/*"就都要登录认证,DELETE, GET, POST, PUT访问都要登录认证。认证的方法是"FORM",登录界面是/jsps/security/protected/login.jsp,登录不对就转向/jsps/security/protected/error.jsp。登录填写的用户名要求拥有"ufo" 或"role1"角色。

 

 

Q4-11 接上面话题。Q4-10中有一个标签是这样的:

      

      <form-max-login-num>200</form-max-login-num>

 

    请问这个标签是什么意思?

 

UFO要求用户做FORM认证时,会把刚才的请求状态保存下来,等用户认证成功后,再把刚才保存的请求状态取出来,为用户服务。

 

但是内存里总不能保存任意多的请求状态。

 

当内存里保存的请求状态超过上面标签规定的数目时,就按照合理的机制把一些保存的请求状态删除。 

 

 

Q4-12 接上面话题。老师,我刚才上大学了,有点吃力,现在补下高中的课程。什么是role?有用户名还要role干什么?

role就是角色的意思。role是与权限密切相关的,UFO里的role的意思与普通系统里的role没有差别。设置某个权限,要填写一堆用户名,没有什么;如果每次设置其它权限,都要填写一堆用户名,那就很麻烦了。有了role,就解决了这个问题,将权限授于角色,而把用户名设置成是否拥有某个角色。

 

一个角色可以拥有多个用户名(相当于一个权利授于多个用户名),而一个用户名可以拥有多个角色(相当于一个用户名拥有多个权利)。

    

 

Q4-13 接上面话题。那么认证用的用户名、密码和role在哪里设置的?

/conf/UFO-users.xml里。例如:

    

   <user name="ufo" password="ufo" roles="ufo" />

 

表示用户名"ufo"的password是"ufo",拥有的role是"ufo"。

 

 

Q4-14 接上面话题。什么是认证?

 Web Server上的一些网页、jsp程序、servlet程序、文件download等资源需要用户输入密码才能访问,这就是认证。

 

 

Q4-15 接上面话题。UFO支持哪些认证?

UFO支持BASIC、DIGEST和FORM等三种方式。

 

BASIC认证:浏览器弹出默认的登陆框,让用户输入用户名和密码,如果有一个不对,默认的登陆框继续弹出,直到输入正确为止。在传输用户名和密码上,只用简单的加密,Hacker截获字节流后,将轻易破译。

 

FORM认证:登陆框可以自己设置成自己的风格,用户名或密码输错后,出现自己定制的页面。在传输用户名和密码上,用POST方法的参数编码方式,Hacker截获字节流后,也将轻易破译。

  

DIGEST认证:在界面表现上与BASIC认证无异。在传输用户名和密码上,采用复杂Hash加密,Hacker截获字节流后,将很难破译。

 

 

Q4-16 接上面话题。这样说来,https和认证是两个不同外延的概念,也就是说,https网站也同样可以做认证,是这样的吗?

 

是。

 

 

Q4-17 接上面话题。关于FORM认证,看了examples/jsp/security/protected/login.jsp,也就是自己制作的登陆框。我的问题是:我是否可以把里面的"j_username""j_password""j_security_check""POST"4个关键字符串改成别的?

 

不可以。这个四个字符串不能修改的,是FORM认证登陆的四个“关键词”。简单地说,您如果要制作其它风格的登陆框,可以修改上面login.jsp的界面部分,却不可以修改其中的“程序”部分。

 

 

Q4-18 接上面话题。在Tomcat中,在https状态下,还提供了一种"Client-Auth"认证,在UFO里,是否支持这个认证?

UFO Pro 5.06UFO中双向SSL认证已经得到支持。

关于如何做双向SSL认证请参见本发布的docs目录下的相关文档。也可到网上查相关文章。

 

 

Q4-19 接上面话题。关于认证的,在ContextWEB-INF/web.xml里的<login-config><security-constraint><web-resource-collection><auth-constraint>等标签是否有数量限制,也就是能否配置多个相同的标签?

是这样的,<login-config>标签只能设置一个,含义是一个Context下的认证方法只能用一个,要么是BASIC、要么是DIGEST、要么是FORM。<security-constraint>标签可以设置多个,同一个<security-constraint>标签里可以设置多个<web-resource-collection>、<auth-constraint>标签,含义是,您可以对多个资源进行约束,并把不同的资源分配给不同的角色。

  

总之,这个问题,您认为怎样才是合理的,UFO就会是那样的。

 

 

Q4-20 接上面话题。关于认证的,<url-pattern>标签体是能用*号进行通配,含义是,如果我要对一个目录下的所有资源都要求认证,总不至于一个个填写吧?

 

支持*号通配!

 

 

 

===================================================================================

提问篇

===================================================================================

 

Q5-1 UFOTomcat等其它Web Server的兼容情况怎样?

 

4.00版开始,UFO不再对Tomcat保持完全兼容,但尽量保持兼容。

不兼容的地方主要在异步处理等新增规范标准的实现上。

 

 

Q5-2 我是个资深的Java工程师,我知道JVM在垃圾回收的时候产生不少运算,消耗不少CPU,因此,我宁可采用那些用C写的Web Server,而不会采用使用起来简单的UFO

UFO采用了非常优秀的对象管理机制和算法,UFO的JVM极少进行垃圾回收。用UFO运行网站,绝大多数时间CPU消耗<0.1%,最多的时候也不会超过5%,几乎永远保持很快的响应速度和高负载能力。 

 

 

Q5-3 我的网站如果要从Tomcat迁移到UFO上,配置上需要做哪些改动?

您只需要把Tomcat的webapps目录和conf目录Copy覆盖UFO的webapps目录和conf目录,然后启动UFO就可以了。

 

虽然UFO的/conf/server.xml文件里不需要<Engine>、<Service>、<Server>三个标签,但是对Tomcat的server.xml文件格式,UFO也完全支持读取。不过从简洁的立场出发,建议您还是参照UFO(发布)里的/conf/server.xml的样子把Tomcat的server.xml改过来(主要是去掉<Engine>、<Service>、<Server>三个标签)。

 

对一些特殊的网站,从Tomcat迁移到UFO上,您还需要做如下一些事情(一般情况您不需要理这些):

 

    1. 如果您的网站用到了认证,请把tomcat-users.xml重命名为UFO-users.xml。

    

    2. 如果您的网站用到了Servlet 3.0的异步处理,请参考UFO的例子做法修改过来。  

 

 

Q5-4 jspservlet程序中取Request参数,为什么取出来后中文显示为乱码?我的取法是:

       String username=request.getParameter("user_name");

 

    结果username在网页中显示为乱码。

 

如果您设置了request的characterEncoding,request.getParameter()就按您设置过的字符编码返回String;否则,按照ISO-8859-1字符编码返回String。在ISO-8859-1字符编码里,中文字符显示为乱码。

 

对此中文乱码问题,有两种解决办法:

 

    1. 先设置request的characterEncoding,再取参数。即:

 

       request.setCharacterEncoding("UTF-8");

       String username=request.getParameter("user_name");

    

    2. 不设置request的characterEncoding,自己转换(推荐)。转换办法如下: 

       

       String oldName=request.getParameter("user_name");

       byte[] bs=oldName.getBytes("ISO-8859-1");

       String username=new String(bs, "UTF-8");

 

特别注意的是,您要确保浏览器端发送这些参数的html网页的编码与Server端取这些参数的编码的一致。

例如,上面的方法中采用"UTF-8"来取参数,那么,对应的发送参数的网页应该是这样的:

 

     <head>

     <meta http-equiv="content-type" content="text/html; charset=UTF-8">

     <title>XXX</title>

     </head>

 

     (当然,所有其它地方也都是UTF-8,即html文件保存的编码方式为UTF-8;html文件里其它如果出现GB2312等编码都把它们换成UTF-8)     

 

 

Q5-5 现在有那么多Web Server,我为什么要采用UFO作为Web Server呢?

使用UFO做Web Server的好处是只简单地管理一个UFO Web Server(而不需要管理配置其它模块), 网站能做得很稳定,永远也不会自己宕掉;UFO在托管机房Ping的TimeOut比率很高、遭受Hacker攻击、高负载压力请求、互联网骨干网被黑等恶劣的环境条件下仍然能很好地运行;UFO在对付Hacker方面也有足够措施。

 

将网站做得很稳定是非常重要的:

 

    1. 将网站做得很稳定,就可以天天睡大觉也收钱;相反网站不稳定,公司上下经常受到折腾。

    2. 网站容易宕,用户、业务就发展不起来;每宕一次会有可观的用户倒向竞争对手。

    3. 对于一个要宕的网站,绝大多数情况是Web Server有垃圾资源的积累,垃圾的积累会使网站的响应速度变慢。因此,对于一个不是很稳定的网站,最大的坏处是它没有宕的时候的响应速度的变慢,研究表明每慢0.5s,就有20%的用户流失。

    4. Web Server过多的垃圾积累,会导致整个Server计算机的变慢,导致别的Server程序响应变慢。

    5. 网站现在越来越成为公司门面,公司网站不稳定或响应速度慢,公司形象受损。

    6. 网站做不稳定,老板就容易失去信心,公司关门;做单子则不能干净利索地交活;技术人员就容易被炒鱿鱼。

 

另外,UFO自带很Cool的UFO Probe,对UFO Web Server的运行状况提供实时监测、诊断和报警。

 

 

Q5-6 怎样判断一个网站是否很稳定?将来是否有可能宕掉?

一个充分条件:如果一个Server程序(例如,Web Server)在启动后,经过一段时间的运行(一般<7天),内存不能稳定下来,一直在增长,那么这个Server迟早要自己宕掉。

 

相反,如果一个Server程序经过一段时间的运行,内存能稳定下来,CPU峰值和响应速度都很正常,那么这个Server程序是一个很稳定的Server。

 

 

Q5-7 我又不是VC,您把UFO说得那么好有什么用?能否举一实例,展示一下UFO做网站的效果?

www.gm365.com网站的Web Server就是UFO。www.gm365.com网站的“硬”条件是:

  1. 与其它六家左右的公司网站,共享100M出口;

  2. www.gm365.com只托管了一台普通的PC Server,UFO与gm365的数据库Server、几十个游戏应用Server同时运行在这台PC Server上,并且,这个UFO还有同时运行wap.gm365.com手机wap网站。

  3. 这台PC Server最近5年操作系统没有重启过。  

 

 

Q5-8 我在使用UFO的过程中遇到问题或者发现Bug,找谁?

将来,您可将问题发帖到UFO Web Server的技术论坛:ufo.gm365.com(待开通),我们的技术人员会在24小时内给予回答。

您也可以直接将问题发到信箱:gm365365@sina.com

 

 

Q5-9 能否给出一个UFO相对于其它Web Server的性能指标的评测报告啊?

作为开发者,我们不便做出这样的评测报告,无论是数据好坏,由开发者给出评测报告总会带来道德甚至法律上的问题。

 

您可以自己下载JMeter等测试工具自己来评测。 

 

 

Q5-10 php速度很快,而且很流行,UFO是否也支持php啊?

您的说法不正确。“猫走不走直线,完全取决于老鼠”。php速度快不快完全取决于运行它的Web Server。类似的错误说法还有:看,利用Google的python做的网站速度有多快。php, asp, jsp, python只是产生动态网页的语法。

 

实际上,我公司正准备使UFO也支持php,asp,以使那些利用php, asp开发的网站只需要简单Copy一下,就可以迁移到UFO下,但是最后还是放弃了。UFO支持php, asp不难,但是好象没有什么意义。

 

首先,我们看不出来php, asp, jsp在绝对大多数地方语法上有什么本质上区别,只是改头换面而言,例如,php的echo对应jsp的print等等。这就是说,网站如果想从php迁移到jsp上,利用jsp把动态网页部分重写一遍,是个不费脑筋的事情,只是花点时间干点体力活而已。

 

其次,我看不出来一些语言有什么前途,例如,一些语言连数据库连接池都没有,这非常致命;再例如,一些语言虽然提供了不少function,但是与jsp的在网页里编程相比是小巫见大巫了;再例如,一些语言是弱类型,这很糟糕。一些语言流行只能说明以前还没有出现稳定运行jsp的Web Server。

 

但是,现在UFO Web Server出现了,情况就不同了。  

 

 

Q5-11 本版本的UFO为什么有时比较消耗内存?

由于Java编译器的问题,在编译一个jsp文件后,内存不能释放,导致本版本的UFO有的时候看上去比较消耗内存。但是这个问题并不影响UFO的稳定性。

 

用户可用这个办法解决这个问题:启动UFO,打开浏览器,将所有的jsp都访问一次(使UFO先编译它们);然后,Kill掉UFO;然后再启动UFO(以后再访问jsp就不需要编译了),这样UFO的运行内存就很小了。

如果您看到UFO的内存突然增加了几M,那一定是由于编译器编译jsp的原因,把UFO重启一下就是了。

与修改jsp程序的麻烦和工作量相比,将UFO重启一下,不过是举手之劳。由于仅仅是新修改过的jsp需要编译,由于编译而将UFO重启的情况其实是很少的。    

将尽快在UFO中采用更加完美的Java编译器,即使这样(采用最好的Java编译器),您最好在jsp编译后,把UFO重启一下,因为再好的Java编译器,也会消耗不少的内存,只不过相对来说,小些而已。 

 

 

Q5-12 我有一个jsp程序,里面有一行代码是这样的:

    out.print(x>0 ? 9 : "0"); 

 

    结果这个jsp程序在Tomcat下运行没有问题,而在UFO下,却出现错误:"java.lang.Int不能转换成java.lang.String"。这是不是UFO的Bug?

 

经查,Tomcat采用的是JDT编译器,而当UFO采用sun公司的com.sun.tools里的Java编译器时就出现这个问题,也就是说,是这个Sun的Java编译器的Bug。

 

可请采用如下的解决办法:

 

    out.print(x>0 ? 9 : 0);

 

   

 

   out.print(x>0 ? 9+"" : "0");     

       

 

Q5-13 我用浏览器打开UFO Probe,屏幕全屏灰屏,不显示数据,是不是Bug? 我按照UFO Probe文档正确操作。

当浏览器的JVM是MS JVM时,就出现这个问题。

 

由于UFO Probe用到了支持https的类,这在MS JVM里不支持,UFO Probe没有办法去掉https有关的类(因UFO可能会在https状态下运行)。

因此,对本问题的结论是,使用UFO Probe要求浏览器采用Sun JVM。(就是在您的计算机里安装一下JDK就可以了。)

 

 

 

===================================================================================

付费篇

===================================================================================

 

Q6-1 UFO的收费情况怎样?

Pro 5.06版本UFO是收费的,它的一个License Fee是30万RMB,含义是:你在一台服务器上使用Pro 5.06版UFO,需要向我公司支付30万RMB。进一步的解释如下:

1. 这台服务器是拥有公网IP的。如果您在局域网内使用Pro 5.06,则不需要支付License Fee。

2. 我公司是按公网IP识别服务器的,如果您购买了Pro 5.06的License Fee(填写了运行它的服务器IP),但后来服务器的公网IP变了,您只需要向我公司申请填写新的IP地址,而不需要再交费。

3. 购买了Pro 5.06的一个License Fee后,您可以在一台服务器内启动多个Pro 5.06进程(端口号不同)。

4. 一旦您购买了Pro 5.06的License Fee,您将永远可以免费升级到更高的Pro版(而无论后者的License Fee是多少)。 

5. 如果您的系统需要在n台公网IP的服务器上运行Pro 5.06版,则您需要购买n个License Fee。

 

Q6-2 我想要支付UFO Pro版的License Fee,应该怎样支付呢?

1. 写mail到gm365365@sina.com信箱,在mail中告之UFO Pro运行所在的服务器的IP地址;

2. gm365公司回mail,告诉您我们的银行帐户;

3. 在我们确定收到您的Money后的24小时内,您将获得UFO Pro的License。

 

 

Q6-3 (在发布了收费的UFO Pro版后)以后免费的UFO普通版是不是不再发布了?

我公司在任何时候永远提供免费的UFO普通版。

 

 

Q6-4 相比于免费的普通版,收费的Pro版有哪些优势?就是我掏钱值不值。

1. Pro版的连接数不受限制,可以很大;而普通版的连接数最大只能为30000(即server.xml里的Connector标签的maxConnectionNum="30000")。

2. Pro版的UFO Probe能监测CPU;而普通版的UFO Probe不能监测CPU

3. Pro版用户的问题(写mail)在24小时内一定会得到回答;而普通版用户的问题很可能得不到回答,除非是发现了UFO的Bug。

4. 对Pro版用户,我公司对他的具体系统帮助给出系统构架、数据库、稳定性方面的真理解,这些帮助一般情况下是免费的;对普通版用户,无此帮助。

5. 对Pro版用户,一些情况下,我公司按照合同提供若干次免费上门服务。

6. 对Pro版用户,我公司提供阅读代码、查找错误的服务,当然这些服务可能要收取一定的费用;对普通版用户,无此服务。

 

 

===================================================================================

Servlet 3.0篇

===================================================================================

 

Q7-1 HttpServletRequestgetPart()getParts()方法实现文件上传,UFO是否支持?

支持。参见UFO发布的examples下的一个Servlet例子。

当然,UFO也支持以前的通过UFOUpload实现文件上传的做法。两种做法相比,无论从方便和性能等方面比较,没有大的差别,但以前的UFOUpload文件上传的做法,可以屏蔽掉一些明显错误的文件类型。(这个比较重要,例如,上传照片,不应该是.txt, .doc文件吧)

 

 

Q7-2 注解支持话题,在Servlet里通过"@WebServlet", "@WebInitParam", "@WebFilter", "@WebListener"等注解替代web.xml<Servlet>等标签的做法,UFO是否支持?

目前不支持。

通过注解来声明,比起web.xml里配置一大堆标签,的确省事轻松了许多。

但是这种做法的坏处也非常明显:

1. Web Server的启动速度慢了,启动时要把每个Servlet的.class文件打开,扫描分析一遍。

  2. Web Server要装进一堆注解分析的支持类,多消耗内存。

  3. 与<Servlet>标签声明的Servlet完全一样,用户的URL要对一堆url-pattern做匹配甚至*匹配,连静止态网页的下载也还是要这么白浪费CPUUFO提倡通过URL里的"/servlet/"字符串识别servlet的做法。(见<Q4-6>---<Q4-9>) 

 

 

Q7-3 可插性支持话题。将新增的Web模块打成JAR包放在WEB-INF/lib目录下,在JAR包的META-INF目录下,放置web-fragment.xml,而无需修改Contextweb.xml文件。这种做法,UFO是否支持?

 

目前不支持。

有这么开发网站的么,咱没见过。

 

 

Q7-4 Servlet的异步处理话题。当Servlet里如果有阻塞等待时间长(例如数据库操作、跨网络调用)的任务时,Servlet线程把请求转交给一个异步线程来执行业务处理,而调用自己的线程则返回,再去执行其它请求任务。UFO是否支持?

前面的3个Servlet 3.0的问题,都是可以用别的方法替代解决的,只是提供了另外一个选择,至多只是提供了方便,每个问题至多值50元钱,加起来也不过150元钱。

 

但是,这个话题所反映的问题价值几万至千万元。因为它可以将好几台Web Server的网站降为1-2台Web Server;将需要1000台Web Server的网站降为几台Web Server。

  

线程的开销是昂贵的,一个Web Server一般也就200个线程。无阻塞情况下,一个线程1s可以完成几百次请求响应,而象数据库操作、跨网络调用这样的阻塞等待时间一般在1s量级,有时是几分钟、几十分钟甚至更长时间。可见线程阻塞带来的负载能力损失时是很可观的,运气不好的时候,Web Server里的所有线程都处在阻塞等待状态,这样导致Web Server假死,网站瘫痪了。

 

 

Q7-5 接上面话题。大师,你好像并没有全部回答完问题,问题的点可能多了,现在接着分开了问:那么,你觉得当Servlet遇到可能有阻塞等待的任务时,就把任务交给另外一个自己启动的线程去干,而调用自己的线程则返回,继续去响应别的用户请求,这种解决办法可行吗?

我以为,这样根本没有解决问题,而且还设置了一个大陷阱:使自己的网站真正宕掉。

 

之所以“Servlet的异步处理”问题很有价值,是因为线程的开销昂贵,而且一个Web Server进程里能容许的线程数是有限的。把任务交给另外一个线程去干,并没有解决在阻塞等待时消耗线程的症结。而且,让用户自己去启动新的线程,很容易是Web Server进程里的线程数不可控,导致内存用光,Web Server真正宕掉。

 

让我给你讲一个类比:

 

你是一个公司的老板(Web Server),手下有200名员工(200个线程),你公司的业务是替客户到车站购买火车票。国庆节长要到了,要你公司购买火车票的客户很多,结果你的200员工都接到了任务,都到火车站的窗口排队买票了。国庆节前排队买票的人很多,结果你的员工都要排很长时间的队才能买到一张车票。你这下着急了:员工们都去排队了,这还接不接活了?

 

有一个高人(Servlet 3.0)看到了问题的严重程度,向你献策:你何不雇佣民工去火车站排队买票,而让员工继续接客户的活。

 

你一听,恩,好象这主意不错。你于是向你的员工下令:你们每个人接到客户的买票单子后,就自己去找一个民工(自己启动一个线程)替你到火车站去排队,民工的工资(内存开销)按时间由我支付。你们自己要不停去接客户的买票单子。

 

结果,你发现,民工的工钱一点也不便宜,你公司的买票单子接了很多,民工也请了很多。最后你付不起工资(内存爆了),你公司破产了(Web Server宕了)。

 

 

Q7-6  接上面话题。那UFO对这个Servlet阻塞问题是否有好的解决办法?

对于上面的类比,UFO的办法是:你去新招一名办事效率高的员工(优先级最高的线程)去窗口排队,你公司200名员工接的所有客户的买票单子都交给他去排队买票。

 

UFO的“Servlet异步处理支持”的类都放在了javax.ufo.async目录下。

 

你的需要做异步处理的Servlet该如何做呢?你一共要做2件事情:

 

. 把你的Servlet写上implements UFOTask, 并把原先service()方法里的东东,全部原封不动挪到go()方法里。

 

. 在service()里写4行代码:

 

        1. 取出UFO Web Server的UFOThread: 

           

           UFOThread worker=UFO.getUFOThread("TomFee");  

     

        2. 取出HttpServletRequest的AsyncContext:

 

           final AsyncContext actx=request.startAsync();

 

        3. 创建一个UFOTaskEntry:

 

           UFOTaskEntry myTask=new UFOTaskEntry(this, actx, request, response);

 

        4. 把这个UFOTaskEntry加到UFOThread的队列里:

 

           worker.addQueTask(myTask);

 

这个名叫"TomFee"的UFOThread是在/conf/server.xml里配置的:

 

    <UFOThread name="TomFee" queSize="5" />

 

更精确的描述请见UFO发布的examples里的Servlet例子。

 

 

Q7-7  接上面话题。恩,UFO的异步方法好象解决了Servlet的阻塞问题,我基本懂了,感觉七窍通了六窍,但是还是有一窍不通:UFO把因为同一把锁而阻塞的所有Servlet任务都交给一个线程依次处理,的确是解决这个阻塞问题。但是,要知道,向用户输出网页内容时,每个用户的网络状况是不一样的,有快有慢,排在后面的网速快的用户岂不是因为前面网速慢的用户而大受影响?

的确是有这个问题。但是你知道,Servlet里输出其实是输出到Web Server的缓存里,并不是真正向用户端输出。UFO Web Server在每个异步Servlet输出完成后,会用另外一个线程来向用户端输出。

 

 

Q7-8  接上面话题。恩,UFO的异步Servlet办法真是一个完美的办法,我试试。先编译下UFO发布的examples里的AsyncHelloUFO例子,但是编译不通过,这个.java里有

      import javax.ufo.async.*;

      import core.UFO;

 

      找不到它们。

 

javax.ufo包在/lib/javax-ufo.zip里,core.UFO类在/bin/core.jar里。请设置classpath。

 

 

Q7-9 接上面话题。jsp好象没异步机制,jsp编译成的servlet好象没有办法做异步处理,我是否也要把那些在jsp里有阻塞等待(数据库访问、现场创建Socket连接)的jsp都改用异步Servlet来做?

是的,jsp没有异步机制。

 

www.gm365.com的登陆和注册就是在jsp里连数据库的,我们准备把那两个jsp改成异步Servlet。

 

不过,目前www.gm365.com访问量不大,在jsp里阻塞等待对网站影响不大。但是作为一个技术上的完全的解决方案,要改!(你总是要假设网站有一天会火爆的吧)。

 

 

 

===================================================================================

WebSocket篇

==================================================================================

 

Q8-1  什么是WebSocket? 它与普通的Socket在开发联网应用方面有什么差别?

WebSocket就是建立在Web Server里的Socket

 

普通的Socket联网的时候,是这么做的:

    Socket sk=new Socket("www.gm365.com", 3950);        

    OutputStream ou=sk.getOutputStream();

    InputStream in=sk.getInputStream();

 

这样您就可以利用这个Socket干活了,进行收发数据。

 

WebSocket联网的时候,是这么做的:

    Socket sk=new Socket("www.gm365.com", 80);        

    OutputStream ou=sk.getOutputStream();

    

    String uri="/examples/websocket/CS/mine";

    ou.write(("GET "+uri+" HTTP/1.1\r\n\r\n").getBytes());

    ou.flush();

 

    InputStream in=sk.getInputStream();  

    NetTool.skipHttpHeaders(in);

 

之后,您就可以利用这个Socket干活了,进行收发数据。就与普通的Socket无任何差别了。

可以看出,WebSocket建立后,要先告诉服务器,您是请求哪个Servlet服务;然后打开InputStream后,利用javax.ufo.ws.NetTool跳过Http头。之后,就可以象一个普通的Socket那样使用了。

关于本话题,请参见UFO Web Server发布的examples这个Context里的websocket例子。

 

 

Q8-2 WebSocket是干什么用的?什么是BS模式的WebSocketCS模式的WebSocket? 

WebSocket是为了解决以前浏览器端对Web Server的长连接太消耗Web Server的资源而推出的。

关于BS模式和CS模式的话题,我不知道是否这是个公认的说法,反正UFO Web Server采用了这种说法。

 

对于浏览器连接到Web Server的Socket,称为BS模式的Socket。

对于应用程序连接到Web Server的Socket,称为CS模式的Socket。

 

两种模式的WebSocket在处理上其实没太大的差别,只是BS模式的WebSocket对Http头检查严格些。

 

 

  Q8-3 在web.xml里配置WebSocket的Servlet与配置普通的Servlet有没有不同?

无论是BS模式WebSocket的Servlet还是CS模式WebSocket的Servlet,在web.xml里配置起来与普通的Servlet没有任何差别。

支持BS模式WebSocket的Servlet要且必须要extends javax.ufo.ws.BWSServlet;支持CS模式WebSocket的Servlet要且必须要extends javax.ufo.ws.CWSServlet。UFO Web Server通过识别一个Servlet的父类是否是javax.ufo.ws.BWSServlet或javax.ufo.ws.CWSServlet,来将它确定为支持WebSocket的Servlet。

 

 

Q8-4 对于浏览器的长连接,采用WebSocket,这个好理解。但是对于网游等联网应用,您为什么也推荐使用WebSocket,这听起来有点搞笑,很明显,对于这些联网应用,普通的Socket更好,更灵活。您不要误导我们。

先替你更正下:是推荐你采用UFO Web Server的WebSocket开发网游等联网应用。

 

虽然其它Web Server也支持WebSocket,但它们能否提供好的性能、是否适合开发网游等联网应用,我们没研究过。

 

UFO Web Server开发网游等联网应用,有2大好处:

 

  1. 负载很高。比您采用普通的Socket(尽管采用NIO)不做技术性的处理所开发出来的应用Server的负载高出至少100倍应该不成问题。      

  2. 服务器体系稳定运行。这种稳定性除了UFO本身很稳定外,还在于在适当的条件下,我公司还为您提供阅读代码服务,为您精准地找出解决您的Servlet里影响稳定性的代码和做法。(本点参见后面相关话题)。

 

 

Q8-5 负载话题我很感兴趣,这涉及到运行成本,钱啊。请问一台服务器能带多少人同时在线?

恩。1年前,被一个曾在多家知名IT公司做过云计算的资深老总问及这个问题。当时,我对这个问题其实很清楚,但是,这个问题却不能用几句话回答清楚,因为一台服务器能带多少人同时在线要取决于多个条件,所以当时我只能吱吱吾吾地回答。

 

    1. 对于视频播放这种很占带宽的应用,带宽是瓶颈,对于这种应用,一台服务器应该是支持不了多少人同时在线。这种应用的服务器负载情况应该是:(平均)一个用户所占带宽有多小,服务器负载就能有多大。

 

    2. 对于那些很消耗CPU的应用,例如,一些集中处理的计算,CPU是瓶颈,对于这种应用,(平均)一个用户所占CPU有多小,服务器负载就能有多大。

      

    以上2种应用,探讨服务的负载问题几乎没什么意义,因为用户所占的带宽、CPU,你几乎无法改变。

 

    但是对于90%的其它情形,用户访问服务器所占用的带宽和CPU其实是很微小的。典型地,对于我们平时访问网站这种情况,表面上看每张网页、图片体积很大,但是用户只是在第1次访问这个网页、图片时,服务器才把整个文件传送给Client,以后当该用户再次访问时,服务器只发送一个"304 Not Modified"的Http头,不过100个左右的Byte,让Client端从自己的缓存里取。因此,对于我们平时访问网站这种情况,服务器的负载其实可能做得很大。

 

    而对于网游等应用,一般的消息只有1-几十个Byte,而且2次消息之间往往间隔几秒-几十秒,对于服务器来说,这是极轻、极稀疏的任务。就是说,从带宽和CPU的因素看,一台服务器估计都可能可以满足全球的人同时访问了。

 

    但是,还有其它不少因素制约着服务器的负载能力,例如:没那么多线程、阻塞、内存不够等。对这些因素的处理就决定了服务器的负载能力,处理的技术水平不一样,服务器的负载能力就大不一样。

 

    因此,如果您问我“一台服务器能带多少人同时在线?”,我没法回答您。您或许应该问:就这个应用,你来做服务器,一台服务器能带多少人同时在线?

 

 

Q8-6 UFO发布里有一个喀秋莎-联网扫雷,是采用UFOWebSocket开发的,我如果拿一台普通的PC服务器来运行它,请问,能带多少人同时在线?

一台普通的PC服务器应该至少能带1百万人同时在线。

 

 

Q8-7 百万?好象很大,对不起,我不是搞技术的,您能给我讲讲单台服务器1百万人同时在线是个什么概念?

www.gm365.com的早期的联网游戏是采用普通的Socket的BIO方式开发的,BIO方式下服务端的每一个Socket都要采用一个线程来监视(有没有数据到来),当一台PC服务器达到300多人同时在线时,服务器的CPU峰值经常在10%以上,服务器反应迟钝。

 

因此采用BIO方式的Socket开发的一台PC网游服务器负载也就是300-500人同时在线。其原因是一台计算机只能有1000个左右的线程,线程多了,线程本身调度的开销很大。

 

后来,www.gm365.com的联网游戏采用NIO方式的Socket开发,NIO方式下,服务器采用一个线程监视所有的Socket(是否有数据到来)。负载能力明显提高,从CPU峰值推算,一台PC网游服务器负载应该3000-5000人同时在线。

 

但是,(在采用NIO后)还有其它的瓶颈在制约着负载能力,负载能力还可以大幅度提高。

 

UFO的WebSocket正是这些实践的成果。UFO的WebSocket解决了NIO以外的瓶颈问题。

 

采用UFO的WebSocket开发的网游等联网应用,单台PC Server的负载能力,可以这么算:(平均)一个用户所占用的服务器内存有多小,服务器的负载就有多大。

 

UFO发布里自带的“喀秋莎-联网扫雷”的一个在线用户占用的服务器内存是3K(平均),现在一台普通的PC服务器内存是32G,这样单台普通的服务器运行这个联网扫雷,能支持的同时在线用户应该在1千万人。但是,这毕竟没有实践测试过(没有那么多用户),可能随着实际运行的同时在线用户数的增加还可能会出现新的问题和瓶颈。所以,目前也只有保守地说,“至少能带1百万人同时在线”。

 

但是,可以肯定的是,在保证响应速度、稳定性的前提下,UFO发布里自带的“喀秋莎-联网扫雷”是最大负载能力的设计。

 

 

Q8-8 我有一个疑问:用WebSocket开发?用UFO Web Server做网游的服务器?我的网游用户体验是第1位的,要时刻保持优良的响应速度,我要把的网游服务器程序放到一个单独的服务器里,而UFO Web Server好象不行,当用户访问网页时,对网游用户有影响。

UFO Web Server的/conf/server.xml里<Connector>标签有一个protocols属性,把它写成这样:

 

    protocols="ws"  

 

UFO Web Server就不支持普通的http协议(但支持创建WebSocket的http协议),这样您的UFO Web Server就不支持用户的网页访问,是一个纯粹的网游服务器了。

 

 

Q8-9 我还有一个问题:好象UFO Web Server的网络部分不够底层,做程序调试起来好象比较费劲。我的意思是:如果我直接采用ServerSocket开发时,我可以方便地使用SelectionKeyisAcceptable(), isReadable()等方法知道是否有新Socket连接,是否有新的数据来了。WebSocket在这些方面好象不方面。

其实采用WebSocket开发与采用普通的Socket开发,在接近网络底层方面是完全一样的。

 

当有新Socket连接来了时,WSProcessor的onOpen(WSClient client)方法被立即调用;

当有新的数据来了时,WSProcessor的onData(WSClient client, byte[] bs)方法立即调用;

如果您想关掉Socket,可以执行WSEndpoint的close(WSClient aclient)方法;

如果您想知道,Socket对端的IP,可以执行WSEndpoint的getRemoteSocketAddress(WSClient aclient)方法;

......

等等。

 

 

Q8-10 我还有一个问题:我把/conf/server.xml<Connector>标签的protocols属性设置成"ws",把UFO Web Server当一个纯粹的应用服务器使用,那些网站访问方面的功能全部不要了,但是,那些其实没用类却都装进内存,这不浪费吗?

 

没多少,绝对没有超过1M。

  

           

Q8-11 基于UFO Web ServerCS模式的WebSocket开发联网应用,有什么成功案例吗?

UFO发布里自带的“喀秋莎-联网扫雷”网游不够标准吗?设计不够先进吗?运行起来有问题吗?

 

另外,www.gm365.com今后的联网游戏以及其它要求高负载的联网应用都采用UFO的WebSocket开发。对于以前有的联网游戏,除了两款已经发布了足够多的手机客户端以外,全部都采用UFO的WebSocket重写。

 

 

Q8-12 UFO发布里带有哪些WebSocket的例子?在哪里?

examples这个Context里有个websocket子目录,UFO的websocket例子都在里面。其中BS子目录有3个例子,借用了Tomcat的例子,演示了BS模式的WebSocket;其中的CS子目录,有4个例子,演示了CS模式的WebSocket。

 

CS模式的hello和many例子,以最简单的方式演示了如何创建UFO的CS模式的WebSocket;TTChat这个例子初步演示了如何利用UFO的CS模式的WebSocket进行联网应用开发;mine这个例子,即“喀秋莎-联网扫雷”,是一个完整的最先进的负载能力最大化设计的利用UFO的CS模式的WebSocket进行联网应用开发的例子,也是我公司未来联网游戏的构架。

 

 

Q8-13 我想阅读喀秋莎-联网扫雷的源代码,但是服务端和客户端的代码加起来不少,有万行左右,有点吃力,你能否在这方面给点帮助?

你先要搞明白大的业务逻辑和大的程序逻辑。

 

    1. 这个联网游戏假定了一台服务器能带1百万人甚至更多的同时在线,(而每个玩区只有300人),这是个最大的

    逻辑。

 

    2. 这个联网游戏在设计上保证用户在任何时候都能登录服务器玩游戏。

 

即使服务器程序写得再稳定,但是由于服务器硬件坏了或机房出事等不可抗力的原因,假定服务器不宕是错误的。

 

这个游戏采用2个(或更多)游戏总站Servlet和2个(或更多)游戏Servlet的方案,保证用户在任何时候得到服务。游戏总站Servlet的IP(采用域名), port和uri固定地放在client端,用户登录发现一个总站连不通,就连到另外一个总站,只有那些总站同时都宕了,用户才无法登陆服务器。

 

但是,细心的技术人员会发现:这个联网游戏还是没做到在任何时候,用户都能登陆,因数据库只有一个服务器,当这个数据库服务器宕了时,用户无法登陆玩游戏了。

 

这的确是个问题。目前,gm365的现役服务器体系也没做到双数据库服务器随时使用(这可能是个技术难点,容易造成数据不一致)。目前,gm365的现役服务器体系是采用双数据库运行,其中一个做热倍份。

 

这个游戏的游戏总站Servlet在examples这个Context下的\WEB-INF\classes\websocket\CS\mine\zz里,总站Servlet可以运行在1个或多个服务器上,它负责用户的登陆和注册。

 

这个游戏的游戏Servlet在examples这个Context下的\WEB-INF\classes\websocket\CS\mine里,这个Servlet也可以运行在1个或多个服务器上,它是用户玩游戏的服务器程序。每个Servlet实例里有m个站点*n个玩区,每个玩区能容纳300人。每个Servlet的站点在总站里的编号是靠onum这个成员变量来确定的。

 

 

Q8-14 在一个Servlet实例部署m*n个玩区,有点意思,这有点象一种排炮,它叫什么来着?

在第二次世界大战的关键的苏德战争的相持时期,苏联发明了一种“喀秋莎”火箭炮,它一次能发射2x8枚炮弹,火力密集;它载于卡车或坦克上,机动灵活。“喀秋莎”火箭炮为苏联打赢苏德战争发挥了重要作用。

 

本联网扫雷游戏“车载”于UFO Web Server,一个Servlet带m*n玩区,只要服务器内存够用,可以布置任意多,因此把这个游戏取名为“喀秋莎-联网扫雷”。

 

 Q8-15 UFO发布的examples里,CS模式的WebSocket HelloCS.java在联网时,是这样的:

 

      ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

      ou.write(("Host: localhost\r\n\r\n").getBytes());

 

     请问,这里的Host是什么意思?

 

如果您在conf/server.xml里配置了多个"Host"标签,也即多个虚拟主机,在CS模式的WebSocket联网时,需要填写"Host"的http头,否则,UFO就可能找不到正确的servlet。

 

这个"Host"的http头的值是conf/server.xml里配置了多个"Host"标签的"name"的值或Alias. 例如,假设您的conf/server.xml的配置是这样的:

 

   

    <Host appBase="webapps" name="www.gm365.com">     

       <Alias>gm365.com</Alias>

       <Alias>222.73.205.120</Alias>     

       <Alias>localhost</Alias>

       <Alias>127.0.0.1</Alias>      

        

       <!--

       <welcome-file>index.html</welcome-file>

       -->    

 

       <Context path="/examples" docBase="webapps/examples" > 

       </Context>

 

       <Context path="/struts2_demo" docBase="webapps/struts2_demo" > 

       </Context>  

 

       <Context path="" docBase="webapps/ROOT" >

       </Context>

       

    </Host>

 

   那么,HelloCS.java在联网时,写成:

 

    ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

    ou.write(("Host: www.gm365.com\r\n\r\n").getBytes());                    

       

    或:

    ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

    ou.write(("Host: gm365.com\r\n\r\n").getBytes());  

 

    或:

    ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

    ou.write(("Host: 222.73.205.120\r\n\r\n").getBytes()); 

 

    或: 

    ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

    ou.write(("Host: localhost\r\n\r\n").getBytes()); 

 

    或: 

    ou.write(("GET /examples/websocket/CS/hello HTTP/1.1\r\n").getBytes());

    ou.write(("Host: 127.0.0.1\r\n\r\n").getBytes()); 

 

    都是正确的。