How to observe sockets until unsubscribing in Rxjava - java

I wrote a small piece of code which takes a parameter ObjectInputStream and observe the data on a socket. The problem raise once readObject() function returns "null" and since the function observeSocket(ObjectInputStream in) takes only Object the subscriber executes onError() function and terminates the program.
But what I need is to continue observing sockets for Objects and return only if an Object is observed over the socket and only when observer unsubscribes should the function terminates its functionality. How could I modify the code to achieve the required functionality.
public Observable<Object> observeSocket(ObjectInputStream in){
return Observable.create(subscriber -> {
while(!subscriber.isUnsubscribed()) {
subscriber.onNext(getData(in));
}
subscriber.onCompleted();
});
}
public Object getData(ObjectInputStream in){
Object streamData = null;
try{
streamData = in.readObject();
}
catch(IOException e){
//e.printStackTrace();
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
return streamData;
}

Avoid using Observable.create(OnSubscribe) because making backpressure aware and contract-compliant Observables is tricky business. This is a good candidate for using Observable.create(SyncOnSubscribe):
ObjectInputStream ois = ...;
Observable<Object> objects =
Observable.create(
SyncOnSubscribe.createStateless(observer -> {
try {
Object value = ois.readObject();
// you decide how end of file is indicated
// a common strategy is to write a null object
// to the end of the Object stream.
if (value == END_OF_FILE) {
observer.onCompleted();
} else {
observer.onNext(value);
}
} catch (Exception e) {
observer.onError(e);
}
}));

Related

Java ObjectStream 'StreamCorruptedException: Invalid type code: 00 [duplicate]

So basically im writing a client-server multiplayer game.
I have a SeverCommunicationThread that creates a gameThread if he receives a RequestForGame creates a gameThread.
When i send a RequestForGame exception is thrown java.io.StreamCorruptedException: invalid type code: 00
I assume it's because both threads try to read the same ObjectInputStream, I don't have much understanding about how it works, i just know how to use it. Could you help me understand what's the problem and how to fix it?
Thanks :)
public class ServerCommunicationThread extends Thread{
private Socket connectionSocket;
private ObjectInputStream inFromClient;
private ObjectOutputStream outToClient;
private String nickname;
private ServerModelManager model;
public ServerCommunicationThread(Socket connectionSocket,
ServerModelManager model) throws IOException {
this.connectionSocket = connectionSocket;
inFromClient = new ObjectInputStream(connectionSocket.getInputStream());
outToClient = new ObjectOutputStream(connectionSocket.getOutputStream());
this.model = model;
start();
}
public void run() {
try {
String nickname = (String) inFromClient.readObject();
if (model.exists(nickname)){
System.out.println(nickname + " already exists");
outToClient.writeObject(new MessageForClient("Please choose another nickname"));
}
else
{
System.out.println(nickname + " connected, adding to list");
model.addClient(nickname, connectionSocket,outToClient,inFromClient);
this.nickname=nickname;
}
while(true){
Object o= inFromClient.readObject();//StreamCorruptedexception
if(o instanceof RequestForGame)
{
RequestForGame r=(RequestForGame)o;
String userToPlayWith=r.getUserToPlayWith();
if(userToPlayWith.equals(nickname))
{
String message="Playing with yourself makes your palms hairy, choose another opponent";
outToClient.writeObject(message);
}
else
{
System.out.println("received request to play with "+userToPlayWith+". starting game");
ClientRepresentative client1=model.getClient(nickname);
ClientRepresentative client2=model.getClient(userToPlayWith);
ServerGameThread s=new ServerGameThread(client2,client1,client2.getInStream(),client1.getInStream(),client1.getOutStream(),client2.getOutStream());
}
}
else if(o instanceof String)
{
String s=(String) o;
if(s.equals("i want to quit"))
{
model.deleteClient(nickname);
inFromClient.close();
String q="quit";
outToClient.writeObject(q);
connectionSocket.close();
System.out.println(nickname+"has quit without exc");
}
}
}
} catch (EOFException e) {
System.out.println(nickname+" has quit");
}
catch (SocketException e)
{
System.out.println(nickname+" has quit");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerGameThread extends Thread {
private ClientRepresentative client1,client2;
private ObjectInputStream inFromClient1,inFromClient2;
private ObjectOutputStream outToClient1,outToClient2;
private Field gameField;
public ServerGameThread(ClientRepresentative client1, ClientRepresentative client2,ObjectInputStream inFromClient1,ObjectInputStream inFromClient2,ObjectOutputStream outToClient1,ObjectOutputStream outToClient2)
{
System.out.println("startin game thred");
this.client1=client1;//client 1 goes first
this.client2=client2;//client 2 started game
this.inFromClient1=inFromClient1;
this.inFromClient2=inFromClient2;
this.outToClient1=outToClient1;
this.outToClient2=outToClient2;
gameField=new Field();
System.out.println("check");
start();
}
public void run()
{
System.out.println("Starting game. players: "+client1.getNickname()+";"+client2.getNickname());
try {
outToClient1.writeObject(gameField);
outToClient2.writeObject(gameField);
while(true)
{
try {
System.out.println("listening to "+client1.getNickname());
Object o1=inFromClient1.readObject();//read move from client 1.**//StreamCorruptedexception**
while(!(o1 instanceof PlayerMove))
{
o1=inFromClient1.readObject();//read move from client 1.
}
PlayerMove move1=(PlayerMove)o1;
System.out.println("received move "+move1+" sending to "+client2.getNickname());
outToClient2.writeObject(move1);
System.out.println("listening to "+client2.getNickname());
Object o2=inFromClient2.readObject();//read move from client 1.
while(!(o2 instanceof PlayerMove))
{
o2=inFromClient2.readObject();//read move from client 1.
}
PlayerMove move2=(PlayerMove)o2;
System.out.println("received move "+move2+" sending to "+client1.getNickname());
outToClient1.writeObject(move2);
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
the model.addClient method though i don't think the problem is here
public void addClient(String nickname, Socket clientSocket,ObjectOutputStream stream,ObjectInputStream inStream)
{
clients.addClient(nickname, clientSocket,stream,inStream);//add to arraylist
//send client list to all clients
String[] users=this.getAvailableClients();
ObjectOutputStream[] streams=clients.getOutStreams();
for(int i=0;i<streams.length;i++)
{
try {
streams[i].writeObject(users);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The client side proxy that sends objects to server, the methods are triggered by user actions in GUI
public class Proxy {
final int PORT = 1337;
String host;
String nickname;
private Socket clientSocket;
private ObjectOutputStream outToServer;
private ObjectInputStream inFromServer;
private ClientModelManager manager;
public Proxy(String nickname,String host,ClientModelManager manager)
{
this.nickname=nickname;
this.host=host;
this.manager=manager;
this.connect(nickname);
}
public void connect(String nick)
{
Socket clientSocket;
try {
clientSocket = new Socket(host, PORT);
System.out.println("client socket created");
outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
inFromServer=new ObjectInputStream(clientSocket.getInputStream());
outToServer.flush();
outToServer.writeObject(nick);
ClientReceiverThread t=new ClientReceiverThread(inFromServer,manager);
t.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void makeRequest(String user)
{
try
{
outToServer.writeObject(new RequestForGame(user));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void quit()
{
try {
outToServer.writeObject(new String("i want to quit"));
//clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMove(PlayerMove move)
{
try {
outToServer.writeObject(move);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This problem can happen if you
construct a new ObjectInputStream or ObjectOutputStream over the same socket instead of using the same ones for the life of the socket;
use another kind of stream over the same socket as well; or,
use the object streams to read or write something that isn't an object and you get out of sync.
This can also happen if the JVM reading the serialized object does not have the correct class/jar files for the object. This usually results in a ClassNotFoundException, but if you have different jar/class versions and the serialVersionUID was not changed between versions, a StreamCorruptedException is produced. (This exception may also be possible if there is a class name conflict. e.g.: a jar containing a different class with the same full class name, though they probably also need the same serilVersionUID).
Check that the client side has the correct versions of jars and class files.
There's another possibility that I ran across where if you implement a custom deserialization routine for a class by adding this method:
private void readObject( ObjectInputStream objectInputStream ) throws IOException
then objectInputStream.defaultReadObject() must be called and called before any further reads of the input stream to properly initialise the object.
I missed this and despite the object returning without an exception being thrown it was the next read of the object stream that confusingly raised the invalid type code exception.
This link provides further information on the process: http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.
I too had this exception. It occurred because I used two threads for Server class and Client class. I used one thread for object sending and receiving thing. Then it was ok. This is easy way to solve the problem if you are not familiar with synchronized.
If ObjectInputStream is constructed only once and then just passed a reference of it to the other Thread then simply enclose the access of this object inside synchronized block to make sure that only one thread can access this object at a time.
Whenever you are reading from ObjectInputStream just access it inside the synchronized block if it is shared between multiple threads.
Sample code:(do it for all the occurrences of readObject())
...
String nickname = null;
synchronized (inFromClient) {
nickname = (String) inFromClient.readObject();
}
java.io.StreamCorruptedException: invalid type code: 00
I recently ran into this problem, not doing what OP did though. Did a quick google search and didn't find anything that was too helpful and because I think I solved it I am making a comment with my solution.
TLDR: Don't have multiple threads write to the same output stream at same time (instead take turns). Will cause issues for when client side tries to read the data. Solution is putting a lock on the writing to output.
I am doing something very similar to OP, making a multiplayer (client-server model) game. I have a thread like OP that is listening for traffic. What was happening, in my server side was that server had multiple threads that were writing to a client's stream at the same time (didn't think it was possible, game was semi turn base). Client side thread that was reading the incoming traffic was throwing this exception. To solve this I basically put a lock on the part that wrote to the client's stream (on server side) so each thread in server side would have to obtain the lock before writing to the stream.

Java runtime.exec user input race condition

I want my app to be able to use a global su instance. I have code that does that, but I have encountered a race condition, I believe.
I am storing some variables for su like so:
public static List<Object> rootObjects = Collections.synchronizedList(new ArrayList<>());
protected void onCreate(Bundle savedInstanceState) {
...
if(PreferenceManager.getDefaultSharedPreferences(
getApplicationContext()).getBoolean("use_su", false) && rootObjects.isEmpty())
{
try {
Process process = Runtime.getRuntime().exec("su");
rootObjects.add(process);
InputStream inputStream = new DataInputStream(process.getInputStream());
rootObjects.add(inputStream);
OutputStream outputStream = new DataOutputStream(process.getOutputStream());
rootObjects.add(outputStream);
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
finally {
synchronized (rootObjects) {
rootObjects.notifyAll();
}
}
}
}
and using them like so:
byte[] getPrivateKeyAsSuperUser() {
byte[] data = null;
DataInputStream inputStream = null;
DataOutputStream outputStream = null;
if(MainActivity.rootObjects.size() != 3)
synchronized (MainActivity.rootObjects)
{
try {
MainActivity.rootObjects.wait();
} catch (InterruptedException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
}
for(Object rootObj : MainActivity.rootObjects)
{
if(rootObj instanceof DataInputStream)
inputStream = (DataInputStream) rootObj;
else if(rootObj instanceof DataOutputStream)
outputStream = (DataOutputStream) rootObj;
}
try {
outputStream.writeBytes(String.format("cat \"%s\"\n", sshPrivateKey.getAbsolutePath()));
outputStream.flush();
data = readStream(inputStream);
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
return data;
}
private byte[] readStream(InputStream stream) {
byte[] data = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte buff[] = new byte[1024];
int count = 0;
while (stream.available() != 0 && (count = stream.read(buff)) != -1) {
bos.write(buff, 0, count);
}
data = bos.toByteArray();
//System.out.println(new String(data));
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
return data;
}
But it does not wait like I expect, and I instantly receive a Toast that the returned private key is not valid with my sanity check (It's probably null).
The code works if I let Process finish initializing, but I'd like the program to do that for me.
I've tried some other synchronization techniques such as locks, but apparently as soon as you know if an object has a lock your info is stale.
What is the best thread safe approach to have the caller of getPrivateKeyAsSuperUser() wait if Process is not initialized properly?
EDIT:
I would like to add that through some debugging, I have found that I do not want be waiting for Process to initialize (because what I have DOES that), but rather, that the shell spawned by su is valid to accept further commands. I suppose I could have a thread pipe something like echo DONE and loop until I get DONE back, but that seems like that would waste CPU horsepower. If someone could lend some knowledge on the subject, I would be extremely grateful.
You're attempting the singleton pattern here. I'm not sure why you want to store these objects in a list. The most sensible way to store them is in an object that you guarantee to create one instance of. There are a few ways you could do this. I think in your case the following would work
public class SuProcessHolder {
// store the state of the process here - this would be your Process and streams as above
// these should be non-static members of the class
// this would be the singleton instance you'll use - it will be constructed once
// on first use
private static SuProcessHolder singletonInstance = new SuProcessHolder();
public SuProcessHolder() {
// put your construction code in here to create an SU process
}
// this will access your SU process
public static SuProcessHolder getInstance() { return singletonInstance; }
}
Then, wherever you need your SU process, just call
SuProcessHolder.getInstance()
and it will be there like a Michael Jackson song.
I have solved it. I did end up having to echo and check for done, but I have done it without a loop, or sleeping in my thread, so it will fire as soon as it can, without hogging the CPU. The concurrent class I was looking for was CountDownLatch as well.
The assignment look like this:
process = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(process.getOutputStream());
outputStream.writeBytes("echo DONE\n");
outputStream.flush();
inputStream = new DataInputStream(process.getInputStream());
byte[] buff = new byte[4];
inputStream.read(buff);
if(new String(buff).equals("DONE"));
MainActivity.rootLatch.countDown();
and getPrivateKeyAsSuperUser() became:
byte[] getPrivateKeyAsSuperUser() {
byte[] data = null;
try {
MainActivity.rootLatch.await();
} catch (InterruptedException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
Su su = Su.getStaticInstance();
try {
su.outputStream.writeBytes(String.format("cat \"%s\"\n", sshPrivateKey.getAbsolutePath()));
su.outputStream.flush();
data = readStream(su.inputStream);
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
return data;
}
Although, this feels slightly sloppy, I may end up posting this on Code Review.

Java Object returning to default values

I have the following code structure.
A transaction handler of type Transaction which is a field in a Client Handler class, which talks to a Server. (the client handler and the server are collocated), the client talks to the client handler via serialized object messages.
When a new transaction request comes in from the client, (comes on thread using the readObject() method of an object input stream), I then do a series of trx_handler.setFoo(trx.getFoo))). This works fine, I can handle the first request. But when a subsequent request comes in (which only starts getting executed after the first request finished due to the loop structure, I find that the trx handler has been reinitialised to its default values, the object is still there, but all the values inside are the defaut ones. What can cause this problem?
My first guess would be garbage collection, but in my Client Handler class, there is always a pointer to this trx_handler.
The code below illustrates what happens. A statement would first be of type start, so the trx_handler will be correctly initialised. handle_statement will then be called. Subsequent statements should then be received, but at this point the trx_handler has been reinitialised to its default settings, so the access_set field is null, the session id as well, and none of the modification made to the object in hande_statement are visible
Thanks
public class Handler {
private Statement trx_handler;
/* Constructor initialises trx_handler to new Statement(); */
public ClientHandler(final Socket socket, long uid, Server server, ObjectInputStream ois) throws IOException, Exception {
LOGGER.info("Constructing Handler");
this.uid = uid;
this.server = server;
this.socket = socket;
this.database = server.getDB();
this.trx_sys = database.getTransactionManager();
create_listening(socket, ois);
out = socket.getOutputStream();
oos = new ObjectOutputStream(out);
this.trx_handler = new Statement(false);
}
private void create_incoming(final Socket socket, final ObjectInputStream stream) {
Thread incoming = new Thread() {
#Override
public void run() {
ObjectInputStream ois = stream;
InputStream in = null;
while (true) {
Object statement = null;
try {
statement = ois.readObject();
execute_stat(statement, socket, null);
LOGGER.info("Ready to execute next ");
} catch (SocketException e) {
LOGGER.severe("Connection Closed");
return;
} catch (IOException e) {
LOGGER.severe("Connection Closed");
return;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
String error_message = e.getMessage();
send_error(socket, error_message);
}
}
}
};
incoming.setDaemon(true);
incoming.start();
}
private synchronized void execute_stat(Statement trx) {
if (trx.getTransactionState() == Consts.trx_end) {
trx_sys.commitTransaction(trx_handler);
return;
} else if (trx.getTransactionState() == Consts.trx_start) {
try {
trx_handler.setAccessSet(trx.getAccessSet());
trx_handler.setSession_id(trx.getSession_id());
trx_sys.startTransaction(trx_handler);
handle_statement(socket, trx_handler);
/* TEST HERE THAT FIELDS IN TRX_HANDLER ARE CORRECTLY SET (INCLUDING SOME MODIFIED IN
handle_statement and they are correctly set */
return;
} catch (Exception ex) {
Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
LOGGER.info("Execute Trx: stat");
/* Can't see modifications made in the start case */
Statement stats = trx.getStatement();
trx_handler.setStatement(stats);
handle_statement(stats, socket, trx_handler);
} catch (Exception e) {
e.printStackTrace();
}
return;
}
You need to either send a brand new object for each transaction, use ObjectOutputStream.writeUnshared(), or else call ObjectOutputStream.reset() between sends.

Concurrency with Java's LinkedList class

Good Day,
I am having concurrency problems with a LinkedList in Java. I have an Object type called "Connection" which has as a member variable LinkedList of "MessageHandlers" called "listeners". I then have two different threads, one modifying and one iterating over the same LinkedList.
I've seen many many other StackOverflow questions that suggest to use the sychronized block of code, but that doesn't appear to be helping it all. I've also try creating the LinkedList as a concurrent linked list, but I am still receiving the
Exception in thread "Thread-1" java.util.ConcurrentModificationException
exception. Does anyone have any other suggestions to try? Here are some snipbits of my code...
public synchronized Object ReadObject() throws java.io.IOException
{
Object obj = null;
try
{
obj = input.readObject();
synchronized(listeners)
{
Iterator<MessageHandler> i = listeners.iterator();
while(i.hasNext())
{
i.next().MessageReceived(obj, this);
}
}
}
catch (IOException e)
{
e.printStackTrace();
throw e;
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
The above code is inside my connection object. It gets called from a function that has a socket's ObjectInputStream reading data from the socket."input" is an instance of ObjectInputStream.
public void addNewLoggedInUser(User user) throws Exception
{
for(User u:loggedInUsers)
{
if(u == user)
{
throw new Exception("That user is already logged in");
}
}
//Add the new users
loggedInUsers.add(user);
synchronized(user.getConnection().getListeners())
{
user.getConnection().getListeners().add(this);
}
this.SendGameStatusUpdateToAllLoggedinPlayers();
}
I then call the method user.getConnection().getListeners().add(this) and thus am getting the exception.
public Connection()
{
//Initialize the variables to NULL
socket = null;
output = null;
input = null;
receiveThread = null;
runReceiveThread = false;
listeners = Collections.synchronizedList(new LinkedList<MessageHandler>());
//Handle the ID counter. Now we have a unique ID for every connection that comes in
connectionID = counterID;
counterID = counterID + 1;
}
This is the constructor for the connection class. Notice he Collections.synchronizedList
Any ideas? Thank you very much for your help!
java.util.ConcurrentModificationException isn't really a threading issue. It is cause by modification of a list locked by it's iterator. I think you are calling addNewLoggedInUser() from MessageReceived(). This would cause the concurrent modification exception since the calling function already has iterator lock on the linkedlist.
Go through BlockingQueue javadoc. It mentions a simple scenario as well that fits your requirements i.e.
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
The synchronized blocks look like they should work. I would expect that there is activity in methods called from within the ReadObject synchronized block which modify the list. Do any of your MessageHandlers call or chain to a call to addNewLoggedInUser (or any other method that might update the listener list)?
If so, the thread would already have the monitor grabbed by the ReadObject synchronized block, and would be able to enter the block in addNewLoggedInUser.

java.io.StreamCorruptedException: invalid type code: 00

So basically im writing a client-server multiplayer game.
I have a SeverCommunicationThread that creates a gameThread if he receives a RequestForGame creates a gameThread.
When i send a RequestForGame exception is thrown java.io.StreamCorruptedException: invalid type code: 00
I assume it's because both threads try to read the same ObjectInputStream, I don't have much understanding about how it works, i just know how to use it. Could you help me understand what's the problem and how to fix it?
Thanks :)
public class ServerCommunicationThread extends Thread{
private Socket connectionSocket;
private ObjectInputStream inFromClient;
private ObjectOutputStream outToClient;
private String nickname;
private ServerModelManager model;
public ServerCommunicationThread(Socket connectionSocket,
ServerModelManager model) throws IOException {
this.connectionSocket = connectionSocket;
inFromClient = new ObjectInputStream(connectionSocket.getInputStream());
outToClient = new ObjectOutputStream(connectionSocket.getOutputStream());
this.model = model;
start();
}
public void run() {
try {
String nickname = (String) inFromClient.readObject();
if (model.exists(nickname)){
System.out.println(nickname + " already exists");
outToClient.writeObject(new MessageForClient("Please choose another nickname"));
}
else
{
System.out.println(nickname + " connected, adding to list");
model.addClient(nickname, connectionSocket,outToClient,inFromClient);
this.nickname=nickname;
}
while(true){
Object o= inFromClient.readObject();//StreamCorruptedexception
if(o instanceof RequestForGame)
{
RequestForGame r=(RequestForGame)o;
String userToPlayWith=r.getUserToPlayWith();
if(userToPlayWith.equals(nickname))
{
String message="Playing with yourself makes your palms hairy, choose another opponent";
outToClient.writeObject(message);
}
else
{
System.out.println("received request to play with "+userToPlayWith+". starting game");
ClientRepresentative client1=model.getClient(nickname);
ClientRepresentative client2=model.getClient(userToPlayWith);
ServerGameThread s=new ServerGameThread(client2,client1,client2.getInStream(),client1.getInStream(),client1.getOutStream(),client2.getOutStream());
}
}
else if(o instanceof String)
{
String s=(String) o;
if(s.equals("i want to quit"))
{
model.deleteClient(nickname);
inFromClient.close();
String q="quit";
outToClient.writeObject(q);
connectionSocket.close();
System.out.println(nickname+"has quit without exc");
}
}
}
} catch (EOFException e) {
System.out.println(nickname+" has quit");
}
catch (SocketException e)
{
System.out.println(nickname+" has quit");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerGameThread extends Thread {
private ClientRepresentative client1,client2;
private ObjectInputStream inFromClient1,inFromClient2;
private ObjectOutputStream outToClient1,outToClient2;
private Field gameField;
public ServerGameThread(ClientRepresentative client1, ClientRepresentative client2,ObjectInputStream inFromClient1,ObjectInputStream inFromClient2,ObjectOutputStream outToClient1,ObjectOutputStream outToClient2)
{
System.out.println("startin game thred");
this.client1=client1;//client 1 goes first
this.client2=client2;//client 2 started game
this.inFromClient1=inFromClient1;
this.inFromClient2=inFromClient2;
this.outToClient1=outToClient1;
this.outToClient2=outToClient2;
gameField=new Field();
System.out.println("check");
start();
}
public void run()
{
System.out.println("Starting game. players: "+client1.getNickname()+";"+client2.getNickname());
try {
outToClient1.writeObject(gameField);
outToClient2.writeObject(gameField);
while(true)
{
try {
System.out.println("listening to "+client1.getNickname());
Object o1=inFromClient1.readObject();//read move from client 1.**//StreamCorruptedexception**
while(!(o1 instanceof PlayerMove))
{
o1=inFromClient1.readObject();//read move from client 1.
}
PlayerMove move1=(PlayerMove)o1;
System.out.println("received move "+move1+" sending to "+client2.getNickname());
outToClient2.writeObject(move1);
System.out.println("listening to "+client2.getNickname());
Object o2=inFromClient2.readObject();//read move from client 1.
while(!(o2 instanceof PlayerMove))
{
o2=inFromClient2.readObject();//read move from client 1.
}
PlayerMove move2=(PlayerMove)o2;
System.out.println("received move "+move2+" sending to "+client1.getNickname());
outToClient1.writeObject(move2);
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
the model.addClient method though i don't think the problem is here
public void addClient(String nickname, Socket clientSocket,ObjectOutputStream stream,ObjectInputStream inStream)
{
clients.addClient(nickname, clientSocket,stream,inStream);//add to arraylist
//send client list to all clients
String[] users=this.getAvailableClients();
ObjectOutputStream[] streams=clients.getOutStreams();
for(int i=0;i<streams.length;i++)
{
try {
streams[i].writeObject(users);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The client side proxy that sends objects to server, the methods are triggered by user actions in GUI
public class Proxy {
final int PORT = 1337;
String host;
String nickname;
private Socket clientSocket;
private ObjectOutputStream outToServer;
private ObjectInputStream inFromServer;
private ClientModelManager manager;
public Proxy(String nickname,String host,ClientModelManager manager)
{
this.nickname=nickname;
this.host=host;
this.manager=manager;
this.connect(nickname);
}
public void connect(String nick)
{
Socket clientSocket;
try {
clientSocket = new Socket(host, PORT);
System.out.println("client socket created");
outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
inFromServer=new ObjectInputStream(clientSocket.getInputStream());
outToServer.flush();
outToServer.writeObject(nick);
ClientReceiverThread t=new ClientReceiverThread(inFromServer,manager);
t.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public void makeRequest(String user)
{
try
{
outToServer.writeObject(new RequestForGame(user));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void quit()
{
try {
outToServer.writeObject(new String("i want to quit"));
//clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMove(PlayerMove move)
{
try {
outToServer.writeObject(move);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This problem can happen if you
construct a new ObjectInputStream or ObjectOutputStream over the same socket instead of using the same ones for the life of the socket;
use another kind of stream over the same socket as well; or,
use the object streams to read or write something that isn't an object and you get out of sync.
This can also happen if the JVM reading the serialized object does not have the correct class/jar files for the object. This usually results in a ClassNotFoundException, but if you have different jar/class versions and the serialVersionUID was not changed between versions, a StreamCorruptedException is produced. (This exception may also be possible if there is a class name conflict. e.g.: a jar containing a different class with the same full class name, though they probably also need the same serilVersionUID).
Check that the client side has the correct versions of jars and class files.
There's another possibility that I ran across where if you implement a custom deserialization routine for a class by adding this method:
private void readObject( ObjectInputStream objectInputStream ) throws IOException
then objectInputStream.defaultReadObject() must be called and called before any further reads of the input stream to properly initialise the object.
I missed this and despite the object returning without an exception being thrown it was the next read of the object stream that confusingly raised the invalid type code exception.
This link provides further information on the process: http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.
I too had this exception. It occurred because I used two threads for Server class and Client class. I used one thread for object sending and receiving thing. Then it was ok. This is easy way to solve the problem if you are not familiar with synchronized.
If ObjectInputStream is constructed only once and then just passed a reference of it to the other Thread then simply enclose the access of this object inside synchronized block to make sure that only one thread can access this object at a time.
Whenever you are reading from ObjectInputStream just access it inside the synchronized block if it is shared between multiple threads.
Sample code:(do it for all the occurrences of readObject())
...
String nickname = null;
synchronized (inFromClient) {
nickname = (String) inFromClient.readObject();
}
java.io.StreamCorruptedException: invalid type code: 00
I recently ran into this problem, not doing what OP did though. Did a quick google search and didn't find anything that was too helpful and because I think I solved it I am making a comment with my solution.
TLDR: Don't have multiple threads write to the same output stream at same time (instead take turns). Will cause issues for when client side tries to read the data. Solution is putting a lock on the writing to output.
I am doing something very similar to OP, making a multiplayer (client-server model) game. I have a thread like OP that is listening for traffic. What was happening, in my server side was that server had multiple threads that were writing to a client's stream at the same time (didn't think it was possible, game was semi turn base). Client side thread that was reading the incoming traffic was throwing this exception. To solve this I basically put a lock on the part that wrote to the client's stream (on server side) so each thread in server side would have to obtain the lock before writing to the stream.

Categories

Resources