http://jimmee.iteye.com/blog/617110
http://jimmee.iteye.com/category/93740
Java TCP/IP Socket 編程 筆記(一)—基本概念 編程SocketJava網(wǎng)絡(luò)協(xié)議網(wǎng)絡(luò)應(yīng)用
一些概念:
通信信道(communication channel):將字節(jié)序列從一個主機(jī)傳輸?shù)搅硪粋€主機(jī)的一種手段,可能是有線電纜,如以太網(wǎng)(Ethernet),也可能是無線的,如WiFi,或是其他方式的連接。
信息(information)是指由程序創(chuàng)建和解釋的字節(jié)序列。在計(jì)算機(jī)網(wǎng)絡(luò)環(huán)境中,這些字節(jié)序列稱為分組報文(packet)。
協(xié)議(protocol)相當(dāng)于相互通信的程序達(dá)成的一種約定,它規(guī)定了分組報文的交換方式和它們包含的意義。一組協(xié)議規(guī)定了分組報文的結(jié)構(gòu)(例如報文中的哪一部分表明了目的地址)以及怎樣對報文中所包含的信息進(jìn)行解析。
TCP和UDP屬于傳輸層,IP屬于網(wǎng)絡(luò)層,TCP,UDP和IP的具體實(shí)現(xiàn)通常駐留在主機(jī)的操作系統(tǒng)中。應(yīng)用程序通過套接字API對UDP協(xié)議和TCP協(xié)議所提供的服務(wù)進(jìn)行訪問。
IP協(xié)議提供了一種數(shù)據(jù)報服務(wù):每組分組報文都由網(wǎng)絡(luò)獨(dú)立處理和分發(fā),就像信件或包裹通過郵政系統(tǒng)發(fā)送一樣。IP報文必須包含一個保存其目的地址的字段,就像你所投遞的每份包裹都寫明了收件人地址一樣。
TCP協(xié)議和UDP協(xié)議使用的地址叫做端口號,都是用來區(qū)分同一主機(jī)中的不同應(yīng)用程序的。
客戶端(client)是通信的發(fā)起者,而服務(wù)器(server)程序則被動等待客戶端發(fā)起通信,并對其作出響應(yīng)。
一個程序是作為客戶端還是服務(wù)器,決定了它在與其對等端(peer)建立通信時使用的套接字API(客戶端的對等端是服務(wù)器,反之亦然)。 客服端必須首先知道服務(wù)器端的地址和端口號,反之則不需要。這個打電話類似。只要通信連接建立成功,服務(wù)器和客戶端之間就沒有區(qū)別了。
Socket(套接字)是一種抽象層,應(yīng)用程序通過它來發(fā)送和接受數(shù)據(jù),就像應(yīng)用程序打開一個文件句柄,將數(shù)據(jù)讀寫到穩(wěn)定的存儲器上一樣。 一個TCP/IP套接字由一個互聯(lián)網(wǎng)地址,一個端對端協(xié)議(TCP或UDP協(xié)議)以及一個端口號唯一確定。
?
Java TCP/IP Socket 編程 筆記(二)—TCP的例子 編程SocketJava網(wǎng)絡(luò)協(xié)議
1.InetAddress類和SocketAddress用于識別網(wǎng)絡(luò)主機(jī)
TCP協(xié)議客戶端和服務(wù)器端的套接字為Socket和ServerSocket
UDP協(xié)議的客戶端和服務(wù)器端的套接字為DatagramSocket
2.
類 NetworkInterface表示一個由名稱和分配給此接口的 IP 地址列表組成的網(wǎng)絡(luò)接口,其getNetworkInterfaces()返回此機(jī)器上的所有接口。getInetAddresses()是返回一個 Enumeration 并將所有 InetAddress 或 InetAddress 的子集綁定到此網(wǎng)絡(luò)接口的便捷方法。(注意:一個網(wǎng)絡(luò)接口可能包含IPv4或IPv6地址)
3.類 InetAddress的getHostAddress()返回 IP 地址字符串(以文本表現(xiàn)形式)。 getAllByName(String host)在給定主機(jī)名的情況下,根據(jù)系統(tǒng)上配置的名稱服務(wù)返回其 IP 地址所組成的數(shù)組。getHostName()獲取此 IP 地址的主機(jī)名。getHostAddress() 返回 IP 地址字符串(以文本表現(xiàn)形式)。
4.TCP套接字
服務(wù)器端ServerSocket實(shí)例監(jiān)聽TCP鏈接請求,并為每個請求創(chuàng)建新的Socket實(shí)例。也就是說,服務(wù)器端要同時處理ServerSocket實(shí)例和Sockete實(shí)例,而客戶端只需要使用Socket實(shí)例。
TCP客戶端:
Java代碼 ?
public ?class ?TCPEchoClient?{ ??????public ?static ?void ?main(String?[]?args)?throws ?UnknownHostException,?IOException,?InterruptedException?{ ?? ????????if (args.length<2 ||args.length>3 ){ ?? ????????????throw ?new ?IllegalArgumentException("Parameter(s):<Server>?<Word>?[<Port>]" ); ?? ????????} ?? ???????? ?? ????????String?server=args[0 ]; ?? ???????? ?? ????????byte ?[]?data=args[1 ].getBytes(); ?? ???????? ?? ????????int ?servPort=(args.length==3 )?Integer.parseInt(args[2 ]):7 ; ?? ???????? ?? ?????????? ????????Socket?socket=new ?Socket(server,servPort); ?? ????????System.out.println("Connected?to?server...?sending?echo?string" ); ?? ???????? ?? ????????? ? ?? ????????InputStream?in=socket.getInputStream(); ?? ????????OutputStream?out=socket.getOutputStream(); ?? ???????? ?? ????????out.write(data); ?? ???????? ?? ????????int ?totalBytesRcvd=0 ; ?? ????????int ?bytesRcvd; ?? ???????? ?? ????????while (totalBytesRcvd<data.length){ ?? ????????????if ((bytesRcvd=in.read(data,?totalBytesRcvd,?data.length-totalBytesRcvd))==-1 ){ ?? ????????????????throw ?new ?SocketException("Connection?closed?prematurely" ); ?? ????????????} ?? ????????????totalBytesRcvd+=bytesRcvd; ?? ????????} ?? ????????System.out.println("Receved:?" +new ?String(data)); ?? ???????? ?? ???????? ?? ????????socket.close(); ?? ????} ?? }?? public class TCPEchoClient {public static void main(String [] args) throws UnknownHostException, IOException, InterruptedException {if(args.length<2||args.length>3){throw new IllegalArgumentException("Parameter(s):<Server> <Word> [<Port>]");}String server=args[0];byte [] data=args[1].getBytes();int servPort=(args.length==3)?Integer.parseInt(args[2]):7;//1.創(chuàng)建一個Socket實(shí)例:構(gòu)造函數(shù)向指定的遠(yuǎn)程主機(jī)和端口建立一個TCP連接Socket socket=new Socket(server,servPort);System.out.println("Connected to server... sending echo string");/***2. 通過套接字的輸入輸出流進(jìn)行通信:一個Socket連接實(shí)例包括一個InputStream和一個OutputStream,它們的用法同于其他Java輸入輸出流。*/InputStream in=socket.getInputStream();OutputStream out=socket.getOutputStream();out.write(data);int totalBytesRcvd=0;int bytesRcvd;while(totalBytesRcvd<data.length){if((bytesRcvd=in.read(data, totalBytesRcvd, data.length-totalBytesRcvd))==-1){throw new SocketException("Connection closed prematurely");}totalBytesRcvd+=bytesRcvd;}System.out.println("Receved: "+new String(data));//3.使用Socet類的close()方法關(guān)閉連接socket.close();}
}
TCP服務(wù)器端代碼:
Java代碼 ?
public ?class ?TCPEchoServer?{ ??????private ?static ?final ?int ?BUFSIZE=32 ; ?? ???? ?? ????public ?static ?void ?main(String?[]?args)?throws ?IOException,?InterruptedException{ ?? ????????if (args.length!=1 ){ ?? ????????????throw ?new ?IllegalArgumentException("Parameter(s):<Port>" ); ?? ????????} ?? ???????? ?? ????????int ?servPort=Integer.parseInt(args[0 ]); ?? ???????? ?? ?????????? ????????ServerSocket?servSock=new ?ServerSocket(servPort); ?? ???????? ?? ????????int ?recvMsgSize; ?? ???????? ?? ????????byte ?[]?receiveBuf=new ?byte [BUFSIZE]; ?? ???????? ?? ?????????? ????????while (true ){ ?? ?????????????? ?????????????? ????????????Socket?clntSock=servSock.accept(); ?? ????????????SocketAddress?clientAddress=clntSock.getRemoteSocketAddress(); ?? ????????????System.out.println("Handling?client?at?" +clientAddress); ?? ???????????? ?? ?????????????? ????????????InputStream?in=clntSock.getInputStream(); ?? ????????????OutputStream?out=clntSock.getOutputStream(); ?? ?? ????????????while ((recvMsgSize=in.read(receiveBuf))!=-1 ){ ?? ????????????????out.write(receiveBuf,?0 ,?recvMsgSize); ?? ????????????} ?? ???????? ?? ?????????????? ????????????clntSock.close(); ?? ????????} ?? ????} ?? }??
Java TCP/IP Socket 編程 筆記(三)—UDP的例子
?
1.UDP套接字與TCP套接字不同。UDP套接字在使用前不需要進(jìn)行連接。TCP協(xié)議與電話通信相似,而UDP協(xié)議則與郵件通信相似:你寄包裹或信件時不要進(jìn)行“連接”,但是你的為每個包裹和信件制定目的地址。 類似地,每條信息(datagram,即數(shù)據(jù)報文)負(fù)載了自己的地址信息,并與其他信息相互獨(dú)立。在接收信息時,UDP套接字扮演的角色就像是一個信箱,從不同地址發(fā)送來的信件和包裹都可以放到里面。一旦被創(chuàng)建,UDP套接字就可以用來連續(xù)地向不同的地址發(fā)送消息,或從任何地址接收信息。 UDP套接字將保留邊界信息。UDP不像TCP一樣,它是盡可能地傳送消息,但并不保證信息一定能成功到達(dá)目的地址,而且信息到達(dá)的順序與其發(fā)送順序不一定一致(就像通過郵政部分寄信一樣)。因此,UDP套接字的程序必須準(zhǔn)備好處理信息的丟失和重排。 UDP的優(yōu)點(diǎn)之一是效率較高,其次是靈活性。 Java通過DatagramPacket類和DatagramSocket類來使用UDP套接字。客戶端和服務(wù)端都使用DatagramSocket來發(fā)送數(shù)據(jù),使用DatagramPacket來接收數(shù)據(jù)。 發(fā)送信息時,Java程序創(chuàng)建一個包含了待發(fā)送信息的DatagramPacket實(shí)例,并將其作為參數(shù)傳遞給DatagramSocket類的send()方法。接收信息時,Java程序首先創(chuàng)建一個DatagramPacket類的實(shí)例,該實(shí)例中預(yù)先分配了一些空間(一個字節(jié)數(shù)組byte[]),并將接收到的信息存放在該空間中。然后把該實(shí)例作為參數(shù)傳遞給DatagramSocket類的receive()方法。 DatagramPacket的內(nèi)部有l(wèi)ength和offset字段,如果指定了offset,數(shù)據(jù)報文的數(shù)據(jù)部分將從字節(jié)數(shù)組的指定位置發(fā)送或接收數(shù)據(jù)。length參數(shù)指定了字節(jié)數(shù)組中在發(fā)送時要傳輸?shù)淖止?jié)數(shù),活在接收數(shù)據(jù)時所能接收的最多字節(jié)數(shù)。length要比data.length小,但不能比它大。 UDP客戶端:
Java代碼 ?
import ?java.io.IOException; ??import ?java.io.InterruptedIOException; ??import ?java.net.DatagramPacket; ??import ?java.net.DatagramSocket; ??import ?java.net.InetAddress; ???? public ?class ?UDPEchoClientTimeout?{ ??????private ?static ?final ?int ?TIMEOUT=3000 ; ?? ????private ?static ?final ?int ?MAXTRIES=5 ; ?? ???? ?? ????public ?static ?void ?main(String[]?args)?throws ?IOException?{ ?? ????????if (args.length<2 ||args.length>3 ){ ?? ????????????throw ?new ?IllegalArgumentException("Parameter(s):<Server>?<Word>?[<Port>]" ); ?? ????????} ?? ???????? ?? ????????InetAddress?serverAddress=InetAddress.getByName(args[0 ]);?? ????????byte ?[]?bytesToSend=args[1 ].getBytes(); ?? ????????int ?servPort=(args.length==3 )?Integer.parseInt(args[2 ]):7 ; ?? ???????? ?? ?????????? ????????DatagramSocket?socket=new ?DatagramSocket(); ?? ?????????? ????????socket.setSoTimeout(TIMEOUT); ?? ???????? ?? ????????DatagramPacket?sendPacket=new ?DatagramPacket(bytesToSend,bytesToSend.length,serverAddress,servPort); ?? ????????DatagramPacket?receivePacket=new ?DatagramPacket(new ?byte [bytesToSend.length],bytesToSend.length); ?? ???????? ?? ????????int ?tries=0 ; ?? ????????boolean ?receivedResponse=false ; ?? ???????? ?? ????????do { ?? ?????????????? ????????????socket.send(sendPacket); ?? ????????????try { ?? ????????????????socket.receive(receivePacket); ?? ????????????????if (!receivePacket.getAddress().equals(serverAddress)){ ?? ????????????????????throw ?new ?IOException("Received?packet?from?an?unknown?source" ); ?? ????????????????} ?? ????????????????receivedResponse=true ; ?? ????????????}catch (InterruptedIOException?e){ ?? ????????????????tries+=1 ; ?? ????????????????System.out.println("Timed?out," +(MAXTRIES-tries)+"?more?tries?..." ); ?? ????????????} ?? ???????????? ?? ????????}while (!receivedResponse&&(tries<MAXTRIES)); ?? ???????? ?? ???????? ?? ????????if (receivedResponse){ ?? ????????????System.out.println("Received:?" +new ?String(receivePacket.getData())); ?? ????????}else { ?? ????????????System.out.println("No?response?--?giving?up." ); ?? ????????} ?? ???????? ?? ?????????? ????????socket.close(); ?? ????} ?? }??
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UDPEchoClientTimeout {private static final int TIMEOUT=3000;private static final int MAXTRIES=5;public static void main(String[] args) throws IOException {if(args.length<2||args.length>3){throw new IllegalArgumentException("Parameter(s):<Server> <Word> [<Port>]");}InetAddress serverAddress=InetAddress.getByName(args[0]);//server address;byte [] bytesToSend=args[1].getBytes();int servPort=(args.length==3)?Integer.parseInt(args[2]):7;//1.創(chuàng)建一個DatagramSocket實(shí)例,可以選擇對本地地址和端口進(jìn)行設(shè)置。 DatagramSocket socket=new DatagramSocket();//設(shè)置receive()方法的最長阻塞時間socket.setSoTimeout(TIMEOUT);DatagramPacket sendPacket=new DatagramPacket(bytesToSend,bytesToSend.length,serverAddress,servPort);DatagramPacket receivePacket=new DatagramPacket(new byte[bytesToSend.length],bytesToSend.length);int tries=0;boolean receivedResponse=false;do{//2.使用DatagramSocket類的send()和receive()方法來發(fā)送和接收DatagramPacket實(shí)例,進(jìn)行通信socket.send(sendPacket);try{socket.receive(receivePacket);if(!receivePacket.getAddress().equals(serverAddress)){throw new IOException("Received packet from an unknown source");}receivedResponse=true;}catch(InterruptedIOException e){tries+=1;System.out.println("Timed out,"+(MAXTRIES-tries)+" more tries ...");}}while(!receivedResponse&&(tries<MAXTRIES));if(receivedResponse){System.out.println("Received: "+new String(receivePacket.getData()));}else{System.out.println("No response -- giving up.");}//3.通信完成后,使用DatagramSocket類的close方法來銷毀該套接字socket.close();}
}
UDP的服務(wù)器端:
Java代碼 ?
import ?java.io.IOException; ??import ?java.net.DatagramPacket; ??import ?java.net.DatagramSocket; ???? public ?class ?UDPEchoServer?{ ??????private ?static ?final ?int ?ECHOMAX=255 ;?? ???? ?? ????public ?static ?void ?main(String[]?args)?throws ?IOException?{ ?? ????????if (args.length!=1 ){ ?? ????????????throw ?new ?IllegalArgumentException("Parameter(s):<Port>" ); ?? ????????} ?? ???????? ?? ????????int ?servPort=Integer.parseInt(args[0 ]); ?? ???????? ?? ?????????? ????????DatagramSocket?socket=new ?DatagramSocket(servPort); ?? ????????DatagramPacket?packet=new ?DatagramPacket(new ?byte [ECHOMAX],ECHOMAX); ?? ???????? ?? ????????while (true ){ ?? ?????????????? ????????????socket.receive(packet); ?? ????????????System.out.println("Handling?client?at?" +packet.getAddress().getHostAddress()+"?on?port?" +packet.getPort()); ?? ???????????? ?? ????????????socket.send(packet); ?? ????????????packet.setLength(ECHOMAX); ?? ????????} ?? ????} ?? }??
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPEchoServer {private static final int ECHOMAX=255;//max size of echo datagrampublic static void main(String[] args) throws IOException {if(args.length!=1){throw new IllegalArgumentException("Parameter(s):<Port>");}int servPort=Integer.parseInt(args[0]);//1.創(chuàng)建一個DatagramSocket實(shí)例,指定本地端口號,可以選擇指定本地地址DatagramSocket socket=new DatagramSocket(servPort);DatagramPacket packet=new DatagramPacket(new byte[ECHOMAX],ECHOMAX);while(true){//2.使用DatagramSocket的receive方法來接收一個DatagramPacket實(shí)例。socket.receive(packet);System.out.println("Handling client at "+packet.getAddress().getHostAddress()+" on port "+packet.getPort());socket.send(packet);packet.setLength(ECHOMAX);}}
}
注意:DatagramPacket的getData()方法的使用,它返回數(shù)據(jù)緩沖區(qū),是一個字節(jié)數(shù)組,需要注意。 ? packet.setData(buf, offset,length);設(shè)置了接收數(shù)據(jù)時放到緩存去buf中的位置 ,因此接收的數(shù)據(jù)new String(packet.getData(),packet.getOffset(),packet.getLength())的方式構(gòu)造的。
?
Java TCP/IP Socket 編程 筆記(四)—發(fā)送和接收數(shù)據(jù) 編程JavaSocket
1.TCP/IP協(xié)議要求信息必須在塊(chunk)中發(fā)送和接收,而塊的長度必須是8位的倍數(shù),因此,我們可以認(rèn)為TCP/IP協(xié)議中傳輸?shù)男畔⑹亲止?jié)序列。如何發(fā)送和解析信息需要一定的應(yīng)用程序協(xié)議。
2.信息編碼:
??? 首先是Java里對基本整型的處理,發(fā)送時,要注意:1)每種數(shù)據(jù)類型的字節(jié)個數(shù);2)這些字節(jié)的發(fā)送順序是怎樣的?(little-endian還是big-endian);3)所傳輸?shù)臄?shù)值是有符號的(signed)還是無符號的(unsigned)。具體編碼時采用位操作(移位和屏蔽)就可以了。具體在Java里,可以采用DataOutputStream類和ByteArrayOutputStream來實(shí)現(xiàn)。恢復(fù)時可以采用DataInputStream類和ByteArrayInputStream類。
??? 其次,字符串和文本,在一組符號與一組整數(shù)之間的映射稱為編碼字符集(coded character set)。發(fā)送者與接收者必須在符號與整數(shù)的映射方式上達(dá)成共識,才能使用文本信息進(jìn)行通信,最簡單的方法就是定義一個標(biāo)準(zhǔn)字符集。具體編碼時采用String的getBytes()方法。
??? 最后,位操作。如果設(shè)置一個特定的設(shè)為1,先設(shè)置好掩碼(mask),之后用或操作;要清空特定一位,用與操作。
3.成幀與解析
成幀(framing)技術(shù)解決了接收端如何定位消息的首位位置的問題。
如果接收者試圖從套接字中讀取比消息本身更多的字節(jié),將可能發(fā)生以下兩種情況之一:如果信道中沒有其他消息,接收者將阻塞等待,同時無法處理接收到的消息;如果發(fā)送者也在等待接收端的響應(yīng)消息,則會形成死鎖(dealock);另一方面,如果信道中還有其他消息,則接收者會將后面消息的一部分甚至全部讀到第一條消息中去,這將產(chǎn)生一些協(xié)議錯誤。因此,在使用TCP套接字時,成幀就是一個非常重要的考慮因素。
有兩個技術(shù):
1. 基于定界符(Delimiter-based):消息的結(jié)束由一個唯一的標(biāo)記(unique marker)指出,即發(fā)送者在傳輸完數(shù)據(jù)后顯式添加的一個特殊字節(jié)序列。這個特殊標(biāo)記不能在傳輸?shù)臄?shù)據(jù)中出現(xiàn)。幸運(yùn)的是,填充(stuffing)技術(shù)能夠?qū)ο⒅谐霈F(xiàn)的定界符進(jìn)行修改,從而使接收者不將其識別為定界符。在接收者掃描定界符時,還能識別出修改過的數(shù)據(jù),并在輸出消息中對其進(jìn)行還原,從而使其與原始消息一致。
2. 顯式長度(Explicit length):在變長字段或消息前附加一個固定大小的字段,用來指示該字段或消息中包含了多少字節(jié)。這種方法要確定消息長度的上限,以確定保存這個長度需要的字節(jié)數(shù)。
接口:
Java代碼 ?
import ?java.io.IOException; ??import ?java.io.OutputStream; ???? public ?interface ?Framer?{ ??????void ?frameMsg(byte ?[]?message,OutputStream?out)?throws ?IOException; ?? ????byte ?[]?nextMsg()?throws ?IOException; ?? }?? import java.io.IOException;
import java.io.OutputStream;public interface Framer {void frameMsg(byte [] message,OutputStream out) throws IOException;byte [] nextMsg() throws IOException;
}
定界符的方式:
Java代碼 ?
import ?java.io.ByteArrayOutputStream; ??import ?java.io.EOFException; ??import ?java.io.IOException; ??import ?java.io.InputStream; ??import ?java.io.OutputStream; ???? public ?class ?DelimFramer?implements ?Framer?{ ??????private ?InputStream?in;?? ????private ?static ?final ?byte ?DELIMTER=(byte )'\n' ;?? ???? ?? ????public ?DelimFramer(InputStream?in){ ?? ????????this .in=in; ?? ????} ?? ?? ????@Override ?? ????public ?void ?frameMsg(byte []?message,?OutputStream?out)?throws ?IOException?{ ?? ?????????? ????????for (byte ?b:message){ ?? ????????????if (b==DELIMTER) ?? ????????????????throw ?new ?IOException("Message?contains?delimiter" ); ?? ????????} ?? ????????out.write(message); ?? ????????out.write(DELIMTER); ?? ????????out.flush(); ?? ???????? ?? ???????? ?? ????} ?? ?? ????@Override ?? ????public ?byte []?nextMsg()?throws ?IOException?{ ?? ????????ByteArrayOutputStream?messageBuffer=new ?ByteArrayOutputStream(); ?? ????????int ?nextByte; ?? ???????? ?? ????????while ((nextByte=in.read())!=DELIMTER){ ?? ????????????if (nextByte==-1 ){?? ????????????????if (messageBuffer.size()==0 ){ ?? ????????????????????return ?null ; ?? ????????????????}else { ?? ????????????????????throw ?new ?EOFException("Non-empty?message?without?delimiter" ); ?? ????????????????} ?? ????????????} ?? ????????????messageBuffer.write(nextByte); ?? ????????} ?? ????????return ?messageBuffer.toByteArray(); ?? ????} ?? }?? import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class DelimFramer implements Framer {private InputStream in;//data source;private static final byte DELIMTER=(byte)'\n';//message delimiterpublic DelimFramer(InputStream in){this.in=in;}@Overridepublic void frameMsg(byte[] message, OutputStream out) throws IOException {//ensure that the message dose not contain the delimiterfor(byte b:message){if(b==DELIMTER)throw new IOException("Message contains delimiter");}out.write(message);out.write(DELIMTER);out.flush();}@Overridepublic byte[] nextMsg() throws IOException {ByteArrayOutputStream messageBuffer=new ByteArrayOutputStream();int nextByte;while((nextByte=in.read())!=DELIMTER){if(nextByte==-1){//end of stream?if(messageBuffer.size()==0){return null;}else{throw new EOFException("Non-empty message without delimiter");}}messageBuffer.write(nextByte);}return messageBuffer.toByteArray();}
}
顯式長度方法:
Java代碼 ?
import ?java.io.DataInputStream; ??import ?java.io.EOFException; ??import ?java.io.IOException; ??import ?java.io.InputStream; ??import ?java.io.OutputStream; ???? public ?class ?LengthFramer?implements ?Framer?{ ??????public ?static ?final ?int ?MAXMESSAGELENGTH=65535 ; ?? ????public ?static ?final ?int ?BYTEMASK=0xff ; ?? ????public ?static ?final ?int ?SHOTMASK=0xffff ; ?? ????public ?static ?final ?int ?BYTESHIFT=8 ; ?? ???? ?? ????private ?DataInputStream?in;?? ???? ?? ????public ?LengthFramer(InputStream?in)?throws ?IOException{ ?? ????????this .in=new ?DataInputStream(in); ?? ????} ?? ?? ????@Override ?? ????public ?void ?frameMsg(byte []?message,?OutputStream?out)?throws ?IOException?{ ?? ????????if (message.length>MAXMESSAGELENGTH){ ?? ????????????throw ?new ?IOException("message?too?long" ); ?? ????????} ?? ???????? ?? ?????????? ????????out.write((message.length>>BYTEMASK)&BYTEMASK); ?? ????????out.write(message.length&BYTEMASK); ?? ?????????? ????????out.write(message); ?? ????????out.flush(); ?? ????} ?? ?? ????@Override ?? ????public ?byte []?nextMsg()?throws ?IOException?{ ?? ????????int ?length; ?? ???????? ?? ????????try { ?? ????????????length=in.readUnsignedShort(); ?? ????????}catch (EOFException?e){ ?? ???????????? ?? ????????????return ?null ; ?? ????????} ?? ?????????? ????????byte ?[]?msg=new ?byte [length]; ?? ????????in.readFully(msg);?? ????????return ?msg; ?? ????} ?? }??
?
總結(jié)
以上是生活随笔 為你收集整理的Java TCP/IP Socket 编程 笔记 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。