2013-07-30 2 views
1

우선 udp를 통해 직렬화 한 다음 반대쪽에서 역 직렬화하여 객체를 보내고 처리하려고합니다. 이전에 udp를 통해 다른 데이터를 보내고 파일 등을 직렬화 한 이후로 사소한 일이 될 것이라고 생각했습니다.Java에서 udp를 통해 객체를 전송하십시오.

지금은 디버깅 한 적이 있으며받는 쪽에서 EOFException을 계속받습니다. 패킷은 제대로 도착하지만 어떻게 든 직렬화가 실패합니다. 실수가 발신자인지 수신자인지 확실하지 않습니다. 문제는 패킷의 크기를 모르는 수신기에 관한 것일 수 있습니다.

/** 
* Serializes packet to be sent over udp to the manager tablet. 
*/ 
public byte[] serializeManagerPacket(ManagerUdpPacket mp) 
{ 
    try 
    { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(mp); 
     oos.close(); 
     // get the byte array of the object 
     byte[] obj= baos.toByteArray(); 
     baos.close(); 
     return obj; 
    } 
    catch(Exception e) { 
     e.printStackTrace(); 
    } 

    return null; 

} 

패킷 수신기 클래스

public class UdpReceiver { 

private DatagramSocket clientSocket; 
private byte[] receiveData; 
private final int timeout = 1; 

/** 
* Create a receiver. 
* @param port Port to receive from. 
* @param signCount Number of signals in a packet 
*/ 
public UdpReceiver(int port) 
{ 

    //receiveData = serializeManagerPacket(new ManagerUdpPacket("asd", new MachineData(1, 2, "asd", "modelName"), 1,2,3,4,5.0,null)); 

    try{ 
     clientSocket=new DatagramSocket(port); 
     clientSocket.setReceiveBufferSize(2048); 
     clientSocket.setSoTimeout(timeout); 
    }catch(SocketException e){ 
     Log.e("ERR", "SocketException in UdpReceiver()"); 
    } 
} 

public void close() 
{ 
    clientSocket.close(); 
} 

/** 
* Receive a data packet and split it into array. 
* @param data Array to put data in, must be correct size 
* @return True on successful read, false otherwise 
*/ 
public ManagerUdpPacket receive() 
{ 

    //receive a packet 
    DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length); 
    try{ 
     clientSocket.receive(recvPacket); 
    }catch(IOException e){ 
     Log.e("ERR", "IOException in UdpReceiver.receive"); 
     return null; 
    } 

    ManagerUdpPacket obj = deserializeManagerPacket(receiveData); 

    if (obj != null) 
     Log.v("udpPacket", "UDP saatu: " + obj.getDriver()); 
    return obj; 
} 


/** 
* Deserialize the udp-packet back to readable data. 
* @param data 
* @return 
*/ 
public ManagerUdpPacket deserializeManagerPacket(byte[] data) 
{ 
    try 
    { 
     ObjectInputStream iStream = new ObjectInputStream(new ByteArrayInputStream(data)); 
     ManagerUdpPacket obj = (ManagerUdpPacket) iStream.readObject(); 
     iStream.close(); 
      return obj; 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 

     return null; 
    } 
} 

수신단에서 패킷을 수신하는 쓰레드 :

여기
package com.machinedata.sensordata; 

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 

import android.content.Context; 
import android.util.Log; 

import com.machinedata.io.DataSerializer; 
import com.machinedata.io.ManagerUdpPacket; 

/** 
* This class sends udp-packets. It is used to send driver's information to the manager tablet. 
* @author tuomas 
* 
*/ 
public class UdpSender 
{ 
    private final int MANAGER_PORT = 1234; 
    private String ip = "192.168.11.50"; //tablet's IP 
    private DatagramSocket sock = null; 
    private InetAddress host; 
    private String mType; 
    private DataSerializer dataser; 

    public UdpSender(Context context) 
    { 
     try 
     { 
      sock = new DatagramSocket();  
      host = InetAddress.getByName(ip); //tabletin ip 
     } 
     catch(Exception e) 
     { 
      System.err.println("Exception alustettaessa senderia" + e); 
     } 

     dataser = new DataSerializer(context); 
    } 

    /** 
    * With this function we can send packets about our machine to the manager to 
    * see in the fleet-view. 
    */ 
    public void sendToManager(ManagerUdpPacket managerUdp) 
    { 

     //serialize 
     Log.v("sendudp", "Send a packet: " + managerUdp.getDriver()); 

     //serialize 
     byte[] data = dataser.serializeManagerPacket(managerUdp); 


     //send 
     try 
     { 
       DatagramPacket dp = new DatagramPacket(data , data.length , host , MANAGER_PORT); 
       sock.send(dp);  
     } 

     catch(IOException e) 
     { 
      System.err.println("IOException senderissa " + e); 
     } 


    } 

    public void close() 
    { 
     sock.close(); 
    } 
} 

직렬화 함수이다 : 여기

내 발신자 클래스

그리고마침내는 UDP를 통해 보내고있다 클래스 :

public class ManagerUdpPacket implements Serializable 
{ 
    private static final long serialVersionUID = 9169314425496496555L; 

    private Location gpsLocation; 
    private double totalFuelConsumption; 
    private long operationTime; 

