I have a server that communicates with a client.
The server is multithreaded, and this thread is created with the socket and a bufferedreader connected to the socket, when the first line read from the socket is "request":
public class scriptComm implements Runnable {
private Socket sock;
private Socket sock2;
private Connection connection;
private BufferedReader reader;
#Override
public void run() {
try {
String name = reader.readLine();
String password = reader.readLine();
String line;
connection = methods.connectToDatabase();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
if (connection != null && name != null && password != null) {
try {
ResultSet rs = connection.createStatement().executeQuery(
"SELECT name, password, doupdate FROM accounts "
+ "WHERE name = '" + name + "' AND doupdate = 'yes'"
+ " AND password = '" + password + "'");
if (rs.next()) {
methods.log("worked");
bw.write("accept");
bw.flush();
bw.close();
reader = new BufferedReader(new InputStreamReader(sock2.getInputStream()));
if ((line = reader.readLine()) != null) {
mainFrame.jTextArea1.append("line \n");
connection.createStatement().executeUpdate(
"UPDATE accounts SET updatetext = '" + line + "' "
+ "WHERE name = '" + name + "'");
}else{
mainFrame.jTextArea1.append("No text received \n");
}
} else {
bw.write("decline");
bw.flush();
}
bw.close();
rs.close();
} catch (SQLException ex) {
methods.log("Error when executing statement in scriptComm");
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
methods.log("missing values in scriptComm");
}
} catch (IOException ex) {
}
}
public scriptComm(Socket sock, BufferedReader reader) {
this.sock = sock;
this.sock2 = sock;
this.reader = reader;
}}
You may notice that I close the bw stream after it writes "accept".
This is due to the client simply hanging there, as if it doesn't receive any input, when the stream is not closed.
The client:
try{
String line;
Socket sock = new Socket("myipaddresshere",portnumber);
PrintWriter writer = new PrintWriter(sock.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
writer.println("script");
writer.flush();
writer.println(jTextField1.getText());
writer.flush();
writer.println(jTextField2.getText());
writer.flush();
if ((reader.readLine()).equals("accept")) {
writer.write("testing123");
writer.flush();
writer.close();
} else {
jTextArea1.append("fail");
}
reader.close();
writer.close();
}catch(IOException e){
jTextArea1.append("Server not available. Please try again later.");
}
When the stream is not closed after writing "accept" from the server, it's as if the client just sits at the if(reader.readLine().equals("accept")) boolean check ( and yes, the stream is flushed server-side ).
However, when the stream is also closed server-side, it passes the boolean check and continues on to write the line "testing123" to the stream. The server can obviously not read this line as the socket stream was closed when the BufferedReader closed. As you may notice, I tried replicating the socket by simply creating another variable called sock2, but it seems this connection closes as well (makes sense).
Note: when connecting with a wrong user/pass (i.e. when rs.next() returns false), it does write "decline" to the stream and the client gets this.
Really confused about this one..
Thanks,
Mike.
Note, a write doesn't write a newline, and you are trying to read whole lines. You need to write a newline character before you flush.
Edither use BufferedWriter.newLine() or append "\n" to the strings that you write.
I'll leave this retracted with a piece of advice:
When you want to write characters to a stream, you should always use an OutputStreamWriter and InputStreamReader with an explicit character encoding. I recommend "UTF-8".
As written, your code will both write and read with the platform-default encoding. Which will work, right up until the time you have someone in China running the client on Windows, with someone in the US running the server on Linux (and depending on what you're sending, it could break much sooner).
Related
My team is building a basic HTTP server from scratch in Java, but our reader threads block once they run out of request text to read from the socket's input stream.
A number of points unique to our situation that don't match up with questions asked previously:
We want to keep the socket open while we process the request and produce a response to send back
We don't parse the data at first, but rather, we first read it off the socket and chuck the entire thing into a recovery file. Then we begin to parse and validate from the file, to ensure that we don't lose the request in case of disaster.
The basic code:
public void readSocket() {
receivedTime = System.currentTimeMillis();
requestFile = new File("recovery/" + receivedTime + ".txt");
try(
FileWriter fw = new FileWriter(requestFile);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(fw);
)
{
String line;
while((line = in.readLine()) != null){ //TODO: this is where it blocks after reading past the last line of the request.
out.write(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
readLine() returns null only if "the end of the stream has been reached", ie the socket has been closed by the other party. When readLine() reads a line break with no preceding data, it returns a non-null String that has a length of 0. So you need to fix you while loop accordingly:
public void readSocket() {
receivedTime = System.currentTimeMillis();
requestFile = new File("recovery/" + receivedTime + ".txt");
try(
FileWriter fw = new FileWriter(requestFile);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(fw);
)
{
String line;
// read request headers...
do {
line = in.readLine();
if (line == null) return; // socket closed
out.write(line);
out.NewLine();
out.flush();
if (line.isEmpty()) break; // end of headers reached
// process line as needed...
}
while (true);
// check received headers for presence of a message
// body, and read it if needed. Refer to RFC 2616
// Section 4.4 for details...
// process request as needed...
} catch (IOException e) {
e.printStackTrace();
}
}
Also see:
While reading from socket how to detect when the client is done sending the request?
I'm implementing a small tool in Java. I have a excel document and from every sheet I need to generate a .sql file. I've created an sql file model, which I have to read from for every excel sheet then replace a value and write it back to another .sql file. The problem is I use a for where I loop through my sheets and for every sheet I need to read that sql file, modify it and export it somewhere else. I get a "Stream closed" error, and I don't know how to close my buffer and/or my InputStream properly. Can you guys help me out with this ?
This is my code:
This gets everything from the file and converts it to a String
public String getString(InputStream is) throws IOException {
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
String line;
try {
reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
sb.append(line + System.lineSeparator());
}
} catch (IOException ex) {
ex.printStackTrace();
}
return sb.toString();
}
This is used to export the file
public void exportFile(String text, String path, String name, String extension) {
BufferedWriter output = null;
try {
File sqlFile = new File(path + name + extension);
output = new BufferedWriter(new FileWriter(sqlFile));
output.write(text);
} catch (IOException e) {
e.printStackTrace();
logger.severe("Unable to write to file!\n");
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
logger.severe("Unable to close buffer\n");
}
}
}
}
And this a the part of my run() method, which uses the code above:
ClassLoader loader = this.getClass().getClassLoader();
InputStream createTableInputStream = loader.getResourceAsStream("val_table_create.sql");
if (createTableInputStream == null) {
logger.severe("No tempalte found for creating table!\n");
return;
}
List<Sheet> bookSheets = getSheets(book);
for (Sheet sheet : bookSheets) {
setHeader(table, sheet);
String exportText = getString(createTableInputStream);
exportText = exportText.replaceAll(TABLE_NAME, tableName);
// exportText = exportText.replaceAll(VAL_DATA_TYPE, valDataType);
// exportText = exportText.replaceAll(MSG_TEXT_DATA_TYPE, messageDataType);
exportFile(exportText, absoluteWorkspacePath + File.separator + outputPath + File.separator, tableName, ".sql");
}
if (createTableInputStream != null) {
createTableInputStream.close();
}
The Problem is in this method:
public String getString(InputStream is) throws IOException {
You close the the reader and stream at the end. (When you close the reader the streams in it are automatic close.
Edit: You should close the reader. getString(InputStream is) throws IOException returns always the same String or? Read it before you go in the loop and reuse the String everytime.
String exportText = getString("val_table_create.sql");
for (Sheet sheet : bookSheets) {
setHeader(table, sheet);
String newExportText = exportText.replaceAll(TABLE_NAME, tableName);
messageDataType);
exportFile(newExportText, absoluteWorkspacePath + File.separator + outputPath + File.separator, tableName, ".sql");
}
Change your getString Method to this:
public String getString(String resourceName) throws IOException {
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
String line;
try {
InputStream createTableInputStream reader.getResourceAsStream(resourceName);
reader = new BufferedReader(new InputStreamReader(is));
while ((line = reader.readLine()) != null) {
sb.append(line + System.lineSeparator());
}
} catch (IOException ex) {
ex.printStackTrace();
}
return sb.toString();
}
and close there all the streams. Now you have one place where you load your file.
createTableInputStream will be closed for the first time you call getString method so for next sheet in loop you will get stream closed.
It's a better practice to close the stream in the method who created it. You should close the stream in run method instead.
I am building a server in Java, and the input feed is giving me trouble - its current setup cannot read more than one line, and it cannot read anything without "\n" at the end. Here is the current input loop:
BufferedReader input = new BufferedReader(new InputStreamReader(serverConnection.getInputStream()));
if(input.ready()){
StringBuilder text = new StringBuilder();
String line;
while((line = input.readLine()) != null){
text.append(line);
System.out.println(line);
}
sentData = text.toString();
return true;
}
My current loop using a BufferedReader cannot read more than one line of incoming data, and if there is no newline character, a timeout exception is thrown (I programmed it to do that), and the data is not read at all. It is, of course, unacceptable to have a listener that can only see one line of data, and stalls when the sent data is not formatted properly.
So I am looking for a method that allows the program to read any number of lines, and for the program to stop reading when it has reached the end of the data stream (even without a new line).
Any help is appreciated.
You're throwing away every odd-numbered line. Remove the readLine() inside the loop.
You can read from the InputStream directly into the StringBuilder. readLine() of BufferedReader will wait for \r or \n character. This looks like stalling.
int ch;
StringBuilder text = new StringBuilder();
while((ch = serverConnection.getInputStream().read())!= -1) { // -1 will be read at EOS
text.append((char)ch);
}
sentData = text.toString();
return true;
Update
The following piece of code is to demonstrate the difference between usage of BufferedReader and InputStream to read bytes and what is available to the user during read operation. BufferedReader will always give you lines which are either terminated by line breaks or by EOS. Whereas InputStream will make the available bytes to the user.
In scenarios where it is NOT necessary to close the streams, and the bytes transferred has it's own way to mark start and end of packets/messages, you will be using InputStream to read bytes. If you try using BufferedReader for these applications, the last line of the message will be made available once the server receives the next packet/message, unless you send each line with a line-break.
public static void main(String[] args) throws Exception {
new Thread(new BufferedReaderServer()).start();
new Thread(new InputStreamServer()).start();
final String requestString = "Line#1\nLine#2";
System.out.println("\nSending to BufferedReaderServer");
Socket clientSocket1 = new Socket(InetAddress.getLocalHost()
.getHostAddress(), 8003);
OutputStream outputStream1 = clientSocket1.getOutputStream();
outputStream1.write(requestString.getBytes());
Thread.sleep(6000);
outputStream1.close();
clientSocket1.close();
Thread.sleep(1000);
System.out.println("\nSending to InputStreamServer");
Socket clientSocket2 = new Socket(InetAddress.getLocalHost()
.getHostAddress(), 8004);
OutputStream outputStream2 = clientSocket2.getOutputStream();
outputStream2.write(requestString.getBytes());
Thread.sleep(6000);
outputStream2.close();
clientSocket2.close();
}
static class BufferedReaderServer implements Runnable {
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8003);
Socket socket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String s = null;
System.out.println("BufferedReaderServer read START");
while ((s = bufferedReader.readLine()) != null) {
System.out.println(s);
}
System.out.println("BufferedReaderServer read END");
socket.getInputStream().close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
static class InputStreamServer implements Runnable {
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8004);
Socket socket = serverSocket.accept();
System.out.println("InputStreamServer read START");
int ch;
while ((ch = socket.getInputStream().read()) != -1) {
System.out.print((char) ch);
}
System.out.println("\nInputStreamServer read END");
socket.getInputStream().close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
The issue what is being faced here could be due to non-closing of client socket. Depends on the user's application
The application is a basic chat client.
I got a Thread for getting data from the server.
I want to get every response from the server separately.
It prints in the console only when the loop breaks (when i send "exit" using the other parts of the application).
So when "System.out.println" responds it prints the whole buffer at once.
How can i make it work and print every response separately?
Thank you!
EDIT!!
The server respond should include "\n" after each line,
it works for me in this way.
Without "\n" it just waits until the loop breaks.
Is there a better way to do this without the "\n" issue?
class ServerThread implements Runnable {
#Override
public void run(){
BufferedReader in = null;
Socket socket;
try
{
if (Thread.currentThread().isAlive()) {
sendString("exit");
Thread.currentThread().interrupt();}
InetAddress serverAddress = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddress, SERVER_PORT);
outr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String serverResponse;
while((serverResponse = in.readLine()) != null)
{
System.out.println(serverResponse);
}
in.close();
outr.close();
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
You're using a BufferedReader and read it with in.readLine(), which, surprise surprise, will return the next line in the response. A line is a string terminated by a newline character, so your BufferedReader will have to wait until it sees a newline until it can return your line. If you don't want to use newlines in your response, don't use readLine(), use one of the other read() methods instead.
Can someone help me in the below scenario,
I need to call a perl script from my java code. The perl script is an interactive code, which gets the input from the user during its execution and continues further to end. So, the example I have used is, the perl script when executed asks for the age by printing in the console "How old are you?", when the user enter some value say '26'. Then it prints "WOW! You are 26 years old!".
When I tried calling this script from my java code, the process waits till I give the value as 26 in the outputstream, while in the inputstream there is no value. Then finally when again I read the inputstream, i get the entire output of the script together. So, here can't I make it interactive?
I have went through many forums and blogs, but couldn't locate any, which exactly target my requirement.
Here is the java code
import java.io.*;
public class InvokePerlScript {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Process process;
try
{
process = Runtime.getRuntime().exec("cmd /c perl D:\\sudarsan\\eclips~1\\FirstProject\\Command.pl");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
out.write("23");
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
process.waitFor();
if(process.exitValue() == 0)
{
System.out.println("Command Successful");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
else
{
System.out.println("Command Failure");
try {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
catch(Exception e)
{
System.out.println("Exception: "+ e.toString());
}
}
}
Perl code is as below
$| = 1;
print "How old are you? \n";
$age = <>;
print "WOW! You are $age years old!";
Thanks in advance,
Sudarsan
Are you calling flush() on the OutputStream in Java after writing the values? If you don't, there's a good chance they'll just be held in the stream's buffer within the Java process, and so never make it to Perl (with the result that both processes end up waiting for the other's IO.)
(Depending on the implementation of the stream this may or may not be necessary, but it certainly wouldn't hurt - and I've been bitten by this in the past. Usually one doesn't need to be as careful, since flushing happens implicitly when close() is called, but here you can't close the stream after you've finished writing.)
It looks like you're trying to read a full line in this code:
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
...
However, in your perl code, you are not printing an endline character, so readLine never returns (as per the documentation).