<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的漫漫程序之旅

    專注于JavaWeb開(kāi)發(fā)
    隨筆 - 39, 文章 - 310, 評(píng)論 - 411, 引用 - 0
    數(shù)據(jù)加載中……

    網(wǎng)絡(luò)數(shù)據(jù)流的java處理

    前言:java程序要處理很多的網(wǎng)絡(luò)數(shù)據(jù),網(wǎng)絡(luò)數(shù)據(jù)發(fā)送和接收以及數(shù)據(jù)流的處理是java程序要特別關(guān)注的方面,隨著java的發(fā)展,這些方法也越來(lái)越得到重視和加強(qiáng)。本文從幾個(gè)方面解釋了java正確處理網(wǎng)絡(luò)數(shù)據(jù)流的要素,這些也是java程序員必須了解的基本的知識(shí)。

    1:龐大的java流處理

    首先,之所以說(shuō)java流的龐大,是因?yàn)閖ava中的流處理比其他語(yǔ)言的流處理在內(nèi)容上多的多。

    java流在處理上分為字符流和字節(jié)流。字符流處理的單元為2個(gè)字節(jié)的Unicode字符,分別操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個(gè)字節(jié),操作字節(jié)和字節(jié)數(shù)組。

    Java內(nèi)用Unicode編碼存儲(chǔ)字符,字符流處理類負(fù)責(zé)將外部的其他編碼的字符流和java內(nèi)Unicode字符流之間的轉(zhuǎn)換。而類InputStreamReader和OutputStreamWriter處理字符流和字節(jié)流的轉(zhuǎn)換。字符流(一次可以處理一個(gè)緩沖區(qū))一次操作比字節(jié)流(一次一個(gè)字節(jié))效率高。

    對(duì)應(yīng)不同的流,需要不同的流構(gòu)建器或流過(guò)濾實(shí)現(xiàn)。java目前依然在逐漸增加其流處理方法,雖然java類庫(kù)的創(chuàng)作人員可以列舉出很多理由來(lái)說(shuō)明這要做的優(yōu)點(diǎn),但我還是覺(jué)得java開(kāi)始變得向其他語(yǔ)言一樣復(fù)雜起來(lái)。






    2:網(wǎng)絡(luò)數(shù)據(jù)流的收發(fā)

    java對(duì)網(wǎng)絡(luò)數(shù)據(jù)的發(fā)送和接收處理,也借用了一般流處理的方法。我們知道,在幾乎其他所有語(yǔ)言中,網(wǎng)絡(luò)數(shù)據(jù)的收發(fā)在利用類似send(或write)和recv(或read)的方法時(shí)并沒(méi)有明顯的流處理。但是java和這些語(yǔ)言的收發(fā)方法有較大區(qū)別,要借助流才可以完成:

    .......
                sock = new Socket(addr, port);
                OutputStream os = sock.getOutputStream();
                InputStream is = sock.getInputStream();
                os.write(byte[] b);
                is.read(byte[] b);

    這些方法總給人一種不太舒服的感覺(jué)。不過(guò)從Jdk1.4開(kāi)始彌補(bǔ)了這一點(diǎn)。JDK1.4中新增加了新的I/O流處理,在緩沖區(qū)管理、可伸縮網(wǎng)絡(luò)和文件IO、字符集支持、正規(guī)表達(dá)式匹配方面做了新的處理。其中緩沖區(qū)管理和通道(Channel)概念則是對(duì)網(wǎng)絡(luò)數(shù)據(jù)流的收發(fā)處理支持的強(qiáng)化。緩沖區(qū)管理中ByteBuffer類更好的支持了網(wǎng)絡(luò)數(shù)據(jù)流處理。在網(wǎng)絡(luò)連接中,通道代表了sockets的連接?;谶@些新的IO處理,以上代碼可以改寫為:

    ......
                ByteBuffer bytebuf = ByteBuffer.allocate(2048); // 創(chuàng)建一個(gè)指定大小的緩沖區(qū)
                InetSocketAddress isa = new InetSocketAddress(hostname,port);
                sc = SocketChannel.open(); // 建立一個(gè)socket通道
                sc.connect( isa);  // 建立一個(gè)socket連接
                …
                sc.write(bytebuf); // 發(fā)送數(shù)據(jù)
                …
                sc.read(bytebuf); // 接收數(shù)據(jù)
                這樣的程序似乎要流暢的多。





    回頁(yè)首


    3:java對(duì)網(wǎng)絡(luò)數(shù)據(jù)流的處理

    java程序?qū)W(wǎng)絡(luò)數(shù)據(jù)流的處理要關(guān)注四個(gè)基本方面:數(shù)據(jù)流的編碼,字節(jié)順序,數(shù)據(jù)格式對(duì)應(yīng)和取數(shù)。這是四個(gè)不同的問(wèn)題,但是都影響到網(wǎng)絡(luò)數(shù)據(jù)的正確接收。

    3.1 網(wǎng)絡(luò)數(shù)據(jù)流的解碼和編碼

    網(wǎng)絡(luò)數(shù)據(jù)流的編碼和解碼主要針對(duì)流中出現(xiàn)的字符串。網(wǎng)絡(luò)數(shù)據(jù)流中的字符串均為原始的字節(jié)流形式。

    要正確接收網(wǎng)絡(luò)數(shù)據(jù)流中的字符串,首先要知道該字符串的編碼方案。然后才可以調(diào)用解碼的方法獲得java能夠認(rèn)識(shí)的Unicode編碼字符串。可以用如下代碼處理網(wǎng)絡(luò)數(shù)據(jù)流中字符串的編碼和解碼:

    // 獲得編碼對(duì)象,即網(wǎng)絡(luò)對(duì)等方的認(rèn)識(shí)的字符串編碼。
                Charset charset = Charset.forName("--?"); // --?為對(duì)等方的編碼名,java必須支持。
                // 生成編碼器和解碼器對(duì)象。
                CharsetDecoder decoder = charset.newDecoder();
                CharsetEncoder encoder = charset.newEncoder();
                .......
                // 對(duì)從網(wǎng)絡(luò)數(shù)據(jù)流中獲得的字節(jié)流解碼取得java字符串
                CharBuffer charbuf = decoder.decode(bytebuff);
                .......
                // 將java字符串編碼成指定編碼的字節(jié)流,以便網(wǎng)絡(luò)發(fā)送
                Bytebuff  bytebuff = encoder.encode(CharBuffer.wrap("Test String");
                .......
                

    3.2 網(wǎng)絡(luò)數(shù)據(jù)流的字節(jié)順序

    目前的字節(jié)順序有兩類:BIG_ENGIAN和LITTLE_ENDIAN。各個(gè)平臺(tái)所支持的字節(jié)序不同,例如AIX、Tru64Unix、Windows等操作系統(tǒng)平臺(tái)采用LITTLE_ENDIAN字節(jié)序,Solaris等操作系統(tǒng)平臺(tái)采用BIG_ENGIAN。Java自身采用的是BIG_ENGIAN字節(jié)序,當(dāng)java和運(yùn)行在其他平臺(tái)上的其他語(yǔ)言編寫的通信程序通信時(shí),則必須考慮到數(shù)據(jù)的字節(jié)序。

    Jkd1.4新增加的包NIO中的類ByteOrder則帶來(lái)了一定的方便。針對(duì)從網(wǎng)絡(luò)數(shù)據(jù)流的字節(jié)序,我們只要增加一行就可以輕松的處理字節(jié)序了:
    bytebuf.order(ByteOrder.LITTLE_ENDIAN); //按照LITTLE_ENDIAN字節(jié)序收發(fā)數(shù)據(jù)
    sc.read(bytebuf); // 接收數(shù)據(jù)

    上面的方法雖然簡(jiǎn)化了我們的編程,但沒(méi)有真正處理好分布式應(yīng)用的網(wǎng)絡(luò)數(shù)據(jù)字節(jié)序問(wèn)題。例如,java同時(shí)和在Tru64Unix、Solaris平臺(tái)上的應(yīng)用通信時(shí),上述方法就不能解決問(wèn)題。因?yàn)橥粩?shù)據(jù)包,可能無(wú)法判斷其字節(jié)序是那一種。此時(shí)要求網(wǎng)絡(luò)數(shù)據(jù)包內(nèi)攜帶附加的字節(jié)序信息顯然是不現(xiàn)實(shí)的。這種情況下,java語(yǔ)言需要提供對(duì)XDR(外部數(shù)據(jù)表達(dá))的支持,目前XDR已經(jīng)為事實(shí)上的網(wǎng)絡(luò)數(shù)據(jù)流的標(biāo)準(zhǔn)格式,分布式應(yīng)用的網(wǎng)絡(luò)數(shù)據(jù)流基本都遵循了這種格式,如果java語(yǔ)言提供了對(duì)XDR的支持,就可以解決通用性的問(wèn)題。對(duì)于分布式應(yīng)用中的網(wǎng)絡(luò)數(shù)據(jù)流的處理就無(wú)需再根據(jù)其平臺(tái)判斷其字節(jié)序,只要按照XDR格式進(jìn)行處理就可以了。

    3.3 網(wǎng)絡(luò)數(shù)據(jù)流中數(shù)據(jù)格式的對(duì)應(yīng)

    C/C++語(yǔ)言編寫的網(wǎng)絡(luò)程序中一般采用數(shù)據(jù)結(jié)構(gòu)的緩沖區(qū)發(fā)送數(shù)據(jù),在java端接收數(shù)據(jù)時(shí),會(huì)出現(xiàn)一些因數(shù)據(jù)組織引起的問(wèn)題:

    如結(jié)構(gòu) typedef struct {
                int   id;
                char  name[32];
                short  val;
                float  fval;
                } SendData

    在32位操作系統(tǒng)中,它的大小并不是42,而是44!數(shù)據(jù)的組織如下圖所示:



    當(dāng)通過(guò)網(wǎng)絡(luò)發(fā)送到客戶端時(shí),客戶端也接收到44個(gè)字節(jié),如果按照順序依次取相應(yīng)的值,則會(huì)發(fā)現(xiàn)最后取得的浮點(diǎn)值不正確。這是因?yàn)榘讯陶蛿?shù)據(jù)后沒(méi)有意義的兩位作為了浮點(diǎn)數(shù)中的其中兩位。如果想正確接收該數(shù)據(jù),則必須跳過(guò)短整型數(shù)據(jù)后沒(méi)有意義的兩位,再取浮點(diǎn)值。

    而如果以上的結(jié)構(gòu)變?yōu)椋?/span>

    typedef struct {
                int   id;
                char  name[32];
                float  fval;
                short  val;
                }


    則java端按照順序依次接收數(shù)據(jù)就不會(huì)發(fā)生問(wèn)題。

    所以,在編寫程序時(shí),對(duì)數(shù)據(jù)的正確組織也是非常重要的。

    3.4從網(wǎng)絡(luò)數(shù)據(jù)流中取得需要的數(shù)據(jù)

    在C/C++的Socket編程時(shí),采用數(shù)據(jù)結(jié)構(gòu)收發(fā)數(shù)據(jù)很方便,特別是接收數(shù)據(jù)時(shí),可以由數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)類型自動(dòng)獲得網(wǎng)絡(luò)數(shù)據(jù)流相應(yīng)的數(shù)據(jù)。但是在java中,目前我們必須對(duì)流進(jìn)行分析,逐一的取得自己所需要的數(shù)據(jù),并且由于網(wǎng)絡(luò)數(shù)據(jù)流是原始的數(shù)據(jù)流,還要根據(jù)程序所需要的數(shù)據(jù)類型對(duì)網(wǎng)絡(luò)數(shù)據(jù)流進(jìn)行解碼處理。發(fā)送網(wǎng)絡(luò)數(shù)據(jù)時(shí)同樣需要對(duì)數(shù)據(jù)進(jìn)行封裝。這個(gè)過(guò)程也增加了java程序的煩瑣性。例如上述結(jié)構(gòu),要用如下代碼獲取相應(yīng)數(shù)據(jù):

    1. int id = bytebuf.getInt(); // 獲得整數(shù)型值
    2. int limit = bytebuf.limit(); // 獲得字節(jié)緩沖區(qū)的限值
    3. bytebuf.limit(36); // 設(shè)置字節(jié)緩沖區(qū)的限值,為字符串后面的第一個(gè)字節(jié)位置
    4. CharBuffer charbuf = decoder.decode(bytebuf); // 解碼獲得字符串
    5. Bytebuf.limit(limit); // 恢復(fù)字節(jié)緩沖區(qū)原來(lái)的限值
    6. float fval = bytebuf.getfloat(); // 獲得浮點(diǎn)型值
    7. short val = bytebuf.getshort(); // 獲得短整型數(shù)值





    4:結(jié)束語(yǔ)

    從上面的介紹可以看出,java程序中對(duì)網(wǎng)絡(luò)數(shù)據(jù)流的處理涉及的問(wèn)題較多。在編寫網(wǎng)絡(luò)程序時(shí),必須注意這些問(wèn)題,以使得程序正確的處理通信的內(nèi)容。



    參考資料



    posted on 2008-12-20 11:21 々上善若水々 閱讀(756) 評(píng)論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 久久久久久AV无码免费网站下载 | 精品一区二区三区免费观看 | 美女18一级毛片免费看| 91在线免费观看| 手机看黄av免费网址| 国产免费私拍一区二区三区 | 亚洲中文久久精品无码ww16| 亚洲网址在线观看| 小说区亚洲自拍另类| 野花香高清视频在线观看免费 | 四虎永久在线观看免费网站网址 | 亚洲娇小性色xxxx| 一级毛片一级毛片免费毛片| 最近最新高清免费中文字幕 | 亚洲免费观看视频| 在线综合亚洲中文精品| 成人免费777777被爆出| 免费看国产成年无码AV片| 精品国产综合成人亚洲区| 亚洲色无码国产精品网站可下载| 国产无遮挡又黄又爽免费网站| 欧美在线看片A免费观看| 亚洲精品国产精品乱码不99| 亚洲精品自偷自拍无码| 99爱在线观看免费完整版| 亚洲Aⅴ无码一区二区二三区软件| 亚洲码在线中文在线观看| 一个人看的在线免费视频| 男人的好看免费观看在线视频| 国产亚洲一区二区在线观看| 亚洲狠狠婷婷综合久久| 亚欧免费视频一区二区三区| 成人午夜亚洲精品无码网站| 亚洲精品无码你懂的| 久久久久久精品免费免费自慰| 亚洲自偷自偷图片| 国产精品亚洲一区二区在线观看| 在线观看永久免费| 国产AV无码专区亚洲AV男同| 免费看又黄又爽又猛的视频软件| 国产又黄又爽又猛免费app|