I am currently working on a Java console application. It is run through the command prompt, connects to a server application coded in python and communicates with that server over TCP. My application sends "ISND" string to server which it accepts and in return server sends three images. The format in which Images are sent in is
Where "<"">" are not actually included. "ISND" is encoded into bytes using ascii. Size is the size of the image converted into bytes from int and it is always composed of 3 bytes regardless of the size of the image. For each individual image, a message in this format is sent.
I have been using BufferedReader to read server responses but at this point, I am at a loss on how to actually handle this message. I searched for ways to separate the incoming message into components since I know the length of the first two parts which are always fixed yet I couldn't find a way to actually accomplish that goal.
It has come to the point it feels like I am smashing my head into a wall. As such, I need advice from anyone that is more familiar with Java and Socket programming on how to handle this issue.
My current code
public class ImageLabeler {
/**
* #param args
*/
public static void main(String[] args) {
String IP = args[0];
System.out.println(IP + "\n");
String port = args[1];
System.out.println(port + "\n");
Socket clientSocket;
DataOutputStream outToServer = null;
BufferedReader inFromServer = null;
String serverResponse;
try {
clientSocket = new Socket(IP, Integer.parseInt(port));
outToServer = new DataOutputStream(clientSocket.getOutputStream());
inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.println("Connection success\n");
} catch (IOException ex) {
System.out.println("Connection failed\n");
System.exit(0);
}
PrintWriter writer = new PrintWriter(outToServer, true);
try {
//outToServer.writeBytes("USER bilkentstu\\n");
//outToServer.flush();
//System.out.println("check\n");
writer.println("USER bilkentstu");
serverResponse = inFromServer.readLine();
System.out.println(serverResponse + "\n");
writer.println("PASS cs421f2019");
//outToServer.writeBytes("PASS cs421f2019\\r\\n");
//outToServer.flush();
serverResponse = inFromServer.readLine();
System.out.println(serverResponse + "\n");
writer.println("IGET");
//This is where I need to handle the incoming Image messages.
writer.println("EXIT");
} catch (IOException ex) {
Logger.getLogger(ImageLabeler.class.getName()).log(Level.SEVERE, null, ex);
}
System.exit(0);
}
}
Don't use buffered reader. You need to write the code reading a string from the InputStream of the socket one byte at a time.
Related
I am trying to read continuous data from TCP IP port of system using Java Socket Programming ServerSocket but I am getting unreadable string data like in following following image :
I am using following code for read data from TCP IP port :
ServerSocket server_socket;
BufferedReader input;
try {
server_socket = new ServerSocket(6666);
LOGGER.info("Server waiting for client on port "
+ server_socket.getLocalPort());
System.out.println("Server waiting for client on port "
+ server_socket.getLocalPort());
while (true) {
Socket socket = server_socket.accept();
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
try {
while (true) {
String message = input.readLine();
if (message == null) {
break;
}
}
} catch (Exception e) {
socket.close();
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
So please let me know what kind of data are in above image and what conversion I should do?
Thanks in advance.
One flaw:
The InputStreamReader is responsible for converting binary data (an InputStream) to a Reader ((Unicode) text). For that you can & should specify a text encoding, a Charset. You are using the default, platform encoding.
input = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.ISO_8859_1));
You can now access this server application yourself by telnet or an other terminal tool. Or even the browser by http://localhost:6666/ (telnet://localhost:6666/?).
What you are seeing does look like non-text binary data - should the default encoding not be Chinese or such.
Furthermore the code would be improved by a new thread from a thread pool handling the socket from the accept.
One should pay attention to the header lines one sends (you do not output) and then receive.
Hello i'm trying to execute a socket client in Java, but the client still reading the data and don't proceed with the program execution. Any ideas?
Here's the code:
import java.io.*;
import java.net.Socket;
public class SocketTeste {
public static void main(String[] args) {
try {
Socket client = new Socket("127.0.0.1", 1987);
System.out.println("Got connection");
DataInputStream handshake = new DataInputStream(client.getInputStream());
String handshakePure = handshake.readUTF();
System.out.println("Got the handshake");
System.out.println(handshakePure);
DataOutputStream saida = new DataOutputStream(client.getOutputStream());
saida.writeUTF("Got it!");
saida.flush();
saida.close();
String returnedData = handshake.readUTF();
System.out.println(returnedData);
handshake.close();
client.close();
} catch (Exception e) {
System.out.println("ERROR: " + e);
}
}
}
I don't think if that matter, but the socket server is a PHP socket server.
DataInputStream.readUTF expects a uniquely weird message format. The first two bytes it reads are interpreted as the length of the string to read, in a big endian binary format. This is then followed by a weird non-standard text encoding similar to but incompatible with UTF-8. Most likely you should not be using DataInputStream.readUTF to read data in a program, unless you used its counterpart DataOutputStream.writeUTF to write it in the first place.
Based on your comments it sounds like your communication protocol is based on lines of text. To read lines of text, you can use for example the BufferedReader class.
BufferedReader handshake = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8));
String handshakePure = handshake.readLine();
I already read some threads here on stackoverflow, also some tutorials, but I don't find a solution to my problem.
I have Java client which connects to a server, then sends exactly one line to the server, and I get 2 or 3 lines as a response.
Here is my code:
public static void main(String[] args) {
String message;
String response;
try {
BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
Socket clientSocket = new Socket(hostname, port);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
message = inFromUser.readLine();
outToServer.writeBytes(message + '\n');
// here my program "freezes"
while ((response = inFromServer.readLine()) != null) {
System.out.println("response: " + response);
}
clientSocket.close();
} catch (UnknownHostException e) {
System.out.println("Unknown Host");
} catch (IOException e) {
System.out.println("IO Exception");
}
}
My problem is, I can read every line of the response, but my program won't exit. The line clientSocket.close(); gets never called. What am I doing wrong?
Presumably your server isn't closing the connection - therefore the underlying stream for the reader isn't closed... at any point the server could send more information. readLine() only returns null when the stream has been closed, i.e. there will definitely not be any more data.
Now we don't know anything about the protocol here, but if the expected behaviour is that the client won't send any more information, and the server will close the connection, then the bug is in the server. If the protocol states that the server will keep the connection open, then the bug is in your client code and you need to work out how to detect the end of data (or send some sort of ack that will cause the server to close the connection, or whatever).
I have the two programs and i want them to connect to my school server afs1.njit.edu but it never connects. That is where i have the files. should i run two ssh programs to each run the different programs? unsure how to test them. (these are a simple ezxample from online i want to test before i write my code) I compile them serperately and they never connect.
singleSocketserver.java
public static void main(String[] args) {
try{
socket1 = new ServerSocket(port);
System.out.println("SingleSocketServer Initialized");
int character;
while (true) {
connection = socket1.accept();
BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
InputStreamReader isr = new InputStreamReader(is);
process = new StringBuffer();
while((character = isr.read()) != 13) {
process.append((char)character);
}
System.out.println(process);
//need to wait 10 seconds for the app to update database
try {
Thread.sleep(10000);
}
catch (Exception e){}
TimeStamp = new java.util.Date().toString();
String returnCode = "SingleSocketServer repsonded at "+ TimeStamp + (char) 13;
BufferedOutputStream os = new BufferedOutputStream(connection.getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(os, "US-ASCII");
osw.write(returnCode);
osw.flush();
}
}
catch (IOException e) {}
try {
connection.close();
}
catch (IOException e) {}
}
}
SocketClient.java
public class SocketClient {
public static void main(String[] args) {
/** Define a host server */
String host = "afs1.njit.edu";
/** Define a port */
int port = 19999;
StringBuffer instr = new StringBuffer();
String TimeStamp;
System.out.println("SocketClient initialized");
try {
/** Obtain an address object of the server */
InetAddress address = InetAddress.getByName(host);
/** Establish a socket connetion */
Socket connection = new Socket(address, port);
/** Instantiate a BufferedOutputStream object */
BufferedOutputStream bos = new BufferedOutputStream(connection.
getOutputStream());
/** Instantiate an OutputStreamWriter object with the optional character
* encoding.
*/
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
TimeStamp = new java.util.Date().toString();
String process = "Calling the Socket Server on "+ host + " port " + port +
" at " + TimeStamp + (char) 13;
/** Write across the socket connection and flush the buffer */
osw.write(process);
osw.flush();
/** Instantiate a BufferedInputStream object for reading
/** Instantiate a BufferedInputStream object for reading
* incoming socket streams.
*/
BufferedInputStream bis = new BufferedInputStream(connection.
getInputStream());
/**Instantiate an InputStreamReader with the optional
* character encoding.
*/
InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");
/**Read the socket's InputStream and append to a StringBuffer */
int c;
while ( (c = isr.read()) != 13)
instr.append( (char) c);
/** Close the socket connection. */
connection.close();
System.out.println(instr);
}
catch (IOException f) {
System.out.println("IOException: " + f);
}
catch (Exception g) {
System.out.println("Exception: " + g);
}
}
}
if you're trying to connect from your home to the school's computer, then you will likely hit a firewall. Usually, though not always, connections initiated from the machine are allowed, but connections to the machine are only allowed on certain ports. You can set up your ssh to tunnel the packets but then you may as well run the 2 programs next to one another.
If you run both programs on the same machine, they should find one another, assuming that:
1: you are allowed to open sockets
2: the socket isn't already taken by anothe program
3: the firewall doesn't block those ports.
to run both on the school machine you can use 2 shells (ssh) but it isn't necessary. you can run the receiver in the background (put a & at the end of the command) and then run the sender. However it is easier to run 2 shells, especially if the program sends to sysout like yours does.
a few pointers, if you use System.out (or System.err) for debug / log output, when you consume an exception, I recommend e.printStackTrace(System.out) if you don't want to pull in a library for this. Most logging frameworks have a logger.error("message", ex) and commons.lang has an exception printer too.
How can I convert a stack trace to a string?
One thing you can do to test your logic, without the socket connection, is to use PipedInputStream and PipedOutputStream. http://docs.oracle.com/javase/7/docs/api/java/io/PipedInputStream.html but if you're sure of your logic and need to test sockets you'll have to run them side by side.
Okay this is a revised question from earlier today, I have included code to help explain the problem. I am sending two messages from the client to the server. The server then picks the messages up and processes them. The server finally attempts to send a message back to the client(please note in the server code "testmessage"), it is here I am having problems. Either I am not recieving the message at the client side or sending it incorrectly from the server side.
public class ClientConnection {
String address, language, message;
int portNumber;
Socket clientSocket = null;
public ClientConnection(String lan, String mes, String add, int pn) throws IOException{
address = add;
portNumber = pn;
language = lan;
message = mes;
}
public String createAndSend() throws IOException{
// Create and connect the socket
Socket clientSocket = null;
clientSocket = new Socket(address, portNumber);
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(),true);
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Send first message - Message is being correctly received
pw.write(language+"\n");
pw.flush();
// Send off the data
// Send the second message - Message is being correctly received
pw.write(message);
pw.flush();
pw.close();
// Send off the data
// NOTE: Either I am not receiving the message correctly or I am not sending it from the server properly.
String translatedMessage = br.readLine();
br.close();
//Log.d("application_name",translatedMessage); Trying to check the contents begin returned from the server.
return translatedMessage;
}
Server Code:
public class ServerConnection {
public static void main(String[] args) throws Exception {
// Delete - Using while loop to keep connection open permanently.
boolean status = false;
while( !status){
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Delete - Working as of here, connection is established and program runs awaiting connection on 4444
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String language = br.readLine();
String message = br.readLine();
// Test - Works
System.out.println(language);
// Test - Works
System.out.println(message);
// Delete - Working as of here, both messages are passed and applied. Messages are received as sent from client.
TranslateMessage tm = new TranslateMessage();
String translatedMessage = tm.translateMessage(language, message);
// NOTE: This seems to be where I am going wrong, either I am not sending the message correctly or I am not receiving it correctly..
// PrintWriter writer = new PrintWriter(new BufferedOutputStream(clientSocket.getOutputStream()));
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream(),true);
// Send translation back
System.out.println(translatedMessage);
// pw.write(translatedMessage+"\n");
pw.write("Return test"); // Test message!
pw.flush();
// Send off the data
pw.close();
br.close();
clientSocket.close();
serverSocket.close();
}
}
}
The code is a bit of a mess and I can see a few duplicates, I have commented where I feel the problems occour.
Thanks for any help!
You are using BufferedReader.readLine() to read the response from the server, but in the test case you are sending a string that is not terminated with a \n or \r\n, so it will not get the line as far as I can tell from the docs...
public String readLine()
throws IOException
Read a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
An additional suggestion...
When writing request response protocols like this I would not rely on line endings to terminate the requests or responses. Typically I would use either a fully formatted JSON string, or my preference is for a binary protocol where all requests and response are prepended with a binary count (usually 4 bytes bigendian/network byte order). Then the client and server reads the 4 bytes then reads the number of bytes that follow. This handles the packet fragmentation that typically happens over network connections, also it helps avoid DOS attacks by malicious users sending long strings that never terminate.
In Java you can use ByteBuffer.order() to handle bigendian numbers.