    //workload distribution 
    private long idleTime = 0; 
    private long normalTime = 0; 
    private long fullTime = 0; 

private int currentTaskId; 
private String driverName; 
String machineModelName = ""; 
String machineName = ""; 
int machineIconId = -1; 
int machinePort = -1; 

public ManagerUdpPacket(String driver, MachineData machine, int currentTaskId, long idleTime, long fullTime, long operationTime, double fuelConsumption, Location location) 
{ 
    driverName = driver; 
    this.currentTaskId = currentTaskId; 
    this.idleTime = idleTime; 
    this.fullTime = fullTime; 
    this.operationTime = operationTime; 
    this.totalFuelConsumption = fuelConsumption; 
    this.gpsLocation = location; 
    machineModelName = machine.getModelName(); 
    machineName = machine.getName(); 
    machineIconId = machine.getIconId(); 
    machinePort = machine.getPort(); 
} 

public String getDriver() 
{ 
    return driverName; 
} 
public int getCurrentTaskId() 
{ 
    return currentTaskId; 
} 
public long getIdleTime() 
{ 
    return idleTime; 
} 
public long getFullTime() 
{ 
    return fullTime; 
} 
public long getOperationTime() 
{ 
    return operationTime; 
} 
public double getTotalFuelConsumption() 
{ 
    return totalFuelConsumption; 
} 
public double getLocation() 
{ 
    return gpsLocation.getLatitude(); 
} 
public String getMachineModelName() 
{ 
    return machineModelName; 
} 
public String getMachineName() 
{ 
    return machineName; 
} 
public int getMachineIconId() 
{ 
    return machineIconId; 
} 
    public int getMachinePort() 
    { 
     return machinePort; 
    } 


} 

내가 직렬화 된 패킷의 크기에서 패킷 크기를 얻기 위해 노력 또는 인터넷에 몇 가지 예에 따라 임의 2,048 삽입. 그래도 작동하지 못했습니다.

+0

바이트 스트림의 일부를 deserialize하려고하기 때문에 deserialization이 실패합니다. 전체 데이터를받은 후에 만 ​​deserialize를 호출해야합니다. – krishna

답변

2

내가 아는 한 receive 함수는받은 바이트의 길이를 반환합니다. 하지만 당신의 버퍼가 가득 할 것이다 :

예 :

int buffersize = 1024;

당신은 UDP를 통해 8bytes를 보냅니다.

그래서 byte[] 1024의 나머지 부분은 당신이 .receive()를 호출하여 얻을 크기를 저장하고 또 다른에 버퍼의 모든 값을 저장 0

하게 될 8 바이트 만 가득 할 것이다 바이트 [] 그리고 당신은 당신의 객체를 가져야한다. 귀하의 예를 들어

: UDP 데이터를 수신 할 때

public ManagerUdpPacket receive() 
{ 
int receivedBytes = 0; 

//receive a packet 
DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length); 
try{ 
    receivedBytes = clientSocket.receive(recvPacket); 
}catch(IOException e){ 
    Log.e("ERR", "IOException in UdpReceiver.receive"); 
    return null; 
} 
byte[] myObject = new byte[receivedBytes]; 

for(int i = 0; i < receivedBytes; i++) 
{ 
    myObject[i] = receiveData[i]; 
} 

ManagerUdpPacket obj = deserializeManagerPacket(myObject); 

if (obj != null) 
    Log.v("udpPacket", "UDP saatu: " + obj.getDriver()); 
return obj; 
} 
+0

수신 한 데이터를 receiveData 바이트 배열에 씁니다. 그러면 수신 된 데이터가 가득 찰 것입니다. 그러나 2048 바이트가 클 때 나머지는 0으로 채워집니다.이 바이트 배열을 비 직렬화하려고하면 2048 바이트 전체를 읽으려고 시도합니다. 배열을 벗겨야합니다.따라서 수신 한 데이터만큼 큰 새 바이트 배열을 만들어야합니다.받은 데이터 수를 읽으면 알 수 있습니다.이 바이트 배열은 이제 deserialize 할 수 있습니다. – Loki

+0

설명 및 예제 코드를 제공해 주셔서 감사합니다! 그것은 지금 일하고있어 :) Btw, clientSocket.receive()는 void 함수이므로 사용해야한다. \t \t clientSocket.receive (recvPacket); receivedBytes = recvPacket.getLength(); 대신. 누군가가 대답을 읽고 궁금해하는 경우를 대비해서. – Tumetsu

+0

오, 예 ... 그 xD에 대해 미안 해요. – Loki

1

, 항상 java.net.DatagramSocket.getReceiveBufferSize();를 사용합니다. 이것은 소켓의 실제 플랫폼 또는 SP_RCVBUF 크기입니다. UDP는 스트리밍 프로토콜 인 TCP와 달리 데이터 그램 기반 프로토콜이기 때문에 수신 버퍼가 데이터 정상성에 중요합니다. 일반적으로 수신 및 송신 버퍼의 크기는 동일하지만 DatagramSocket.send(DatagramPacket)을 사용할 때 송신하는 동안 신경 쓰지 않아도되고 DatagramSocket.setSendBufferSize(DatagramSocket.getSendBufferSize())을 사용하여이 소켓에 SO_SNDBUF 옵션을 사용할 수 있습니다. UDP에서 플랫폼보다 큰 SO_SNDBUF 크기를 사용하면 패킷을 버릴 수 있습니다.

관련 문제