[Java]Serializable序列化Socket傳送範例

java Socket傳送過程中,可利用ObjectInputStream及ObjectOutputStream傳接送物件當做資料,傳送後的資料可以直接取用,省去需要再讀取xml、文字、json等格式的麻煩。

要利用socket傳送首先需先定義一個Object,而Object必需implements java.io.Serializable介面才可以。Serializable可以參考Serializable序列化

package test; 

public class DataTest implements java.io.Serializable { 
  private int x = 0 ; 
  public DataTest() 
  { 
    
  } 
  public void setP(int x) 
  { 
    this.x = x; 
  } 
  public int getP() 
  { 
    return x; 
  } 
}

再來建立一個Server,利用ObjectInputStream的ReadObject()把Object讀進來,再把這個Object做想要的處理。

SendServer.java

package test; 

import java.net.ServerSocket; 
import java.net.Socket; 



public class SendServer extends java.lang.Thread{ 
  
  private boolean OutServer = false; 
  private ServerSocket server ; 
  private final int ServerPort = 8765; 

  
  public SendServer() 
  { 
    try 
    { 
      server = new ServerSocket(ServerPort); 
      
    } 
    catch(java.io.IOException e) 
    { 
      System.out.println("Socket啟動有問題 !" ); 
      System.out.println("IOException :" + e.toString()); 
    } 
  } 
  
  

  
  
  public void run() 
  { 
    Socket socket ; 
    java.io.ObjectInputStream in ; 

    System.out.println("伺服器已啟動 !"  ); 
    while(!OutServer) 
    { 
      socket = null; 
      try 
      { 
        synchronized(server) 
        { 
          socket = server.accept(); 
        } 
        System.out.println("取得連線 : InetAddress = " + 
socket.getInetAddress()  ); 
        socket.setSoTimeout(15000); 
        

        in = new 
java.io.ObjectInputStream(socket.getInputStream()); 
        
        DataTest data = (DataTest)in.readObject(); 
        System.out.println("我取得的值:"+data.getP()); 
        in.close(); 
        in = null ; 
        socket.close(); 
        
        
        
      } 
      catch(java.io.IOException e) 
      { 
        System.out.println("Socket連線有問題 !" ); 
        System.out.println("IOException :" + e.toString()); 
      } 
      catch(java.lang.ClassNotFoundException e) 
      { 
        System.out.println("ClassNotFoundException :" + 
e.toString()); 
      } 
    } 
  } 
  
  public static void main(String args[]) 
  { 
    (new SendServer()).start(); 
  } 
  
}

最後建立一個socket Client來傳送Object, 利用ObjectOutputStream把Data writeObject()出去。

SendClient.java

package test; 

import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.io.ObjectOutputStream; 
public class SendClient { 
  private String address = "127.0.0.1"; 
  private int port = 8765; 
  public SendClient() 
  { 
    //準備要傳送的資料 
    DataTest data = new DataTest(); 
      data.setP(102928); 
    
    Socket client = new Socket() ; 
        InetSocketAddress isa = new 
InetSocketAddress(this.address,this.port); 
        try 
        { 
          client.connect(isa,10000); 
          ObjectOutputStream out = new 
ObjectOutputStream(client.getOutputStream()); 
          //送出object 
          out.writeObject(data); 
          out.flush(); 
          out.close(); 
          out = null ; 
          data = null ; 
          client.close(); 
          client = null ; 
          
        } 
        catch(java.io.IOException e) 
        { 
          System.out.println("Socket連線有問題 !" ); 
      System.out.println("IOException :" + e.toString()); 
        } 
  } 
  
  public static void main(String args[]) 
  { 
    new SendClient(); 
  } 
}

—–Server端回應—–

伺服器已啟動 !

取得連線 : InetAddress = /127.0.0.1

我取得的值:102928

原始碼下載

延伸:

Java 1.4可用Serializable類別Object列表

