??xml version="1.0" encoding="utf-8" standalone="yes"?>韩国亚洲伊人久久综合影院,亚洲中文字幕久久精品无码A,亚洲H在线播放在线观看Hhttp://m.tkk7.com/illhan/zh-cnSun, 11 May 2025 06:17:41 GMTSun, 11 May 2025 06:17:41 GMT60MIME邮g面面?/title><link>http://m.tkk7.com/illhan/archive/2007/12/01/164513.html</link><dc:creator>java执著?/dc:creator><author>java执著?/author><pubDate>Sat, 01 Dec 2007 08:36:00 GMT</pubDate><guid>http://m.tkk7.com/illhan/archive/2007/12/01/164513.html</guid><wfw:comment>http://m.tkk7.com/illhan/comments/164513.html</wfw:comment><comments>http://m.tkk7.com/illhan/archive/2007/12/01/164513.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/illhan/comments/commentRss/164513.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/illhan/services/trackbacks/164513.html</trackback:ping><description><![CDATA[<span id="ArticleContent1_ArticleContent1_lblContent"> <p class="bhw98"><strong class="bhw98">Q</strong> 什么是MIMEQ什么是MIME邮gQ? </p> <p class="bhw98"><strong class="bhw98">A</strong> MIME, 全称?#8220;Multipurpose Internet Mail Extensions”, 比较切的中文名UCؓ“多用途互联网邮g扩展”。它是当前广泛应用的一U电子邮件技术规范,基本内容定义于RFC 2045-2049? </p> <p class="bhw98">自然QMIME邮g是W合MIME规范的电子邮Ӟ或者说ҎMIME规范~码而成的电子邮件? </p> <p class="bhw98">在MIME出台之前Q用RFC 822只能发送基本的ASCII码文本信息,邮g内容如果要包括二q制文g、声韛_动画{,实现h非常困难。MIME提供了一U可以在邮g中附加多U不 同编码文件的ҎQI补了原来的信息格式的不。实际上不仅仅是邮g~码Q现在MIMEl成为HTTP协议标准的一个部分? </p> <p class="bhw98">下面丑և个MIME邮g的例子,让我们先对MIME~码的格式有个直观的印象。例1是最单的Q只带纯文本 正文Q基本上是RFC 822格式Q例2复杂一些,包含U文本和文本正文;?是最复杂的,包含U文本正文、超文本正文、内嵌资源和文g附g。其中,行号和行号后的空格是Z 分析方便而另外加的,“... ... ... ...”表示此处省略了大D늼码? </p> <p class="bhw98">? </p> <pre class="bhw98"><code class="bhw98"> 1 Date: Thu, 18 Apr 2002 09:32:45 +0800<br /> 2 From: <bhw98@sina.com><br /> 3 To: <bhwang@jlonline.com><br /> 4 Subject: Test<br /> 5 Mime-Version: 1.0<br /> 6 Content-Type: text/plain; charset="iso-8859-1"<br /> 7<br /> 8 This is a simple mail.<br /> 9</code></pre> <p class="bhw98">? </p> <pre class="bhw98"><code class="bhw98"> 1 From: "bhw98" <bhw98@sina.com><br /> 2 Reply-To: bhw98@sina.com<br /> 3 To: <bluesky7810@163.com><br /> 4 Subject: Re: help<br /> 5 X-Mailer: Foxmail 4.2 [cn]<br /> 6 Mime-Version: 1.0<br /> 7 Content-Type: multipart/alternative;<br /> 8 boundary="=====002_Dragon307572345230_====="<br /> 9<br /> 10<br /> 11 This is a multi-part message in MIME format.<br /> 12<br /> 13 --=====002_Dragon307572345230_=====<br /> 14 Content-Type: text/plain; charset="GB2312"<br /> 15 Content-Transfer-Encoding: quoted-printable<br /> 16<br /> 17 bluesky7810=A3=AC=C4=FA=BA=C3=A3=A1<br /> 18<br /> 19 =A1=A1=A1=A1=D4=DA=CF=C2=C6=AA=D7=EE=BA=F3=BF=C9=D2=D4=CF=C2=D4=D8=B0=A1=A3=AC=C4=E3<br /> ... ... ... ...<br /> 30 =A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A1=A12003-04-07<br /> 31<br /> 32 --=====002_Dragon307572345230_=====<br /> 33 Content-Type: text/html; charset="GB2312"<br /> 34 Content-Transfer-Encoding: quoted-printable<br /> 35<br /> 36 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><br /> 37 <HTML><HEAD><br /> 38 <META content=3D"text/html; charset=3Dgb2312"=<br /> 39 http-equiv=3DContent-Type><br /> 40 <META content=3D"MSHTML 5.00.2920.0" name=3DGENERATOR><br /> ... ... ... ...<br /> 79 </HTML><br /> 80<br /> 81 --=====002_Dragon307572345230_=====--<br /> 82</code></pre> <p class="bhw98">? </p> <pre class="bhw98"><code class="bhw98"> 1 Return-Path: <bluesky7810@163.com><br /> 2 Delivered-To: bhw98@sina.com<br /> 3 Received: (qmail 75513 invoked by alias); 20 May 2002 02:19:53 -0000<br /> 4 Received: from unknown (HELO bluesky) (61.155.118.135)<br /> 5 by 202.106.187.143 with SMTP; 20 May 2002 02:19:53 -0000<br /> 6 Message-ID: <007f01c3111c$742fec00$0100007f@bluesky><br /> 7 From: "=?gb2312?B?wLbAtrXEzOwNCg==?=" <bluesky7810@163.com><br /> 8 To: "bhw98" <bhw98@sina.com><br /> 9 Cc: <bhwang@jlonline.com><br /> 10 Subject: =?gb2312?B?ztK1xLbgtK6/2rPM0PI=?=<br /> 11 Date: Sat, 20 May 2002 10:03:36 +0800<br /> 12 MIME-Version: 1.0<br /> 13 Content-Type: multipart/mixed;<br /> 14 boundary="----=_NextPart_000_007A_01C3115F.80DFC5E0"<br /> 15 X-Priority: 3<br /> 16 X-MSMail-Priority: Normal<br /> 17 X-Mailer: Microsoft Outlook Express 5.00.2919.6700<br /> 18 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700<br /> 19<br /> 20 This is a multi-part message in MIME format.<br /> 21<br /> 22 ------=_NextPart_000_007A_01C3115F.80DFC5E0<br /> 23 Content-Type: multipart/related; type="multipart/alternative";<br /> 24 boundary="----=_NextPart_001_007B_01C3115F.80DFC5E0"<br /> 25<br /> 26<br /> 27 ------=_NextPart_001_007B_01C3115F.80DFC5E0<br /> 28 Content-Type: multipart/alternative;<br /> 29 boundary="----=_NextPart_002_007C_01C3115F.80DFC5E0"<br /> 30<br /> 31 ------=_NextPart_002_007C_01C3115F.80DFC5E0<br /> 32 Content-Type: text/plain; charset="gb2312"<br /> 33 Content-Transfer-Encoding: quoted-printable<br /> 34<br /> 35 bhw98, =C4=E3=BA=C3!<br /> 36 =D5=E2=CA=C7=CE=D2=D0=B4=B5=C4=B6=E0=B4=AE=BF=DA=CD=A8=D0=C5=B5=C4=B3=CC=D0=<br /> 37 =F2, =C7=EB=D6=B8=BD=CC!<br /> 38<br /> 39<br /> 40 ------=_NextPart_002_007C_01C3115F.80DFC5E0<br /> 41 Content-Type: text/html; charset="gb2312"<br /> 42 Content-Transfer-Encoding: quoted-printable<br /> 43<br /> 44 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><br /> 45 <HTML><HEAD><TITLE>=C7=E7=C0=CA</TITLE><br /> 46 <META content=3D"text/html; charset=3Dgb2312" http-equiv=3DContent-Type><br /> 47 <STYLE>BODY {<br /> 48 COLOR: #0033cc; FONT-FAMILY: =CB=CE=CC=E5, Arial, Helvetica; FONT-SIZE: =<br /> 49 9pt; MARGIN-LEFT: 10px; MARGIN-TOP: 25px<br /> 50 }<br /> 51 </STYLE><br /> 52 <META content=3D"MSHTML 5.00.2920.0" name=3DGENERATOR></HEAD><br /> 53 <BODY background=3Dcid:007901c3111c$72b978a0$0100007f@bluesky =<br /> 54 bgColor=3D#ffffff><br /> 55 <DIV><br /> 56 <DIV>bhw98, =C4=E3=BA=C3!</DIV><br /> 57 <P>=D5=E2=CA=C7=CE=D2=D0=B4=B5=C4=B6=E0=B4=AE=BF=DA=CD=A8=D0=C5=B5=C4=B3=CC=<br /> 58 =D0=F2, =C7=EB=D6=B8=BD=CC!</P></DIV><br /> 59 <P> </P></BODY></HTML><br /> 60<br /> 61 ------=_NextPart_002_007C_01C3115F.80DFC5E0--<br /> 62<br /> 63 ------=_NextPart_001_007B_01C3115F.80DFC5E0<br /> 64 Content-Type: image/jpeg; name="=?gb2312?B?x+fAyrGzvrAuSlBH?="<br /> 65 Content-Transfer-Encoding: base64<br /> 66 Content-ID: <007901c3111c$72b978a0$0100007f@bluesky><br /> 67<br /> 68 /9j/4AAQSkZJRgABAgEASABIAAD/7QVoUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA<br /> 69 AQBIAAAAAQABOEJJTQPzAAAAAAAIAAAAAAAAAAA4QklNBAoAAAAAAAEAADhCSU0nEAAAAAAACgAB<br /> 70 AAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEA<br /> ... ... ... ...<br /> 169 RxVw98Vawq12xQ44q0cKtHFDWKGsKt4EtiuKt4q//9k=<br /> 170<br /> 171 ------=_NextPart_001_007B_01C3115F.80DFC5E0--<br /> 172<br /> 173 ------=_NextPart_000_007A_01C3115F.80DFC5E0<br /> 174 Content-Type: application/msword; name="readme.doc"<br /> 175 Content-Transfer-Encoding: base64<br /> 176 Content-Disposition: attachment; filename="readme.doc"<br /> 177<br /> 178 0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAAJgAAAAAAAAAA<br /> 179 EAAAKAAAAAEAAAD+////AAAAACUAAAD/////////////////////////////////////////////<br /> 180 ////////////////////////////////////////////////////////////////////////////<br /> ... ... ... ...<br /> 1688 AAAAAAAAAAAAAAAAAAA=<br /> 1689<br /> 1690 ------=_NextPart_000_007A_01C3115F.80DFC5E0<br /> 1691 Content-Type: application/x-zip-compressed;<br /> 1692 name="=?gb2312?B?tuC0rr/azajQxbXE1LTC6y56aXA=?="<br /> 1693 Content-Transfer-Encoding: base64<br /> 1694 Content-Disposition: attachment;<br /> 1695 filename="=?gb2312?B?tuC0rr/azajQxbXE1LTC6y56aXA=?="<br /> 1696<br /> 1697 UEsDBBQAAAAIAFKAoi7qOMOvLw0AAABWAAAUAAAAtuC0rr/azajQxbXE1LTC6y5kb2PtXHtwVNUZ<br /> 1698 /+4+kk3IQoAkBkRYQkSgbrKb7IYNEMwmm6ckG0jCI0boZneTbJJ9sNlAEsdOtFqd8Z846tQ6PhB1<br /> 1699 hrZTJoK0Vhgf1aGt4rMy6D8tdugfTjuOpcBIR9j+vvsIy4YkRNTRen87v/ud53cee+6557vn7L73<br /> ... ... ... ...<br /> 3125 zajQxbXE1LTC6y5kb2NQSwUGAAAAAAEAAQBCAAAAYQ0AAA==<br /> 3126<br /> 3127 ------=_NextPart_000_007A_01C3115F.80DFC5E0--<br /> 3128</code></pre> <p class="bhw98"><strong class="bhw98">Q</strong> 在开始研IMIME邮g的时候,如何得到q样的源码? </p> <p class="bhw98"><strong class="bhw98">A</strong> 一些功能比较完善的邮g客户端YӞ如微软的Outlook ExpressQ国产的Foxmail{,都提供了查看和保存邮件源?原始信息)的功能。在Foxmail中,选择邮g列表右键菜单?#8220;原始信息”q行 查看Q主菜单?#8220;文g-导出”q行保存。在Outlook Express中,对应的操作分别是“属?#8221;?#8220;另存?#8221;。所保存?eml文gQ可以调用这些程序打开? </p> <p class="bhw98"><strong class="bhw98">Q</strong> 请介l一下MIME邮g的组成? </p> <p class="bhw98"><strong class="bhw98">A</strong> M来说QMIME消息由消息头和消息体两大部分l成。现在我们关注的是MIME邮gQ因此在以下的讨Z姑且U?#8220;消息”?#8220;邮g”。在上面的例子中Q例 1?-6行,???行,??-18行,是邮件头Q例1??行,??0?2行,??0?128行,是邮件体。邮件头与邮件体? 间以Iq行分隔Q如?的第7行,?的第9行,?的第19行。邮件头中不允许出现I。有一些邮件不能被邮g客户端Y件识别,昄的是原始码,是 因ؓ首行是空行? </p> <p class="bhw98">邮g头包含了发g人、收件h、主题、时间、MIME版本、邮件内容的cd{重要信息。每条信息称Z个域Q? 由域名后?#8220;: ”和信息内Ҏ成,可以是一行,较长的也可以占用多行。域的首行必?#8220;头”写,卛_边不能有I白字符Q空格和制表W)Q箋行则必须以空白字W打_且第 一个空白字W不是信息本w固有的Q解码时要过滤掉。如??-8行,??-5行,13-14行,分别属于一个域? </p> <p class="bhw98">邮g体包含邮件的内容Q它的类型由邮g头的“Content-Type”域指出。常见的单类型有text/plain(U文?和text/html(文?? </p> <p class="bhw98">?和例3中出现的multipartcdQ是MIME邮g的精髓。邮件体被分为多个段Q每个段又包含段头和 D体两部分,q两部分之间也以I分隔。常见的multipartcd有三U:multipart/mixed, multipart/related和multipart/alternative。从它们的名Uͼ不难推知q些cd各自的含义和用处。它们之间的层次? pd归纳Z图所C: </p> <pre class="diag">+------------------------- multipart/mixed ----------------------------+<br /> | |<br /> | +----------------- multipart/related ------------------+ |<br /> | | | |<br /> | | +----- multipart/alternative ------+ +----------+ | +------+ |<br /> | | | | | 内嵌资源 | | | 附g | |<br /> | | | +------------+ +------------+ | +----------+ | +------+ |<br /> | | | | U文本正?| | 文本正?| | | |<br /> | | | +------------+ +------------+ | +----------+ | +------+ |<br /> | | | | | 内嵌资源 | | | 附g | |<br /> | | +----------------------------------+ +----------+ | +------+ |<br /> | | | |<br /> | +------------------------------------------------------+ |<br /> | |<br /> +----------------------------------------------------------------------+<br /> </pre> <p class="bhw98">可以看出Q如果在邮g中要d附gQ必d义multipart/mixedD;如果存在内嵌资源Q至要定义 multipart/relatedD;如果U文本与文本共存,臛_要定义multipart/alternativeDc什么是“臛_”QD个例? _如果只有U文本与文本正文,那么在邮件头中将cd扩大化,定义为multipart/relatedQ甚至multipart/mixedQ都是允 许的? </p> <p class="bhw98">multipart诸类型的共同特征是,在段头指?#8220;boundary”参数字符ԌD体内的每个子段以此 串定界。所有的子段都以“--”+boundary行开始,父段则以“--”+boundary+“--”行结束。段与段之间也以I分隔。在邮g体是 multipartcd的情况下Q邮件体的开始部?W一?#8220;--”+boundary行之?可以有一些附加的文本行,相当于注释,解码时应忽略。段? 也可以有一些附加的文本行,不会昄出来Q如果有兴趣Q不妨验证一下? </p> <p class="bhw98">l合boundary定界和multipart层次关系图,我们分析一下例2和例3的邮件体层次与段嵌套关系? </p> <p class="bhw98">在例2中,10-12行是附加文本行,13-82行是multipart/alternative型的D,包含两个子段Q?3-30行是U文本正文,32-79行是文本正文? </p> <p class="bhw98">在例3中,20-21行是附加文本行,22-3127行是multipart/mixed型的D,包含3个子 D:22-171行是multipart/relatedD,173-1688行与1690-3125行是两个附g。multipart/related D又包含两个子段Q?7-61行是multipart/alternativeD,63-169行是一个内嵌资?囄)? multipart/alternativeD又包含两个子段Q?1-48行是U文本正文,40-59行是文本正文? </p> <p class="bhw98">?只有U文本正文,实际上属于multipart层次关系图中的一个特D情c如果非要避qQ写成下面的形式Q也是完全符合MIME_的? </p> <pre class="bhw98"><code class="bhw98">Date: Thu, 18 Apr 2002 09:32:45 +0800<br /> From: <bhw98@sina.com><br /> To: <bhwang@jlonline.com><br /> Subject: Test<br /> Mime-Version: 1.0<br /> Content-Type: multipart/alternative; boundary="{[(^_^)]}"<br /> <br /> --{[(^_^)]}<br /> Content-Type: text/plain; charset="iso-8859-1"<br /> Content-Transfer-Encoding: 7bit<br /> <br /> This is a simple mail.<br /> <br /> --{[(^_^)]}--</code></pre> <p class="bhw98"><strong class="bhw98">Q</strong> 在邮件头和段头中Q有哪一些常见的域? </p> <p class="bhw98"><strong class="bhw98">A</strong> 在邮件头中,有很多从RFC 822沿用的域名,MIME也增加了一些。常见的标准域名和含义如? <table class="bhw98" align="center"> <tbody> <tr class="bhw98"> <td class="bhw98">域名</td> <td class="bhw98">含义</td> <td class="bhw98">d? </td> </tr> <tr class="bhw98"> <td class="bhw98">Received</td> <td class="bhw98">传输路径</td> <td class="bhw98">各邮g服务? </td> </tr> <tr class="bhw98"> <td class="bhw98">Return-Path</td> <td class="bhw98">回复地址</td> <td class="bhw98">目标邮g服务? </td> </tr> <tr class="bhw98"> <td class="bhw98">Delivered-To</td> <td class="bhw98">发送地址</td> <td class="bhw98">目标邮g服务? </td> </tr> <tr class="bhw98"> <td class="bhw98">Reply-To</td> <td class="bhw98">回复地址</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">From</td> <td class="bhw98">发g人地址</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">To</td> <td class="bhw98">收g人地址</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Cc</td> <td class="bhw98">抄送地址</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Bcc</td> <td class="bhw98">暗送地址</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Date</td> <td class="bhw98">日期和时?/td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Subject</td> <td class="bhw98">主题</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Message-ID</td> <td class="bhw98">消息ID</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">MIME-Version</td> <td class="bhw98">MIME版本</td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Type</td> <td class="bhw98">内容的类?/td> <td class="bhw98">邮g的创? </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Transfer-Encoding</td> <td class="bhw98">内容的传输编码方?/td> <td class="bhw98">邮g的创? </td> </tr> </tbody> </table> </p> <p class="bhw98">非标准的、自定义域名都以X-开_例如X-Mailer, X-MSMail-Priority{,通常在接收和发送邮件的是同一E序时才能理解它们的意义? </p> <p class="bhw98">在段头中Q大致有如下一些域 <table class="bhw98" align="center"> <tbody> <tr class="bhw98"> <td class="bhw98">域名</td> <td class="bhw98">含义 </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Type</td> <td class="bhw98">D体的类? </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Transfer-Encoding</td> <td class="bhw98">D体的传输编码方? </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Disposition</td> <td class="bhw98">D体的安排方? </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-ID</td> <td class="bhw98">D体的ID </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Location</td> <td class="bhw98">D体的位|?路径) </td> </tr> <tr class="bhw98"> <td class="bhw98">Content-Base</td> <td class="bhw98">D体的基位置 </td> </tr> </tbody> </table> </p> <p class="bhw98">有的域除了g外,q带有参数。g参数、参C参数之间?#8220;;”分隔。参数名与参数g间以“=”分隔。如 ??8-29行,Content-Type域的gؓ“multipart/alternative”Q此外有一个参数boundaryQgؓ"--- -=_NextPart_002_007C_01C3115F.80DFC5E0"。又如例3的第176行,Content-Disposition域的 gؓ“attachment”Q此外有一个参数filenameQgؓ“readme.doc”?</p> <p class="bhw98"><strong class="bhw98">Q</strong> Content-Type以及它们的参数有哪些形式Q? </p> <p class="bhw98"><strong class="bhw98">A</strong> Content-Type都是“ȝ?子类?#8221;的Ş式。主cd有text, image, audio, video, application, multipart, message{,分别表示文本、图片、音频、视频、应用、分Dc消息等。每个主cd都可能有多个子类型,如textcd包含plain, html, xml, css{子cd。以X-开头的ȝ型和子类型,同样表示自定义的cdQ未向IANA正式注册Q但大多已经U定成俗了。如application/x- zip-compressed是ZIP文gcd。在Windows中,注册表的“HKEY_CLASSES_ROOT\MIME\Database\ Content Type”内列举了除multipart之外大部分已知的Content-Type? </p> <p class="bhw98">关于参数的Ş式,RFC里有很多补充规定Q有的允许带几个参数Q较为常见的? <table class="bhw98" align="center"> <tbody> <tr class="bhw98"> <td class="bhw98">ȝ?/td> <td class="bhw98">参数?/td> <td class="bhw98">含义 </td> </tr> <tr class="bhw98"> <td class="bhw98">text</td> <td class="bhw98">charset</td> <td class="bhw98">字符? </td> </tr> <tr class="bhw98"> <td class="bhw98">image</td> <td class="bhw98">name</td> <td class="bhw98">名称 </td> </tr> <tr class="bhw98"> <td class="bhw98">application</td> <td class="bhw98">name</td> <td class="bhw98">名称 </td> </tr> <tr class="bhw98"> <td class="bhw98">multipart</td> <td class="bhw98">boundary</td> <td class="bhw98">边界 </td> </tr> </tbody> </table> </p> <p class="bhw98">其中字符集也能在Windows注册表的“HKEY_CLASSES_ROOT\MIME\Database\Charset”内见到? </p> <p class="bhw98"><strong class="bhw98">Q</strong> Content-Transfer-Encoding有哪些?有什么特点? </p> <p class="bhw98"><strong class="bhw98">A</strong> Content-Transfer-Encoding共有Base64, Quoted-printable, 7bit, 8bit, Binary{几U。其?bit是缺省的~码方式。电子邮件源码最初设计ؓ全部是可打印的ASCII码的形式。非ASCII码的文本或数据要~码成要? 的格式,如上面的三个例子。Base64, Quoted-Printable是在非英语国家用最q的编码方式。Binary方式只具有象征意义,而没有Q何实用h倹{? </p> <p class="bhw98">Base64输入的字符串或一D|据编码成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}q?4个字W的Ԍ'='用于填充。其~码的方法是Q将输入数据每ơ取6 bitQ用? bit的?0-63)作ؓ索引L表,输出相应字符。这P?个字节将~码?个字W?3×8 → 4×6)Q不?个字W的?='填充。有的场合,?#8220;=?charset?B?xxxxxxxx?=”表示xxxxxxxx是Base64~码Q且原文 的字W集是charset。如?W??=?gb2312?B?wLbAtrXEzOwNCg==?="是由体中?#8220;蓝蓝的天”~码而成的。在D体? 则直接编码,适当时机换行QMIME每行最?6个字W。如??697-3125行,是一个ZIP文g的Base64~码? </p> <p class="bhw98">Quoted-printableҎ输入的字W串或字节范围进行编码,若是不需~码的字W,直接输出Q若 需要编码,则先输出'='Q后面跟着?个字W表C的十六q制字节倹{有的场合,?#8220;=?charset?Q?xxxxxxxx?=”表示 xxxxxxxx是Quoted-printable~码Q且原文的字W集是charset。在D体内则直接~码Q适当时机换行Q换行前额外输出一?= '。如??4-59行,是HTML文本的Quoted-printable~码。其中第45?#8220;=C7=E7=C0=CA”原文?#8220;晴朗”Q因? “?#8221;的GB2312码是C7E7Q?#8220;?#8221;的GB2312码是C0CA。第48?3?7行末֏有孤雉?='Q表C是由~码造成的Y回RQ而非 原文固有的? </p> <p class="bhw98">q年来,国内多数邮g服务器已l支?bit方式Q因此只在国内传输的邮gQ特别是在邮件头中,可直接?bit~码Q对汉字不做处理。如果邮件要出国Q还是老老实实地按Base64或Quoted-printable~码才行? </p> <p class="bhw98"><strong class="bhw98">Q</strong> 什么是内嵌资源Q它有哪些Ş式? </p> <p class="bhw98"><strong class="bhw98">A</strong> 内嵌资源也是MIME的一个发光点Q它能邮g内容变得生动zL、丰富多彩。可在邮件的multipart/related框架内定义一些与正文兌的图 片、动甅R声音甚至CSS样式和脚本的Dc通常在HTML正文内,使用链接与内嵌资源相联系。如在例3中,HTML正文53-54行,解码后ؓ </p> <pre class="bhw98"><code class="bhw98"><BODY background=cid:007901c3111c$72b978a0$0100007f@bluesky bgColor=#ffffff></code></pre> <p class="bhw98">它指出用一个Content-ID?07901c3111c$72b978a0$0100007f@bluesky的图片作?cid:xxxxxxxx也是一U超U链?。?4-169行恰好就是这样一个内嵌资源? </p> <p class="bhw98">除了用Content-IDq行联系外,q有另外一U常用Ş式:用普通超U连接和Content-Location。例如: </p> <p class="bhw98">在HTML正文中, </p> <pre class="bhw98"><code class="bhw98">... ... ... ...<br /> <IMG SRC="http://www.dangdang.com/images/all/anti_joyo_dm_book.gif"><br /> ... ... ... ...<br /> <IMG SRC="http://www.dangdang.com/dd2001/getimage_small.asp?id=486341"><br /> ... ... ... ...</code></pre> <p class="bhw98">对应的内嵌资源ؓ </p> <pre class="bhw98"><code class="bhw98">Content-Type: image/gif; name="anti_joyo_dm_book.gif"<br /> Content-Transfer-Encoding: base64<br /> Content-Location: http://www.dangdang.com/images/all/anti_joyo_dm_book.gif<br /> ... ... ... ...<br /> Content-Type: application/octet-stream; name="getimage_small.asp?id=486341"<br /> Content-Transfer-Encoding: base64<br /> Content-Location: http://www.dangdang.com/dd2001/getimage_small.asp?id=486341<br /> ... ... ... ...</code></pre> <p class="bhw98">另外Q? </p> <pre class="bhw98"><code class="bhw98">Content-Location: http://www.dangdang.com/images/all/anti_joyo_dm_book.gif</code></pre> <p class="bhw98">? </p> <pre class="bhw98"><code class="bhw98">Content-Location: anti_joyo_dm_book.gif<br /> Content-Base: http://www.dangdang.com/images/all/</code></pre> <p class="bhw98">是等效的? </p> <p class="bhw98"><strong class="bhw98">Q</strong> 邮g病毒如何利用附g和内嵌资源传播? </p> <p class="bhw98"><strong class="bhw98">A</strong> 有的邮g附g可能带有病毒Q容易理解。附件毕竟是文gQ也好预Ԍ不轻易打开是了。但内嵌资源是在览邮g内容时就要访问的Q若其中藏有病毒或恶意代码,你在不知不觉中就中招了。如前两q曾l在全球范围内流行的Nimda病毒Q功能性源码如下: </p> <pre class="bhw98"><code class="bhw98">MIME-Version: 1.0<br /> Content-Type: multipart/related;<br /> type="multipart/alternative";<br /> boundary="====_ABC1234567890DEF_===="<br /> <br /> --====_ABC1234567890DEF_====<br /> Content-Type: multipart/alternative;<br /> boundary="====_ABC0987654321DEF_===="<br /> <br /> --====_ABC0987654321DEF_====<br /> Content-Type: text/html;<br /> charset="iso-8859-1"<br /> Content-Transfer-Encoding: 7bit<br /> <br /> <HTML><HEAD></HEAD><BODY bgColor=#ffffff><br /> <iframe src=cid:EA4DMGBP9p height=0 width=0><br /> </iframe></BODY></HTML><br /> --====_ABC0987654321DEF_====--<br /> <br /> --====_ABC1234567890DEF_====<br /> Content-Type: audio/x-wav; name="readme.exe"<br /> Content-Transfer-Encoding: base64<br /> Content-ID: <EA4DMGBP9p><br /> <br /> TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<br /> AAAA2AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1v<br /> ZGUuDQ0KJAAAAAAAAAA11CFvcbVPPHG1TzxxtU88E6pcPHW1TzyZqkU8dbVPPJmqSzxytU88cbVO<br /> ... ... ... ... ... ... ... ...<br /> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=<br /> <br /> --====_ABC1234567890DEF_====</code></pre> <p class="bhw98">它将一个可执行文g作ؓ资源嵌入了框架型面Q却声明q段可执行代码是波Ş声音cd。由于当时微软的IE(版本5.0 及以?存在重大安全漏洞Q没有检查Content-Type与name的扩展名是否匚wQ于是就被轻易骗q了Q致使点选或打开邮g时自动运行了q个 “readme.exe”Q机器就感染上病毒。带毒的机器利用地址向别h发送带毒的邮gQ一传十Q十传百QNimda蠕虫大行光? </p> <p class="bhw98">U观历史Q病毒刚出来时是厉害Q但没有M一U能够持l肆虐下厅RNimda如此QSARS亦当如此。曰Q?#8220;多难兴邦Q众志成?#8221;Q又曎ͼ“非典l将倒下Q城市精永?#8221;Q相信我们定能很快战?#8220;非典”! </p> <p class="bhw98">病毒库升U是跟在新病毒屁股后q行的,不要q分依赖杀毒Y件。一个良好的习惯是关闭邮仉览功能,或者设定预览纯文本部分Q先查看邮g源码Q确信排除病毒嫌疑后再打开。对陌生人发来的带超文本正文的邮Ӟ其要当心。永q不要在邮g客户端Y件内直接打开附g? </p> <p class="bhw98"><strong class="bhw98">Q</strong> 一些垃N仉取隐藏发件h的方式,如何q查它们来自哪里Q? </p> <p class="bhw98"><strong class="bhw98">A</strong> 从上面的邮g头域名表中可以看出,邮g的创可以掌握大部分的域的内容,但Received{域由各U服务器自动dQ发件h是鞭长莫及。垃N件一? 采用了群发Y件发送,邮g头的From?发g人地址)可以L伪造,甚至写成收g人地址(收到了自己ƈ没有发过的垃NӞ气愤吧?)。查? Received?传输路径)铑֏以找到真正的出处。每个服务器d的Received语句都在邮g首,故最下面一个Received包含了发g人所 用的SMTP或HTTP服务器,及最初的|关外部IP地址?</p> <p class="bhw98">Receive语句的基本格式是Qfrom A by B。A为发送方QB为接收方。例如: </p> <pre class="bhw98"><code class="bhw98">Received: (qmail 45304 invoked from network); 4 May 2003 17:05:47 -0000<br /> Received: from unknown (HELO bjapp9.163.net) (202.108.255.197)<br /> by 202.106.182.244 with SMTP; 4 May 2003 17:05:47 -0000<br /> Received: from localhost (localhost [127.0.0.1])<br /> by bjapp9.163.net (Postfix) with SMTP id E1C761D84C631<br /> for <bhw98@sina.com>; Mon, 5 May 2003 01:07:26 +0800 (CST)<br /> Received: from fanyingxxxx@tom.com (unknown [211.99.162.194])<br /> by bjapp9.163.net (Coremail) with SMTP id OgEAAM1ItT7MNaLC.1<br /> for <bhw98@sina.com>; Mon, 05 May 2003 01:07:26 +0800 (CST)<br /> </code></pre> <p class="bhw98">从上面的例子中不隄出,该邮件的传输路径是:211.99.162.194 → bjapp9.163.net (Coremail 202.108.255.197?) → bjapp9.163.net (Postfix, 202.108.255.197?) → 202.106.182.244。恰好出C发g人邮fanyingxxxx@tom.comQ但多数情况不一定能列出来? </p> <p class="bhw98">此例的localhost [127.0.0.1]Q意味着bjapp9.163.net上安装了邮g服务代理性质的Y件? </p> </span> <img src ="http://m.tkk7.com/illhan/aggbug/164513.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/illhan/" target="_blank">java执著?/a> 2007-12-01 16:36 <a href="http://m.tkk7.com/illhan/archive/2007/12/01/164513.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Java/J2EE中文问题l极解决之道http://m.tkk7.com/illhan/archive/2007/09/20/146711.htmljava执著?/dc:creator>java执著?/author>Thu, 20 Sep 2007 03:07:00 GMThttp://m.tkk7.com/illhan/archive/2007/09/20/146711.htmlhttp://m.tkk7.com/illhan/comments/146711.htmlhttp://m.tkk7.com/illhan/archive/2007/09/20/146711.html#Feedback0http://m.tkk7.com/illhan/comments/commentRss/146711.htmlhttp://m.tkk7.com/illhan/services/trackbacks/146711.html  最古老的解决Ҏ是用String的字节码转换Q这U方案问题是不方便,我们需要破坏对象封装性,q行字节码{换?/p>

  q有一U方式是对J2EE容器q行~码讄Q如果J2EE应用pȝq该容器,则会发生qQ而且指定容器配置不符合J2EE应用和容器分ȝ原则?/p>

