im trying to implement a basic chat applcation via sockets but i have problem with ObjectInputStream. Im using both write-read methods in while(true) loop and compiling process got stuck when there is nothing to read and waits for it infinitly. Thus, i need to check wheter is it empty or not before read it.
Here is my codes.
Server:
Socket socket = server.accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject("Server connected!");
oos.flush();
String message = (String) ois.readObject();
System.out.println(ois.available());
txtChat.setText(message);
while(true) {
if(sendMessage) {
oos.writeObject(txtMessage.getText());
oos.flush();
sendMessage = false;
}
while(!sendMessage) {
message = (String) ois.readObject();
txtChat.setText(txtChat.getText()+"\n"+"Client: "+message);
}
Thread.sleep(100);
}
Client:
socket = new Socket(host.getHostName(), 9876);
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
oos.flush();
String message = (String) ois.readObject();
txtChat.setText(message);
while(true) {
message = (String) ois.readObject();
txtChat.setText(txtChat.getText()+"\n"+"Server: "+message);
if(sendMessage) {
oos.writeObject(txtMessage.getText());
oos.flush();
sendMessage = false;
}
Thread.sleep(100);
}
The stream is either closed or open.
The input stream isn't aware that it is closed until you read something out of it. This is precisely why there exists no such isClosed() method on the stream.
You can read the bytes from the stream, into an object. At best you'll be able to construct the object. Else, you should handle the IO exception and decide accordingly.
Optionally, you can check how many bytes you can read without blocking. If it's 0, you're looking at an empty stream that is waiting for input.
inputStream.available() != 0 //handle exception
Related
I am using a server and a client. The client only should deserialize the received protobuf message if the string "yes" is received.
EDIT:
The first message of protobuf is received well. But, if I want to send multiple messages at a time, it gives me:
System.OverflowException: Number overflow.
at ProtoBuf.ProtoReader.TryReadUInt32Variant (System.IO.Stream source, System.UInt32& value)
I read through this link, but I can't figured out what I should do in my case...
I am using TCP sockets. Here is an example code:
Client C#:
TcpClient tcpClient = new TcpClient(host, port);
NetworkStream netStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(netStream);
while(true)
{
// Read multiple messages one after another.
string message = reader.ReadLine();
if(message.Equals("yes"))
{
Command command = Serializer.DeserializeWithLengthPrefix<Command> (netStream, PrexiStyle.Base128);
BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create));
bw.Write(command.File);
bw.Flush();
bw.Close();
}
}
Server Java:
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream, true);
try{
// send "yes" and the protobuf messages ten times one after another
for(int i=0; i<10; i++)
{
writer.println("yes");
command.writeDelimitedTo(outputStream);
}
}catch(Exception e)
e.printStackTrace();
}
finally{
outputStream.close();
clientSocket.close();
}
My .proto file and proto contract has the same types. It works if I don't want to send a string, but only the protobuf message.
How can I solve this with using a string before deserializing the protobuf message? Is it possible?
Try separating protobuf data and other data in different sockets. Added a while loop to be able to read multiple messages from server.
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
// Protobuf data is read on this socket
TcpClient tcpClient = new TcpClient(host, port);
NetworkStream netStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(netStream);
BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create));
bool running = true;
while(running)
{
bw.Write(Serializer.DeserializeWithLengthPrefix<Command>(netStream, PrexiStyle.Base128).File);
}
bw.Flush();
bw.Close();
}).Start();
// Other data is read no this socket
TcpClient tcpClientForOtherStuff = new TcpClient(host, port);
NetworkStream netStream = tcpClientForOtherStuff.GetStream();
StreamReader readerForOtherStuff = new StreamReader(netStream);
string message;
bool running = true;
BinaryWriter bwForOtherStuff = new BinaryWriter(File.Open(path2, FileMode.Create));
bool running = true;
while(running) bwForOtherStuff.Write(readerForOtherStuff.ReadLine());
bwForOtherStuff.Flush();
bwForOtherStuff.Close();
I have not tested or compiled the code.
I'm creating a server to receive both text and binary data from clients. It works with text data as well as the first time receiving binary file, but after this it didn't continue to reading data and throw an exception.
Here is my server code:
public class ConnectedProcessThread implements Runnable{
private final Socket socket;
public ConnectedProcessThread(Socket clientSocket){
socket = clientSocket;
}
public void run(){
DataInputStream dis = null;
try{
while(true) {
dis = new DataInputStream(socket.getInputStream());
String meta = dis.readUTF();
Log.i("Data received", meta);
if(meta.equalsIgnoreCase("Text")){
String message = dis.readUTF();
Log.i("Data received", message);
}else if(meta.equalsIgnoreCase("Binary")){
InputStream is = socket.getInputStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
stream.flush();
//read object input
try {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
byte[] buffer = (byte[])ois.readObject();
FileOutputStream fos = new FileOutputStream("/storage/emulated/0/DCIM/IMG-Saved.jpeg");
fos.write(buffer);
}catch (ClassNotFoundException e){
e.printStackTrace();
}
finally {
Log.i("Binary_Transfer","File created");
}
}
}
} catch (IOException e){
e.printStackTrace();
}finally {
Log.i("Client_Socket","Stream will close");
if(dis!=null){
try {
dis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
For both text and binary data, before sending the data, client will sent text meta-data to inform the server the data is text or binary. But after receiving a file(image), it throws an EOFException at line: String meta = dis.readUTF(); I guessed it happened because after reading and writing binary file, the thread continues to loop so DataInputStream will read again, and now there's nothing to receive so readUTF() throws EOFException. I tried to send a meta-data from client after sending the binary file to let DataInputStream can read something and not throw an exception, but it didn't work, the client did send the meta-data but the server still throws EOFException. Anyone knows what the problem is? Thanks so much.
Here is my send binary method from client:
public void sendBinaryData(byte[] binaryData){
if(dos!=null && socket!=null){
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(binaryData);
Log.d("Binary_Transfer", "C: Sent.");
oos.close();
dos.writeUTF("Binary_End");
dos.flush();
}catch (Exception e){
Log.e("File_Exception",e.toString());
}
}
}
Because when you start reading the binary data, you enter a loop that only terminates at end of stream, i.e. when the peer disconnects:
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
At that point you are at the end of the stream. There was no more data, there is no more data, and there never will be any more data.
You need to completely remove this part:
InputStream is = socket.getInputStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
stream.flush();
There is rarely any point in reading things into ByteArrayOutputStreams anyway, and this is no exception. Just remove that completely, and change the next part:
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
to
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
and continue as you are already. However you have another problem:
oos.close();
This closes the socket. So the next part:
dos.writeUTF("Binary_End");
dos.flush();
cannot possibly work. Just flush the ObjectOutputStream instead of closing it.
But I would strongly suggest you discard the DataInput/OutputStreams and use a single ObjectInput/OutputStream for the life of the socket, at both ends.
I set up a client and server sockets. When I use classes ObjectOutputStream and ObjectInputStream and the method readObject/writeObject everything works fine.
It simulates communication with a robot that I know for sure interprets correctly only method
DataOutputStream.writeBytes.
So I set up the new architecture for simulation since the robot is not available for testing on a daily basis.
In the following code where ObjectOutputStream/ObjectInputStream readObject/writeObject were replaced with DataInputStream/DataOutputStream writeBytes and IOutils.toByteArray.
The server socket correctly receives the message but when it tries to write back a response I get a broken pipe as if the connection was closed somewhere.
Notice that I never close sockets or streams because the robot can answer even after 30 seconds.
Any help to make DataOutputStream.writeBytes work would be appreciated.
Here's the non-working code:
Client:
Socket serverSocket = new Socket("server", 9899);
DataOutputStream outputStream = new DataOutputStream(serverSocket.getOutputStream());
//ObjectOutputStream outputStream = new ObjectOutputStream(serverSocket.getOutputStream());
//outputStream.writeObject("\n" + "message" + "\r");
outputStream.writeBytes("\n" + "message" + "\r");
outputStream.flush();
DataInputStream inputStream = new DataInputStream(serverSocket.getInputStream());
//ObjectInputStream inputStream = new ObjectInputStream(serverSocket.getInputStream());
byte [] bytes = IOUtils.toByteArray(inputStream);
String serverResponse = new String(bytes,"UTF-8");
// String serverResponse = (String)inputStream.readObject();
Server:
ServerSocket serverSocket = new ServerSocket(9899);
while (true) {
Socket socket = serverSocket.accept();
//ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
byte [] bytes = IOUtils.toByteArray(inputStream);
String message = new String(bytes,"UTF-8");
//String message = (String) inputStream.readObject();
Thread.sleep(15000);
//ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
//outputStream.writeObject("server response");
outputStream.writeBytes("server response"); //EXCEPTION THROWN HERE FOR BROKEN PIPE
outputStream.flush();
}
Thanks for your time
IOUtils.toString(InputStream) must read the stream until its end, which would imply that the peer has disconnected. So you can't write to it.
If you're exchanging Strings with data streams you should use writeUTF() and readUTF().
Or read and write lines, with a BufferedReader/Writer.
I develop a client-server java application and I used ObjectOutputStream and ObjectInputStream to send and receive data between client and server process. I need to send Array or object or primitive data
but the problem appears when I use ObjectOutputStream and ObjectInputStream to send and receive primitive values ( writeDouble(), readDouble(), writeUTF(), readUTF() ) . the program suspended and stopped working. why, what is the problem?
these are a fragments of my program
// client program
ObjectOutputStream toServer;
ObjectInputStream fromServer;
// Establish connection with the server
Socket socket = new Socket(host, 7000);
// Create an output stream to the server
toServer = new ObjectOutputStream(socket.getOutputStream());
fromServer = new ObjectInputStream(socket.getInputStream());
double num1 = Double.parseDouble(jtf1.getText().trim());
double num2 = Double.parseDouble(jtf2.getText().trim());
try {
toServer.writeUTF("multiply");
toServer.writeDouble(num1);
toServer.writeDouble(num2);
double result = fromServer.readDouble();
res.setText(String.valueOf(result));
} catch (IOException ex) {
System.err.println(ex);
}
// server program
private ObjectOutputStream outputToClient;
private ObjectInputStream inputFromClient;
// Create a server socket
ServerSocket serverSocket = new ServerSocket(7000);
while (true) {
// Listen for a new connection request
Socket socket = serverSocket.accept();
System.out.println("connect ");
outputToClient = new ObjectOutputStream(socket.getOutputStream());
// Create an input stream from the socket
inputFromClient =
new ObjectInputStream(socket.getInputStream());
while(true) {
// Read from input
String command = inputFromClient.readUTF();
System.out.println("receive command");
checkRequest(command);
}
// Write to the file
//outputToFile.writeObject(object);
}
public void checkRequest(String cmd){
//Object o = null;
try{
if(cmd.equals(MULTIBLY)){
double x = inputFromClient.readDouble();
double y = inputFromClient.readDouble();
double result = x*y;
outputToClient.writeDouble(result);
System.out.println("send result");
}else if (cmd.equals(DIVIDE)){
int x = inputFromClient.readInt();
int result = 1000/x;
outputToClient.writeDouble(result);
}
} catch(IOException io){
}
}
when I change ObjectOutputstream and ObjectInputStream to DataOutputStream
and DataInputStream every thing goes correctly !
You must call flush() on the stream on the client side to actually send the data (if the socket's buffer is not full).
You see your program hanging because the client does not send the data, and the server is blocking, waiting for the data that will never come.
I have a server chat and client chat programs running on localhost. When I try to connect to the server my client program freezes on next line in = new ObjectInputStream(socket.getInputStream());
here is a piece of code where I try to connect to the server
Socket socket = new Socket(host, port);
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
Message m = new Message(null, nick, Message.Type.REGISTER);
out.writeObject(m);
out.flush();
} catch (IOException ex) {
socket.close();
throw ex;
}
Message class implements Serializable interface, so it can be serialized over the network. And here is a piece of code where server hadle client request
try {
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(client.getInputStream()));
Message m = (Message) in.readObject();
switch (m.getMessageType()) {
case REGISTER:
registerUser(m);
break;
case CHATMESSAGE:
sendMessageToAll(m);
break;
case UNREGISTER:
unregisterUser(m);
break;
}
} catch (ClassNotFoundException ex) {
Logger.getLogger(Chatserver.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Chatserver.class.getName()).log(Level.SEVERE, null, ex);
}
methods registerUser, unregisterUser, sendMessageToAll simply call next method
private void sendMessage(Message m, Socket s) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(s.getOutputStream()));
out.writeObject(m);
out.flush();
// out.close();
}
Where is a mistake?
It seems like the problem might be the same as the one described here.
Just faced this problem .. So giving the answer in this thread itself :
ObjectOutputStream writes a stream header when we create it (new ObjectOutputStream(out))
Similarly , ObjectInputStream , when we create it (new ObjectInputStream(in)) , tries to read the same header from the corresponding ObjectOutputStream at the server side
Here , in client ,
in = new ObjectInputStream(socket.getInputStream());
the ObjectInputStream created blocks when trying to read the stream header , which will not come since there is no corresponding ObjectOutputStream at server which will write the header to the client .
The problem is not just this . If the ObjectOutputStream creation at one side aligns with some other reads at the client side which is supposed to read something of our choice , it may read the stream header instead of the actual value and end up in an incorrect value .
Solution :
The ObjectOutputStream and the ObjectInputStream created at the client and server sides must align with each other .