I have a server-client setup over TCP where the client is sending a number of data sets to the server. The reading/writing uses ObjectInput/OutputStream. I don't have any problems under normal conditions, but when the data flow gets heavy, I get a StreamCorruptedException: invalid type code. The invalid code is different every time. I open the socket once and call a synchronized method to send data from multiple threads.
Client:
socket = new Socket("localhost", sockNum);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
public synchronized void sendMsg(Message msg){
try{
out.writeObject(security.signObject(msg, privKey));
out.reset();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Server:
ServerSocket server = new ServerSocket(sockNum);
Socket client = server.accept();
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
while(threadActive){
Object line = in.readObject();
handleObject(line);
}
Update: I added out.reset() after each send, but that didn't help the problem. I've also added sleep statments in my loop to decrease the data rate. This gets rid of the error but is not a real solution.
Edit: So it's been a little while since I originally asked this, but I'm running into the problem again. I tried setting up my system so that after every sent message, the thread waits for an "acknowledge" message in return. If the receiving process has the StreamCorruptedException, it sends back a "resend" rather than an ack. This seems to be causing more problems than solutions. Any other ideas?
It sounds like you are writing to the output stream in a multi threaded way i.e. you are writing to it somewhere other than in your example.
BTW: Are you reset()ing the stream regularly to prevent a memory leak?
Related
I made a simple UDP server/client system for my game now.
This is the code of the method that waits for data to be sent to it:
while (handler.isRunning()) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Server - " + new String(data).trim());
}
socket.close();
So, the thing is, when the game closes meaning that isRunning() gets set to false, all threads die except the server and client. The reason is because here, socket.receive() method blocks and it needs to receive at least one more packet to then check if isRunning() is true and exit. So after I close the game, I want this thread to die immediately without receiving anymore packets, but i dont know how to do that!
Thanks for help
There's a couple of options. First, the simplest option is to set a timeout: https://docs.oracle.com/javase/7/docs/api/java/net/DatagramSocket.html#setSoTimeout(int).
Next, another option is to use callbacks and Async I/O. Take a look at java.nio.channels.DatagramChannel
Answered here. Similar for your case for DatagramSocket.receive
I am writing an app for android 4.2, currently debugged on a Samsung s2+.
The app establishes a connection to a server using a Socket, and the server is using a ServerSocket and the establish()-method to get its socket. So far so good. Since I have to make all the networking in android in a new thread, I created a new class extending Thread which communicates with an underlying Activity (for user input) using a BlockingQueue. The threads run method:
public void run() {
Socket s = null;
try {
s = new Socket(info.getIp(), 1337);
} catch (IOException e) {
e.printStackTrace();
}
String code = null;
try {
code = queue.take();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
Log.e("DONE", code);
PrintWriter out = null;
try {
out = new PrintWriter(s.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
out.write(code);
out.flush();
}
The connection is up and running, and the logged message "DONE"+code is logged. However, nothing is received on the server side until I force close the app. Is an android thread not able to flush data?
EDIT: If close the socket immediately after writing to it, the text arrives without having to force close the app. Why can't I read the text in the server if the socket is still alive?
try add a newline to the string you sent to server , something like :
out.write(code+"\n");
out.flush();
and as EJP said above put the out.write inside the try / catch
A socket connection only provides the ability to send and receive bytes. As soon as the client sends a byte, the server will receive it. Also, as soon as a client is disconnected, the server will know about it - this is about the extend of what you get from sockets.
The concept of a message does not exist at this level. A message is instead defined by whatever lies above the socket, so most protocols use one or more of three different ways to chunk streams of bytes into "messages"
a special byte or sequence of bytes indicates the end of the message (a new line for example, which seems to have been your case :)
each message starts with x bytes which provide the length of the message (so a simple "05aaaaa02bb" stream of bytes might mean that 2 messages were send - "aaaaa" and "bb"
the entire socket connection lasts for a single message (end of message comes when the connection is closed). This is how HTTP 1.0 works for example.
I have not been able to find a satisfying answer to this question anywhere. Could someone with an understanding of the internals please explain this?
I wrote a simple client/server to demonstrate this issue. The server reads one line of text then closes the socket. The client writes one line of text, waits 10 seconds, then writes two more lines of text. The second write (after 10 seconds) fails but the first write always succeeds.
Why can't the BufferedWriter throw an exception on the first write itself? After all the socket was normally closed a long time before. The code also does a read on the socket right before the first write, returns -1 to show that the input side has already detected the socket close. Why can't the output side also know this?
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9000);
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(in.readLine());
s.close();
System.out.println("Socket closed");
}
}
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Socket s = new Socket("localhost", 9000);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
out.write("Hello, World!\n"); out.flush();
Thread.sleep(10000);
System.out.println("Read from socket returns: " + s.getInputStream().read());
out.write("First write\n"); out.flush();
System.out.println("First write succeeded without detecting socket closed");
out.write("Second write\n"); out.flush();
System.out.println("Second write succeeded without detecting socket closed");
}
}
A remote close is indistinguishable from a remote shutdown for output. This end receives a FIN in both cases, meaning the peer has stopped sending. There is no indication that he has stopped receiving, even in fact if he has shutdown for input. So the only way the sender can detect is by getting an RST on sending, and that can't happen on the first send, by definition, unless maybe the sent data is larger than the socket send buffer.
we looked at this on a project. I am of the opinion that the Internet Protocol more or less guarantee's the TCP/IP socket will do this.
The IP protocol is intended to do the best-job-possible to route a packet. You will only ever know a connection was gone at the other end after a write/delivery has failed. Remembering that the internet was designed to be resilient and try different routes, etc to get the message delivered.
Different network and data-link transports might work differently. A long while back I had to do a session layer over tcp/ip and this problem sounds oddly familiar.
It seems that you could work around it by sending a couple of test bytes before your main send.
I have this problem, and I can't figure it out whats is wrong. I have searched on all over the internet, but without success.
So, I have to send an object over sockets in Java, and I can't figure out how to do it. I tried so many ways. I serialized the object, I tried to write the object directly. But nothing seems to work.
The detail is that I have a chat running in parallel. And sometimes when i open an ObjectOutputStream, or ObjectInputStream, I get busted in a deadlock. And I guess you guys could help me.
Its a hangman game where the clients connects to the server, and the server should send a random word, which is a object, to clients.
Server:
try{
socketConexao = socketRecepcao.accept();
toClient = new DataOutputStream(socketConexao.getOutputStream());
fromClient = new BufferedReader(new InputStreamReader(socketConexao.getInputStream()));
//starts the chat
Thread chat = new Thread(this);
chat.start();
}catch(IOException e){}
//i dont really know how to send the object
try{
byte[] bytes = serialize(palavraSorteada);
toClient.write(bytes);
} catch (IOException e){
e.printStackTrace();
}
Client:
socketCliente = new Socket(ip, port);
toServer = new DataOutputStream(socketCliente.getOutputStream());
fromServer = new BufferedReader(new InputStreamReader(socketCliente.getInputStream()));
// starts the chat
Thread chat = new Thread(this);
chat.start();
}catch(IOException e){System.exit (0);}
// and dont really know how to receive the object
try{
ObjectInputStream os = new ObjectInputStream(socket.getInputStream());
palavraSorteada = (Palavra) os.readObject();
os.close();
}catch(Exception e){
e.printStackTrace();
}
It should be fairly obvious what wrong here (from your description): You use one communication channel to send two different kinds of data. Since the receiving end can not predict what its going to receive you need to add information what comming next, so the receiving end knows what to do.
And probably noone is going to the trouble to figure out what your code fragments are really doing, reduce the fluff to what you want to ask about or even better make a one class copy&pasteable runnable example (as short as possible) that demonstrates the issue.
In Server, split class Server in Server (accepts connections) and ServerConnection (separate thread). Place variables toClient and fromClient into ServerConnection. Now you spoil that variables when new client connects.
In Client, no need to start new Thread.
I'm working on a game with a event based structure with the main game logic hosted on a server; currently it's a very small featureset that only allows to host one game between exactly two participants. I've read on various questions about ServerSocket and none of them answers my question. I already took a look at
ServerSocket accept continues to block
ServerSocket.accept()
Java ServerSocket won't accept new connections until close() is called on the accepted socket
ServerSocket accept() method
In my project I utilize ObjectInputStream and ObjectOutputStream. Everything works as expected (receiving / sending both on server and client side), but after both sockets are registered, the accept method of the ServerSocket instance continues to block forever, even if the same code is invoked before. Perhaps it's an issue that appears after communicating over a socket once?
My server log shows the following:
waiting for accept
accepting first socket
sending an event to socket1 for informing about waiting for the opponent
waiting for accept
accept second socket
sending responses to both sockets
waiting for accept (and blocking forever)
When the log says response events where sent, they were properly received and processed at the client side. The client side debug outputs show that the next event is definitely sent. Maybe it's about not closing the client sockets (mentioned in the third linked question)? Anyway I can't close the client sockets because further communication would be impossible.
Client side code
public void send(Event e) {
try {
ObjectOutputStream out = new ObjectOutputStream(
socket.getOutputStream());
out.writeObject(e);
out.flush();
log.debug("sending event... "+e);
}
catch(IOException ioe) {
log.fatal("constructing oos failed", ioe);
}
}
Server side code
#Override
public void run() {
running = true;
while(running) {
try {
Socket s = socket.accept();
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
Event event = (Event) ois.readObject();
try {
Event[] response = controller.consume(event);
ObjectOutputStream oos = new ObjectOutputStream(sockets[0].getOutputStream());
oos.writeObject(response[0]);
oos.flush();
ObjectOutputStream oos2 = new ObjectOutputStream(sockets[1].getOutputStream());
oos2.writeObject(response[1]);
oos2.flush();
}
catch(...) {
// multiple catch clauses for different exceptions
// all just logging (nothing passes silently!)
}
}
}
For shortening, the method for assigning the two sockets to the Socket[] array was left out, but since there are no exceptions, keeping the socket works. Do you have any idea what could cause the described behavior? Thank you in advance.
The accept method only accepts new connections. Since you only have two clients attempting to connect to your server, it will hang indefinitely on your third invocation of accept.
Side note: You don't need to continuously create new ObjectInputStreams and ObjectOutputStreams. You can just create one of each for each Socket and keep references to them for reuse.