17 thoughts to “[Java]Serializable序列化Socket傳送範例”

  1. 您好!

    当我在不同的package建立client和Server的时候,Datatest 也分别在各自的package创建,比如Datatest1.java, Datatest2.java,
    其中两个文件里面都是一样的。运行时出现
    Server 端:
    java.lang.ClassNotFoundException: com.mlh.Datapackage1
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at java.io.ObjectInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at com.google.facebook.s_new.run(s_new.java:34)
    at java.lang.Thread.run(Unknown Source)
    Client端:
    TCPC: Connecting…
    TCP C: Sending…
    TCP C: Receiving…
    TCP S: Error
    java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at com.mlh.mlh_client.main(mlh_client.java:44)

    为什么出现这种错误?

    1. java.lang.ClassNotFoundException是指你的class讀取不到
      請問是否可以提供您的目錄結構呢?
      Datapackage1理論上應該要放在./com/mlh月山錄裡的

  2. 您好
    我把Client跟server寫在兩個不同的專案
    然後DataTest.java我在Client跟Server兩個專案的地方都有加入
    這時候運行Client端時會出現
    java.lang.ClassNotFoundException: com.client.DataTest
    這個錯誤
    另外因為我Client是寫在Android上
    所以沒辦法將Client跟Server都寫在同一個專案內
    請問我該怎樣才能解決這個問題呢?

    1. 這個錯誤是說在你package com.clinet裡的DataTest並不存在
      在幾個專案裡應該沒什麼差別

      1. @yku,
        感謝回復
        但是我再com.client下確實有DataTest.java這個檔案
        真是奇怪 我是直接在com.client那右鍵新增出個Java檔來當作DataTest
        之後還需要什麼動作嗎? Clent跟DataTest確實是放在同一個package裡

        1. 你犯了一個很容易犯的錯
          你在Clinet 傳的object是com.client.DataTest
          而接收的Server是用com.server.DataTest
          是不一樣的Object喔
          請把Server端的package改成package com.client;

  3. 您好,我的情況是,

    Client 和 Server 是分開的兩個 Project (Client 是跑在手機 , Server 則是 跑在電腦)

    所以我的 DataTest 必定是不同的 .Class (但Client 和 Server 的DataTest 內容是相同的),

    請問要怎麼處理這個問題呢?

    1. @Frizan,
      你就讓DataTest在二邊都相同應該就可以了
      ps.因為vm不同,所以不是很確定可不可以
      不過在不同環境下建意你用json或文字格式當傳送介值會比較好

  4. 版大你好:
    如果我需要Server每隔幾秒傳送資料給多個client端,是否不要關閉Server與Client間的連接會比較好,因為一方面是資料的產生時間不同,只有Server知道資料什麼時候產生完畢,所以不太可能利用Client定時連上Server抓取資料,我目前做法是:Server等待Client連線後,將此Socket建立的ObjectOutputStream加入一個ArrayList裡(藉此存放多個Client),當資料產生完畢後,呼叫一個方法利用foreach去輪詢每一個output物件執行輸出但第一輪Client可以接到資料,第二輪就收不到了,以版大的範例要如何修改呢? 希望版大可以給我一些建議或方向。
    謝謝。

    1. 您好
      我不太懂您的意思
      server A要能傳送給clinet B ,那你可以想成那一個clinet其實是server B,所以 clinet A每一段時間就連線server B一次

      1. 謝謝您的回覆
        我要做的是Server一段時間會產生一批資料,將這批資料包成物件分別傳送到多個Client,目前執行狀況是第一輪能夠正常發送與接收,但第二輪就無法接收到資料,我於傳送前測試是有資料的,但client接收時,是無法接收到資料的。
        謝謝

        1. 因為連線已經被設定eof掉了,所以等於是中斷了,要重新再連線,你可以考慮clinet定時連線server,check有無需要下載資料

  5. 謝謝您的回覆
    本來想說,保持連線狀態,產生資料後就可以直接傳送的,
    我再調整看看。
    謝謝。

發表迴響