??xml version="1.0" encoding="utf-8" standalone="yes"?> Java version 1.6.0_13 Direct access using member field: Java version 1.6.0_13 Direct call using member field: Java version 1.6.0_13 Direct Object creation: Java version 1.6.0_13 Direct access using member field: Java version 1.6.0_13 Direct call using member field: Java version 1.6.0_13 Direct Object creation:
PermGen是指内存的永久保存区域,它用于存放class?method 对象Q以及String 对象
Qsun原文Qpermanent generation is the area of the heap where class and method objects are stored. If an application loads a very large number of classes, then the size of the permanent generation might need to be increased using the -XX:MaxPermSize option.
回到我的问题来,打开%java_home%bin\jvisualvm.exe (jdk6以上?
查看tomcat的内存情况,点击tomcat标签下monitor , 当used heap = max heap used PermGen = max PermGen 时tomcatq在启动中,一会就报错Q?br />׃此前已经myeclipse中server->tomcat->tomcatx.x->jdk的参数设|成-Xms64m -Xmx512m -XX:MaxPermSize=80m
但是monitor 画面中max heap?256M
点击overview标签,发现jvm参数如下Q?br />-Xms64m
-Xmx512m
-XX:MaxPermSize=80m
-Xms64m
-Xmx256m
昄tomcat使用了最后的讄-Xms64m -Xmx256mQ这个是在myeclipse的属?》java->installed jres 中的vm启动参数里,双击默认启用的jreQ把参数L或者设|成-Xms64m -Xmx512m
再回到server->tomcat->tomcatx.x->jdk中把-XX:MaxPermSize=80m修改?XX:MaxPermSize=128m
保存后再启动tomcatQok
另外Q用jvisualvm持箋监测tomcat内存情况发现heap区域的内存用会在一个高峰后E_降低Q内存被回收了;
而PermGen区域的内存则是不断增加到达一个峰值后׃再增加,但之后此区的内存没有被回Ӟ验证了上面的说法Q?br />
多说两句Qjava的动态加载衍生出诸多框架Q在I间上也暴露出问题,反射在时间上也存在效率问题:下面是组试数据Q?br />
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
47 125 47 46 46
average time = 66 ms.
Reference access to member field:
109 109 110 94 109
average time = 106 ms.
Reflection access to member field:
13094 12984 13063 13062 13094
average time = 13051 ms.
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
47 31 109 109 31
average time = 70 ms.
Direct call using passed value:
16 16 16 31 15
average time = 20 ms.
Call to object using member field:
46 47 47 47 32
average time = 43 ms.
Call to object using passed value:
15 16 31 16 16
average time = 20 ms.
Reflection call using member field:
812 782 844 844 844
average time = 829 ms.
Reflection call using passed value:
938 953 954 1031 953
average time = 973 ms.
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
62 47 78 32 93
average time = 63 ms.
Reflection Object creation:
125 94 94 109 187
average time = 121 ms.
Direct byte[8] creation:
125 187 94 172 94
average time = 137 ms.
Reflection byte[8] creation:
266 171 187 188 219
average time = 191 ms.
Direct byte[64] creation:
250 172 156 125 203
average time = 164 ms.
Reflection byte[64] creation:
281 219 203 203 219
average time = 211 ms.
http://wiki.apache.org/tomcat/FAQ/Deployment
http://download.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/memleaks.html#gbyuu
]]>
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
47 125 47 46 46
average time = 66 ms.
Reference access to member field:
109 109 110 94 109
average time = 106 ms.
Reflection access to member field:
13094 12984 13063 13062 13094
average time = 13051 ms.
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
47 31 109 109 31
average time = 70 ms.
Direct call using passed value:
16 16 16 31 15
average time = 20 ms.
Call to object using member field:
46 47 47 47 32
average time = 43 ms.
Call to object using passed value:
15 16 31 16 16
average time = 20 ms.
Reflection call using member field:
812 782 844 844 844
average time = 829 ms.
Reflection call using passed value:
938 953 954 1031 953
average time = 973 ms.
Java HotSpot(TM) Client VM
11.3-b02
Sun Microsystems Inc.
62 47 78 32 93
average time = 63 ms.
Reflection Object creation:
125 94 94 109 187
average time = 121 ms.
Direct byte[8] creation:
125 187 94 172 94
average time = 137 ms.
Reflection byte[8] creation:
266 171 187 188 219
average time = 191 ms.
Direct byte[64] creation:
250 172 156 125 203
average time = 164 ms.
Reflection byte[64] creation:
281 219 203 203 219
average time = 211 ms.
]]>
wtp(web tools platform )目在eclipseq_上进行扩展,是一个开发j2ee web应用E序的工具集。wtp包含以下工具Q?/p>
* 一个源码编辑器www.ssbbww.com用来~辑html, javascript, css, jsp, sql, xml, dtd, xsd, 和wsdl?/p>
* 一个图形编辑器用来~辑xsd与wsdl?/p>
* j2ee目构徏器和一个j2ee向导工具?/p>
* 一个web服务创徏向导和管理器Q和ws-i 试工具?/p>
* 一个数据库讉KQ查询工L?/p>
wtp׃个子目构成:wst(web标准工具? 与jst(j2ee标准工具?8ttt8 wtp是什么意?是什么东西_什么叫-什么是wtp
wtp支付愿意原则Q用于分析社会成员ؓ目所产出的效益愿意支付的价倹{?/p>
2.安装及工E创建发布:eclipse for java ee 里已l安装wtp,so不用׃动手Qeclipse l典版安装wtp?
工程的创建及发布
见【传送门】:http://www.vogella.de/articles/EclipseWTP/article.html
3.wtp{疑见【传送门?a >http://wiki.eclipse.org/WTP_Tomcat_FAQ
4.接着创徏一个xfire webservice
q样"试".getBytes("gb2312")变成一个byte数组Q这时候你可以随意重新指定~码如iso-8859-1,
String s1=new String("试".getBytes("gb2312"),"iso-8859-1");
~ؓs1,q是s1变成一个是iso-8859-1~码的字W串Q如果你想重新{Z文,那么Q你用什么字W集~码的,必须用什么字W集来解码,q里是iso-8859-1,
可以q么来做
String s2 = new String(s1.getBytes("ISO-8859-1"),"gb2312");
q样s2又重新变回中文了Q所以当你打印s2Ӟ是“试”?br />
2.用iso-8859-1做中间编码,原因Q?br /> [1]iso-8859-1是单字节字符~码Q?br /> [2]ANSI ~码 (如:GB2312, BIG5,Shift_JIS,ISO-8859-2{等Q,是多字节~码Q英文单字节Q中文多字节Q;
[3]UNICODE ~码QUTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig....Q?是宽字节~码Q所有字W均是多字节Q?br /> 因此用iso-8859-1做中间码Q会保持原有字节的秩序,不发生乱;可以理解为其他的~码对iso-8859-1兼容吧?br />
因此Q我们常怋?bytes = string.getBytes("iso-8859-1") 坐中间码来进行逆向操作Q得到原始的“字节?#8221;。然后再使用正确?br /> ANSI ~码Q比?string = new String(bytes, "GB2312")Q来得到正确?#8220;UNICODE 字符?#8221;?br />
不信的话可以试试Qutf8和gb不能互相转换Q只有iso-8859-1做中间码可以完美互相转码Q!Q?br />
/**
* 用于的 Browser 不缓存页面的qo?br />
*/
public class ForceNoCacheFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
((HttpServletResponse) response).setHeader("Cache-Control","no-cache");
((HttpServletResponse) response).setHeader("Pragma","no-cache");
((HttpServletResponse) response).setDateHeader ("Expires", -1);
filterChain.doFilter(request, response);
}
public void destroy()
{
}
public void init(FilterConfig filterConfig) throws ServletException
{
}
}
二、检用h否登陆的qo?/p>
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.IOException;
/**
* 用于用h否登陆的qo器,如果未登录,则重定向到指的登录页?lt;p>
* 配置参数<p>
* checkSessionKey 需查的?Session 中保存的关键?lt;br/>
* redirectURL 如果用户未登录,则重定向到指定的面QURL不包?ContextPath<br/>
* notCheckURLList 不做查的URL列表Q以分号分开Qƈ?URL 中不包括 ContextPath<br/>
*/
public class CheckLoginFilter
implements Filter
{
protected FilterConfig filterConfig = null;
private String redirectURL = null;
private List notCheckURLList = new ArrayList();
private String sessionKey = null;
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
if(sessionKey == null)
{
filterChain.doFilter(request, response);
return;
}
if((!checkRequestURIIntNotFilterList(request)) && session.getAttribute(sessionKey) == null)
{
response.sendRedirect(request.getContextPath() + redirectURL);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy()
{
notCheckURLList.clear();
}
private boolean checkRequestURIIntNotFilterList(HttpServletRequest request)
{
String uri = request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo());
return notCheckURLList.contains(uri);
}
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
redirectURL = filterConfig.getInitParameter("redirectURL");
sessionKey = filterConfig.getInitParameter("checkSessionKey");
String notCheckURLListStr = filterConfig.getInitParameter("notCheckURLList");
if(notCheckURLListStr != null)
{
StringTokenizer st = new StringTokenizer(notCheckURLListStr, ";");
notCheckURLList.clear();
while(st.hasMoreTokens())
{
notCheckURLList.add(st.nextToken());
}
}
}
}
三、字W编码的qo?/p>
import javax.servlet.*;
import java.io.IOException;
/**
* 用于讄 HTTP h字符~码的过滤器Q通过qo器参数encoding指明使用何种字符~码,用于处理Html Formh参数的中文问?br />
*/
public class CharacterEncodingFilter
implements Filter
{
protected FilterConfig filterConfig = null;
protected String encoding = "";
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
if(encoding != null)
servletRequest.setCharacterEncoding(encoding);
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy()
{
filterConfig = null;
encoding = null;
}
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
}
}
四、资源保护过滤器
package catalog.view.util; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Iterator; import java.util.Set; import java.util.HashSet; // import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This Filter class handle the security of the application. ** It should be configured inside the web.xml. * * @author Derek Y. Shen */ public class SecurityFilter implements Filter { //the login page uri private static final String LOGIN_PAGE_URI = "login.jsf"; //the logger object private Log logger = LogFactory.getLog(this.getClass()); //a set of restricted resources private Set restrictedResources; /** * Initializes the Filter. */ public void init(FilterConfig filterConfig) throws ServletException { this.restrictedResources = new HashSet(); this.restrictedResources.add("/createProduct.jsf"); this.restrictedResources.add("/editProduct.jsf"); this.restrictedResources.add("/productList.jsf"); } /** * Standard doFilter object. */ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { this.logger.debug("doFilter"); String contextPath = ((HttpServletRequest)req).getContextPath(); String requestUri = ((HttpServletRequest)req).getRequestURI(); this.logger.debug("contextPath = " + contextPath); this.logger.debug("requestUri = " + requestUri); if (this.contains(requestUri, contextPath) && !this.authorize((HttpServletRequest)req)) { this.logger.debug("authorization failed"); ((HttpServletRequest)req).getRequestDispatcher(LOGIN_PAGE_URI).forward(req, res); } else { this.logger.debug("authorization succeeded"); chain.doFilter(req, res); } } public void destroy() {} private boolean contains(String value, String contextPath) { Iterator ite = this.restrictedResources.iterator(); while (ite.hasNext()) { String restrictedResource = (String)ite.next(); if ((contextPath + restrictedResource).equalsIgnoreCase(value)) { return true; } } return false; } private boolean authorize(HttpServletRequest req) { //处理用户d /* UserBean user = (UserBean)req.getSession().getAttribute(BeanNames.USER_BEAN); if (user != null && user.getLoggedIn()) { //user logged in return true; } else { return false; }*/ } }
双重查锁定及单例模式全面理解q一失效的编E习?/em> ![]() |
![]() |
![]() |
U别Q?中 Peter Haggar, 高软g工程? IBM 2004 q?5 ?01 ?/p> 所有的~程语言都有一些共用的习语。了解和使用一些习语很有用Q程序员们花费宝늚旉来创建、学习和实现q些习语。问题是Q稍后经q证明,一些习语ƈ不完全如其所声称的那P或者仅仅是与描q的功能不符。在 Java ~程语言中,双重查锁定就是这L一个绝不应该用的习语。在本文中,Peter Haggar 介绍了双重检查锁定习语的渊源Q开发它的原因和它失效的原因? ~辑?/strong>Q本文在针对 Java 5.0 修订前参考了 Java 内存模型Q关于内存排序的描述也许不再正确。尽如此,在新的内存模型中Q双重检查锁定习语仍旧是无效的?/em> 单例创徏模式是一个通用的编E习语。和多线E一起用时Q必需使用某种cd的同步。在努力创徏更有效的代码ӞJava E序员们创徏了双重检查锁定习语,其和单例创建模式一起用,从而限制同步代码量。然而,׃一些不太常见的 Java 内存模型l节的原因,q不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是d败。此外,它失败的原因q不明显Q还包含 Java 内存模型的一些隐U细节。这些事实将D代码p|Q原因是双重查锁定难于跟t。在本文余下的部分里Q我们将详细介绍双重查锁定习语,从而理解它在何处失效?/p> 要理解双重检查锁定习语是从哪里v源的Q就必须理解通用单例创徏习语Q如清单 1 中的阐释Q?/p>
此类的设计确保只创徏一?
l果? 清单 2. U程安全?getInstance() Ҏ
清单 2 中的代码针对多线E访? Z此方法更为有效,一个被UCؓ双重查锁定的习语应q而生了。这个想法是Z避免寚wW一ơ调用外的所有调用都实行同步的昂贵代仗同步的代h在不同的 JVM 间是不同的。在早期Q代L当高。随着更高U的 JVM 的出玎ͼ同步的代价降低了Q但出入 因ؓ只有清单 2 中的 //2 行需要同步,我们可以只将其包装到一个同步块中,如清?3 所C: 清单 3. getInstance() Ҏ
清单 3 中的代码展示了用多线E加以说明的和清?1 相同的问题。当
为处理清?3 中的问题Q我们需要对 清单 4. 双重查锁定示?/strong>
双重查锁定背后的理论是:?//2 处的W二ơ检查Q如清单 3 中那P创徏两个不同?
双重查锁定背后的理论是完的。不q地是,现实完全不同。双重检查锁定的问题是:q不能保证它会在单处理器或多处理器计机上顺利运行?/p> 双重查锁定失败的问题q不归咎?JVM 中的实现 bugQ而是归咎?Java q_内存模型。内存模型允许所谓的“无序写入”Q这也是q些习语p|的一个主要原因?/p>
释该问题Q需要重新考察上述清单 4 中的 //3 行。此行代码创Z一? 什么?q一说法可能让您始料未及Q但事实实如此。在解释q个现象如何发生前,请先暂时接受q一事实Q我们先来考察一下双重检查锁定是如何被破坏的。假设清?4 中代码执行以下事件序列:
此事件序列发生在U程 2 q回一个尚未执行构造函数的对象的时候?/p> 为展C此事g的发生情况,假设Z码行
q段伪代码不仅是可能的,而且是一?JIT ~译器上真实发生的。执行的序是颠倒的Q但鉴于当前的内存模型,q也是允许发生的。JIT ~译器的q一行ؓ使双重检查锁定的问题只不q是一ơ学术实践而已?/p> 明这一情况Q假设有清单 5 中的代码。它包含一个剥ȝ? 清单 5. 用于演示无序写入的单例类
清单 6 包含?Sun JDK 1.2.1 JIT ~译器ؓ清单 5 中的 清单 6. 由清?5 中的代码生成的汇~代?/strong>
? 为引用下列说明中的汇~代码行Q我引用指令地址的最后两个|因ؓ它们都以 汇编代码是通过q行一个在无限循环中调?
不是所有的 JIT ~译器都生成如上代码。一些生成了代码Q从而只在构造函数执行后?
考虑到当前的双重查锁定不起作用,我加入了另一个版本的代码Q如清单 7 所C,从而防止您刚才看到的无序写入问题? 清单 7. 解决无序写入问题的尝?/strong>
看着清单 7 中的代码Q您应该意识C情变得有点荒谬。请CQ创建双重检查锁定是Z避免对简单的三行 此代码试N免无序写入问题。它试图通过引入局部变?
q里的关键行?//5。此行应该确? ׃当前内存模型的定义,清单 7 中的代码无效。Java 语言规范QJava Language SpecificationQJLSQ要求不能将 JIT ~译器会在这里看C个优化的Z。此优化会删?//4 ?//5 处的代码Q组合ƈ且生成清?8 中所C的代码? 清单 8. 从清?7 中优化来的代码?/strong>
如果q行此项优化Q您同样遇到我们之前讨的无序写入问题?/p>
另一个想法是针对变量 W二点值得展开讨论。假设有清单 9 中的代码Q?/p>
Ҏ JLSQ由?
底线是Q无Z何种形式Q都不应使用双重查锁定,因ؓ您不能保证它在Q?JVM 实现上都能顺利运行。JSR-133 是有兛_存模型寻址问题的,管如此Q新的内存模型也不会支持双重查锁定。因此,您有两种选择Q?/p>
选择?2 如清?10 中所C?/p>
清单 10 的代码没有用同步,q且保调用
鉴于无序写入和引用在构造函数执行前变成?
此代码在 //4 处创Z? 在旧版的 JVM ?Sun JDK 1.2.1 上运行此代码会导致无序写入问题。ƈ因此D一个非不变?
为避免单例中代h高昂的同步,E序员非常聪明地发明了双重检查锁定习语。不q的是,鉴于当前的内存模型的原因Q该习语未得到q泛使用Q就明显成ؓ了一U不安全的编E结构。重定义脆弱的内存模型这一领域的工作正在进行中。尽如此,即是在新提议的内存模型中,双重查锁定也是无效的。对此问题最佳的解决Ҏ是接受同步或者用一? |
来源Qhttp://blog.ednchina.com/qinyonglyz/194674/message.aspx
1Q故事的h
“endian”q个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开q是从小?Little-Endian)敲开Q由此曾发生q六ơ叛乱,其中一个皇帝送了命,另一个丢了王位?/p>
我们一般将endian译?#8220;字节?#8221;Q将big endian和little endianUC“大尾”?#8220;尾”?/p>
2Q什么是Big Endian和Little EndianQ?/strong>
在设计计机pȝ的时候,有两U处理内存中数据的方法。一U叫为little-endianQ存攑֜内存中最低位的数值是来自数据的最双部分Q也是数据的最低位部分Q。比如一?6q制数字0x12345678Q在内存存放的方式如下:
?/p> |
0111Q?000 |
0101Q?110 |
0011Q?100 |
0001Q?010 |
地址 |
100 |
101 |
102 |
103 |
另一U称为big-endianQ正好相反,存放在内存中最低位的数值是来自数据的最左边辚w分(也就是数据的最高ؓ部分Q。比如一?6q制数字0x12345678Q在内存存放的方式如下:
?/p> |
0001Q?010 |
0011Q?100 |
0101Q?110 |
0111Q?000 |
地址 |
100 |
101 |
102 |
103 |
比如某些文g需要在不同q_处理Q或者通过Socket通信。这斚w我们可以借助ntohl(), ntohs(), htonl(), and htons()函数q行格式转换?/p>
3Q如何判断系l是Big Endianq是Little EndianQ?/strong>
?usr/include/中(包括子目录)查找字符串BYTE_ORDER(或_BYTE_ORDER, __BYTE_ORDER)Q确定其倹{这个g般在endian.h或machine/endian.h文g中可以找?有时在feature.h中,不同?a onclick="javascript:tagshow(event, '%B2%D9%D7%F7%CF%B5%CD%B3');" href="javascript:;" target="_self">操作pȝ可能有所不同。一般来_Little EndianpȝBYTE_ORDER(或_BYTE_ORDER,__BYTE_ORDER)?234QBig Endianpȝ?321。大部分用户的操作系l(如windows, FreeBsd,LinuxQ是Little Endian的。少部分Q如MAC OS ,是Big Endian 的。本质上_Little Endianq是Big Endian与操作系l和芯片cd都有关系?/p>
======================================================================
ext3 文gpȝ在硬盘分Z的数据是按照 Intel ?Little-endian 格式存放的,如果是在 PC 以外的^C开?ext3 相关的程序,要特别注意这一炏V?/font>
谈到字节序的问题Q必然牵涉到两大 CPUz。那是Motorola的PowerPCpdCPU和Intel的x86pdCPU。PowerPCpd采用big endian方式存储数据Q而x86pd则采用little endian方式存储数据。那么究竟什么是big endianQ什么又是little endian呢?
其实big endian是指低地址存放最高有效字节(MSBQ,而little endian则是低地址存放最低有效字节(LSBQ?/font>
用文字说明可能比较抽象,下面用图像加以说明。比如数?x12345678在两U不同字节序CPU中的存储序如下所C:
Big Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 | 34 | 56 | 78 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 78 | 56 | 34 | 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
从上面两囑֏以看出,采用big endian方式存储数据是符合我们hcȝ思维习惯的。而little endianQ?@#$%^&*Q见鬼去?-_-|||
Z么要注意字节序的问题呢?你可能这么问。当Ӟ如果你写的程序只在单机环境下面运行,q且不和别h的程序打交道Q那么你完全可以忽略字节序的存在。但是,如果你的E序要跟别h的程序生交互呢Q在q里我想说说两种语言。C/C++语言~写的程序里数据存储序是跟~译q_所在的CPU相关的,?JAVA~写的程序则唯一采用big endian方式来存储数据。试惻I如果你用C/C++语言在x86q_下编写的E序跟别人的JAVAE序互通时会生什么结果?拿上面?0x12345678来说Q你的程序传递给别h的一个数据,指?x12345678的指针传l了JAVAE序Q由于JAVA采取big endian方式存储数据Q很自然的它会将你的数据译?x78563412。什么?竟然变成另外一个数字了Q是的,是q种后果。因此,在你的CE序传给JAVAE序之前有必要进行字节序的{?a onclick="javascript:tagshow(event, '%B9%A4%D7%F7');" href="javascript:;" target="_self">工作?br />
无独有偶Q所有网l协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式UC为网l字节序。当两台采用不同字节序的L通信Ӟ在发送数据之前都必须l过字节序的转换成ؓ|络字节序后再进行传输?/font>
来源Qhttp://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html
不同的CPU有不同的字节序类?q些字节序是指整数在内存中保存的序 q个叫做L?br />
最常见的有两种
1Q?Little endianQ将低序字节存储在v始地址
2Q?Big endianQ将高序字节存储在v始地址
LE little-endian
最W合人的思维的字节序
地址低位存储值的低位
地址高位存储值的高位
怎么讲是最W合人的思维的字节序Q是因ؓ从h的第一观感来说
低位值小Q就应该攑֜内存地址的地方Q也卛_存地址低位
反之Q高位值就应该攑֜内存地址大的地方Q也卛_存地址高位
BE big-endian
最直观的字节序
地址低位存储值的高位
地址高位存储值的低位
Z么说直观Q不要考虑对应关系
只需要把内存地址从左到右按照׃到高的顺序写?br />
把值按照通常的高位到低位的顺序写?br />
两者对照,一个字节一个字节的填充q去
例子Q在内存中双?x01020304(DWORD)的存储方?br />
内存地址
4000 4001 4002 4003
LE 04 03 02 01
BE 01 02 03 04
例子Q如果我们将0x1234abcd写入C0x0000开始的内存中,则结果ؓ
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86pdCPU都是little-endian的字节序.
|络字节序是TCP/IP中规定好的一U数据表C格式,它与具体的CPUcd、操作系l等无关Q从而可以保证数据在不同L之间传输时能够被正确解释。网l字节顺序采用big endian排序方式?br />
Zq行转换 bsd socket提供了{换的函数 有下面四?br />
htons 把unsigned shortcd从主机序转换到网l序
htonl 把unsigned longcd从主机序转换到网l序
ntohs 把unsigned shortcd从网l序转换C机序
ntohl 把unsigned longcd从网l序转换C机序
在用little endian的系l中 q些函数会把字节序进行{?br />
在用big endiancd的系l中 q些函数会定义成I宏
同样 在网l程序开发时 或是跨^台开发时 也应该注意保证只用一U字节序 不然两方的解释不一样就会生bug.
注:
1、网l与L字节转换函数:htons ntohs htonl ntohl (s 是short l是long h是host n是network)
2、不同的CPU上运行不同的操作pȝQ字节序也是不同的,参见下表?br />
处理?nbsp; 操作pȝ 字节排序
Alpha 全部 Little endian
HP-PA NT Little endian
HP-PA UNIX Big endian
Intelx86 全部 Little endian <-----x86pȝ是小端字节序pȝ
Motorola680x() 全部 Big endian
MIPS NT Little endian
MIPS UNIX Big endian
PowerPC NT Little endian
PowerPC 非NT Big endian <-----PPCpȝ是大端字节序pȝ
RS/6000 UNIX Big endian
SPARC UNIX Big endian
IXP1200 ARM核心 全部 Little endian
=============================================
字节序{换类Q?br />
/**
* 通信格式转换
*
* Java和一些windows~程语言如c、c++、delphi所写的|络E序q行通讯Ӟ需要进行相应的转换
* 高、低字节之间的{?br />
* windows的字节序Z字节开?br />
* linux,unix的字节序为高字节开?br />
* java则无论^台变化,都是高字节开?br />
*/
public class FormatTransfer {
/**
* int转ؓ低字节在前,高字节在后的byte数组
* @param n int
* @return byte[]
*/
public static byte[] toLH(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* int转ؓ高字节在前,低字节在后的byte数组
* @param n int
* @return byte[]
*/
public static byte[] toHH(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* short转ؓ低字节在前,高字节在后的byte数组
* @param n short
* @return byte[]
*/
public static byte[] toLH(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* short转ؓ高字节在前,低字节在后的byte数组
* @param n short
* @return byte[]
*/
public static byte[] toHH(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 将int转ؓ高字节在前,低字节在后的byte数组
public static byte[] toHH(int number) {
int temp = number;
byte[] b = new byte[4];
for (int i = b.length - 1; i > -1; i--) {
b = new Integer(temp & 0xff).byteValue();
temp = temp >> 8;
}
return b;
}
public static byte[] IntToByteArray(int i) {
byte[] abyte0 = new byte[4];
abyte0[3] = (byte) (0xff & i);
abyte0[2] = (byte) ((0xff00 & i) >> 8);
abyte0[1] = (byte) ((0xff0000 & i) >> 16);
abyte0[0] = (byte) ((0xff000000 & i) >> 24);
return abyte0;
}
*/
/**
* float转ؓ低字节在前,高字节在后的byte数组
*/
public static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}
/**
* float转ؓ高字节在前,低字节在后的byte数组
*/
public static byte[] toHH(float f) {
return toHH(Float.floatToRawIntBits(f));
}
/**
* String转ؓbyte数组
*/
public static byte[] stringToBytes(String s, int length) {
while (s.getBytes().length < length) {
s += " ";
}
return s.getBytes();
}
/**
* 字节数l{换ؓString
* @param b byte[]
* @return String
*/
public static String bytesToString(byte[] b) {
StringBuffer result = new StringBuffer("");
int length = b.length;
for (int i=0; i<length; i++) {
result.append((char)(b & 0xff));
}
return result.toString();
}
/**
* 字W串转换为byte数组
* @param s String
* @return byte[]
*/
public static byte[] stringToBytes(String s) {
return s.getBytes();
}
/**
* 高字节数组转换为int
* @param b byte[]
* @return int
*/
public static int hBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b >= 0) {
s = s + b;
} else {
s = s + 256 + b;
}
s = s * 256;
}
if (b[3] >= 0) {
s = s + b[3];
} else {
s = s + 256 + b[3];
}
return s;
}
/**
* 低字节数组转换为int
* @param b byte[]
* @return int
*/
public static int lBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[3-i] >= 0) {
s = s + b[3-i];
} else {
s = s + 256 + b[3-i];
}
s = s * 256;
}
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
return s;
}
/**
* 高字节数l到short的{?br />
* @param b byte[]
* @return short
*/
public static short hBytesToShort(byte[] b) {
int s = 0;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
s = s * 256;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
short result = (short)s;
return result;
}
/**
* 低字节数l到short的{?br />
* @param b byte[]
* @return short
*/
public static short lBytesToShort(byte[] b) {
int s = 0;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
s = s * 256;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
short result = (short)s;
return result;
}
/**
* 高字节数l{换ؓfloat
* @param b byte[]
* @return float
*/
public static float hBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[0]&0xff)<<8 | (b[1]&0xff))<<8) | (b[2]&0xff))<<8 | (b[3]&0xff);
return F.intBitsToFloat(i);
}
/**
* 低字节数l{换ؓfloat
* @param b byte[]
* @return float
*/
public static float lBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[3]&0xff)<<8 | (b[2]&0xff))<<8) | (b[1]&0xff))<<8 | (b[0]&0xff);
return F.intBitsToFloat(i);
}
/**
* byte数组中的元素倒序排列
*/
public static byte[] bytesReverseOrder(byte[] b) {
int length = b.length;
byte[] result = new byte[length];
for(int i=0; i<length; i++) {
result[length-i-1] = b;
}
return result;
}
/**
* 打印byte数组
*/
public static void printBytes(byte[] bb) {
int length = bb.length;
for (int i=0; i<length; i++) {
System.out.print(bb + " ");
}
System.out.println("");
}
public static void logBytes(byte[] bb) {
int length = bb.length;
String ut = "";
for (int i=0; i<length; i++) {
ut = out + bb + " ";
}
}
/**
* intcd的D{换ؓ字节序颠倒过来对应的int?br />
* @param i int
* @return int
*/
public static int reverseInt(int i) {
int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
return result;
}
/**
* shortcd的D{换ؓ字节序颠倒过来对应的short?br />
* @param s short
* @return short
*/
public static short reverseShort(short s) {
short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
return result;
}
/**
* floatcd的D{换ؓ字节序颠倒过来对应的float?br />
* @param f float
* @return float
*/
public static float reverseFloat(float f) {
float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
return result;
}
}