I'm trying to implement object serialization but stuck at the StreamCorruptedException.
On the server's side:
public class MulticastServer {
public static void main(String[] args) throws java.io.IOException {
new MulticastServerThread().start();
}
}
Which calls:
public class MulticastServerThread extends QuoteServerThread {
boolean moreQuotes=true;
public void run() {
while (moreQuotes) {
try {
byte[] buf = new byte[256];
String dString="Server";
System.out.println(dString);
buf = dString.getBytes();
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length,
group, 4446);
socket.send(packet);
ObjectInputStream is=null;
ByteArrayInputStream byteStream = new ByteArrayInputStream(recvBuf);
is = new ObjectInputStream(new BufferedInputStream(byteStream));
Object o1=(Object)is.readObject();
System.out.println(o1.a);
is.close();
socket.close();
}}}}
And Object class on both server and client:
public class Object implements Serializable{
private static final long serialVersionUID=1L;
int a=10;
}
And Client side code:
public class MulticastClient {
public static void main(String[] args) throws IOException {
MulticastSocket socket = new MulticastSocket(4446);
InetAddress address = InetAddress.getByName("230.0.0.1");
socket.joinGroup(address);
Object o1=new Object();
DatagramPacket packet;
for (int i = 0; i < 5; i++) {
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData());
System.out.println("received data" +received);
ObjectOutputStream os = null;
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(15000);
os = new ObjectOutputStream(new BufferedOutputStream(byteStream));
os.flush();
os.writeObject((Object)o1);
System.out.println(o1.a);
os.flush();
}
socket.leaveGroup(address);
socket.close();
}
}
I've done all this:
Put all classes under the same path on both machines
attach breaks and try to find out where the problem is
Can someone please help me? Thanks!
If you are trying to do object serialization over UDP, then you need to serialize the object into the packet's byte array, and read the object from that at the receiving end. There is an old Java World article: Object transport via datagram packets which you might find useful.
It looks like you want to implement a two-directional communication:
server -> send packet
client -> receive packet
client -> send object
server -> receive object
I'm not sure how that's going to work out for you (especially if you have multiple clients).
But at least the following changes will be needed to get anything working:
Your server code is going to need to do a blocking receive call after sending the packet.
The client code is going to need to send the object in a packet.
Related
I am doing a server and client socket datagram.
The client connects to the server and you need to write in the client a string that contains Hello or hello.
When the server detects a string with hello or Hello, repplies to the client with another string.
The problem is that the client doesn't read the string that the server sends.
Here is my code.
Client
public class Client {
public static void main(String[] args) {
try {
System.out.println("Creando socket datagram");
DatagramSocket datagramSocket = new DatagramSocket();
Scanner myObj = new Scanner(System.in); // Create a Scanner object
System.out.println("Say Hello");
String saludo = myObj.nextLine();
System.out.println("Sending message");
InetAddress addr = InetAddress.getByName("localhost");
DatagramPacket datagrama = new DatagramPacket(saludo.getBytes(), saludo.getBytes().length, addr, 5555);
datagramSocket.send(datagrama);
System.out.println("Message sent");
System.out.println("Reading message");
byte[] mensaje = new byte[25];
DatagramPacket datagrama1 = new DatagramPacket(mensaje, 25);
datagramSocket.receive(datagrama1);
System.out.println("Message recieved: " + new String(mensaje));
System.out.println("Closing");
datagramSocket.close();
System.out.println("FInished");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server
public class Server {
public static void main(String[] args) throws InterruptedException {
try {
for (;;) {
System.out.println("Creating socket datagram");
InetSocketAddress addr = new InetSocketAddress("localhost", 5555);
DatagramSocket datagramSocket = new DatagramSocket(addr);
System.out.println("RReading message");
byte[] mensaje = new byte[25];
DatagramPacket datagrama1 = new DatagramPacket(mensaje, 25);
datagramSocket.receive(datagrama1);
System.out.println("Message recieved: " + new String(mensaje));
if (new String(mensaje).contains("hello") || new String(mensaje).contains("Hello")) {
String quetal = "¿Hello, how are you doing?";
System.out.println("Sending message");
TimeUnit.SECONDS.sleep(2);
DatagramPacket datagrama2 = new DatagramPacket(quetal.getBytes(), quetal.getBytes().length, addr.getAddress(),
5555);
datagramSocket.send(datagrama2);
System.out.println("Message Sent");
}
datagramSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have tried putting a sleep in the server in case the server sends the string before the client tries to read.
Many thanks for the help as always.
The client is using the parameter-less DatagramSocket() constructor to bind to a random port with which to send and receive on:
Constructs a datagram socket and binds it to any available port on the local host machine. The socket will be bound to the wildcard address, an IP address chosen by the kernel.
However, when the server receives a datagram, you are ignoring the IP and port where the datagram was actually sent from:
DatagramSocket.receive(DatagramPacket)
Receives a datagram packet from this socket. When this method returns, the DatagramPacket's buffer is filled with the data received. The datagram packet also contains the sender's IP address, and the port number on the sender's machine.
When the server is sending the reply, you are sending it back to the server itself at localhost:5555, not to the client at all.
On the server side, you need to change this:
DatagramPacket datagrama2 = new DatagramPacket(..., addr.getAddress(), 5555);
To either this:
DatagramPacket datagrama2 = new DatagramPacket(..., datagrama1.getAddress(), datagrama1.getPort());
Or to this:
DatagramPacket datagrama2 = new DatagramPacket(..., datagrama1.getSocketAddress());
On a side note, your server is also ignoring the actual length of the data that is being sent by the client. The server is receiving data using a 25-byte array, but the client may not actually be sending 25 bytes. If the client sends less than 25 bytes, you will end up with a String that contains random garbage on the end of it. And if the client sends more than 25 bytes, `receive() will truncate the data.
Try something more like this instead:
System.out.println("Reading message");
byte[] buffer = new byte[65535];
DatagramPacket datagrama1 = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(datagrama1);
String mensaje = new String(datagrama1.getData(), datagrama1.getLength());
System.out.println("Message recieved: " + mensaje);
if (mensaje.contains("hello") || mensaje.contains("Hello")) {
...
}
This was fun :)
Kindly keep in mind, the way this is coded might not be the best, however it works as you want.
The Client sends Hello, The server receives Hello, and Sends (Hello back at you).
Both then terminate. It doesnt keep on looping those 2 messages forever, but I showed you the idea.
The Server needs to act as a Client as well in order to send messages.
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class DReceiver{
public static void replyToTheClientListening() throws IOException {
DatagramSocket ds = new DatagramSocket();
String str = "hello back at you";
InetAddress ia = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), ia, 3001);
ds.send(dp);
ds.close();
}
public static void listenToMessagesFromTheClient() throws IOException {
DatagramSocket ds = new DatagramSocket(3000);
ds.setSoTimeout(60000); //Wait 60 SECONDS for messages
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, 1024);
ds.receive(dp);
String strRecv = new String(dp.getData(), 0, dp.getLength());
if("hello".equalsIgnoreCase(strRecv)) { //hello in any case
System.out.println("Received a MSG from the Client " + strRecv);
replyToTheClientListening();
}
ds.close();
}
public static void main(String[] args) throws Exception {
listenToMessagesFromTheClient();
}
}
The DSender is a Client but also needs to act as a Server (To Listen to Messages coming in from the other Server)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class DSender{
public static void actAsAServerAndListenToMessages() throws IOException {
//Listen to Port 3001 --The Server will send to that port
DatagramSocket dsReceive = new DatagramSocket(3001);
dsReceive.setSoTimeout(60000); //Make it wait 60 SECONDS
byte[] buf = new byte[1024];
DatagramPacket dpReceive = new DatagramPacket(buf, 1024);
dsReceive.receive(dpReceive);
String strRecv = new String(dpReceive.getData(), 0, dpReceive.getLength());
System.out.println("Client -- Received a Msg back from Server --" + strRecv);
dsReceive.close();
}
public static void sendAMessageAsAClientToTheServer() throws IOException {
// Client will send a message to Port 3000 which the Server listens to.
DatagramSocket ds = new DatagramSocket();
String str = "hello";
InetAddress ia = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), ia, 3000);
ds.send(dp);
ds.close();
}
public static void main(String[] args) throws Exception {
sendAMessageAsAClientToTheServer();
actAsAServerAndListenToMessages();
}
}
Reference :
https://www.javatpoint.com/DatagramSocket-and-DatagramPacket
I run the server, then the Client.
Here I am creating two separate packets to send and receive. Instead of this how can I use the same packet to reply, by overwriting the data, using the setData method with a new data buffer: packet.setData(newbuffer);
Client
package labsheet2;
import java.net.*;
import java.io.*;
public class Clientnew {
public final static int UDP_PORT = 50001;
public static void main(String[] args) throws Exception {
System.out.println("Server Time >>>>");
//create a DatagramSocket object
DatagramSocket clientSocket = new DatagramSocket();
InetAddress ip = InetAddress.getByName("localhost");
//create buffers to store datagram data in DatagramPacket Objecct
byte[] buffReceiveData = new byte[100]; //for incoming data
byte[] buffSendData = new byte[100]; //for outgoing data
//create the outgoing Datagram with ip and port
DatagramPacket packetOut = new DatagramPacket(buffSendData,
buffSendData.length, ip, UDP_PORT);
//create the incoming DatagramPacket object to wrap receiving data
DatagramPacket packetIn = new DatagramPacket(buffReceiveData,
buffReceiveData.length);
clientSocket.send(packetOut); //send data
clientSocket.receive(packetIn); //receive data from the server
String time = new String(packetIn.getData());
System.out.println(time);
clientSocket.close(); //close the client socket
}
}
Server
package labsheet2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Date;
public class Servernew {
public final static int UDP_PORT = 50001;
public static void main(String[] args) throws Exception {
//create a DatagramSocket and bind it to the PORT
DatagramSocket serverSocket = new DatagramSocket(UDP_PORT);
while (true) {
System.out.println("Server is up....");
//create buffers to store datagram data in DatagramPacket Objecct
byte[] buffReceiveData = new byte[100]; //for incoming data
byte[] buffSendData = new byte[100]; //for outgoing data
//Datagram object to wrap incoming data
DatagramPacket packetIn = new DatagramPacket(buffReceiveData,
buffReceiveData.length);
//Receive the incoming data packet to DatagramPacket Object
serverSocket.receive(packetIn);
//Get the source ip from the incoming packet
InetAddress ip = packetIn.getAddress();
//Get the source port from the incoming packet
int port = packetIn.getPort();
buffSendData = new Date().toString().getBytes();//get Date in bytes
//packetIn.setData(buffReceiveData, buffReceiveData.length, ip, port);
//create the outgoing Datagram with source ip and port
DatagramPacket packetOut = new DatagramPacket(buffSendData,
buffSendData.length, ip, port);
serverSocket.send(packetOut);
packetIn = null; //reset incoming DatagramPacket Object
System.out.println("Done !! ");
}
}
}
how can I use the same packet to reply, by overwriting the data, using the setData method with a new data buffer: packet.setData(newbuffer);
By overwriting the data, using the setData() method with a new data buffer: packet.setData(newbuffer);
Socket socket = new Socket("192.168.178.47", 82);
OutputStream out = socket.getOutputStream();
out.write("{ \"phone\": \"23456789\" }".getBytes());
out.flush();
//Server
InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
int i = 0;
while((i = in.read()) >= 0) {
bOut.write(i);
}
String complete = new String(bOut.toByteArray(), "UTF-8");
I had tried to send data via OutputStream to a socket but the data is not flushing. If I add an out.close(); to the end then it works perfectly, but the socket is closed and I cannot accept the response. Does anybody know why? The server is not giving any type of error. I had used Java 1.7!
It is possible that the server is waiting for the end of line. If this is the case add "\n" to the text
I'm not sure of the labelling "//Server" in your question, but I'm assuming the following code is the server code:
InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
int i = 0;
while((i = in.read()) >= 0) {
bOut.write(i);
}
String complete = new String(bOut.toByteArray(), "UTF-8");
This will continue to read, blocking each time, until it gets a value from read() less than zero. That only happens if the stream is closed.
It really looks like you need to establish your own protocol. So instead of looking for "<=0" look for some constant value that signals the end of the message.
Here's a quick demonstration of what I mean (I didn't have time yesterday). I have 3 classes, Message,MyClient (which also is the main class), and MyServer. Notice there isn't anything about sending or receiving a newline. Nothing is setting tcpNoDelay. But it works fine. Some other notes:
This code only sends and receives a single request and response.
It doesn't support sending multiple Message instances. That would require checking for the start of a Message as well as the end.
Message class:
public class Message {
public static final String MSG_START = "<message>";
public static final String MSG_END = "</message>";
private final String content;
public Message(String string){
content = string;
}
#Override
public String toString(){
return MSG_START + content + MSG_END;
}
}
MyServer class
public class MyServer implements Runnable{
public static final int PORT = 55555;
#Override
public void run(){
try {
ServerSocket serverSocket = new ServerSocket(PORT);
Socket socket = serverSocket.accept();
String message = getMessage(socket);
System.out.println("Server got the message: " + message);
sendResponse(socket);
}catch (IOException e){
throw new IllegalStateException(e);
}
}
private void sendResponse(Socket socket) throws IOException{
Message message = new Message("Ack");
System.out.println("Server now sending a response to the client: " + message);
OutputStream out = socket.getOutputStream();
out.write(message.toString().getBytes("UTF-8"));
}
private String getMessage(Socket socket) throws IOException{
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
StringBuilder sb = new StringBuilder(100);
byte[] bytes = new byte[1024<<8];
while(sb.lastIndexOf(Message.MSG_END) == -1){
int bytesRead = in.read(bytes);
sb.append(new String(bytes,0,bytesRead,"UTF-8"));
}
return sb.toString();
}
}
MyClient class
public class MyClient {
public static void main(String[] args){
MyClient client = new MyClient();
Thread server = new Thread(new MyServer());
server.start();
client.performCall();
}
public void performCall(){
try {
Socket socket = new Socket("127.0.0.1",MyServer.PORT);
sendMessage(socket, "Why hello there!");
System.out.println("Client got a response from the server: " + getResponse(socket));
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public String getResponse(Socket socket) throws IOException{
String response;
StringBuilder sb = new StringBuilder(100);
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
while(sb.lastIndexOf(Message.MSG_END) == -1){
int bytesRead = in.read(bytes);
sb.append(new String(bytes,0,bytesRead,"UTF-8"));
}
response = sb.toString();
return response;
}
public void sendMessage(Socket socket, String message) throws IOException{
Message msg = new Message(message);
System.out.println("Client now sending message to server: " + msg);
OutputStream out = socket.getOutputStream();
out.write(msg.toString().getBytes("UTF-8"));
}
}
The output
Client now sending message to server: Why hello there!
Server got the message: Why hello there!
Server now sending a response to the client: Ack
Client got a response from the server: Ack
Process finished with exit code 0
The problem is not that you are not flushing properly, but that the reading code waits for the socket to disconnect before handling the data:
while((i = in.read()) >= 0)
Will loop as long as something can be read from in (the socket's InputStream). The condition will not fail until the other peer disconnects.
Try using
socket.setTcpNoDelay(true);
There is buffering that occurs for performance reasons (read up on Nagle's algorithm).
Looking at your code it seems ok. However you are sending less than the MTU Nagle's algothrim could be holding it back until enough data is present for a full packet or you close the socket.
So - try this:
socket.setTCPNoDelay(true);
http://en.wikipedia.org/wiki/Nagle%27s_algorithm
https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setTcpNoDelay-boolean-
I am trying to send vector object from UDP server to UDP client in Java.
Sending and Receiving string as an object after serializing has been achieved , but I am unable to send or receive vectors. Below is server ide code.
public class UDPReceive {
public UDPReceive() throws IOException {
try {
int port = Integer.parseInt("1233");
int allReceived=0;
String[] custData=new String[3];
DatagramSocket dsocket = new DatagramSocket(port);
byte[] buffer = new byte[2048];
for(;;) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
dsocket.receive(packet);
String msg = new String(buffer, 0, packet.getLength());
String msg2 = new String(packet.getData());
custData[allReceived]=msg;
allReceived++;
if(allReceived == 3){
System.out.println("All Data Received");
for(int i=0;i<3;i++){
System.out.println(custData[i]);
}
Vector rawData=getTransactions(custData[0],custData[1],custData[2]);
System.out.println("Vectot size "+ rawData.size());
byte[] sendData = new byte[1024];
sendData=(object[])rawData.toArray();
allReceived=0;
}/*if ends here */
}
}
catch (Exception e) {
System.err.println(e);
}
}
Here I want to send back "rawData" variable to client and receive it, and covert it to vector in client side. I tried using byte[] as well, but it didn't work
I suggest you serialize the Vector as an ObjectOutputStream and use ObjectInputStream to get the original Vector.
public static byte[] objectToBytes(Object o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return baos.toByteArray();
}
to reverse
public static <T> T bytesToObject(byte[] bytes) throws IOException, ClassNotFoundException {
return (T) new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
}
I get this exception while trying to send objects over UDP socket in java
java.io.StreamCorruptedException: invalid stream header: 00000000
Here is the code for sender: `
public class Epl_Client implements Serializable{
public static void main(String[] args )
{
try{
ParseMessage pm = new PaseMessage();
DatagramSocket Sock;
Sock = new DatagramSocket();
DatagramPacket Dp;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(4 * 1024);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(lg);
byte[] objectBytes = byteArrayOutputStream.toByteArray();
Dp = new DatagramPacket(objectBytes, objectBytes.length,InetAddress.getByName("localhost"),9876);
Sock.send(Dp);
Sock.close();
}
catch (Exception e){
System.out.println("exception caught" + e);
}
}}
Code for receiver :
public class ClassServer{
public static void main(String[] args){
ParseMessage pm=new ParseMessage();
try{
byte[] recvBuf = new byte[5000];
while(true){
DatagramSocket serverSocket = new DatagramSocket(9876);
ByteArrayInputStream bais = new ByteArrayInputStream(recvBuf);
ObjectInputStream objectInputStream = new ObjectInputStream(bais);
pm= (ParseMessage)objectInputStream.readObject();
System.out.println(pm.message);
bais.close();
objectOutputStream.close();
}
}
catch(Exception e)
{
System.out.println("Exceptiom"+e);
}
}}
And the class
public class ParseMessage implements Serializable{
String message;
public ParseMessage()
{ message="Inavalid";}}
Can anyone help to resolve this error?
You're never actually receiving anything from the socket. Look at your code - you create a DatagramSocket and then never refer to it again. You're always building a ByteArrayInputStream wrapping an array full of zeroes.
You need to call DatagramSocket.receive, and then use the length of the received data when constructing a ByteArrayInputStream. However, you'll need to be certain that you can fit all the data in a single packet. Are you sure you don't want a stream-based protocol?