在Java内部q算中,涉及到的所有字W串都会被{化ؓUTF-8~码来进行运。那么,在被Java转化之前Q字W串是什么样的字W集Q? JavaLҎ操作pȝ的默认编码字W集来决定字W串的初始编码,而且Javapȝ的输入和输出的都是采取操作系l的默认~码?/p>

  ? 此,如果能统一Javapȝ的输入、输出和操作pȝ3者的~码字符集合Q将能够使Javapȝ正确处理和显C汉字。这是处理Javapȝ汉字的一个原则, 但是在实际项目中Q能够正抓住和控制住Javapȝ的输入和输出部分是比较难的。J2EE中,׃涉及到外部浏览器和数据库{,所以中文问题ؕ码显得非 常突出?/p>

  J2EE应用E序是运行在J2EE容器中。在q个pȝ中,输入途径有很多种Q一U是通过面表单打包成请求(requestQ? 发往服务器的Q第二种是通过数据库读入;q有W?U输入比较复杂,JSP在第一ơ运行时L被编译成ServletQJSP中常常包含中文字W,那么~译 使用javacӞJava根据默认的操作pȝ~码作ؓ初始~码。除非特别指定,如在Jbuilder/eclipse中可以指定默认的字符集?/p>

  输出途径也有几种Q第一U是JSP面的输出。由于JSP面已经被编译成ServletQ那么在输出Ӟ也将Ҏ操作pȝ的默认编码来选择输出~码Q除非指定输出编码方式;q有输出途径是数据库Q将字符串输出到数据库?/p>

  由此看来Q一个J2EEpȝ的输入输出是非常复杂Q而且是动态变化的Q而Java是跨q_q行的,在实际编译和q行中,都可能涉及到不同的操作系l,如果ȝJava自由Ҏ操作pȝ来决定输入输出的~码字符集,q将不可控制地出Cؕ码?/p>

  正是׃Java的跨q_Ҏ,使得字符集问题必ȝ具体pȝ来统一解决Q所以在一个Java应用pȝ中,解决中文q的根本办法是明确指定整个应用pȝl一字符集?/strong>

  指定l一字符集时Q到底是指定ISO8859_1 、GBKq是UTF-8呢?

  Q?Q如l一指定为ISO8859_1Q因为目前大多数软g都是西方人编制的Q他们默认的字符集就是ISO8859_1Q包括操作系lLinux和数据库MySQL{。这P如果指定Jivel一~码为ISO8859_1Q那么就有下?个环节必L握:

  开发和~译代码时指定字W集为ISO8859_1?/p>

  q行操作pȝ的默认编码必LISO8859_1Q如Linux?/p>

  在JSP头部声明Q?lt;%@ page contentType="text/html;charset=ISO8859_1" %>?/p>

  Q?Q如果统一指定为GBK中文字符集,上述3个环节同样需要做刎ͼ不同的是只能q行在默认编码ؓGBK的操作系l,如中文Windows?/p>

  l一~码为ISO8859_1和GBK虽然带来~制代码的方便,但是各自只能在相应的操作pȝ上运行。但是也破坏了Java跨^台运行的优越性,只在一定范围内行得通。例如,Z使得GBK~码在linux上运行,讄Linux~码为GBK?/p>

  那么有没有一U除了应用系l以外不需要进行Q何附加设|的中文~码Ҏ解决Ҏ呢?

  Java/J2EEpȝ的统一~码定义为UTF-8。UTF-8~码是一U兼Ҏ有语a的编码方式,惟一比较ȝ的就是要扑ֈ应用pȝ的所有出入口Q然后用UTF-8?#8220;l扎”它?/p>

  一个J2EE应用pȝ需要做下列几步工作Q?/p>

  1. 开发和~译代码时指定字W集为UTF-8。JBuilder和Eclipse都可以在目属性中讄?
  2. 使用qo器,如果所有请求都l过一个Servlet控制分配器,那么使用Servlet的filter执行语句Q将所有来自浏览器的请求(requestQ{换ؓUTF-8Q因为浏览器发过来的h包根据浏览器所在的操作pȝ~码Q可能是各种形式~码。关键一句:
    request.setCharacterEncoding("UTF-8")?br /> |上有此filter的源码,Jdon框架源码中com.jdon.util.SetCharacterEncodingFilter
    需要配|web.xml Ȁz该Filter?
  3. 在JSP头部声明Q?lt;%@ page contentType="text/html;charset= UTF-8" %>?
  4. 在Jsp的html代码中,声明UTF-8:
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. 讑֮数据库连接方式是UTF-8。例如连接MYSQL旉|URL如下Q?br /> jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
    注意Q上q写法是JBoss的mysql-ds.xml写法Q多亏网友提C,在tomcat?amp;amp;要写?amp;卛_。一般其他数据库都可以通过理讄讑֮UTF-8
  6. 其他和外界交互时能够讑֮~码时就讑֮UTF-8Q例如读取文Ӟ操作XML{?
W者以前在Jsp/Servlet时就采取q个原则Q后来用Struts、Tapestry、EJB、Hibernate、Jdon{框架时Q从未被? 码困扰过Q可以说适合各种架构。希望本Ҏ供更多初学者分享,减少Java/J2EE的第一个拦路虎Q也避免因ؓ采取一些时解x案,D中文问题一? 出现在新的技术架构中 

]]>
[转蝲]Session详解 http://m.tkk7.com/illhan/archive/2006/09/19/70524.htmljava执著?/dc:creator>java执著?/author>Tue, 19 Sep 2006 06:35:00 GMThttp://m.tkk7.com/illhan/archive/2006/09/19/70524.htmlhttp://m.tkk7.com/illhan/comments/70524.htmlhttp://m.tkk7.com/illhan/archive/2006/09/19/70524.html#Feedback1http://m.tkk7.com/illhan/comments/commentRss/70524.htmlhttp://m.tkk7.com/illhan/services/trackbacks/70524.html标题QSession详解
[评论]

作者:郎云鹏(dev2dev ID: hippiewolfQ?/p>

摘要Q虽然session机制在web应用E序中被采用已经很长旉了,但是仍然有很多h不清楚session机制的本质,以至不能正确的应用这一技术。本文将详细讨论session的工作机制ƈ且对在Java web application中应用session机制时常见的问题作出解答?/p>

目录Q?br />一、术语session
二、HTTP协议与状态保?/a>
三、理解cookie机制
四、理解session机制
五、理解javax.servlet.http.HttpSession
六、HttpSession常见问题
七、跨应用E序的session׃n
八、ȝ
参考文?/a>

一、术语session
在我的经验里Qsessionq个词被滥用的程度大概仅ơ于transactionQ更加有的是transaction与session在某些语境下的含义是相同的?/p>

sessionQ中文经常翻译ؓ会话Q其本来的含义是指有始有l的一pd动作/消息Q比如打电话时从拿v电话拨号到挂断电话这中间的一pdq程可以UCZ个session。有时候我们可以看到这L话“在一个浏览器会话期间Q?..”,q里的会话一词用的就是其本义Q是指从一个浏览器H口打开到关闭这个期间①。最混ؕ的是“用P客户端)在一ơ会话期间”这样一句话Q它可能指用L一pd动作Q一般情况下是同某个具体目的相关的一pd动作Q比如从d到选购商品到结账登样一个网上购物的q程Q有时候也被称Z个transactionQ,然而有时候也可能仅仅是指一ơ连接,也有可能是指含义①,其中的差别只能靠上下文来推断②?/p>

然而当session一词与|络协议相关联时Q它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到Ҏ接了电话通信才能开始,与此相对的是写信Q在你把信发出去的时候你q不能确认对方的地址是否正确Q通信渠道不一定能建立Q但对发信h来说Q通信已经开始了。“保持状态”则是指通信的一方能够把一pd的消息关联v来,使得消息之间可以互相依赖Q比如一个服务员能够认出再次光的老顾客ƈ且记得上ơ这个顾客还Ơ店里一块钱。这一cȝ例子有“一个TCP session”或者“一个POP3 session”③?/p>

而到了web服务器蓬勃发展的时代Qsession在web开发语境下的语义又有了新的扩展Q它的含义是指一cȝ来在客户端与服务器之间保持状态的解决Ҏ④。有时候session也用来指q种解决Ҏ的存储结构,如“把xxx保存在session里”⑤。由于各U用于web开发的语言在一定程度上都提供了对这U解x案的支持Q所以在某种特定语言的语境下Qsession也被用来指代该语a的解x案,比如l常把Java里提供的javax.servlet.http.HttpSessionUCؓsession⑥?/p>

鉴于q种混ؕ已不可改变,本文中session一词的q用也会Ҏ上下文有不同的含义,请大家注意分辨?br />在本文中Q用中文“浏览器会话期间”来表达含义①,使用“session机制”来表达含义④,使用“session”表辑֐义⑤Q用具体的“HttpSession”来表达含义?/p>

二、HTTP协议与状态保?/strong>
HTTP协议本n是无状态的Q这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器h下蝲某些文gQ无论是客户端还是服务器都没有必要纪录彼此过ȝ行ؓQ每一ơ请求之间都是独立的Q好比一个顾客和一个自动售货机或者一个普通的Q非会员Ӟ大卖Z间的关系一栗?/p>

然而聪明(或者贪心?Q的Z很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用Q就像给有线电视加上Ҏ功能一栗这U需求一斚wqHTML逐步d了表单、脚本、DOM{客L行ؓQ另一斚w在服务器端则出现了CGI规范以响应客L的动态请求,作ؓ传输载体的HTTP协议也添加了文g上蝲、cookieq些Ҏ。其中cookie的作用就是ؓ了解决HTTP协议无状态的~陷所作出的努力。至于后来出现的session机制则是又一U在客户端与服务器之间保持状态的解决Ҏ?/p>

让我们用几个例子来描qC下cookie和session机制之间的区别与联系。笔者曾l常ȝ一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠Q然而一ơ性消?杯咖啡的Z微乎其微Q这时就需要某U方式来U录某位֮的消Ҏ量。想象一下其实也无外乎下面的几种ҎQ?br />1、该店的店员很厉宻I能记住每位顾客的消费数量Q只要顾客一走进咖啡店,店员q道该怎么对待了。这U做法就是协议本w支持状态?br />2、发l顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每ơ消ҎQ如果顾客出C张卡片,则此ơ消费就会与以前或以后的消费相联pv来。这U做法就是在客户端保持状态?br />3、发l顾客一张会员卡Q除了卡号之外什么信息也不纪录,每次消费Ӟ如果֮出示该卡片,则店员在店里的纪录本上找到这个卡号对应的U录d一些消费信息。这U做法就是在服务器端保持状态?/p>

׃HTTP协议是无状态的Q而出于种U考虑也不希望使之成ؓ有状态的Q因此,后面两种Ҏ成为现实的选择。具体来说cookie机制采用的是在客L保持状态的ҎQ而session机制采用的是在服务器端保持状态的Ҏ。同时我们也看到Q由于采用服务器端保持状态的Ҏ在客L也需要保存一个标识,所以session机制可能需要借助于cookie机制来达C存标识的目的Q但实际上它q有其他选择?/p>

三、理解cookie机制
cookie机制的基本原理就如上面的例子一L单,但是q有几个问题需要解冻I“会员卡”如何分发;“会员卡”的内容Q以及客户如何用“会员卡”?/p>

正统的cookie分发是通过扩展HTTP协议来实现的Q服务器通过在HTTP的响应头中加上一行特D的指示以提C浏览器按照指示生成相应的cookie。然而纯_的客户端脚本如JavaScript或者VBScript也可以生成cookie?/p>

而cookie的用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器查所有存储的cookieQ如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置Q则把该cookie附在h资源的HTTPh头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示Q如果某家分店还发行了自q会员卡,那么q这家店的时候除了要出示麦当劳的会员卡,q要出示q家店的会员卡?/p>

cookie的内容主要包括:名字Q|q期旉Q\径和域?br />其中域可以指定某一个域比如.google.comQ相当于d招牌Q比如宝z公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.comQ可以用飘柔来做比?br />路径是跟在域名后面的URL路径Q比?或?foo{等Q可以用某飘柔专柜做比?br />路径与域合在一起就构成了cookie的作用范围?br />如果不设|过期时_则表C个cookie的生命期为浏览器会话期间Q只要关闭浏览器H口Qcookie消׃。这U生命期为浏览器会话期的cookie被称Z话cookie。会话cookie一般不存储在硬盘上而是保存在内存里Q当然这U行为ƈ不是规范规定的。如果设|了q期旉Q浏览器׃把cookie保存到硬盘上Q关闭后再次打开览器,q些cookie仍然有效直到过讑֮的过期时间?/p>

存储在硬盘上的cookie可以在不同的览器进E间׃nQ比如两个IEH口。而对于保存在内存里的cookieQ不同的览器有不同的处理方式。对于IEQ在一个打开的窗口上按Ctrl-NQ或者从文g菜单Q打开的窗口可以与原窗口共享,而用其他方式新开的IEq程则不能共享已l打开的窗口的内存cookieQ对于Mozilla Firefox0.8Q所有的q程和标{N都可以共享同Lcookie。一般来说是用javascript的window.open打开的窗口会与原H口׃n内存cookie。浏览器对于会话cookie的这U只认cookie不认人的处理方式l常l采用session机制的web应用E序开发者造成很大的困扰?/p>

下面是一个goolge讄cookie的响应头的例?br />HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html


q是使用HTTPLookq个HTTP Sniffer软g来俘LHTTP通讯U录的一部分


览器在再次讉Kgoolge的资源时自动向外发送cookie


使用Firefox可以很容易的观察现有的cookie的?br />使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理?/p>


IE也可以设|在接受cookie前询?/p>


q是一个询问接受cookie的对话框?/p>

四、理解session机制
session机制是一U服务器端的机制Q服务器使用一U类g散列表的l构Q也可能是使用散列表)来保存信息?/p>

当程序需要ؓ某个客户端的h创徏一个session的时候,服务器首先检查这个客L的请求里是否已包含了一个session标识 - UCؓsession idQ如果已包含一个session id则说明以前已lؓ此客L创徏qsessionQ服务器按照session id把这个session索出来用(如果索不刎ͼ可能会新Z个)Q如果客Lh不包含session idQ则为此客户端创Z个sessionq且生成一个与此session相关联的session idQsession id的值应该是一个既不会重复Q又不容易被扑ֈ规律以仿造的字符Ԍq个session id被在本ơ响应中q回l客L保存?/p>

保存q个session id的方式可以采用cookieQ这样在交互q程中浏览器可以自动的按照规则把q个标识发挥l服务器。一般这个cookie的名字都是类gSEEESIONIDQ而。比如weblogic对于web应用E序生成的cookieQJSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764Q它的名字就是JSESSIONID?/p>

׃cookie可以被h为的止Q必L其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一U技术叫做URL重写Q就是把session id直接附加在URL路径的后面,附加方式也有两种Q一U是作ؓURL路径的附加信息,表现形式为http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一U是作ؓ查询字符串附加在URL后面Q表现Ş式ؓhttp://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
q两U方式对于用h说是没有区别的,只是服务器在解析的时候处理的方式不同Q采用第一U方式也有利于把session id的信息和正常E序参数区分开来?br />Z在整个交互过E中始终保持状态,必d每个客户端可能请求的路径后面都包含这个session id?/p>

另一U技术叫做表单隐藏字Dc就是服务器会自动修改表单,d一个隐藏字D,以便在表单提交时能够把session id传递回服务器。比如下面的表单
<form name="testform" action="/xxx">
<input type="text">
</form>
在被传递给客户端之前将被改写成
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
q种技术现在已较少应用Q笔者接触过的很古老的iPlanet6(SunONE应用服务器的前n)׃用了q种技术?br />实际上这U技术可以简单的用对action应用URL重写来代ѝ?/p>

在谈论session机制的时候,常常听到q样一U误解“只要关闭浏览器Qsession消׃”。其实可以想象一下会员卡的例子,除非֮d对店家提出销卡,否则店家l对不会L删除֮的资料。对session来说也是一LQ除非程序通知服务器删除一个sessionQ否则服务器会一直保留,E序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会d在关闭之前通知服务器它要关闭Q因此服务器Ҏ不会有机会知道浏览器已经关闭Q之所以会有这U错觉,是大部分session机制都用会话cookie来保存session idQ而关闭浏览器后这个session id消׃Q再ơ连接服务器时也无法找到原来的session。如果服务器讄的cookie被保存到盘上,或者用某U手D|写浏览器发出的HTTPh_把原来的session id发送给服务器,则再ơ打开览器仍然能够找到原来的session?/p>

恰恰是由于关闭浏览器不会Dsession被删除,q服务器ؓseesion讄了一个失效时_当距dL上一ơ用session的时间超q这个失效时间时Q服务器可以认为客L已经停止了活动,才会把session删除以节省存储空间?/p>

五、理解javax.servlet.http.HttpSession
HttpSession是Javaq_对session机制的实现规范,因ؓ它仅仅是个接口,具体到每个web应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作ؓ例子来演C?/p>

首先QWeblogic Server提供了一pd的参数来控制它的HttpSession的实玎ͼ包括使用cookie的开关选项Q用URL重写的开关选项Qsession持久化的讄Qsession失效旉的设|,以及针对cookie的各U设|,比如讄cookie的名字、\径、域Qcookie的生存时间等?/p>

一般情况下Qsession都是存储在内存里Q当服务器进E被停止或者重启的时候,内存里的session也会被清I,如果讄了session的持久化Ҏ,服务器就会把session保存到硬盘上Q当服务器进E重新启动或q些信息能够被再次使用QWeblogic Server支持的持久性方式包括文件、数据库、客Lcookie保存和复制?/p>

复制严格说来不算持久化保存,因ؓsession实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进E中Q这样即使某个服务器q程停止工作也仍然可以从其他q程中取得session?/p>

cookie生存旉的设|则会媄响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解?/p>

cookie的\径对于web应用E序来说是一个非帔R要的选项QWeblogic Server对这个选项的默认处理方式得它与其他服务器有明昄区别。后面我们会专题讨论?/p>

关于session的设|参考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

六、HttpSession常见问题
Q在本小节中session的含义ؓ⑤和⑥的混合Q?/p>


1、session在何时被创徏
一个常见的误解是以为session在有客户端访问时p创徏Q然而事实是直到某server端程序调用HttpServletRequest.getSession(true)q样的语句时才被创徏Q注意如果JSP没有昄的?<%@page session="false"%> 关闭sessionQ则JSP文g在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);q也是JSP中隐含的session对象的来历?/p>

׃session会消耗内存资源,因此Q如果不打算使用sessionQ应该在所有的JSP中关闭它?/p>

2、session何时被删?br />l合前面的讨论,session在下列情况下被删除a.E序调用HttpSession.invalidate();或b.距离上一ơ收到客L发送的session id旉间隔过了session的超时设|?或c.服务器进E被停止Q非持久sessionQ?/p>

3、如何做到在览器关闭时删除session
严格的讲Q做不到q一炏V可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进E这些非常规手段仍然无能为力?/p>

4、有个HttpSessionListener是怎么回事
你可以创Llistenerȝ控session的创建和销毁事Ӟ使得在发生这L事g时你可以做一些相应的工作。注意是session的创建和销毁动作触发listenerQ而不是相反。类似的与HttpSession有关的listenerq有HttpSessionBindingListenerQHttpSessionActivationListener和HttpSessionAttributeListener?/p>

5、存攑֜session中的对象必须是可序列化的?br />不是必需的。要求对象可序列化只是ؓ了session能够在集中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放|一个不可序列化的对象在控制C会收C个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象Q在session销毁时会有一个ExceptionQ很奇怪?/p>

6、如何才能正的应付客户端禁止cookie的可能?br />Ҏ有的URL使用URL重写Q包括超链接Qform的actionQ和重定向的URLQ具体做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

7、开两个览器窗口访问应用程序会使用同一个sessionq是不同的session
参见W三节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器Q不同的H口打开方式以及不同的cookie存储方式都会对这个问题的{案有媄响?/p>

8、如何防止用h开两个览器窗口操作导致的session混ؕ
q个问题与防止表单多ơ提交是cM的,可以通过讄客户端的令牌来解冟뀂就是在服务器每ơ生成一个不同的idq回l客LQ同时保存在session里,客户端提交表单时必须把这个id也返回服务器Q程序首先比较返回的id与保存在session里的值是否一_如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表C层模式的部分。需要注意的是对于用javascript window.open打开的窗口,一般不讄q个idQ或者用单独的idQ以防主H口无法操作Q徏议不要再window.open打开的窗口里做修Ҏ作,q样可以不用设|?/p>

9、ؓ什么在Weblogic Server中改变session的值后要重新调用一ơsession.setValue
做这个动作主要是Z在集环境中提示Weblogic Server session中的值发生了改变Q需要向其他服务器进E复制新的session倹{?/p>

10、ؓ什么session不见?br />排除session正常失效的因素之外,服务器本w的可能性应该是微乎其微的,虽然W者在iPlanet6SP1加若q补丁的Solaris版本上倒也遇到q;览器插件的可能性次之,W者也遇到q?721插g造成的问题;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题?br />出现q一问题的大部分原因都是E序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨个问题?/p>

七、跨应用E序的session׃n

常常有这L情况Q一个大目被分割成若干项目开发,Z能够互不q扰Q要求每个小目作ؓ一个单独的web应用E序开发,可是C最后突然发现某几个项目之间需要共享一些信息,或者想使用session来实现SSO(single sign on)Q在session中保存login的用户信息,最自然的要求是应用E序间能够访问彼此的session?/p>

然而按照Servlet规范Qsession的作用范围应该仅仅限于当前应用程序下Q不同的应用E序之间是不能够互相讉KҎ的session的。各个应用服务器从实际效果上都遵守了q一规范Q但是实现的l节却可能各有不同,因此解决跨应用程序session׃n的方法也各不相同?/p>

首先来看一下Tomcat是如何实现web应用E序之间session的隔ȝQ从Tomcat讄的cookie路径来看Q它对不同的应用E序讄的cookie路径是不同的Q这样不同的应用E序所用的session id是不同的Q因此即使在同一个浏览器H口里访问不同的应用E序Q发送给服务器的session id也可以是不同的?br />

Ҏq个Ҏ,我们可以推测Tomcat中session的内存结构大致如下?br />

W者以前用q的iPlanet也采用的是同L方式Q估计SunONE与iPlanet之间不会有太大的差别。对于这U方式的服务器,解决的思\很简单,实际实行h也不难。要么让所有的应用E序׃n一个session idQ要么让应用E序能够获得其他应用E序的session id?/p>

iPlanet中有一U很单的Ҏ来实现共享一个session idQ那是把各个应用程序的cookie路径都设?Q实际上应该?NASAppQ对于应用程序来讲它的作用相当于根)?br /><session-info>
<path>/NASApp</path>
</session-info>

需要注意的是,操作׃n的session应该遵@一些编E约定,比如在session attribute名字的前面加上应用程序的前缀Q得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")Q以防止命名I间冲突Q导致互相覆盖?/p>


在Tomcat中则没有q么方便的选择。在Tomcat版本3上,我们q可以有一些手D|׃nsession。对于版?以上的TomcatQ目前笔者尚未发现简单的办法。只能借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段?/p>

我们再看一下Weblogic Server是如何处理session的?br />

从截屏画面上可以看到Weblogic ServerҎ有的应用E序讄的cookie的\径都?Q这是不是意味着在Weblogic Server中默认的可以共享session了呢Q然而一个小实验卛_证明即不同的应用程序用的是同一个sessionQ各个应用程序仍然只能访问自己所讄的那些属性。这说明Weblogic Server中的session的内存结构可能如?br />

对于q样一U结构,在session机制本n上来解决session׃n的问题应该是不可能的了。除了借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段Q还有一U较为方便的做法Q就是把一个应用程序的session攑ֈServletContext中,q样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

应用E序A
context.setAttribute("appA", session);

应用E序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

值得注意的是q种用法不可ULQ因为根据ServletContext的JavaDocQ应用服务器可以处于安全的原因对于context.getContext("/appA");q回I|以上做法在Weblogic Server 8.1中通过?/p>

那么Weblogic ServerZ么要把所有的应用E序的cookie路径都设?呢?原来是ؓ了SSOQ凡是共享这个session的应用程序都可以׃n认证的信息。一个简单的实验可以证明这一点,修改首先d的那个应用程序的描述Wweblogic.xmlQ把cookie路径修改?appA讉K另外一个应用程序会重新要求dQ即使是反过来,先访问cookie路径?的应用程序,再访问修改过路径的这个,虽然不再提示dQ但是登录的用户信息也会丢失。注意做q个实验时认证方式应该用FORMQ因为浏览器和web服务器对basic认证方式有其他的处理方式Q第二次h的认证不是通过session来实现的。具体请参看[7] secion 14.8 AuthorizationQ你可以修改所附的CZE序来做q些试验?/p>

八、ȝ
session机制本nq不复杂Q然而其实现和配|上的灵zL却使得具体情况复杂多变。这也要求我们不能把仅仅某一ơ的l验或者某一个浏览器Q服务器的经验当作普遍适用的经验,而是始终需要具体情况具体分析?/p>

关于作者:
郎云鹏(dev2dev ID: hippiewolfQ,软g工程师,从事J2EE开?br />电子邮gQlangyunpeng@yahoo.com.cn
地址Q大qY件园?1L技大厦A座大q博涵咨询服务有限公?/p>

参考文档:
[1] Preliminary Specification http://wp.netscape.com/newsref/std/cookie_spec.html
[2] RFC2109 http://www.rfc-editor.org/rfc/rfc2109.txt
[3] RFC2965 http://www.rfc-editor.org/rfc/rfc2965.txt
[4] The Unofficial Cookie FAQ http://www.cookiecentral.com/faq/
[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869
[6] http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
[7] RFC2616 http://www.rfc-editor.org/rfc/rfc2616.txt

代码下蝲Q?a >sampleApp.zip



java执著?/a> 2006-09-19 14:35 发表评论
]]>
谈谈Unicode~码Q简要解释UCS、UTF、BMP、BOM{名?/title><link>http://m.tkk7.com/illhan/archive/2006/06/29/55781.html</link><dc:creator>java执著?/dc:creator><author>java执著?/author><pubDate>Thu, 29 Jun 2006 08:56:00 GMT</pubDate><guid>http://m.tkk7.com/illhan/archive/2006/06/29/55781.html</guid><wfw:comment>http://m.tkk7.com/illhan/comments/55781.html</wfw:comment><comments>http://m.tkk7.com/illhan/archive/2006/06/29/55781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/illhan/comments/commentRss/55781.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/illhan/services/trackbacks/55781.html</trackback:ping><description><![CDATA[ <p> <font size="2">q是一程序员写给E序员的味ȝ。所谓趣x指可以比较轻村֜了解一些原来不清楚的概念,增进知识Q类g打RPG游戏的升U。整理这文章的动机是两个问题:</font> </p> <dl> <dt> <font size="2">问题一Q?/font> </dt> <dd> <p> <font size="2">使用WindowsC本的“另存ؓ”,可以在GBK、Unicode、Unicode big endian和UTF-8q几U编码方式间怺转换。同htxt文gQWindows是怎样识别~码方式的呢Q?/font> </p> <p> <font size="2">? 很早前就发现Unicode、Unicode big endian和UTF-8~码的txt文g的开头会多出几个字节Q分别是FF、FE QUnicodeQ?FE、FFQUnicode big endianQ?EF、BB、BFQUTF-8Q。但q些标记是基于什么标准呢Q?/font> </p> </dd> <dt> <font size="2">问题二: </font> </dt> <dd> <font size="2">最 q在|上看到一个ConvertUTF.cQ实CUTF-32、UTF-16和UTF-8q三U编码方式的怺转换。对于Unicode(UCS2)? GBK、UTF-8q些~码方式Q我原来׃解。但q个E序让我有些p涂Q想不v来UTF-16和UCS2有什么关pR?/font> </dd> </dl> <p> <font size="2">查了查相兌料,ȝ这些问题弄清楚了,带也了解了一些Unicode的细节。写成一文章,送给有过cM疑问的朋友。本文在写作时尽量做到通俗易懂Q但要求读者知道什么是字节Q什么是十六q制?/font> </p> <h3> <font size="2">0、big endian和little endian</font> </h3> <p> <font size="2">big endian 和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode~码?C49。那么写到文仉ӞI竟是将6C写在前面Q? q是?9写在前面Q如果将6C写在前面Q就是big endian。如果将49写在前面Q就是little endian?/font> </p> <p> <font size="2">“endian”这个词《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开q是从小?Little-Endian)敲开Q由此曾发生q六ơ叛乱,一个皇帝送了命,另一个丢了王位?/font> </p> <p> <font size="2">我们一般将endian译成“字节序”,big endian和little endianUC“大䏀和“小䏀?/font> </p> <h3> <font size="2">1、字W编码、内码,带介绍汉字~码</font> </h3> <p> <font size="2">字符必须~码后才能被计算机处理。计机使用的缺省编码方式就是计机的内码。早期的计算Z?位的ASCII~码Qؓ了处理汉字,E序员设计了用于体中文的GB2312和用于繁体中文的big5?/font> </p> <p> <font size="2">GB2312(1980q?一共收录了7445个字W,包括6763个汉字和682个其它符受汉字区的内码范围高字节从B0-F7Q低字节从A1-FEQ占用的码位?2*94=6768。其中有5个空位是D7FA-D7FE?/font> </p> <p> <font size="2">GB2312支持的汉字太?995q的汉字扩展规范GBK1.0收录?1886个符P它分为汉字区和图形符号区。汉字区包括21003个字W?/font> </p> <p> <font size="2">从ASCII? GB2312到GBKQ这些编码方法是向下兼容的,卛_一个字W在q些Ҏ中L有相同的~码Q后面的标准支持更多的字W。在q些~码中,英文和中文可? l一地处理。区分中文编码的Ҏ是高字节的最高位不ؓ0。按照程序员的称|GB2312、GBK都属于双字节字符集?DBCS)?/font> </p> <p> <font size="2">2000 q的GB18030是取代GBK1.0的正式国家标准。该标准收录?7484个汉字,同时q收录了藏文、蒙文、维向ְ文等主要的少数民族文字。从汉字? 汇上_GB18030在GB13000.1?0902个汉字的基础上增加了CJK扩展A?582个汉字(Unicode?x3400- 0x4db5Q,一共收录了27484个汉字?/font> </p> <p> <font size="2">CJK是中日韩的意思。UnicodeZ节省码位Q将中日韩三国语a中的文字l一~码。GB13000.1是ISO/IEC 10646-1的中文版Q相当于Unicode 1.1?/font> </p> <p> <font size="2">GB18030 的编码采用单字节、双字节?字节Ҏ。其中单字节、双字节和GBK是完全兼容的?字节~码的码位就是收录了CJK扩展A?582个汉字。 例如: UCS?x3400在GB18030中的~码应该?139EF30QUCS?x3401在GB18030中的~码应该?139EF31?/font> </p> <p> <font size="2">微Y提供了GB18030的升U包Q但q个升包只是提供了一套支持CJK扩展A?582个汉字的新字体:新宋?18030Qƈ不改变内码。Windows 的内码仍然是GBK?/font> </p> <p> <font size="2">q里q有一些细节:</font> </p> <ul> <li> <p> <font size="2">GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0?/font> </p> </li> <li> <p> <font size="2">? 于Q何字W编码,~码单元的顺序是q码方案指定的Q与endian无关。例如GBK的编码单元是字节Q用两个字节表示一个汉字。 这两个字节的顺序是? 定的Q不受CPU字节序的影响。UTF-16的编码单元是wordQ双字节Q,word之间的顺序是~码Ҏ指定的,word内部的字节排列才会受? endian的媄响。后面还会介lUTF-16?/font> </p> </li> <li> <p> <font size="2">GB2312的两个字节的最高位都是1。但W合q个条g的码位只? 128*128=16384个。所以GBK和GB18030的低字节最高位都可能不?。不q这不媄响DBCS字符的解析Q在dDBCS字符时Q只 要遇到高位ؓ1的字节,可以将下两个字节作Z个双字节~码Q而不用管低字节的高位是什么?/font> </p> </li> </ul> <h3> <font size="2">2、Unicode、UCS和UTF</font> </h3> <p> <font size="2">前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容Q更准确地说Q是与ISO-8859-1兼容Q,与GB码不兼容。例如“汉”字的Unicode~码?C49Q而GB码是BABA?/font> </p> <p> <font size="2">Unicode 也是一U字W编码方法,不过它是由国际组l设计,可以容纳全世界所有语a文字的编码方案。Unicode的学名是"Universal Multiple -Octet Coded Character Set"Q简UCؓUCS。UCS可以看作?Unicode Character Set"的羃写?/font> </p> <p> <font size="2">Ҏl基癄全书(<a target="_blank">http://zh.wikipedia.org/wiki/)</a>的记载:历史上存在两个试囄立设计Unicode的组l,卛_际标准化l织QISOQ和一个Y件制造商的协会(unicode.orgQ。ISO开发了ISO 10646目QUnicode协会开发了Unicode目?/font> </p> <p> <font size="2">?991q前后,双方都认识到世界不需要两个不兼容的字W集。于是它们开始合q双方的工作成果Qƈ为创立一个单一~码表而协同工作。从Unicode2.0开始,Unicode目采用了与ISO 10646-1相同的字库和字码?/font> </p> <p> <font size="2">目前两个目仍都存在Qƈ独立地公布各自的标准。Unicode协会现在的最新版本是2005q的Unicode 4.1.0。ISO的最新标准是ISO 10646-3:2003?/font> </p> <p> <font size="2">UCS 只是规定如何~码Qƈ没有规定如何传输、保存这个编码。例如“汉”字的UCS~码?C49Q我可以?个ascii数字来传输、保存这个编码;也可以用 utf-8~码:3个连l的字节E6 B1 89来表C它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的Ҏ? UTF-8的一个特别的好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的~写?/font> </p> <p> <font size="2">IETF 的RFC2781和RFC3629以RFC的一贯风|清晰、明快又不失严}地描qCUTF-16和UTF-8的编码方法。我LC得IETF? Internet Engineering Task Force的羃写。但IETF负责l护的RFC是Internet上一切规范的基础?/font> </p> <h4> <font size="2">2.1、内码和code page</font> </h4> <p> <font size="2">目前Windows的内核已l支持Unicode字符集,q样在内怸可以支持全世界所有的语言文字。但是由于现有的大量E序和文都采用了某U特定语a的编码,例如GBKQWindows不可能不支持现有的编码,而全部改用Unicode?/font> </p> <p> <font size="2">Windows使用代码?code page)来适应各个国家和地区。code page可以被理解ؓ前面提到的内码。GBK对应的code page是CP936?/font> </p> <p> <font size="2">微Y也ؓGB18030定义了code pageQCP54936。但是由于GB18030有一部分4字节~码Q而Windows的代码页只支持单字节和双字节~码Q所以这个code page是无法真正用的?/font> </p> <h3> <font size="2">3、UCS-2、UCS-4、BMP</font> </h3> <p> <font size="2">UCS有两U格式:UCS-2和UCS-4。顾名思义QUCS-2是用两个字节编码,UCS-4是?个字节(实际上只用了31位,最高位必须?Q编码。下面让我们做一些简单的数学游戏Q?/font> </p> <p> <font size="2">UCS-2?^16=65536个码位,UCS-4?^31=2147483648个码位?/font> </p> <p> <font size="2">UCS -4Ҏ最高位?的最高字节分?^7=128个group。每个group再根据次高字节分?56个plane。每个planeҎW?个字节分? 256行?rows)Q每行包?56个cells。当然同一行的cells只是最后一个字节不同,其余都相同?/font> </p> <p> <font size="2">group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节ؓ0的码位被UCBMP?/font> </p> <p> <font size="2">UCS-4的BMPL前面的两个零字节得CUCS-2。在UCS-2的两个字节前加上两个零字节,得CUCS-4的BMP。而目前的UCS-4规范中还没有M字符被分配在BMP之外?/font> </p> <h3> <font size="2">4、UTF~码</font> </h3> <p> <font size="2">UTF-8是?位ؓ单元对UCSq行~码。从UCS-2到UTF-8的编码方式如下:</font> </p> <table border="1" width="75%"> <tbody> <tr> <td> <font size="2">UCS-2~码(16q制)</font> </td> <td> <font size="2">UTF-8 字节?二进?</font> </td> </tr> <tr> <td> <font size="2">0000 - 007F</font> </td> <td> <font size="2">0xxxxxxx</font> </td> </tr> <tr> <td> <font size="2">0080 - 07FF</font> </td> <td> <font size="2">110xxxxx 10xxxxxx</font> </td> </tr> <tr> <td> <font size="2">0800 - FFFF</font> </td> <td> <font size="2">1110xxxx 10xxxxxx 10xxxxxx</font> </td> </tr> </tbody> </table> <p> <font size="2">例如“汉”字的Unicode~码?C49?C49?800-FFFF之间Q所以肯定要?字节模板了:</font> <font color="#0000ff" size="2">1110</font> <font size="2">xxxx </font> <font color="#0000ff" size="2">10</font> <font size="2">xxxxxx </font> <font color="#0000ff" size="2">10</font> <font size="2">xxxxxx。将6C49写成二进制是Q?110 110001 001001Q 用q个比特依ơ代替模板中的xQ得刎ͼ</font> <font color="#0000ff" size="2">1110</font> <font size="2">0110 </font> <font color="#0000ff" size="2">10</font> <font size="2">110001 </font> <font color="#0000ff" size="2">10</font> <font size="2">001001Q即E6 B1 89?/font> </p> <p> <font size="2">读者可以用C本测试一下我们的~码是否正确。需要注意,UltraEdit在打开utf-8~码的文本文件时会自动{换ؓUTF-16Q可能生؜淆。你可以在设|中xq个选项。更好的工具是Hex Workshop?/font> </p> <p> <font size="2">UTF -16?6位ؓ单元对UCSq行~码。对于小?x10000的UCS码,UTF-16~码q于UCS码对应的16位无W号整数。对于不于 0x10000的UCS码,定义了一个算法。不q由于实际用的UCS2Q或者UCS4的BMP必然于0x10000Q所以就目前而言Q可以认为UTF -16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题?/font> </p> <h3> <font size="2">5、UTF的字节序和BOM</font> </h3> <p> <font size="2">UTF -8以字节ؓ~码单元Q没有字节序的问题。UTF-16以两个字节ؓ~码单元Q在解释一个UTF-16文本前,首先要弄清楚每个~码单元的字节序。例? “奎”的Unicode~码?94EQ“乙”的Unicode~码?E59。如果我们收到UTF-16字节?94E”,那么q是“奎”还? “乙”?</font> </p> <p> <font size="2">Unicode规范中推荐的标记字节序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:</font> </p> <p> <font size="2">在UCS ~码中有一个叫?ZERO WIDTH NO-BREAK SPACE"的字W,它的~码是FEFF。而FFFE在UCS中是不存在的字符Q所以不应该 出现在实际传输中。UCS规范我们在传输字节流前,先传输字W?ZERO WIDTH NO-BREAK SPACE"?/font> </p> <p> <font size="2">q样如果接收者收到FEFFQ就表明q个字节是Big-Endian的;如果收到FFFEQ就表明q个字节是Little-Endian的。因此字W?ZERO WIDTH NO-BREAK SPACE"又被UCBOM?/font> </p> <p> <font size="2">UTF -8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字W?ZERO WIDTH NO-BREAK SPACE"的UTF-8~码? EF BB BFQ读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收CEF BB BF开头的字节,q道这是UTF-8~码了?/font> </p> <p> <font size="2">Windows是使用BOM来标记文本文件的~码方式的?/font> </p> <h3> <font size="2">6、进一步的参考资?/font> </h3> <p> <font size="2">本文主要参考的资料是?Short overview of ISO-IEC 10646 and Unicode" (<a target="_blank">http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)</a>?/font> </p> <p> <font size="2">我还找了两篇看上M错的资料Q不q因为我开始的疑问都找C{案Q所以就没有看:</font> </p> <ol> <li> <font size="2">"Understanding Unicode A general introduction to the Unicode Standard" (<a target="_blank">http://scripts.sil.org/cms/scrip ... S-Chapter04a) </a></font> </li> <li> <font size="2">"Character set encoding basics Understanding character set encodings and legacy encodings" (<a target="_blank">http://scripts.sil.org/cms/scrip ... WS-Chapter03) </a></font> </li> </ol> <p> <font size="2">我写qUTF-8、UCS-2、GBK怺转换的Y件包Q包括用Windows API和不使用Windows API的版本。以后有旉的话Q我会整理一下放到我的个Z上(<a target="_blank">http://fmddlmyy.home4u.china.com)</a>?/font> </p> <p> <font size="2">我是x楚所有问题后才开始写q篇文章的,原以Z会儿p写好。没惛_考虑措辞和查证细节花费了很长旉Q竟然从下午1:30写到9:00。希望有读者能从中受益?/font> </p> <h3> <font size="2">附录1 再说说区位码、GB2312、内码和代码?/font> </h3> <p> <font size="2">有的朋友Ҏ章中q句话还有疑问:<br />“GB2312的原文还是区位码Q从Z码到内码Q需要在高字节和低字节上分别加上A0。?/font> </p> <p> <font size="2">我再详细解释一下:</font> </p> <p> <font size="2">“GB2312 的原文”是指国?980q的一个标准《中华h民共和国国家标准 信息交换用汉字编码字W集 基本集 GB 2312-80》。这个标准用两个数来~码? 字和中文W号。第一个数UCؓ“区”,W二个数UCؓ“位”。所以也UCؓZ码?-9区是中文W号Q?6-55区是一U汉字,56-87区是二汉字。现? Windows也还有区位输入法Q例如输?601得到“啊”。(q个Z输入法可以自动识?6q制的GB2312?0q制的区位码Q也是说输? B0A1同样会得到“啊”。)</font> </p> <p> <font size="2">内码是指操作pȝ内部的字W编码。早期操作系l的内码是与语言相关的。现在的Windows在系l内部支持UnicodeQ然后用代码适应各种语言Q“内码”的概念比较模p了。微软一般将~省代码|定的~码说成是内码?/font> </p> <p> <font size="2">内码q个词汇Qƈ没有什么官方的定义Q代码页也只是微软这个公司的叫法。作为程序员Q我们只要知道它们是什么东西,没有必要q多地考证q些名词?/font> </p> <p> <font size="2">所谓代码页(code page)是针对一U语a文字的字W编码。例如GBK的code page是CP936QBIG5的code page是CP950QGB2312的code page是CP20936?/font> </p> <p> <font size="2">Windows中有~省代码늚概念Q即~省用什么编码来解释字符。例如Windows的记事本打开了一个文本文Ӟ里面的内Ҏ字节:BA、BA、D7、D6。Windows应该L么解释它呢Q?/font> </p> <p> <font size="2">? 按照Unicode~码解释、还是按照GBK解释、还是按照BIG5解释Q还是按照ISO8859-1去解释?如果按GBK去解释,׃得到“汉字”两? 字。按照其它编码解释,可能找不到对应的字符Q也可能扑ֈ错误的字W。所谓“错误”是指与文本作者的本意不符Q这时就产生了ؕ码?/font> </p> <p> <font size="2">{案是Windows按照当前的缺省代码页去解释文本文仉的字节流。缺省代码页可以通过控制面板的区域选项讄。记事本的另存ؓ中有一ANSIQ其实就是按照缺省代码页的编码方法保存?/font> </p> <p> <font size="2">Windows的内码是UnicodeQ它在技术上可以同时支持多个代码c只要文件能说明自己使用什么编码,用户又安装了对应的代码页QWindowsp正确昄Q例如在HTML文g中就可以指定charset?/font> </p> <p> <font size="2">? 的HTML文g作者,特别是英文作者,认ؓ世界上所有h都用英文,在文件中不指定charset。如果他使用?x80-0xff之间的字W,中文 Windows又按照缺省的GBK去解释,׃出现q。这时只要在q个html文g中加上指定charset的语句,例如Q?br /><meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1"><br />如果原作者用的代码和ISO8859-1兼容Q就不会出现q了?/font> </p> <p> <font size="2">? 说区位码Q啊的区位码?601Q写?6q制?x10,0x01。这和计机q泛使用的ASCII~码冲突。ؓ了兼?0-7f的ASCII~码Q我 们在Z码的高、低字节上分别加上A0。这样“啊”的~码成为B0A1。我们将加过两个A0的编码也UCؓGB2312~码Q虽然GB2312的原文根? 没提到这一炏V?<br /></font> </p> <img src ="http://m.tkk7.com/illhan/aggbug/55781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/illhan/" target="_blank">java执著?/a> 2006-06-29 16:56 <a href="http://m.tkk7.com/illhan/archive/2006/06/29/55781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转蝲]UTF-16http://m.tkk7.com/illhan/archive/2006/06/29/55779.htmljava执著?/dc:creator>java执著?/author>Thu, 29 Jun 2006 08:51:00 GMThttp://m.tkk7.com/illhan/archive/2006/06/29/55779.htmlhttp://m.tkk7.com/illhan/comments/55779.htmlhttp://m.tkk7.com/illhan/archive/2006/06/29/55779.html#Feedback0http://m.tkk7.com/illhan/comments/commentRss/55779.htmlhttp://m.tkk7.com/illhan/services/trackbacks/55779.html UTF-16是Unicode的其中一个用方式?UTF?Unicode Translation FormatQ即把Unicode转做某种格式的意思?

它定义于ISO/IEC 10646-1的附录QQ而RFC2781也定义了怼的做法?

在Unicode基本多文U^面定义的字符Q无论是拉丁字母、汉字或其他文字或符PQ一律?字节储存。而在辅助q面定义的字W,会以代理?/i>Qsurrogate pairQ的形式Q以两个2字节的值来储存?

UTF-16比vUTF-8Q好处在于大部分字符都以固定长度的字?(2字节) 储存Q但UTF-16却无法兼容于ASCII~码?

UTF-16的编码模?/font>

UTF-16的大ֺ和小ֺ储存形式都在用。一般来_以Macintosh制作或储存的文字使用大尾序格式,以Microsoft或Linux制作或储存的文字使用尾序格式?

Z弄清楚UTF-16文g的大尾序,在UTF-16文g的开首,都会攄一个U+FEFF字符作ؓByte Order Mark (UTF-16LE ?FF FE 代表QUTF-16BE ?FE FF 代表)Q以昄q个文字案是以UTF-16~码?

以下的例子有四个字符Q“朱”、半角逗号、“聿”、“𨮁”?

使用 UTF-16 ~码的例?
~码名称 ~码ơ序 ~码
UTF-16LE 尾? 31 67, 2C 00, 7F 80, 62 D8 81 DF
UTF-16BE 大尾? 67 31, 00 2C, 80 7F, D8 62 DF 81
UTF-16 尾序,包含BOM FF FE, 31 67, 2C 00, 7F 80, 62 D8 81 DF
UTF-16 大尾序,包含BOM FE FF, 67 31, 00 2C, 80 7F, D8 62 DF 81

UTF-16 ?UCS-2 的关p?

UTF-16可看成是UCS-2的父集。在没有辅助q面字符前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助^面字W后Q就只称为UTF-16了。现在若有Y件声U自己支援UCS-2~码Q那其实是暗指它不能支援辅助q面字符的委婉语?



]]>
[转蝲]UTF-8 字符集基 http://m.tkk7.com/illhan/archive/2006/06/29/55763.htmljava执著?/dc:creator>java执著?/author>Thu, 29 Jun 2006 08:00:00 GMThttp://m.tkk7.com/illhan/archive/2006/06/29/55763.htmlhttp://m.tkk7.com/illhan/comments/55763.htmlhttp://m.tkk7.com/illhan/archive/2006/06/29/55763.html#Feedback0http://m.tkk7.com/illhan/comments/commentRss/55763.htmlhttp://m.tkk7.com/illhan/services/trackbacks/55763.html 字符集简?/font>

在所有字W集中,最知名可能 要数被称为ASCII?位字W集了。它是美国信息交换标准委员会 QAmerican Standards Committee for Information InterchangeQ的~写, 为美国英语通信所? 计。它?28个字W组成,包括大小写字母、数?-9、标点符受非打印字符Q换行符、制表符{?个)以及控制字符Q退根{响铃等Q组成?/font>

? 是,׃他是针对p设计的,当处理带有音调标P形如汉语的拼韻I的欧z文字时׃出现问题。因此,创徏Z一些包?55个字W的由ASCII扩展? 字符集。其中有一U通常被成为IBM字符集,它把gؓ128-255之间的字W用于画囑֒ȝQ以及一些特D的Ƨ洲字符。另一U?位字W集? ISO 8859-1 Latin 1Q也UCؓISO Latin-1。它把位?28-255之间的字W用于拉丁字母表中特D语a字符的编码,也因? 而得名?/font>

Ƨ洲语言不是地球上的唯一语言Q因此亚z和非洲语言q不能被8位字W? 集所支持。仅汉语Q或pictogramsQ字母表有80000以上个字W。但是把汉语、日语和南语的一些相似的字符l合hQ在不同的语a里,使不 同的字符代表不同的字Q这样只?个字节就可以~码地球上几乎所有地区的文字。因此,创徏了UNICODE~码。它通过增加一个高字节? ISO Latin-1字符集进行扩展,当这些高字节位ؓ0Ӟ低字节就是ISO Latin-1字符。UNICODE支持Ƨ洲、非zӀ中东、亚zԌ包括 l一标准的东亚像形汉字和韩国像Ş文字Q。但是,UNICODEq没有提供对诸如Braille, Cherokee, Ethiopic,  Khmer, Mongolian, Hmong, Tai Lu, Tai Mau文字的支持。同时它也不支持如Ahom, Akkadian,  Aramaic, Babylonian Cuneiform, Balti, Brahmi, Etruscan, Hittite, Javanese,  Numidian, Old Persian Cuneiform, Syrian之类的古老的文字?/font>

? 实证明,对可以用ASCII表示的字W用UNICODEq不高效Q因为UNICODE比ASCII占用大一倍的I间Q而对ASCII来说高字节的0对他 毫无用处。ؓ了解册个问题,出C一些中间格式的字符集,他们被称为通用转换格式Q既UTF QUniversal Transformation FormatQ。目前存在的UTF格式有:UTF-7, UTF-7.5, UTF-8, UTF -16, 以及 UTF-32。本文讨论UTF-8字符集的基础?/font>

UTF_8字符?/font>

UTF -8是UNICODE的一U变长字W编码,由Ken Thompson?992q创建。现在已l标准化为RFC 3629。UTF-8??个字节编 码UNICODE字符。如果UNICODE字符?个字节表C,则编码成UTF-8很可能需?个字节,而如果UNICODE字符?个字节表C,则编? 成UTF-8可能需?个字节。用4个或6个字节去~码一个UNICODE字符可能太多了,但很会遇到那样的UNICODE字符?/font>

UFT-8转换表表C如下:

UNICODE UTF-8 
00000000 - 0000007F 0xxxxxxx 
00000080 - 000007FF 110xxxxx 10xxxxxx 
00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx 
00010000 - 001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
00200000 - 03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
04000000 - 7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

? 际表CASCII字符的UNICODE字符Q将会编码成1个字节,q且UTF-8表示与ASCII字符表示是一L。所有其他的UNCODE字符转化? UTF-8需要至?个字节。每个字节由一个换码序列开始。第一个字节由唯一的换码序列,由n?加一?l成。n?表示字符~码所需的字节数?/font>

CZ

UNICODE uCA(11001010) ~码成UTF-8需?个字节:

uCA -> C3 8A

1100 1010
110xxxxx 10xxxxxx

1100 1010 -> 110xxxxx 10xxxxxx
-> 110xxxxx 10xxxxx0
-> 110xxxxx 10xxxx10
-> 110xxxxx 10xxx010
-> 110xxxxx 10xx1010
-> 110xxxxx 10x01010
-> 110xxxxx 10001010
-> 110xxxx1 10001010
-> 110xxx11 10001010
-> 11000011 10001010
-> C3 8A

UNICODE uF03F (11110000 00111111) ~码成UTF-8需?个字?

u F03F -> EF 80 BF

1111 0000 0011 1111 -> 1110xxxx 10xxxxxx 10xxxxxx
-> 11101111 10000000 10111111
-> EF 80 BF

译者注Q由上分析可以看刎ͼUNCODE到UTF-8的{换就是先定~码所需要的字节敎ͼ然后用UNICODE~码位从低位到高位依ơ填入上面表CZؓx的位上,不的高位以0补充。以上是个hl验Q如有错误,请不惜指教,谢过?)

UTF-8~码的优点:

UTF-8~码可以通过屏蔽位和UM操作快速读写?br />字符串比较时strcmp()和wcscmp()的返回结果相同,因此使排序变得更加容易?br />字节FF和FE在UTF-8~码中永q不会出玎ͼ因此他们可以用来表明UTF-16或UTF-32文本Q见BOMQ?br />UTF-8 是字节顺序无关的。它的字节顺序在所有系l中都是一LQ因此它实际上ƈ不需要BOM?/font>

UTF-8~码的缺点:

你无法从UNICODE字符数判断出UTF-8文本的字节数Q因为UTF-8是一U变长编?br />它需要用2个字节编码那些用扩展ASCII字符集只需1个字节的字符
ISO Latin-1 是UNICODE的子集,但不是UTF-8的子?br />8位字W的UTF-8~码会被email|关qoQ因为internet信息最初设计ؓ7为ASCII码。因此生了UTF-7~码?br />UTF-8 在它的表CZ使用?00xxxxx的几率超q?0%Q 而现存的实现如ISO 2022Q?873Q?429Q 和8859pȝQ会把它错认为是C1 控制码。因此生了UTF-7.5~码?/font>

修正的UTF-8Q?/font>


java使用UTF-16表示内部文本Qƈ支持用于字符串串行化的非标准的修正UTF-8~码。标准UTF-8和修正的UTF-8有两点不同:
? 正的UTF-8中,null字符~码?个字节(11000000 00000000Q 而不是标准的1个字节(00000000Q,q样作可以保证编? 后的字符串中不会嵌入null字符。因此如果在cC语言中处理字W串Q文本不会在W一个null字符时截断(C字符串以nulll尾Q?br />在标? UTF-8~码中,出基本多语a范围QBMP - Basic Multilingual PlainQ的字符被编码ؓ4字节格式Q但是在修正的UTF -8~码中,他们׃理编码对Qsurrogate pairsQ表C,然后q些代理~码对在序列中分别重新编码。结果标准UTF-8~码中需?个字? 的字W,在修正后的UTF-8~码中将需?个字节?/font>

位序标志BOM


BOMQByte Order MarkQ是一个字W,它表明UNICODE文本的UTF-16,UTF-32的编码字节顺序(高字节低字节序Q和~码方式QUTF-8,UTF-16,UTF-32Q 其中UTF-8~码是字节顺序无关的Q?/font>

如下所C:

Encoding Representation 
UTF-8 EF BB BF 
UTF-16 Big Endian FE FF 
UTF-16 Little Endian FF FE 
UTF-32 Big Endian 00 00 FE FF
UTF-32 Little Endian FF FE 00 00

UTF-8 C++ E序~码CZQ?/font>

下面是四个C++函数Q他们分别实?字节?字节UNICODE和UTF-8之间的{换?/font>

#define MASKBITS 0x3F
#define MASKBYTE 0x80
#define MASK2BYTES 0xC0
#define MASK3BYTES 0xE0
#define MASK4BYTES 0xF0
#define MASK5BYTES 0xF8
#define MASK6BYTES 0xFC

typedef unsigned short Unicode2Bytes;
typedef unsigned int Unicode4Bytes;

void UTF8Encode2BytesUnicode(std::vector< Unicode2Bytes > input,
std::vector< byte >& output)
{
for(int i=0; i < input.size(); i++)
{
// 0xxxxxxx
if(input < 0x80)
{
output.push_back((byte)input);
}
// 110xxxxx 10xxxxxx
else if(input < 0x800)
{
output.push_back((byte)(MASK2BYTES | input >> 6));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if(input < 0x10000)
{
output.push_back((byte)(MASK3BYTES | input >> 12));
output.push_back((byte)(MASKBYTE | input >> 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
}
}

void UTF8Decode2BytesUnicode(std::vector< byte > input,
std::vector< Unicode2Bytes >& output)
{
for(int i=0; i < input.size();)
{
Unicode2Bytes ch;

// 1110xxxx 10xxxxxx 10xxxxxx
if((input & MASK3BYTES) == MASK3BYTES)
{
ch = ((input & 0x0F) << 12) | (
(input[i+1] & MASKBITS) << 6)
| (input[i+2] & MASKBITS);
i += 3;
}
// 110xxxxx 10xxxxxx
else if((input & MASK2BYTES) == MASK2BYTES)
{
ch = ((input & 0x1F) << 6) | (input[i+1] & MASKBITS);
i += 2;
}
// 0xxxxxxx
else if(input < MASKBYTE)
{
ch = input;
i += 1;
}

output.push_back(ch);
}
}

void UTF8Encode4BytesUnicode(std::vector< Unicode4Bytes > input,
std::vector< byte >& output)
{
for(int i=0; i < input.size(); i++)
{
// 0xxxxxxx
if(input < 0x80)
{
output.push_back((byte)input);
}
// 110xxxxx 10xxxxxx
else if(input < 0x800)
{
output.push_back((byte)(MASK2BYTES | input > 6));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if(input < 0x10000)
{
output.push_back((byte)(MASK3BYTES | input >> 12));
output.push_back((byte)(MASKBYTE | input >> 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input < 0x200000)
{
output.push_back((byte)(MASK4BYTES | input >> 18));
output.push_back((byte)(MASKBYTE | input >> 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input >> 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input < 0x4000000)
{
output.push_back((byte)(MASK5BYTES | input >> 24));
output.push_back((byte)(MASKBYTE | input >> 18 & MASKBITS));
output.push_back((byte)(MASKBYTE | input >> 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input >> 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if(input < 0x8000000)
{
output.push_back((byte)(MASK6BYTES | input >> 30));
output.push_back((byte)(MASKBYTE | input >> 18 & MASKBITS));
output.push_back((byte)(MASKBYTE | input >> 12 & MASKBITS));
output.push_back((byte)(MASKBYTE | input >> 6 & MASKBITS));
output.push_back((byte)(MASKBYTE | input & MASKBITS));
}
}
}

void UTF8Decode4BytesUnicode(std::vector< byte > input,
std::vector< Unicode4Bytes >& output)
{
for(int i=0; i < input.size();)
{
Unicode4Bytes ch;

// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
if((input & MASK6BYTES) == MASK6BYTES)
{
ch = ((input & 0x01) << 30) | ((input[i+1] & MASKBITS) << 24)
| ((input[i+2] & MASKBITS) << 18) | ((input[i+3]
& MASKBITS) << 12)
| ((input[i+4] & MASKBITS) << 6) | (input[i+5] & MASKBITS);
i += 6;
}
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
else if((input & MASK5BYTES) == MASK5BYTES)
{
ch = ((input & 0x03) << 24) | ((input[i+1]
& MASKBITS) << 18)
| ((input[i+2] & MASKBITS) << 12) | ((input[i+3]
& MASKBITS) << 6)
| (input[i+4] & MASKBITS);
i += 5;
}
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
else if((input & MASK4BYTES) == MASK4BYTES)
{
ch = ((input & 0x07) << 18) | ((input[i+1]
& MASKBITS) << 12)
| ((input[i+2] & MASKBITS) << 6) | (input[i+3] & MASKBITS);
i += 4;
}
// 1110xxxx 10xxxxxx 10xxxxxx
else if((input & MASK3BYTES) == MASK3BYTES)
{
ch = ((input & 0x0F) << 12) | ((input[i+1] & MASKBITS) << 6)
| (input[i+2] & MASKBITS);
i += 3;
}
// 110xxxxx 10xxxxxx
else if((input & MASK2BYTES) == MASK2BYTES)
{
ch = ((input & 0x1F) << 6) | (input[i+1] & MASKBITS);
i += 2;
}
// 0xxxxxxx
else if(input < MASKBYTE)
{
ch = input;
i += 1;
}
output.push_back(ch);
}
}


限译者水qx限,有不解之处请参考原文。版权属原文作者所有,转蝲h明出处及作者?/font>

原文参见Q?a target="_blank">http://www.codeguru.com/Cpp/misc ... article.php/c10451/



]]>
新的技?-开发者挑?/title><link>http://m.tkk7.com/illhan/archive/2006/03/27/37639.html</link><dc:creator>java执著?/dc:creator><author>java执著?/author><pubDate>Mon, 27 Mar 2006 09:00:00 GMT</pubDate><guid>http://m.tkk7.com/illhan/archive/2006/03/27/37639.html</guid><wfw:comment>http://m.tkk7.com/illhan/comments/37639.html</wfw:comment><comments>http://m.tkk7.com/illhan/archive/2006/03/27/37639.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/illhan/comments/commentRss/37639.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/illhan/services/trackbacks/37639.html</trackback:ping><description><![CDATA[现在的开发技术的发展的速度比v开发者的学习速度不知道要快多,每隔一两天׃有一个开源的工程诞生Q学习如何去使用q些开源的工程不如学习一下其中的思想。比如HibernateQibatis{ORM{framework它只不过是帮你摆脱那些DAO模式为每个数据对象作一个DAO对象专门来负责数据库操作Q你可以用一个统一的接口来q行数据库的操作。与其去专研如何去配|,如何M用还不如d好的研究一些他所体现的一些思想Q比如数据库查询的优化,利用~存机制Q数据库q接池等{?br />q有是springQ它到底体现了什么是用来替换现在的J2EE的技术,不,pspring的作者都说是在合时的情况下用合适的技术,一句看似空z的话却包含了深意。spring的核心思想在我看来是DIQ他在其他的open source的项目的基础上加以抽象,比如他提供了spring mvc--可以M用底层的web mvc可以有很多,但是现在可以用一个统一的接口来调用Q底层的实现机制与上层无养Iq不证实了分层开发的思想吗,DI的思想正是用接口编E?br />技术的快速的发展Q给开发者带了很多的学习的难度,但是开发者如何来面对q种挑战Q与其掌握如何去使用q不如去掌握它的思想。只有掌握了思想是用时才会有更深的理解?img src ="http://m.tkk7.com/illhan/aggbug/37639.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/illhan/" target="_blank">java执著?/a> 2006-03-27 17:00 <a href="http://m.tkk7.com/illhan/archive/2006/03/27/37639.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BlogJavahttp://m.tkk7.com/illhan/archive/2006/03/08/34345.htmljava执著?/dc:creator>java执著?/author>Wed, 08 Mar 2006 12:52:00 GMThttp://m.tkk7.com/illhan/archive/2006/03/08/34345.htmlhttp://m.tkk7.com/illhan/comments/34345.htmlhttp://m.tkk7.com/illhan/archive/2006/03/08/34345.html#Feedback0http://m.tkk7.com/illhan/comments/commentRss/34345.htmlhttp://m.tkk7.com/illhan/services/trackbacks/34345.html今天来了BlogJava开了自qBolgQ工作了一q_在公怸用java的机会ƈ不是很多Q但是在有限的几个项目中我都选择了java作ؓ我的开发语aQƈ且用了许多开源的java的工PHibernateQAntQLog4JQDom4j{等Q我是一个追求新事物的hQ对于眼前那许许多多的java的开源的目Q我也有些茫然。然而上个礼拜去Sybase公司面试的经历,却让我重新认识了原来我懂得尽然是那么。Java的本质是什么,JVM是怎么工作的,gc是怎么工作的,ClassLoad是什么样的,现在的程序员有几个h能真正回{的完整的,也许很少。看着那些滔滔不绝说出C什么新技术的人,我只有暗地里感到Q我真的惛_劝那些朋友有I好好去看看JVM的书Q不要满口说什么新的技术?/P>

]]>
վ֩ģ壺 þþ뾫Ʒպý| ձɫѹۿ| aëƬȫƵ18| ŮaëƬѹۿ| þþƷѹۿ97| 99re߾ƷƵ| þþƷһ糱| ˳www| þ޾ƷƷ| ˾Ʒձר| ҹþAAAAAëƬѿ| 91þó| ޳?߹ۿ| ɫavɫ߹| ۺƵ| ޹ƷɫƬۿ| þ޾Ʒרɫ| þþþѿ| 붯xxxxx| þþƷ㽶| Ѽվһҳ| ھƷ鶹վ91鶹| AVҹ丣㽶149 | 51ƷƵѹר| Ƶֻ| պӰ߹ۿƵ| ѹվ߿| ۺϾƷһ| ĻѵӰվ| ޾ƷƷ벻| aƵѹۿ| 뾫Ʒ| wwwѲƵ| 67paoǿ67194ҹ| AVѲ| þƷѹۿ| þ޾ƷAVӣ| Ļ߹ۿ| AVרAVԾ | Ƶ߹ۿ| һëƬ߲|