i have a java client-server app in java, both using the same connection class that contains both send/receive messages.
for some reason, some of the messages i send are received in a malformed order:
here's the code
//set up
_in = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));
_out = new BufferedWriter(new OutputStreamWriter(this._socket.getOutputStream()));
this._socket.setSoTimeout(S_TIMEOUT);
public synchronized boolean send(String message){
try {
_out.write(message);
_out.write(Connection.DELIMITER);
_out.flush();
return true;
} catch (IOException e) {
}
return false;
}
public String receive(){
int c;
try {
String message = "";
System.out.println("Getting message:");
c = _in.read();
while(c != -1 && c != Connection.DELIMITER) {
message += (char) c;
c = _in.read();
}
if (c == -1) {
return null;
}
return message;
} catch (IOException e) { }
return null;
}
some messages, for example "new_order" will might return with "ew_ord".
some characters are lost, others are sent separately. this seems odd as its TCP
could this be an encoding related issue?
Delimiter is (char) 0
socket timeout is 20000 (ie 20 senconds). every 10 seconds i send an empty message to make sure socket does not close
EDIT:
although it was solved using the Scanner, i must say that the original code worked fine for many messages/various machines for a very long time (a few weeks), and then suddenly failed to work with one specific message on one specific machine (other messages went through just fine). i've done socket data transfer in java MANY times and i've written many read/write methods to handle the sockets. it's the first time i ran into this.
although in the original code i set the encoding (in the posted code i didn't), i believe that the problem was encoding related. at one point, the message that was received had every second character missing. afterwards i changed it a bit, and the first/second character of the message were received in a separate message. from my understanding, it's either an encoding issue or some firewall/other security program that was running on the message sender machine, that decided to filter outgoing packets.
Try replacing your receive with a Scanner and let it do the work for you.
// in your setup
Scanner sc = new Scanner(_in).useDelimiter(Connection.DELIMETER);
public String receive() {
try {
return sc.next();
} catch(IOException e) {
return "";
}
}
For starters, I would make sure you're printing exceptions in those catch blocks.
Then, you're using the platform default encoding for converting characters to bytes. If these two processes are running on different machines, it's possible they're using different encodings. I would make sure you're specifying an encoding when you set up the Reader and Writer.
You can use UTF encoding for getting Full String of Message.
U can try this code and I am Sure About this code because i used it in My Chat Application.
String data=" ";
socket = new Socket("localhost",999);
while(true)
{
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
jta.append(data +"\n");
}
Where jta is JTextArea.
It's for Client Side
Now For Server Side:
try
{
server = new ServerSocket(999);
Socket soc = server.accept();
while(true)
{
String data="";
try
{
dis = new DataInputStream(soc.getInputStream());
dos = new DataOutputStream(soc.getOutputStream());
data = dis.readUTF();
}
catch(Exception e)
{ }
jta.append(data + "\n");
}
}
catch (IOException e)
{
JOptionPane.showMessageDialog(this, e);
System.exit(-1);
}
Related
I have a 2 nodes that should always communicate with each other, but they don't seem to talk for more than 1 interaction. After successfully sending and receiving 1 message, they stop.
My code looks like this:
The initiator:
try {
Socket client = new Socket(ip, port);
OutputStream toNode = client.getOutputStream();
DataOutputStream out = new DataOutputStream(toNode);
out.writeUTF("Start:Message");
System.out.println("Sent data");
InputStream fromNode = client.getInputStream();
DataInputStream in = new DataInputStream(fromNode);
if(in.readUTF().equals("Return Message")) {
System.out.println("Received data");
out.writeUTF("Main:Message");
System.out.println("Sent data again");
}
else
System.out.println("Error");
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The responder:
while(true) {
Socket server;
try {
server = s.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
String msg = in.readUTF();
String[] broken_msg = msg.split(":");
if(broken_msg.length > 0)
System.out.println("Looping");
String ret;
if (broken[0].equalsIgnoreCase("Start")) {
ret = "Return Message";
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF(ret);
}
else if (broken[0].equalsIgnoreCase("Main")) {
//Do Useful work
}
} catch (IOException e) {
e.printStackTrace();
}
}
My output looks like this:
Looping
and:
Sent data
Received data
Sent data again
You are looping around the accept() call, accepting new connections, but your actual I/O code only reads one message per connection. You need an inner loop around the readUTF() calls, handling the entire connection until EOFException is thrown. Normally all the I/O for a connection is handled in a separate thread.
In order for programs to do repetitive actions, you would generally use looping of some sort, including for loops, while loops and do-while loops. For something like this where you don't know how many times you'd need to communicate in advance, then you would need to use a while loop, not a for loop.
Having said that, you have no while loops whatsoever inside of your connection code... so without code that would allow continued communication, your program will stop, exactly as you've programmed it to do.
Solution: fix this. Put in while loops where continued communication is needed.
I'm working on a java server-client based file transfer over socket project, I'll sum up the project shortly, I have text files related to server and client, server related text contains which ports are going to be opened and client text contains the IP and port to be connected on(server side is like 4444 and client side is like 4444 localhost) The file transfer on a single client is running pretty ok, now I'm working on second client connection and transfer, what I'm trying to do is; when a second client is run, it will read the first line of the text file (which is already in use by the first client), I thought a recursion will solve the problem but seems I couldn't figure out what I've done wrong, below are the code snippet from client side
boolean connected = false;
private void connection() {
while (!connected) {
try {
FileReader fr = new FileReader("c_input.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
String delims = "[ ]";
String[] elements = new String[8];
elements = line.split(delims);
serverPort = Integer.parseInt(elements[portIndex]);
hostIP = elements[ipIndex];
clientSocket = new Socket(hostIP, serverPort);
is = clientSocket.getInputStream();
if (is != null) {
connected = true;
System.out.println("connected to " + hostIP + " from port "
+ serverPort);
br.close();
fr.close();
} else {
System.out.println("The port " + serverPort
+ " is occupied, now trying another port.");
portIndex = portIndex + 2;
ipIndex = ipIndex + 2;
connection();
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
}
}
I used recursion there, because if a port is bound by another client it has to read another line from text file and split and retry connection with the new line's inputs.(in terms short the whole method will run again) But when it comes to running, the first client connects and when second one tries to connect from same port with client1 the code still gets in if loop instead of getting in else block (I get the message from the if check's println on the console and by the way is in the if check stands for InputStream) which means there is a stream coming from server, is this normal? if so how can I achieve the whole thing connection method does all over again if the port is bound by another client?
My project involves reading the status of an LED on Arduino, from java. It will move on to reading temperature from Arduino, but I got stuck. So here it is:
I send the "Turn on/off!" message from my java program, and I want it to show if the LED is on and off.
So when I send "192.168.0.100/ON", the LED turns on and I shoud get the "ON" message in my program.
The code on Arduino:
byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0x2F, 0xD4 };
IPAddress ip(192,168,0,100);
EthernetServer server(80);
String message = String(30);
void setup()
{
pinMode(2, OUTPUT);
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.begin(9600);
}
void loop()
{
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (message.length() < 30) {
message += c;
}
Serial.print(message);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n') {
if (message.indexOf("ON") > 0) {
digitalWrite(2, HIGH);
client.print("ON");
}
if (message.indexOf("OFF") > 0) {
digitalWrite(2, LOW);
client.print("OFF");
}
message = "";
client.stop();
}
}
}
// give the web browser time to receive the data
delay(1);
}
}
The code in java:
public class TestClient {
public static void main(String[] args) {
HttpURLConnection connection = null;
BufferedReader serverResponse = null;
try {
// OPEN CONNECTION
connection = (HttpURLConnection) new URL("http://192.168.0.100/ON")
.openConnection();
connection.connect();
// RESPONSE STREAM
serverResponse = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// READ THE RESPOSNE
String line;
while ((line = serverResponse.readLine()) != null) {
System.out.println(line);
}
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (connection != null)
connection.disconnect();
if (serverResponse != null) {
try {
serverResponse.close();
} catch (Exception ex) {
}
}
}
}
}
What happens: The LED turns on, but I get this error in java:
java.net.SocketException: Unexpected end of file from server at TestClient.main(TestClient.java:23) -> connection.getInputStream();
What I want: After sending the "ON" message, it should be printed in console.
Mention: if I send 192.168.0.100/ON from my browser, the LED turns on and the message appears in the web page.
There are two issues here:
If the exception is thrown when getting the InputStream, then it's happening because the connection has been closed at that point, and this happens because the Arduino sends the message then immediately "closes" the client, effectively terminating the connection. You can do three things:
a. Try and creating the input stream before calling connect(), but this most likely will fail due to the connection not existing at that point.
b. Put a delay before calling client.stop();
c. (recommended) Let the client close the connection, don't do it on the server.
Try adding a \n after ON and OFF in client.print() method, in the Arduino code.
client.print("ON\n");
...
client.print("OFF\n");
readLine() will read until the first end-of-line char which never comes.
Try reverse the order in your finally block. Close the input stream before you close the socket.
As this guy here says, the Arduino can serve HTML pages, so I guessed my HttpURLConnection must know about this. Here, it says that "The version of an HTTP message is indicated by an HTTP-Version field in the first line of the message."
So I simply added the following code into the Arduino sketch, right after I check (c == "\n"):
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
I didn't get to this very quickly, but after reading others` code and the resources I mentioned above, I came to this conclusion. The explanation could be as well wrong for all I know, but it worked, and my project runs.
In the code below, what determines what will be sent back to the client (the PHP page). I am trying to alter this so that it sends a variable back to the PHP page with an error message that is defined based on actions made in my java code.
Edit: To answer some questions, what I am trying to do is this.
Send a string to the java script with a socket and convert it to a variable to be used in the java script. It will run through some if statements and I need to set the error statements to a variable lets say "reply". I need to send "reply" then back to the PHP file.
public class MyJavaServer {
public static void main(String[] args) {
int port = 20222;
ServerSocket listenSock = null; //the listening server socket
Socket sock = null; //the socket that will actually be used for communication
try {
listenSock = new ServerSocket(port);
while (true) { //we want the server to run till the end of times
sock = listenSock.accept(); //will block until connection recieved
BufferedReader br =
new BufferedReader(new InputStreamReader(sock.getInputStream()));
BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
String line = "";
while ((line = br.readLine()) != null) {
bw.write("PHP said: " + line + "\n");
bw.flush();
}
//Closing streams and the current socket (not the listening socket!)
bw.close();
br.close();
sock.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
If I get your question right, the line where the answer gets sent to the peer is
bw.write("PHP said: " + line + "\n");
which writes the given string to bw.
I have written a server is java here is the code:
public mainClass()
{
try
{
ss = new ServerSocket(8080);
while (true)
{
socket = ss.accept();
System.out.println("It is accept!");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//out = new PrintWriter(socket.getOutputStream(),true);
line = in.readLine();
System.out.println("you input is :" + line);
//out.close();
in.close();
socket.close();
}
}
catch (IOException e)
{
}
and I am using an iPhone application as the client.
now what my problem is that the server is not reading the inputstream while the appication is running on the iphone.. But as soon as the application is terminated the java program prints out the String which has been sent to the server..Not sure what is happening here..sorry if this is not a good question..
- (void)viewDidLoad {
[super viewDidLoad];
socket = [[LXSocket alloc]init];
if ([socket connect:#"10.211.55.2" port:8080]) {
NSLog(#"socket has been created");
}
else {
NSLog(#"socket couldn't be created created");
}
#try {
[socket sendString:#"Hi This is a second test"];
}
#catch (NSException * e) {
NSLog(#"Unable to send data");
}
[super viewDidLoad];
}
thanks,
TC
From my own experience, readLine is not a good idea, especially when working with different languages and platforms, a better approach will be to use InputStreamReader and its read(char[] buff) method, and agree on both sides regarding the length to be sent each time.
Again, I have no reference to that, only my experience.
Also, looking at your code, you send a string without a new line character: [socket sendString:#"Hi This is a second test"]; maybe adding \n at the end will solve it for you.
My guess is that the client application doesn't send any line break at the end of the string it sends. So BufferedReader.readLine() waits for an EOL character, and only returns the string when the client application ends, because at this point the connection is closed and the reader knows there won't ever be an EOL, and the string is the last line it will ever receive.
BufferedReader can be dangerous; the buffering can cause short lines to get "stuck" if you're only reading a little data at a time, or if the data is coming across a network. If you're only using BufferedReader to get readLine(), then do this:
new BufferedReader(new InputStreamReader(socket.getInputStream()), 1);
That extra argument sets the buffer size to 1 character, effectively turning it off. That generally solves this kind of problem.