I have a situation with a Java Socket Input reader.
I am trying to develop an URCAP for Universal Robots and for this I need to use JAVA.
The situation is as follow:
I connect to the Dashboard server through a socket on IP 127.0.0.1, and port 29999.
After that the server send me a message "Connected: Universal Robots Dashboard Server".
The next step I send the command "play".
Here starts the problem. If I leave it like this everything works.
If I want to read the reply from the server which is "Starting program" then everything is blocked.
I have tried the following:
-read straight from the input stream-no solution
-read from an buffered reader- no solution
-read into an byte array with an while loop-no solution
I have tried all of the solution presented here and again no solution for my case.
I have tried even copying some code from the Socket Test application and again no solution.
This is strange because as mentioned the Socket Test app is working with no issues.
Below is the link from the URCAP documentation:
https://www.universal-robots.com/articles/ur/dashboard-server-cb-series-port-29999/
I do not see any reason to post all the trials code because I have tried everything.
Below is the last variant of code maybe someone has an idea where I try to read from 2 different buffered readers. The numbers 1,2,3 are there just so I can see in the terminal where the code blocks.
In conclusion the question is: How I can read from a JAVA socket 2 times?
Thank you in advance!
public void sendPlay() {
try {
// Create a new Socket Client
Socket sc = new Socket("127.0.0.1", 29999);
if (sc.isConnected()) {
InputStream is = sc.getInputStream();
BufferedInputStream in = new BufferedInputStream(is);
String data = "";
int s = in.read();
data += ""+(char)s;
int len = in.available();
System.out.println("Len got : "+len);
if(len > 0) {
byte[] byteData = new byte[len];
in.read(byteData);
data += new String(byteData);
}
System.out.println(data);
System.out.println("1");
// Create stream for data
DataOutputStream out;
out = new DataOutputStream(sc.getOutputStream());
String command = new String();
command = "play"+"\n";
// Send command
out.write(command.getBytes("US-ASCII"));
out.flush();
System.out.println("2");
InputStream is1 = sc.getInputStream();
BufferedInputStream in1 = new BufferedInputStream(is1);
String data1 = "";
int s1 = in1.read();
data1 += ""+(char)s1;
int len1 = in1.available();
System.out.println("Len got : "+len1);
if(len1 > 0) {
byte[] byteData1 = new byte[len1];
in.read(byteData1);
data1 += new String(byteData1);
}
System.out.println(data1);
System.out.println("3");
// Perform housekeeping
out.close();
sc.close();
}
sc.close();
} catch (IOException e) {
System.out.println(e);
}
}
The problem seems to be that you are opening several input streams to the same socket for reading commands.
You should open one InputStream for reading, one OutputStream for writing, and keep them both open till the end of the connection to your robot.
Then you can wrap those streams into helper classes for your text-line based protocol like Scanner and PrintWriter.
Sample program to put you on track (can't test with your hardware so it might need little tweaks to work):
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class RobotTester implements AutoCloseable {
private Socket clientSocket;
private Scanner inputReader;
private PrintWriter outWriter;
private int incounter;
private int outcounter;
public static void main(String[] args) {
System.out.println("Program started. Connecting to robot");
try (RobotTester robot = new RobotTester("127.0.0.1", 29999)) {
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
if (resp.toLowerCase().startsWith("fail")) {
throw new Exception("Play command failed: " + resp);
}
System.out.println("Command succeeded!");
} catch (Throwable t) {
t.printStackTrace();
}
}
public RobotTester(String host, int port) throws UnknownHostException, IOException {
clientSocket = new Socket(host, port);
inputReader = new Scanner(clientSocket.getInputStream());
outWriter = new PrintWriter(clientSocket.getOutputStream());
}
public String nextInput() {
String mess = inputReader.nextLine();
System.out.println("< " + (++incounter) + ": " + mess);
return mess;
}
public void writeCommand(String command) {
System.out.println("> " + (++outcounter) + ": " + command);
outWriter.print(command);
outWriter.print('\n');
outWriter.flush();
}
#Override
public void close() throws Exception {
if (inputReader != null) {
inputReader.close();
inputReader = null;
}
if (outWriter != null) {
outWriter.close();
outWriter = null;
}
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
}
}
In addition, you're using 127.0.0.1 as server IP address, which is the loopback on your PC. Unless the interface to your robot works in a very peculiar way, the actual IP you should use is probably not this one.
I'm refering to this part of documentation here:
Setup a static IP-address and subnet mask on PC, so it matches the
robot, e.g.:
PC: IP-addr: 192.168.3.10 Robot: IP-addr: 192.168.3.3
Subnet: 255.255.255.0 Subnet: 255.255.255.0
Edit
If you've got more commands to put, use it like this:
//Inside your actual main class
public static void main(String[] args) {
System.out.println("Program started. Connecting to robot");
try (RobotTester robot = new RobotTester("127.0.0.1", 29999)) {
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
if (resp.toLowerCase().startsWith("fail")) {
throw new Exception("Play command failed: " + resp);
}
System.out.println("Command succeeded!");
robot.writeCommand("command1"); //Send command
resp = robot.nextInput(); //Read result
//Process result for command1
robot.writeCommand("command2"); //Send command
resp = robot.nextInput(); //Read result
//Process result for command2
//...
} catch (Throwable t) {
t.printStackTrace();
}
}
The latest update is that I have moved all the functions in the same Dialog and just called them straight from there, and is still not working.
I already double check there is just one stream and one writer and reader in the entire project.
JButton btnNewButton_2 = new JButton("START");
btnNewButton_2.setBackground(Color.GREEN);
btnNewButton_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
RobotTester("127.0.0.1", 29999);
nextInput();
String command="play";
writeCommand(command);
nextInput();
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
close();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} });
public void RobotTester(String host, int port) throws UnknownHostException, IOException {
clientSocket = new Socket(host, port);
inputReader = new Scanner(clientSocket.getInputStream());
outWriter = new PrintWriter(clientSocket.getOutputStream());
}
public String nextInput() {
String mess = inputReader.nextLine();
System.out.println("< " + (++incounter) + ": " + mess);
return mess;
}
public void writeCommand(String command) {
System.out.println("> " + (++outcounter) + ": " + command);
outWriter.print(command);
outWriter.print('\n');
outWriter.flush();
}
public void close() throws Exception {
if (inputReader != null) {
inputReader.close();
inputReader = null;
}
if (outWriter != null) {
outWriter.close();
outWriter = null;
}
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
}
I have found a solution to the issue of reading the from the socket multiple times with a Swing GUI.
public void sendPlay() {
Thread appThread = new Thread() {
public void run() {
try {
RobotTester robot = new RobotTester("127.0.0.1", 29999);
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();}
It seems that the background socket reading needs to be on a separate thread. This was causing the entire robot to be blocked. The idea was from an forum. It was not mine, but hey, it works.
Thank you very much!
Related
I made two classes in Java named Server.java and Client.java. The Server is listening to a port and is waiting for a Client to connect (using sockets). When the client connects he can type a pair of numbers separated by "space" and if that pair exists in my edge_list.txt file the Server returns "1" to the client, if not it returns "0". After I completed my initial project I wanted to also use Threads so that it can handle multiple users at once, but when the Client connects I get -> java.net.SocketException: Socket is closed.
I reviewed my code and try using flush() instead of close(). Also, I thought I was closing the socket before the user can read the file, but it didn't seem that was the case. Below I will have the Server.java code block and not the Client.java, cause it doesn't seem to be the problem.
Server.java
import java.io.*;
import java.net.*;
import java.util.*;
public class Server {
private static final int PORT = 9999;
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server is listening on port " + PORT);
while (true) {
try (Socket socket = serverSocket.accept()) {
System.out.println("Client connected: " + socket);
new ClientHandler(socket).start();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class ClientHandler extends Thread {
private Socket socket;
ClientHandler(Socket socket){
this.socket = socket;
}
#Override
public void run() {
try {
//Creating Sockets and Streams
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output));
while (socket.isConnected() && !socket.isClosed()) {
//Reading what the Client types
String request = reader.readLine();
//Split the values with "space" and store them in an array,
//then parse those values to two integers
String[] values = request.split(" ");
int A = Integer.parseInt(values[0]);
int B = Integer.parseInt(values[1]);
//Check if the pair in the file exists using checkPairInFile() method
boolean exists = checkPairInFile(A, B);
//if it does print 1 else 0
writer.println(exists ? "1" : "0");
//Flush the output to send the response back to the client
writer.flush();
}
//Print the disconnected user
System.out.println("Client disconnected: " + socket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean checkPairInFile(int A, int B) {
try (Scanner scanner = new Scanner(new File("edge_list.txt"))) {
//Scanning the file lines
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
//Split the values with "space"
String[] values = line.split(" ");
//Parse the values from String -> Int
int a = Integer.parseInt(values[0]);
int b = Integer.parseInt(values[1]);
//if both exist return true
if (A == a && B == b) {
return true;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return false;
}
}
P.S. Thanks in advance for your help, in case this is problem with my Client.java file I will update the post.
This part:
try (Socket socket = serverSocket.accept()) {
System.out.println("Client connected: " + socket);
new ClientHandler(socket).start();
}
accepts a socket, then prints a message, then starts a new thread, then closes the socket. At some point later the new thread finishes starting up and tries to use the socket and realizes it was already closed.
try (...) {...} (officially called try-with-resources) always closes the things when it gets to the }. That's the point of it. If you don't want to close the socket at the } then you shouldn't use this type of statement.
I've been working on a university project for a bit where I essentially coded a GUI along with a few other features on it. Recently, we've been tasked with implementing a server/client communication on the application, and the topic hasn't really been explained very well to us so I have been struggling. My idea for the implementation is to take the username & password that the client provides at the login screen, send it to a Server class, verify the details, and then send a boolean value of either true or false, depending on whether or not they have the correct details. This hasn't worked, and I don't believe the username/password test variables in the server class take on any values. I will share the relevant snippets of code from both the Client & Server class down below.
Client Part:
private void loginMessage() {
/*
* This is the default login message that will be displayed. We could add
* checkers and such to the information we receive from the username/password
* fields, however that is outside of the scope of our current homework
* assignment. I did, however, make sure to store the username in a string and
* personalize the welcome message.
*/
String uName = txtUsername.getText();
try {
dout.writeUTF(uName);
} catch (Exception e) {
}
String password = new String(usPassword.getPassword());
try {
dout.writeUTF(password);
} catch (Exception e) {
}
try {
boolean loginSuccess = din.readBoolean();
if (loginSuccess) {
JOptionPane.showMessageDialog(this,
"Thank you for logging in " + uName
+ ". You will now get redirected to our Customer Zone, where you can make purchases. Press OK to continue.",
"Success!", JOptionPane.INFORMATION_MESSAGE);
finished = true;
} else {
JOptionPane.showMessageDialog(this,
"Error. Either your username or password is incorrect. Please try again.", "Error",
JOptionPane.ERROR_MESSAGE);
}
} catch (Exception e) {
}
}
private void cancel() {
/*
* This is the cancel operation. We will close the application when the cancel
* option is selected.
*/
System.exit(1);
}
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 7000);
InputStream in = socket.getInputStream();
DataInputStream din = new DataInputStream(in);
// send a message from client to server
OutputStream out = socket.getOutputStream();
DataOutputStream dout = new DataOutputStream(out);
} catch (Exception e) {
}
// We define a new MyApplication object in order to run our application.
MyApplication x = new MyApplication();
Progress a = new Progress();
Secondpage s = new Secondpage();
Thread t1 = new Thread(x);
t1.start();
try {
t1.join();
} catch (Exception e) {
e.printStackTrace();
}
a.start();
try {
a.join();
} catch (Exception e) {
e.printStackTrace();
}
s.start();
try {
s.join();
} catch (Exception e) {
e.printStackTrace();
}
}
Server Part:
public class MyServer {
Socket serverSocket;
BufferedReader br;
FileReader fr;
static String uname;
static String pwd;
static String filepath = "login.txt";
static String sep = ",";
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(7000);
System.out.println("Waiting for a client...");
Socket mySocket = serverSocket.accept();
System.out.println("I have a client");
DataInputStream clientIn = new DataInputStream(mySocket.getInputStream());
DataOutputStream clientOut = new DataOutputStream(mySocket.getOutputStream());
uname = clientIn.readUTF();
pwd = clientIn.readUTF();
System.out.println("I have a username " + uname + pwd);
boolean verif = verifyUserLogin(uname, pwd, filepath, sep);
clientOut.writeBoolean(verif);
System.out.println("Username: " + uname);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static boolean verifyUserLogin(String user, String pwd, String fp, String sep) {
String currentLine;
String data[];
try {
// We use FileReader to read file, and BufferedReader to read character stream.
FileReader fr = new FileReader(fp);
try (BufferedReader br = new BufferedReader(fr)) {
while ((currentLine = br.readLine()) != null) {
data = currentLine.split(sep);
if (data[0].equals(user) && data[1].equals(pwd)) {
return true;
}
}
}
} catch (Exception e) {
}
return false;
}
}
Now, my issue is I am struggling with sending the login and password strings over to the server. I don't think the username & password variables in the Server class are even holding any values to be honest, and I am unsure of how to fix this. I'm kind of lost, and really need some help. Thank you very much :)
I made a client-server application where the server has to send a list of emails to the client, which after load that into a ListView gives the possibility, through a menuBar, to delete them. In the client all these operations are made in the Data Model (I followed the MVC pattern). This is the server:
class ThreadedEchoHandler implements Runnable {
private Socket incoming;
private String nomeAccount = "";
public void run() {
try {
incoming = s.accept();
} catch (IOException ex) {
System.out.println("Unable to accept requests");
}
contenutoTextArea.append("Connected from: " + incoming.getLocalAddress() + "\n");
textarea.setText(contenutoTextArea.toString());
try {
//PHASE 1: The server receives the email
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
nomeAccount = in.readLine();
} catch (IOException ex) {
System.out.println("Not works");
}
//PHASE 2: I'm getting all the emails from the files
File dir = new File("src/server/" + nomeAccount);
String[] tmp = new String[100];
int i = 0;
for (File file : dir.listFiles()) {
if (file.isFile() && !(file.getName().equals(".DS_Store"))) {
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
tmp[i++] = line;
}
} catch (IOException ex) {
System.out.println("Cannot read from file");
}
}
}
//PHASE 3: The server sends the ArrayList to the client
PrintWriter out = new PrintWriter(incoming.getOutputStream(), true);
for (int j = 0; j < i; j++) {
out.println(tmp[j]); // send the strings to the client
}
} catch (IOException ex) {
System.out.println("Cannot send the strings to the client");
}
//PHASE 4: Here I loop and wait for the client choise
BufferedReader in;
String op;
try {
in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
while ((op = in.readLine()) != null) {
if (op.equals("Elimina")) {
String tmp = in.readLine();
File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
file.delete();
} else if (op.equals("Invia")) {
//...
} else {
//...
}
}
} catch (IOException ex) {
System.out.println("Non so");
} finally {
try {
incoming.close();
} catch (IOException ex) {
System.out.println("Cannot closing the socket");
}
}
}
}
These are the methods of the client:
public void loadData() throws IOException, ClassNotFoundException, ParseException {
try {
s = new Socket("127.0.0.1", 5000);
ArrayList<Email> email = new ArrayList<Email>();
DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date data;
/* PHASE 1: The client sends a string to the server */
//try {
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println(account); // send the account name to server
/* PHASE 2: The client receives the ArrayList with the emails */
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
String message[] = new String[5];
for (int j=0; (line = in.readLine()) != null;) {
message[j++] = line;
if (j==5) {
data = format.parse(message[3]);
email.add(new Email((Integer.parseInt(message[0])), message[1], account, message[2], message[4], data));
j=0;
}
}
//Casting the arrayList
emailList = FXCollections.observableArrayList(email);
//Sorting the emails
Collections.sort(emailList, (Email o1, Email o2) -> {
if (o1.getData() == null || o2.getData() == null) {
return 0;
}
return o1.getData().compareTo(o2.getData());
});
/*} finally {
s.close();*/
//}
} catch (SocketException se) {
emailList.setAll(null, null);
}
}
public void deleteMail(Email da_elim) throws IOException {
int id_del = da_elim.getID();
emailList.remove(da_elim);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("Elimina");
out.println(id_del);
}
The PHASE 1, 2, 3 of the Server are for the upload of the emails, and work with the loadData() method. Without the PHASE 4 the program works. Now, if I write that loop, the GUI of the client doesn't load and I cannot press on the DELETE button (which should make the input to innescate something (in this the elimination of the file) into that loop. Why the client doesn't load even if they are two different threads? And why without that loop it works?
EDIT: with the Listener class implemented but still doesn't works
//PHASE 4: Here I loop and wait for the client choise
BufferedReader in;
String op;
try {
in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
/*while ((op = in.readLine()) != null) {
System.out.println("OP: " + op);
if (op.equals("Elimina")) {
String tmp = in.readLine();
contenutoTextArea.append("Ho eliminato la mail ").append(tmp).append(" \n");
textarea.setText(contenutoTextArea.toString());
File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
file.delete();
}
}*/
Listener lis = new Listener(in, new LinkedBlockingQueue<String>());
lis.run();
System.out.println("bbbbb");
} catch (IOException ex) {
System.out.println("Unable to read messages");
} finally {
try {
incoming.close();
} catch (IOException ex) {
System.out.println("Cannot close the socket");
}
}
I think you should run jvisualvm (it's a tool installed with jdk in /bin/ location of your jdk) and look for that Thread lifecycle you create on server. Also check if your Thread don't go through the code and just ends his life skipping waiting for client.
Is this Thread somehow connected with client? Because you cannot run client App. Are they separated? Another think that came to my mind is using
Platform.runLater(()->{
});
if your client GUI is in JavaFX. Use it if you are creating GUI, changing values in fields and anything you do on your GUI. Maybe your server is waiting for user response and after that GUI is built? Which causes that you can't press DELETE button.
I'm not currently able to comment, so I can't ask for clarification, but I think I'm correctly interpreting what's wrong. "The program hangs when it enters a loop that waits for input from two controllers". Assuming I got that part right, the most likely culprit would be that buffered reader is hanging indefinitely because its not receiving input. When I first ran into this issue, I threw it inside its own "receiver" class and used a Queue to bus over anything it received to a loop in my main class. my code looked something like this:
import java.io.BufferedReader;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
public class Listener implements Runnable
{
private BufferedReader br;
private BlockingQueue<String> q;
private boolean shouldClose = false;
public Listener(BufferedReader br, BlockingQueue<String> q)
{
this.q = q;
this.br = br;
}
public void run()
{
loop();
System.out.println("listener has stopped");
}
public void loop()
{
String line = "";
try
{
while((line = br.readLine()) != null && !shouldClose)
{
q.put(line);
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
}
public void shutdown()
{
shouldClose = true;
}
}
apologies if I've misunderstood in any way, or missed something in your code.
I'm trying to make a server/client to send text from client to server then sending back an ok message or something similar back to the client, but for some error that I can't see, either the server gets stuck right before sending the ok back to the client, or the client does not receive the message (I think it's the first one though).
Any help is appreciated.
This is the server code:
class ActiveServer extends Thread {
InputStream inStream;
OutputStream outStream;
public ActiveServer(InputStream inStream, OutputStream outStream) {
this.inStream = inStream;
this.outStream = outStream;
}
#Override
public void run() {
boolean ret = false;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
PrintWriter writer = new PrintWriter(outStream);) {
String line = null;
while((line = reader.readLine()) != null) {
String[] str = line.split(";");
line = null;
switch (str[0]) {
case "insert" : //ret = SQLOptions.insert(str[1], str[2]);
System.out.println(str[1]);
break;
}
writer.print(ret);
writer.flush();
// As far as i can see it gets stuck at the end of this while, but I don't know why.
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Server {
private static final int PORT = 39165;
public static void main(String[] args) {
try (ServerSocket server = new ServerSocket(PORT);) {
System.out.println("Servidor online");
ExecutorService service = Executors.newFixedThreadPool(10);
while (true) {
Socket client = server.accept();
InetAddress ip = client.getInetAddress();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
Date time = new Date();
System.out.print(sdf.format(time));
System.out.println(" " + ip + " connected");
InputStream inStream = client.getInputStream();
OutputStream outStream = client.getOutputStream();
service.execute(new ActiveServer(inStream,outStream));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here goes the client code:
public class Telnet {
static Console console = System.console();
public static void connect(String ip, String port) {
try(Socket socket = new Socket(ip, Integer.parseInt(port));
PrintWriter writer = new PrintWriter(socket.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));) {
String msg = null;
while(true) {
msg = console.readLine();
writer.println(msg);
writer.flush();
if (msg.equals(".quit")) {
System.out.println("Exiting...");
break;
}
String input = reader.readLine();
System.out.println(input);
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
if(args.length < 2) {
err.println("Telnet <ip> <port>");
return;
}
if (console == null) {
err.println("A console is not available");
return;
}
connect(args[0], args[1]);
}
}
On the server side, you write the response without a terminating newline:
writer.print(ret);
But on the client side, you read until the end of line:
String input = reader.readLine();
The documentation for BufferedReader#readLine says:
Reads 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.
Thus, the client will wait forever for the newline sequence which the server will never send.
I've written some serverside socket handling code and I'm concerned that potentially my packets are not always making it back to the client. I am logging all my events and in my log files it says I am sending the information. But the client is also logging events and in their logs they say they do not receive anything.
My code to send the data is as follows:
public void write(Packet packet) {
String data = packet.serialize();
log("Send=[" + data + "]", "Write"); // log to file
try {
_writer.write(data);
_writer.flush();
} catch (Exception ex) {
log(ex, "write");
}
}
Each socket is created on a new thread and I create my writers and readers immediately like so (in the public run method):
// _sockt is a Java Socket object
_writer = new BufferedWriter(new OutputStreamWriter(_socket
.getOutputStream()));
_reader = new SocketReader(_socket);
SocketReader is just a wrapper class I created for listening for responses and has a public read method like so:
public String read() throws IOException, SocketTimeoutException {
_socket.setSoTimeout(_timeOut);
if(_reader == null)
_reader = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
// read from the stream
return new PacketDataInputStream(_reader).read();
}
The PacketDataInputStream wrapper class:
BufferedReader _reader = null;
public PacketDataInputStream(BufferedReader reader)
{
_reader = reader;
}
public String read() throws IOException, SocketException {
StringBuilder builder = new StringBuilder();
int c = 0;
while((c = _reader.read()) != -1)
{
char ch = (char)c;
builder.append(ch);
if(ch == PacketConstants.ETX)
break;
}
if(builder.length() > 0)
return builder.toString();
else
return null;
}
The way I'm creating the actual socket listener objects is pretty standard I think:
InetAddress address = InetAddress.getByName(IP);
server = new ServerSocket( port, 0, address);
// My own manager class to handle all the sockets connected
WebSocketManager manager = new WebSocketManager(this);
Socket connection = null;
while(bContinue)
{
connection = server.accept();
if(bContinue) {
// assign the socket to a new thread and start
// that thread
manager.newSocket(connection);
} else {
connection.close();
}
}
Is is possible that I'm using the wrong objects for sending the data back.
Should I even be using a bufferedwriter and reader? I had thought that these were the best way to go but now I'm not so sure.
It's important to note that this does not happen all the time, just sporadically. It could be the clients code having bugs but I need to make sure that I'm doing it correctly before going back to them.
This code is run on a Linux Ubuntu server. Logging occurs to a text file, nothing special there. My log files show the Send="" data going back to the client and no exception so it appears as if the .write and .flush() worked? Socket connections are persistant and only closed by the client and or network issues.
UPDATE ----- Client Side code -------:
I did manage to get some of the client side code for how they are handling the send and receiving of data (just in case it's more obvious on their end). The client is actually connecting to this server via an Android device (if that helps).
Creation of socket
static final int BUFFER_SIZE = 20000; // Maximum packet size
java.net.InetAddress server = java.net.InetAddress.getByName(url);
socket = new Socket(server, port);
// Set socket options:
socket.setReceiveBufferSize(BUFFER_SIZE);
socket.setSendBufferSize(BUFFER_SIZE);
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
Sending:
try {
// Send the packet:
OutputStream stream = socket.getOutputStream();
stream.write(p.getByteArray ());
stream.flush();
// Update the time:
lastPacketSendTime = new Date ();
} catch (IOException e) {
setError("Error sending packet (" + e.getMessage() + ")", ERROR_IO);
return false;
}
Receiving:
socket.setSoTimeout(timeout);
// Get the reader:
inputStream = socket.getInputStream();
while (true) {
// Get the next character:
int value = inputStream.read();
// Check for -1, indicating that the socket is closed:
if (value == -1) {
// The socket is closed remotely, so close it locally as well:
disconnect();
inputStream = null;
return null;
}
// ... and a bunch of other stuff to handle the actual data
}
EDIT 14-Nov:
This is actually proving to be more of a problem now. Both the client logs and the server logs appear to be sending. But at times the data doesn't appear to come through or if it does it is sometimes coming through 10 - 30 - 60 second delayed.
I can provide more information if required.
When you use BufferedReaders and BufferedWriters things get buffered. How about using the input and output streams directly.. Also, writers are character based, I don't know if you need to send binary data but if so that will be a problem with writers.
I am not sure whether this will be to your any use or not.. but i am giving you the code i used for client server communication..
Client Side:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket("127.0.0.1", 4444);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server Code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}