Ⅰ java TCP傳輸數據有沒有大小限制,有,是多少,沒有,為什麼
MTU最大傳輸單元,這個最大傳輸單元實際上和鏈路層協議有著密切的關系,EthernetII幀的結構DMAC+SMAC+Type+Data+CRC由於乙太網傳輸電氣方面的限制,每個乙太網幀都有最小的大小64bytes最大不能超過1518bytes,對於小於或者大於這個限制的乙太網幀我們都可以視之為錯誤的數據幀,一般的乙太網轉發設備會丟棄這些數據幀。
由於乙太網EthernetII最大的數據幀是1518Bytes這樣,刨去乙太網幀的幀頭(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和幀尾CRC校驗部分4Bytes那麼剩下承載上層協議的地方也就是Data域最大就只能有1500Bytes這個值我們就把它稱之為MTU。
PPPoE所謂PPPoE就是在乙太網上面跑PPP協議,有人奇怪了,PPP協議和Ethernet不都是鏈路層協議嗎?怎麼一個鏈路層跑到另外一個鏈路層上面去了,難道升級成網路層協議了不成。其實這是個誤區:就是某層協議只能承載更上一層協議。
為什麼會產生這種奇怪的需求呢?這是因為隨著寬頻接入(這種寬頻接入一般為Cable Modem或者xDSL或者乙太網的接入),因為乙太網缺乏認證計費機制而傳統運營商是通過PPP協議來對撥號等接入服務進行認證計費的.
PPPoE帶來了好處,也帶來了一些壞處,比如:二次封裝耗費資源,降低了傳輸效能等等,這些壞處俺也不多說了,最大的壞處就是PPPoE導致MTU變小了乙太網的MTU是1500,再減去PPP的包頭包尾的開銷(8Bytes),就變成1492。
UDP 包的大小就應該是 1492 - IP頭(20) - UDP頭(8) = 1464(BYTES)
TCP 包的大小就應該是 1492 - IP頭(20) - TCP頭(20) = 1452(BYTES)
目前大多數的路由設備的MTU都為1500
我對上面的理解是:如果我們定義的TCP和UDP包小於1452,1464,那麼我們的包在IP層就不用分包了,這樣傳輸過程中就避免了在IP層組包發生的錯誤。如果使用UDP協議,如果IP層組包發生錯誤,那麼包就會被丟棄,UDP不保證可靠傳輸。但是TCP發生組包錯誤時,該包會被重傳,保證可靠傳輸。所以,我們在用Socket編程時,包的大小設定不一定非要小於1400,UDP協議要求包小於64K,TCP沒有限定
Ⅱ Java TCP socket通信,如何實現發送十六進制值,並在數據接收窗口中顯示這些數據對應的字元串,非常感謝!
我自己的電腦上有一段源代碼,就是基於TCP聊天小代碼,能進行相互之間的消息接受。我的代碼是直接傳輸字元串的,不是16進制滴。嗯,也貼出來看看吧!
運行伺服器,c1,c2就可以了,c1與c2可進行通信。
Client.java
import java.net.*;
public class Client{
static byte num=1;
private int portNum;
public Client(int portnum){
this.portNum=portnum;
System.out.println("您是第"+num+"位客服端");
num++;
}
public void sentMessage(String me){
//都是向伺服器發信息埠號1999
try{
DatagramSocket ds=new DatagramSocket();
DatagramPacket dp=new DatagramPacket(me.getBytes(),me.length(),InetAddress.getByName("127.0.0.1"),1999);
ds.send(dp);
ds.close();
}catch(Exception e){
e.printStackTrace();
}
}
public String receiveMessage(){
String str="";
try{
DatagramSocket ds=new DatagramSocket(this.portNum);//表示哦自己的接收埠號是1999
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,1024);
ds.receive(dp);
str=new String(dp.getData(),0,dp.getLength());
ds.close();
}catch(Exception e){
e.printStackTrace();
}
return str;
}
}
c1.java
import java.util.*;
public class c1 implements Runnable{
Client cl;
boolean goon=true;
Scanner sc=new Scanner(System.in);
public c1(){
cl=new Client(2000);
System.out.println("這里是2000客戶端\n你可以發送信息。請輸入要發送的信息。out退出");
new Thread(this).start();
while(this.goon==true){
say();
}
if(goon==false){
System.exit(0);
}
}
public static void main(String[] args){
new c1();
}
public void say(){
String mess=sc.nextLine();
System.out.println("是否發送y/n");
String key=sc.nextLine();
if(key.equals("y")){
System.out.println("信息信息發送中……");
try{
cl.sentMessage(mess);
}catch(Exception e){
e.printStackTrace();
}
}
else if(key.equals("out")){
goon=false;
}
}
public void run(){
while(this.goon==true){
String sst="";
try{
sst=cl.receiveMessage();
}catch(Exception e){
e.printStackTrace();
}
if(sst.length()>0){
System.out.println(sst);
}
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("程序結束!");
}
}
c2.java
import java.util.*;
public class c2 implements Runnable{
Client cl;
boolean goon=true;
Scanner sc=new Scanner(System.in);
public c2(){
cl=new Client(2001);
System.out.println("這里是2001客戶端\n你可以發送信息。請輸入要發送的信息。out退出");
new Thread(this).start();
while(goon==true){
say();
}
if(goon==false){
System.exit(0);
}
}
public static void main(String[] args){
new c2();
}
public void say(){
String mess=sc.nextLine();
System.out.println("是否發送y/n");
String key=sc.nextLine();
if(key.equals("y")){
System.out.println("信息信息發送中……");
try{
cl.sentMessage(mess);
}catch(Exception e){
e.printStackTrace();
}
}
else if(key.equals("out")){
this.goon=false;
}
}
public void run(){
while(this.goon==true){
String sst="";
try{
sst=cl.receiveMessage();
}catch(Exception e){
e.printStackTrace();
}
if(sst.length()>0){
System.out.println(sst);
}
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("聊天關閉!");
}
}
Server.java
import java.net.*;
import java.util.*;
public class Server implements Runnable{
private String message;
boolean work=true;
byte tm=10;
String[] clomessage={"信息:正在斷開網路連接.",".",".\n","信息:設置保存中……","","","完成\n","信息:歡迎下次使用\n","信息:完成\n","Goodbye!"};
public Server(){
new Thread(this).start();
System.out.println("本程序為服務端Server");
Scanner sc=new Scanner(System.in);
System.out.println("輸入命令out關閉伺服器");
String clo=sc.nextLine();
if(clo.equals("out")){
System.out.println("正在關閉伺服器……");
setwork(false);
System.exit(0);
}
}
public static void main(String[] args){
new Server();
}
public void setwork(boolean bo)
{
this.work=bo;
}
public void setMessage(String str){
this.message=str;
}
public String getMessage(){
return this.message;
}
public void sentMessage(){
String mes=this.getMessage();
try{
DatagramSocket ds=new DatagramSocket();
DatagramPacket dp=new DatagramPacket(mes.getBytes(),mes.length(),InetAddress.getByName("127.0.0.1"),2000);
DatagramPacket dp2=new DatagramPacket(mes.getBytes(),mes.length(),InetAddress.getByName("127.0.0.1"),2001);
ds.send(dp);
ds.send(dp2);
ds.close();
System.out.println("信息發送至:127.0.0.1:2000 & 127.0.0.1:2001");
this.setMessage("");
}catch(Exception e){
e.printStackTrace();
}
}
public void receiveMessage() throws Exception{
try{
DatagramSocket ds=new DatagramSocket(1999);//表示哦自己的接收埠號是1999
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,1024);
ds.receive(dp);
String str=new String(dp.getData(),0,dp.getLength());
if(str.length()>0){
this.setMessage(str);
System.out.println("信息:Server從"+dp.getAddress().getHostAddress()+"主機(埠號:"+dp.getPort()+")收到信息:"+this.getMessage());
}
ds.close();
}catch(Exception e){
e.printStackTrace();
}
}
public void run(){
while(tm>0){
if(work==false){
tm--;
System.out.print(clomessage[9-tm]);
}
try{
receiveMessage();//時刻接受信息
}catch(Exception e){
e.printStackTrace();
}
if(this.getMessage().length()>0){//如果接收到信息則發送信息
try{
sentMessage();
}catch(Exception e){
e.printStackTrace();
}
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
}
呵呵,請指教啊!
Ⅲ 在Java中實現TCP協議編程中怎麼傳
在Java中實現TCP協議編程
ServerSocket:編寫TCP網路服務程序,首先要用到java.net.ServerSocket類用以創建伺服器Socket
構造方法:
ServerSocket(intport):創建綁定到特定埠的伺服器套接字
ServerSocket(intport,intbacklog):利用指定的backlog(伺服器忙時保持連接請求的等待客戶數量),創建伺服器套接字並將其綁定到指定的本地埠號。
ServerSocket(intport,intbacklog,InetAddressbindAddr):使用指定的埠、偵聽backlog和要綁定到的本地IP地址創建伺服器。
Socket:客戶端要與伺服器建立連接,必須先創建一個Socket對象
常用構造方法
Socket(Stringhost,intport):創建一個流套接字並將其連接到指定主機上的指定埠號。
Socket(InetAddressaddress,intport):創建一個流套接字並將其連接到指定IP地址的指定埠號。
伺服器端程序調用ServerSocket類中的accept()方法等待客戶端的連接請求,一旦accept()接收了客戶端連接請求,該方法返回一個與該客戶端建立了專線連接的Socket對象,不用程序去創建這個Socket對象。建立了連接的兩個Socket是以IO流的方式進行數據交換的,Java提供了Socket類中的getInputStream()返回Socket的輸入流對象,getOutputStream()返回Socket的輸出流對象。
TCP伺服器與TCP客戶端間的數據的接受圖示:
用TCP實現伺服器與客戶端的「聊天」:
實例代碼:
客戶端:
packagecom.hbsi.net;
importjava.net.Socket;
importjava.io.*;
publicclassTcpClient{
publicstaticvoidmain(String[]args)throwsException{
//1.建立tcp客戶端socket,要確定要連接的伺服器ip,port
Sockets=newSocket("192.168.49.87",9009);
//獲取鍵盤錄入
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
//2.通過建立的socket,獲取輸出流對象
//數據輸出給伺服器端
OutputStreamout=s.getOutputStream();
BufferedWriterbwout=newBufferedWriter(newOutputStreamWriter(out));
//獲取伺服器端返回的數據
//讀取伺服器端發過來的信息InputStreamReader()
BufferedReaderbrin=newBufferedReader(newInputStreamReader(
s.getInputStream()));
Stringline=null;
while((line=br.readLine())!=null){
if(line.equals("over"))
break;
bwout.write(line);
bwout.newLine();
bwout.flush();
Stringstr=brin.readLine();
System.out.println("server:"+str);
}
br.close();
s.close();
}
}
伺服器端:
packagecom.hbsi.net;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStreamWriter;
importjava.net.ServerSocket;
importjava.net.Socket;
publicclassTcpServer{
publicstaticvoidmain(String[]args)throwsException{
//1.建立伺服器socket
ServerSocketss=newServerSocket(9009);
//2.調用accept()
Sockets=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()
+"...connection");
//讀取客戶的信息的輸入流
InputStreamin=s.getInputStream();
BufferedReaderbrin=newBufferedReader(newInputStreamReader(in));
//向客戶端發送信息輸出流,服務端向客戶端返回信息OutputStreamWriter()
BufferedWriterbrout=newBufferedWriter(newOutputStreamWriter(
s.getOutputStream())); Stringline=null;
while((line=brin.readLine())!=null){
System.out.println("client:"+line);
brout.write(line.toUpperCase());//伺服器端收到信息後,將信息轉為大寫返回給客戶端toUpperCase()
brout.newLine();
brout.flush();
}
s.close();
ss.close();
}
}
Ⅳ 在java中怎麼將一組數據從客戶端發送到伺服器端
1 服務來器端的技術是不是Java?
2 如果是Java,請自使用ObjectOutputStream將實現了serializable介面的Java對象,發送到伺服器,伺服器使用ObjectInputStream流讀取,不過他們需要包裝SocketOutputStream和SocketInputStream
3 如果伺服器是其他技術,請使用WebService技術!
祝你好運!
Ⅳ JAVA TCP通信,客戶端給伺服器傳送JAVA對象通信出錯了,求各位大神指教
在java中用socket傳輸對象的時候,底層是把java對象序列化,然後以二進制數據進行傳輸的。socket的服務端和客戶端都需要有這個對象的聲明,比如客戶端發送的是com.client.MsgPackage對象,那麼這個對象的class文件必須在服務端的classpath中。否則就會是接收方接收了tcp的數據包,但是無法還原成對象。
底層要能把對象序列化,這個對象要實現一個可序列化的介面:java.io.Serializable。
類通過實現 java.io.Serializable
介面以啟用其序列化功能。未實現此介面的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化介面沒有方法或欄位,僅用於標識可序列化的語義。
writeObject 方法負責寫入特定類的對象的狀態,以便相應的 readObject 方法可以恢復它。通過調用
out.defaultWriteObject 可以調用保存 Object 的欄位的默認機制。該方法本身不需要涉及屬於其超類或子類的狀態。通過使用
writeObject 方法或使用 DataOutput 支持的用於基本數據類型的方法將各個欄位寫入 ObjectOutputStream,狀態可以被保存。
readObject 方法負責從流中讀取並恢復類欄位。它可以調用 in.defaultReadObject
來調用默認機制,以恢復對象的非靜態和非瞬態欄位。defaultReadObject
方法使用流中的信息來分配流中通過當前對象中相應指定欄位保存的對象的欄位。這用於處理類演化後需要添加新欄位的情形。該方法本身不需要涉及屬於其超類或子類的狀態。通過使用
writeObject 方法或使用 DataOutput 支持的用於基本數據類型的方法將各個欄位寫入 ObjectOutputStream,狀態可以被保存。
Ⅵ 怎麼用java的socket進行文件傳輸誰能給個簡單的例子,包括發送端和接收端。
java中的網路信息傳輸方式是基於TCP協議或者UD協議P的,socket是基於TCP協議的
例子1
(1)客戶端程序:
import java.io.*;
import java.net.*;
public class Client
{ public static void main(String args[])
{ String s=null;
Socket mysocket;
DataInputStream in=null;
DataOutputStream out=null;
try{
mysocket=new Socket("localhost",4331);
in=new DataInputStream(mysocket.getInputStream());
out=new DataOutputStream(mysocket.getOutputStream());
out.writeUTF("你好!");//通過 out向"線路"寫入信息。
while(true)
{
s=in.readUTF();//通過使用in讀取伺服器放入"線路"里的信息。堵塞狀態,
//除非讀取到信息。
out.writeUTF(":"+Math.random());
System.out.println("客戶收到:"+s);
Thread.sleep(500);
}
}
catch(IOException e)
{ System.out.println("無法連接");
}
catch(InterruptedException e){}
}
}
(2)伺服器端程序:
import java.io.*;import java.net.*;
public class Server
{ public static void main(String args[])
{ ServerSocket server=null;
Socket you=null;String s=null;
DataOutputStream out=null;DataInputStream in=null;
try{ server=new ServerSocket(4331);}
catch(IOException e1){System.out.println("ERRO:"+e1);}
try{ you=server.accept();
in=new DataInputStream(you.getInputStream());
out=new DataOutputStream(you.getOutputStream());
while(true)
{
s=in.readUTF();// 通過使用in讀取客戶放入"線路"里的信息。堵塞狀態,
//除非讀取到信息。
out.writeUTF("你好:我是伺服器");//通過 out向"線路"寫入信息.
out.writeUTF("你說的數是:"+s);
System.out.println("伺服器收到:"+s);
Thread.sleep(500);
}
}
catch(IOException e)
{ System.out.println(""+e);
}
catch(InterruptedException e){}
}
}
例子(2)
(1) 客戶端
import java.net.*;import java.io.*;
import java.awt.*;import java.awt.event.*;
import java.applet.*;
public class Computer_client extends Applet implements Runnable,ActionListener
{ Button 計算;TextField 輸入三邊長度文本框,計算結果文本框;
Socket socket=null;
DataInputStream in=null; DataOutputStream out=null;
Thread thread;
public void init()
{ setLayout(new GridLayout(2,2));
Panel p1=new Panel(),p2=new Panel();
計算=new Button(" 計算");
輸入三邊長度文本框=new TextField(12);計算結果文本框=new TextField(12);
p1.add(new Label("輸入三角形三邊的長度,用逗號或空格分隔:"));
p1.add( 輸入三邊長度文本框);
p2.add(new Label("計算結果:"));p2.add(計算結果文本框);p2.add(計算);
計算.addActionListener(this);
add(p1);add(p2);
}
public void start()
{ try
{ //和小程序所駐留的伺服器建立套接字連接:
socket = new Socket(this.getCodeBase().getHost(), 4331);
in =new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
}
catch (IOException e){}
if(thread == null)
{ thread = new Thread(this);
thread.start();
}
}
public void run()
{ String s=null;
while(true)
{ try{ s=in.readUTF();//堵塞狀態,除非讀取到信息。
計算結果文本框.setText(s);
}
catch(IOException e)
{ 計算結果文本框.setText("與伺服器已斷開");
break;
}
}
}
public void actionPerformed(ActionEvent e)
{ if(e.getSource()==計算)
{ String s=輸入三邊長度文本框.getText();
if(s!=null)
{ try { out.writeUTF(s);
}
catch(IOException e1){}
}
}
}
}
(2) 伺服器端
import java.io.*;import java.net.*;
import java.util.*;import java.sql.*;
public class Computer_server
{ public static void main(String args[])
{ ServerSocket server=null;Server_thread thread;
Socket you=null;
while(true)
{ try{ server=new ServerSocket(4331);
}
catch(IOException e1)
{ System.out.println("正在監聽"); //ServerSocket對象不能重復創建。
}
try{ you=server.accept();
System.out.println("客戶的地址:"+you.getInetAddress());
}
catch (IOException e)
{ System.out.println("正在等待客戶");
}
if(you!=null)
{ new Server_thread(you).start(); //為每個客戶啟動一個專門的線程。
}
else
{ continue;
}
}
}
}
class Server_thread extends Thread
{ Socket socket;Connection Con=null;Statement Stmt=null;
DataOutputStream out=null;DataInputStream in=null;int n=0;
String s=null;
Server_thread(Socket t)
{ socket=t;
try { in=new DataInputStream(socket.getInputStream());
out=new DataOutputStream(socket.getOutputStream());
}
catch (IOException e)
{}
}
public void run()
{ while(true)
{ double a[]=new double[3] ;int i=0;
try{ s=in.readUTF();堵塞狀態,除非讀取到信息。
StringTokenizer fenxi=new StringTokenizer(s," ,");
while(fenxi.hasMoreTokens())
{ String temp=fenxi.nextToken();
try{ a[i]=Double.valueOf(temp).doubleValue();i++;
}
catch(NumberFormatException e)
{ out.writeUTF("請輸入數字字元");
}
}
double p=(a[0]+a[1]+a[2])/2.0;
out.writeUTF(" "+Math.sqrt(p*(p-a[0])*(p-a[1])*(p-a[2])));
sleep(2);
}
catch(InterruptedException e){}
catch (IOException e)
{ System.out.println("客戶離開");
break;
}
}
}
}
這些例子都是Java2實用教程上的.
Ⅶ plc採集的數據如何傳輸到java語言生成的程序
建議使用TCP/IP通訊模式傳輸數據。
用java程序實現一般會使用 mina框架搭一個socketserver(網上有很多使用實例)
http://blog.sina.com.cn/s/blog_720bdf0501010b8r.html
定義通訊協議,一般使用定長報文,一般定義報文頭(由時間戳、報文體長度等組成),報文體組成(報文體格式由業務需求確定)。
4.PLC通過3G、4G通訊模塊調用TCP客戶端,連接Socketserver(可以在網上查詢C語言連接socket server通信的實例),然後按確定的通訊協議發送字元流。使用C語言實現 socket client。
http://blog.csdn.net/chinazhd/article/details/45134811
Ⅷ TCP/IP協議 怎麼用JAVA發送和接收二進制數據 要具體實例
1.TCP/IP協議要求信息必須在塊(chunk)中發送和接收,而塊的長度必須是8位的倍數,因此,我們可以認為TCP/IP協議中傳輸的信息是位元組序列。如何發送和解析信息需要一定的應用程序協議。
2.信息編碼:
首先是Java里對基本整型的處理,發送時,要注意:1)每種數據類型的位元組個數;2)這些位元組的發送順序是怎樣的?(little-endian還是
big-endian);3)所傳輸的數值是有符號的(signed)還是無符號的(unsigned)。具體編碼時採用位操作(移位和屏蔽)就可以了。
具體在Java里,可以採用DataOutputStream類和ByteArrayOutputStream來實現。恢復時可以採用
DataInputStream類和ByteArrayInputStream類。
其次,字元串和文本,在一組符號與一組整數之間的映射稱為編碼字元集(coded character
set)。發送者與接收者必須在符號與整數的映射方式上達成共識,才能使用文本信息進行通信,最簡單的方法就是定義一個標准字元集。具體編碼時採用
String的getBytes()方法。
最後,位操作。如果設置一個特定的設為1,先設置好掩碼(mask),之後用或操作;要清空特定一位,用與操作。
3.成幀與解析
成幀(framing)技術解決了接收端如何定位消息的首位位置的問題。
如果接收者試圖從套接字中讀取比消息本身更多的位元組,將可能發生以下兩種情況之一:如果信道中沒有其他消息,接收者將阻塞等待,同時無法處理接收
到的消息;如果發送者也在等待接收端的響應消息,則會形成死鎖(dealock);另一方面,如果信道中還有其他消息,則接收者會將後面消息的一部分甚至
全部讀到第一條消息中去,這將產生一些協議錯誤。因此,在使用TCP套接字時,成幀就是一個非常重要的考慮因素。
有兩個技術:
1.基於定界符(Delimiter-based):消息的結束由一個唯一的標記(unique
marker)指出,即發送者在傳輸完數據後顯式添加的一個特殊位元組序列。這個特殊標記不能在傳輸的數據中出現。幸運的是,填充(stuffing)技術
能夠對消息中出現的定界符進行修改,從而使接收者不將其識別為定界符。在接收者掃描定界符時,還能識別出修改過的數據,並在輸出消息中對其進行還原,從而
使其與原始消息一致。
2.顯式長度(Explicit length):在變長欄位或消息前附加一個固定大小的欄位,用來指示該欄位或消息中包含了多少位元組。這種方法要確定消息長度的上限,以確定保存這個長度需要的位元組數。
介面:
Java代碼 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;//data source; private static final byte DELIMTER=(byte)'\n';//message delimiter public DelimFramer(InputStream in){ this.in=in; } @Override public void frameMsg(byte[] message, OutputStream out) throws IOException { //ensure that the message dose not contain the delimiter 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){//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;// wrapper for data I/O 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"); } //write length prefix out.write((message.length>>BYTEMASK)&BYTEMASK); out.write(message.length&BYTEMASK); //write message out.write(message); out.flush(); } @Override public byte[] nextMsg() throws IOException { int length; try{ length=in.readUnsignedShort(); }catch(EOFException e){ //no (or 1 byte) message; return null; } //0<=length<=65535; byte [] msg=new byte[length]; in.readFully(msg);//if exception,it's a framing error; return msg; } }