I have two applications, one written in Java and the other in C#. I am trying to send a string from the Java app to C# app.
My java code for sending the string is as follows:
String response;
try {
DataOutputStream outToServer =
new DataOutputStream(outGoingSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(outGoingSocket.getInputStream()));
outToServer.writeBytes(message + '\n');
outToServer.flush();
response = inFromServer.readLine();
System.out.println("Received: " + response);
} catch (Exception ex) {
System.err.println("Exception in incoming socket: " + ex.getMessage());
}
My C# code for receiving the data is as follows:
Byte[] bytes = new Byte[1000];
String data = null;
try {
Console.Write("Waiting for a connection... ");
TcpClient client = incomingSocket.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
while (true) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) {
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received:", data);
processReceivedMessage(data);
ackSocket(stream, "OK");
}
}
} catch (Exception ex) {
Console.WriteLine("Exception: ", ex);
}
I have a problem with receiving the data in the C# application. When I send the string "Data" in the Java app, and try to print the data received by the C# application using Console.WriteLine("Received: {0}", data), the output is:
Received: D
Received: ata
If I use Console.WriteLine("Received: ", data), the output is:
Received:
Received:
I want my C# application to receive the full string that is sent by the Java application. I tried to increase the buffer byte array size to 1000 but it doesn't help. I don't have experience using sockets, can someone show me what I did wrong?
So, as you can see, the receiving end picks up a response in chunks that might be considerably smaller than the total message.
You shouldn't be seeking to change this behaviour... it's a fact of network programming. It's your job to glue them back together again.
"I want my c# application receive the full string"
So, how is your receiving app meant to know that it has received the full string? Did you send a length field to indicate how much data is coming? Perhaps you expect \n to indicate the end of message? A zero byte?
If your terminator is indeed a newline, you might want to consider passing your NetworkStream to a StreamReader and calling ReadLine on it. Now, the StreamReader will keep reading from the stream until it hits a newline, then hand you the line.
Related
I've edited the code to explain that better.
I've got Android application, which is client and Java server. I'm trying to send info from client to server, process that information and send the result back to client.
I'm using BufferedReader, InputStreamReader and DataOutputStream to send and receive messages.
So my Client.java has this code:
try {
//Sending message to server
DataOutputStream outToServer = new DataOutputStream(sock.getOutputStream());
outToServer.writeBytes(messageString + '\n');
outToServer.flush();
} catch (IOException e) {
System.err.print(e);
}
try {
System.out.println("This line is showing");
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String res;
System.out.println("And this line is showing");
res=inFromServer.readLine();
System.out.println("But this never is");
System.out.println("Received: " + res); //This line is never printed in console
}catch (IOException e) {
System.out.println(e);
}
And my Server.java has this:
try{
System.out.println("Creating InputStream");
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = inFromClient.readLine();
System.out.println("Received: " + message); //correct string received
} catch (Exception ex) {
System.out.println("Creating InputStream failed");
System.err.print(ex);
}
try{
String response = "Response from server"
DataOutputStream outToClient = new DataOutputStream(clientSocket.getOutputStream());
outToClient.writeBytes(response + '\n');
outToClient.flush();
System.out.println("Sent to client: " + response); //correct string is showing in console
} catch(Exception ex) {
System.out.print("Error! " + ex);
}
The thing is that my server gets the message correctly, as understandable string. It shows in console what it's sending to client and that also is understandable string.
But when I'm trying to get the message at client it does nothing.
inFromServer.readline() isn't throwing any exception to console and I don't know why it's not working.
I tried inFromServer.toString(), and then I received something, but it definitely wasn't the string sent from server. It was something like:
java.io.BufferedReader#b3d109a0
I don't know what I'm doing wrong. The sending/receiving function is called from login function, which is called from onPostExecute. I don't know how can do this from doInBackground.
BufferedReader.readLine() isn't working
Oh yes it is. Your error is in trying to convert the reader into a string, instead of using the line that was read.
Yo should remove the ready() test. It is pointless.
You should also use symmetrical streams. If you use Readersat one end you should use Writers at the other, such as BufferedWriter. Not DataOutputStream.
I suggest that this isn't the real code, and that there isn't a \n on the end of the sent message, which would explain readLine() blocking until the non-existent line terminator arrives, but you should redo this using BufferedWriter instead of DataOutputStream as mentioned above.
Im making an app that has to send a class to a server written in c++ using Sockets. The class consists of to variables both are Ints. I want to convert the java class into bytes then send it over the socket as a packet. The server is expecting 8 bytes for the packet size. When I try to convert my object I get more than 8 bytes. How else can I send my object to the server? Also the my code below sends 4 bytes of data in two 2 bytes chucks. Why is it doing that?
public void connect2() {
String serverHostname = new String("My IP");
ObjectOutputStream out2 = null;
ObjectInputStream in2 = null;
try {
echoSocket = new Socket(serverHostname, MYPORT);
StatusPacket p = new StatusPacket();
byte[] data = new byte[8];
data = serializeObject(p);
int j = data.length;
out2 = new ObjectOutputStream(echoSocket.getOutputStream());
out2.flush();
in2 = new ObjectInputStream(echoSocket.getInputStream());
DataOutputStream dOut = new DataOutputStream(echoSocket.getOutputStream());
out2.write(data);
out2.close();
in2.close();
echoSocket.close();
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: " + serverHostname);
System.exit(1);
}
}
ObjectOutputStream and ObjectInputStream use Java serialization mechanisms, which includes a lot more info than just the class property values. You don't want to deal with those in C++ code, so I recommend you remove all serialization code and those two streams from your code.
Since you already know what you want on byte level, you should really be using that DataOutputStream instead. It allows you to transfer scalar data types like byte, int, long etc. without any overhead. Just get those two 32-bit integers from your object and pass them to DataOutputStream.writeInt(..) and you're set.
I got to implement a chat in my application. Connection to a server is made using sockets. I should register to that server and the server will aknowledge that with a reply.
I have implemented this in a single method where I send the command using a BufferedWriter, and then start reading from the input stream until it tells me there is no more data.
I read properly the server reply. However, I never get the negative value from the second in.read call and thus my method stays blocked in the while loop (in the conditionnal statement where I make that call).
How should this be done with sockets? I usually do that with files or other input streams without problem.
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
or make the server send a code to notify it has finished to send its response?
Currently I am doing the following:
private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
if (!isConnected()) openConnection();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()), 2048);
out.append(request);
out.flush();
out = null;
} catch (IOException e) {
LogHelper.error("Unable to send socket request: " + request, e);
throw new ChatException("Unable to send socket request: " + request, e);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()), 2048);
StringBuffer response = new StringBuffer();
char[] buffer = new char[2048];
int charsRead = -1;
// >>>>>>>> This is where it gets blocked <<<<<<<<<
while ((charsRead = in.read(buffer)) >= 0) {
if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
}
return response.toString();
} catch (IOException e) {
LogHelper.error("Unable to read socket response: " + request, e);
throw new ChatException("Unable to read socket response: " + request, e);
}
}
Connection to the server is made with the following method:
public synchronized void openConnection() throws ChatException {
try {
socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
socket.setKeepAlive(true);
LogHelper.debug("CHAT >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
} catch (UnknownHostException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
} catch (IOException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
}
}
The amount of data to be sent/received over a socket based connection is protocol dependend and not known to the TCP/IP stack, but only to the application layer.
The protocol used is developer dependend ... ;-) so coming to your questions:
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
Yes, this is one possibility.
or make the server send a code to notify it has finished to send its response?
Also yes, as this is another possibility. Common markers are \n or \r\n. The NUL/'\0' character also might make sense.
A third option is to prefix each data chunk with a constant number of bytes describing the amount of bytes to come.
Instead of dealing with bytes, maybe it's simpler handling instances of ad-hoc classes, like - for instance - a Message class:
The server:
// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;
// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());
// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();
The client then sends a message by simply:
// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);
Message can be as complex as needed as long as its members implement Serializable interface.
I have an Android application where I'm trying to send a picture to a server. I did this using Base64 encoding and it worked quite well, but it took too much memory (and time) to encode the picture before sending it.
I'm trying to strip the Android application down to where it just simply sends the byte array and doesn't fiddle around with any kind of encoding scheme so it'll save as much memory and CPU cycles as possible.
This is what I would like the Android code to look like:
public String sendPicture(byte[] picture, String address) {
try {
Socket clientSocket = new Socket(address, 8000);
OutputStream out = clientSocket.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out.write(picture);
return in.readLine();
}
catch(IOException ioe) {
Log.v("test", ioe.getMessage());
}
return " ";
}
The server is written in Java. How do I write the server code so I can properly retrieve the exact same byte array? My goal is to save as many CPU cycles on the Android as possible.
So far, all the methods I've tried resulted in corrupt data or a thrown exception.
Any help will be appreciated.
Try something like this:
public byte[] getPicture(InputStream in) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int data;
while ((data = in.read())>=0) {
out.write(data);
}
return out.toByteArray();
} catch(IOException ioe) {
//handle it
}
return new byte[]{};
}
Based on Robert's and Zaki's comment, here is the modified code that should perform better.
public byte[] getPicture(InputStream in) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int length = 0;
while ((length = in.read(data))!=-1) {
out.write(data,0,length);
}
return out.toByteArray();
} catch(IOException ioe) {
//handle it
}
return null;
}
If you want bi-directional communication, the server must know when you're ready - you should prepend a 4 byte length field to your sender side indicating the number of bytes to come.
On the server side you read the length and then stay listening until everything has arrived. Then you can reply your acknowledge string.
If it is enough to send only the picture, you can simply send the data and then close the connection. The server side is implemented as shown by #thejh.
I've been trying to create a Java and C# app that would communicate together. In this case the user sends a String from the C# side, it should display on the Java console and echo back. Unfortunately, I have only been able to establish the connection, without being able to send or receive anything.
Java code snippet:
public CommunicationThreadHandler(Socket socket, CarList carList) {
this.socket = socket;
this.carList = carList;
try {
this.in = new DataInputStream(socket.getInputStream());
this.out = new DataOutputStream(socket.getOutputStream());
this.writer = new Writer(out);
} catch (IOException e) {
System.out.println("Exception when reading or receiving data!");
e.printStackTrace();
}
this.ip = socket.getRemoteSocketAddress().toString();
}
#Override
public void run() {
while (true) {
try {
Gson gson = new Gson();
String msgJson = in.readUTF();
String msg = gson.fromJson(msgJson,String.class);
System.out.println("Message from C# client: "+msg);
String reply = "Server echo: "+msg;
String replyJson = gson.toJson(reply);
out.writeUTF(replyJson);
if (msg.equals(Package.EXIT))
break;
} catch (IOException e) {
e.printStackTrace();
}
}
C# snippet:
public static void StartClient()
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true)
{
Console.Write("Enter message to server: ");
string message = Console.ReadLine();
Console.WriteLine($"To be sent: {message}");
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes(message);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
string msgFromServer = Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (msgFromServer.Equals("EXIT"))
break;
Console.WriteLine($"Server says: {msgFromServer}");
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
Your problem is that you're using DataInputStream/DataOutputStream in Java, which use a Java-specific, XDR-like datatype serialization protocol. You are not using that protocol at your C# side.
Switching to using the raw input/output stream should be sufficient (although very brittle). However, notice that as you are sending raw bytes from C#, it will be impossible to tell for the recipient when the message is complete. It would be better to send the number of bytes of the message, followed by the actual message (this is what DataInputStream/DataOutputStream does, but it comes with additional considerations that you would need to correctly implement in your C# side, for example readUTF/writeUTF use a 'modified UTF-8' format instead of normal UTF-8).
The problem right now, is that you send raw bytes from C#, the readUTF() method reads the first two bytes as length, and then tries to read a message of that length. For example if C# sends "Hello" (encoded as 0x48, 0x65, 0x6c, 0x6c, 0x6f), then the Java side will read 0x48, 0x65 ("He") as "message length is 18533" and then tries to read 18533 bytes, while the actual remaining bytes are only 3 (the "llo"). This causes the input to block waiting for the remaining 18530 bytes, which never arrive.