I've started work on a simple newtworking project which creates a new thread for each connection and I'm trying to send multiple things across. What I'm wondering is there an easy way of simple say declaring a variable sending that whole variable to the server and that being sent to other clients. For example if I wanted to send a simple integer array? Basically how would I send an array or even an image across a socket?
Yes, it is possible. What you are looking for is called serialization and can be used to send entire objects through a stream (socket, file, etc.). Have a look at this java socket serialization tutorial.
Check the docs on ObjectOutpuStream and ObjectInputStream.
Basically what you have to do is have any custom type that you want to be serialized implement the Serializable interface:
class MyCustomType implements Serializable {
...
}
This is a marker interface that tells the runtime that this type can be sent over a stream.
Next, once your connections are set up you can obtain the socket input/output stream and write objects using ObjectOutputStream:
MyCustomType obj = new MyCustomType();
ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
oos.writeObject(obj);
oos.flush();
or read them using ObjectInputStream:
ObjectInputStream ois = new ObjectInputStream(client.getOutputStream());
MyCustomType obj = (MyCustomType) ois.readObject();
(client above is a Socket).
Related
Is it possible to send a TreeMap (containing keys and values) over a socket from server to client?
Writing to a socket is no different than writing to a file. The ObjectOutputStream class abstracts that layer for us. So you can test that your Serialization is working smoothly with file IO; then it is very easy to write to a Socket.
First Step: Test Your Serialization
TreeMap<YourKeyClass, YourValueClass> treeMap =
new TreeMap<>();
buildMyTree(treeMap);
FileOutputStream fout = new FileOutputStream("path/to/your/file.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(treeMap);
Second Step: Test Your Deserialization
Read your object back to check deserialization:
FileInputStream fin = new FileInputStream("path/to/your/file.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
TreeMap<YourKeyClass, YourValueClass> treeMapFromFile = ois.readObject();
TreeMap is Serializable. Everything runs perfectly fine, as long as YourValueClass does not have complex structure that hinders serialization. For instance you may have recursive references to other objects in your YourValueClass, in which case you have to work on your work on your own writeObject and readObject implementations for Serialization.
So a read and write check is very important to be sure everything runs according to your structure.
Third Step: Move to Socket Programming
Once you are sure your serialization is working, move to socket programming. It is very important that you're confident that your serialization is working perfectly, before moving on to the socket, since if you miss a point on serialization then if anything fails during socket implementation, it will be very hard to find where the problem is.
Server Side:
//initialize your socket
//start listening on your socket
TreeMap<YourKeyClass, YourValueClass> treeMap = new TreeMap<>();
buildMyTree(treeMap);
ObjectOutputStream oos = new ObjectOutputStream(socketToClient.getOutputStream());
oos.writeObject(treeMap);
Client Side:
//initialize your socket
ObjectInputStream ios = new ObjectInputStream(socketToServer.getInputStream());
TreeMap<YourKeyClass, YourValueClass> treeMapFromSocket = ois.readObject();
You can use refer to the following sources:
Serialization
Oracle Tutorial for Java Socket Prog
ServerSocketChannel
Yes, it's possible.
java.util.TreeMap implements interface java.io.Serializable.
Also all of keys and values int TreeMap must implements this interface.
I try to establish a client / server connection for a mastermind game.
I though of using enumerations to represent the different pegs and made them serializable.
Then I have to implement the connection, using serversocket and getting the socket using accept and so on.
Once the connection is established, I first have to read for client objects, and it is where I am having problems...
Here is a piece of my code, which produces EOFException before I could ever do anything!
(the client data is send on user's interaction).
ObjectInputStream ois =
new ObjectInputStream(socket.getInputStream());
ArrayList<Peg> combination = new ArrayList<Peg>();
do
{
combination.clear();
for (int i = 0; i < 4; i++)
{
combination.add((Peg)ois.readObject());
}
}
while (!checkCombination(combination));
ois.close();
socket.close();
Thank's in advance
We need more details. How are you syncing up writes from the client and the reads on the server? Can you post more details?
BTW, is using raw sockets an absolute requirement? If not, try out RMI which does what you want to do with much less hassle (i.e. sending across Java objects transparently and much more).
If you are getting an EOFException it means the other end has closed the connection.
If you want to send a list, just send the list. i.e.
// on the sender
List<Peg> list =
oos.writeObject(list);
// on the receiver
List<Peg> list = (List<Peg>) oid.readObject();
This is an example of a user defined class I'd like to send from a client application to a server application:
class dataStruct implements Serializable{
byte data;
int messageNum;
public void setData(byte datum, int messageNumber){
data=datum;
messageNum=messageNumber;
}
}
How do you send a user defined class over a tcp/ip connection in java?
What types of streams can I use to accomplish this (if I'm sending more than just text)?
Can I pass a full object via a socket stream, or will I always have to cast it after it has been passed via a stream?
I'm writing a server/client application, and I've only been able to find tutorials with examples of primitive types or strings being passed over a network connection - not user defined types.
Your help and direction are greatly appreciated.
Use an ObjectOutputStream on the sending side and an ObjectInputStream on the receiving side.
To be a bit more clear, here is an example (without any exception handling).
sending side:
dataStruct ds = ...;
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(ds);
oos.close();
receiving side:
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object o = ois.readObject();
if(o instanceof dataStruct) {
dataStruct ds = (dataStruct)o;
// do something with ds
}
else {
// something gone wrong - this should not happen if your
// socket is connected to the sending side above.
}
So yes, you have to cast at the receiving side so the compiler knows the right class. (The casting does not change the class of the object, only changes the compiler's knowledge of it.)
This Serialization is also usable to save objects to a file.
Of course, this gives only interoperability to Java, if you have a non-Java partner, you might want to use a custom serialization protocol, or some XML-based format.
Let the objects implement the Serializable marker interface, and then transfer the objects using ObjectOutputStream and ObjectInputStream. When the object comes out on the other end, it will be via the readObject() method on ObjectInputStream, which returns Object, so yes, you will need to cast it to the proper type.
I have a client Server application which communicate using objects.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get
StreamCorruptedException.
Can some one direct me to the cause of this error?
client write method
private SecMessage[] send(SecMessage[] msgs)
{
SecMessage result[]=new SecMessage[msgs.length];
Socket s=null;
ObjectOutputStream objOut =null;
ObjectInputStream objIn=null;
try
{
s=new Socket("localhost",12345);
objOut=new ObjectOutputStream( s.getOutputStream());
for (SecMessage msg : msgs)
{
objOut.writeObject(msg);
}
objOut.flush();
objIn=new ObjectInputStream(s.getInputStream());
for (int i=0;i<result.length;i++)
result[i]=(SecMessage)objIn.readObject();
}
catch(java.io.IOException e)
{
alert(IO_ERROR_MSG+"\n"+e.getMessage());
}
catch (ClassNotFoundException e)
{
alert(INTERNAL_ERROR+"\n"+e.getMessage());
}
finally
{
try {objIn.close();} catch (IOException e) {}
try {objOut.close();} catch (IOException e) {}
}
return result;
}
server read method
//in is an inputStream Defined in the server
SecMessage rcvdMsgObj;
rcvdMsgObj=(SecMessage)new ObjectInputStream(in).readObject();
return rcvdMsgObj;
and the SecMessage Class is
public class SecMessage implements java.io.Serializable
{
private static final long serialVersionUID = 3940341617988134707L;
private String cmd;
//... nothing interesting here , just a bunch of fields , getter and setters
}
If you are sending multiple objects, it's often simplest to put them some kind of holder/collection like an Object[] or List. It saves you having to explicitly check for end of stream and takes care of transmitting explicitly how many objects are in the stream.
EDIT: Now that I formatted the code, I see you already have the messages in an array. Simply write the array to the object stream, and read the array on the server side.
Your "server read method" is only reading one object. If it is called multiple times, you will get an error since it is trying to open several object streams from the same input stream. This will not work, since all objects were written to the same object stream on the client side, so you have to mirror this arrangement on the server side. That is, use one object input stream and read multiple objects from that.
(The error you get is because the objectOutputStream writes a header, which is expected by objectIutputStream. As you are not writing multiple streams, but simply multiple objects, then the next objectInputStream created on the socket input fails to find a second header, and throws an exception.)
To fix it, create the objectInputStream when you accept the socket connection. Pass this objectInputStream to your server read method and read Object from that.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get StreamCorruptedException.
Actually, your client code is writing one object to the server and reading multiple objects from the server. And there is nothing on the server side that is writing the objects that the client is trying to read.
This exception may also occur if you are using Sockets on one side and SSLSockets on the other. Consistency is important.
In Java, how would you set up a socket listener that listened to a socket for a series of bytes that represented a command and on recieving called a method which parsed the incoming data and invoked the appropriate command?
Clarification:
My issue is not with handling the commands (Which might also be error codes or responses to commands from the server) but with creating the socket and listening to it.
More Clarification:
What I want to do is mimic the following line of .Net (C#) code:
_stream.BeginRead(_data,0, _data.Length, new
AsyncCallback(this.StreamEventHandler), _stream);
Where:
_stream is a network stream created from a socket
_data is an array of Byte of length 9
this.StreamHandler is a delegate (function pointer) which get executed when data is read.
I am rewriting a library from C# into Java and the component I am currently writing passes commands to a server over TCPIP but also has to be able to bubble up events/responses to the layer above it.
In C# this seems to be trivial and it's looking less and less so in Java.
Starting from my other answer: The specific part you request is the one that goes into the section: "Magic goes here". It can be done in ohh so many ways, but one is:
final InputStream in = socket.getInputStream();
// This creates a new thread to service the request.
new Thread(new Runnable(){
public void run(){
byte[] retrievedData= new byte[ITEM_LENGTH];
in.read(retrievedData, 0, ITEM_LENGTH);
in.close();
// Here call your delegate or something to process the data
callSomethingWithTheData(retrievedData);
}
}).start();
Have a small main method which sets up the socket and listens for incoming connections. Pass each connection to a worker object (possibly in its own thread).
The worker object should have two APIs: The server and the client. The client API gets a connection and reads data from it, the server API takes a connection and writes data to it.
I like to keep these two in a single class because that makes it much more simple to keep the two in sync. Use a helper class to encode/decode the data for transmission, so you have single point to decide how to transmit integers, commands, options, etc.
If you want to go further, define a command class and write code to serialize that to a socket connection and read it from it. This way, you worker objects just need to declare which command class they handle and the server/client API gets even more simple (at the expense of the command class).
I would
put each command into a class of its own, where each class implements a specific interface (e.g. Command)
create a Map<String,Command> which contains a lookup table from each command string to an instance of the class that implements that command
This should help.
Lesson 1: Socket Communications
The TCP connection provides you with one InputStream and one OutputStream. You could just poll the InputStream continuously for the next command (and its inputs) on a dedicated thread. ByteBuffer.wrap(byte[] array) may be useful in interpreting the bytes as chars, ints, longs, etc. You could also pass objects around using serialization.
Any naive approach most likely will not scale well.
Consider using a REST-approach with a suitable small web-server. Jetty is usually a good choice.
To create an listen to a socket, in a very naive way:
mServerSocket = new ServerSocket(port);
listening = true;
while (listening) {
// This call blocks until a connection is made
Socket socket = serverSocket.accept();
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
// Here you do your magic, reading and writing what you need from the streams
// You would set listening to true if you have some command to close the server
// remotely
out.close();
in.close();
socket.close();
}
Normally it is a good idea to delegate the processing of the input stream to some other thread, so you can answer the next request. Otherwise, you will answer all requests serially.
You also need to define some kind of protocol of what bytes you expect on the input and output streams, but from your question it looks like you already have one.
You could create an enum with one member per command
interface Comamnd {
// whatever you expect all command to know to perform their function
void perform(Context context);
}
enum Commands implements Command{
ACTIONONE() {
void perform(Context context) {
System.out.println("Action One");
}
},
ACTIONTWO() {
void perform(Context context) {
System.out.println("Action Two");
}
}
}
// initialise
DataInputStream in = new DataInputStream(socket.getInputStream());
// in a loop
byte[] retrievedData= new byte[ITEM_LENGTH];
in.readFully(retrievedData);
String command = new String(retrievedData, 0);
Commands.valueOf(command).perform(context);