I am trying to implement a simple java server and client - where client sends "hey" and server sends "hello" back. The problem I am having is even though the server sees hey but client never receives hello.
Here is the server code
try {
InputStream input = clientSocket.getInputStream();
System.out.println("client's request"+ IOUtils.toString(input));
OutputStream output = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(output);
pw.write("hello");
pw.flush();
/*BufferedOutputStream bf = new BufferedOutputStream(output);
bf.write("hello".getBytes());*/
/*output.write(("hello").getBytes());*/
long time = System.currentTimeMillis();
System.out.println("Request processed: " + time);
}
catch (IOException e)
{
// report exception somewhere.
e.printStackTrace();
}
Client program
Socket s = new Socket("localhost",9000);
OutputStream out = s.getOutputStream();
out.write("hey".getBytes());
/*PrintWriter pw = new PrintWriter(out);
pw.write("hey");
pw.flush(); */
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
while((line =br.readLine())!= null)
{
System.out.println(line);
}
s.close();
I have different variations of reading and writing the input/output but with no luck. Suggestions please.
Thanks
This won't work. IOUtils.toString(input) will read from the input until end of stream, which won't occur until the peer closes the connection, which won't occur at all because he is blocked in readLine() trying to read the response to the request that you are blocked forever reading.
Use BufferedReader.readLine(), but without the loop you have in the client.
This
void writeLine(BufferedWriter writer, String text) throws IOException {
writer.write(text); // the actual characters we want to send
writer.newLine(); // something that signals the end of the message.
writer.flush(); // and we must enforce that these bytes are sent and not buffered locally.
}
can be read by
String readLine(BufferedReader reader) throws IOException {
// reads characters until it finds either a newline or end of stream
// returns data or null when the stream has already ended
return reader.readLine();
}
When you send messages over sockets you must make sure that you have some kind of "protocol" to delimit your messages. For example by sending a newline after each message. That way both sides know where messages in a continuous stream of data ends.
Besides sending the right kind message, you also have to make sure to actually send it. BufferedWriter for example has a data-buffer and will not send data until the buffer is full enough. This will in most cases mean that messages will remain in the buffer instead of being sent over the wire. To do that call flush() once you have written everything you need.
I have different variations of reading and writing the input/output but with no luck.
In your case you don't send a newline but wait for it via readLine. The client should have actually received the "hello" part but it's not going to return from readLine without newline/end of stream (which should happen if you stop the server at this point). The same should apply to the message you send to your server but I guess you do kill the client at this point and therefore see the message.
Here is also the code I made while playing around with this
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
class Hello {
static int port = 12345;
private static void writeLine(BufferedWriter writer, String line) throws IOException {
System.out.println(">> " + line);
writer.write(line); // the actual characters that we want to send
writer.newLine(); // something that signals the end of the message.
writer.flush(); // and we must enforce that these bytes are sent and not buffered locally.
}
private static String readLine(BufferedReader reader) throws IOException {
// reads characters until it finds either a newline or the end of the stream
// returns data or null when the stream has already ended
return reader.readLine();
}
static void handle(Socket cs, boolean controlling) {
try (Socket socket = cs) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
if (controlling) {
writeLine(writer, "hey");
}
loop: while (!Thread.currentThread().isInterrupted()) {
String readLine = readLine(reader);
System.out.println("<< " + readLine);
if (readLine == null)
break;
switch (readLine) {
case "hey":
writeLine(writer, "ho");
break;
case "ho":
writeLine(writer, "bye");
break;
case "bye":
break loop;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
static void server(CountDownLatch latch) {
try (ServerSocket ss = new ServerSocket(port)) {
System.out.println("Listening.");
latch.countDown();
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = ss.accept();
// spawn a new thread per client
new Thread(() -> handle(clientSocket, false)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static void client() {
System.out.println("Connecting.");
try (Socket socket = new Socket("localhost", port)) {
System.out.println("Connected.");
handle(socket, true);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> server(latch)).start();
latch.await();
new Thread(() -> client()).start();
}
}
Related
I've created a single threaded server but turn around times are slow when processing multiple requests, how would i implement multithreading into this? I've attempted a few ways but it tehy alwasy have issues such as only being able to accept a single client or only taking commands from the first client that joined the server.
`
import java.net.*;
import java.io.*;
public class SocketServer {
public static void main(String[] args) {
if (args.length < 1)
return; // minimum length
int port = Integer.parseInt(args[0]); // set port
SocketServer.start(port);
}
public static void start(int port) {
// initialize server sockets and accept connection
try (ServerSocket serverSocket = new ServerSocket(port);) {
System.out.println("Server is listening on port " + port);
while (true) {
Socket socket = serverSocket.accept();
System.out.println("New client connected");
// read data from client
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input)); // buffered reader for strings
// send data to client
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true); // sends data in text format, the true in autoflush
// clears data after each call
String text;
//
do {
text = reader.readLine(); // reads text from client
Process p = Runtime.getRuntime().exec(text);
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
String outputLine;
while ((outputLine = stdout.readLine()) != null) { // while serverMsg is not empty keep printing
writer.println(outputLine);
}
stdout.close();
writer.println("ENDCMD");
// Text here should just write back directly what the server is reading...?
}
while (!text.toLowerCase().equals("exit"));
// close
System.out.println("Connection Terminated.");
socket.close(); // closes connection with client
serverSocket.close();
}
} catch (IOException ex) // catch server exception and prints it
{
System.out.println("Encountered an exception, connection terminated.");
} catch (NullPointerException e) {
System.out.println("Encountered an exception, connection terminated.");
}
}
}
`
I did an experiment and I created a program with 2 threads: a server thread and a client thread.
The server thread accepts a connection from the client, does a long process (emulated by sleep()), and prints the result.
The client on the other hand sends messages really fast.
See the code:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTest {
public static void main(String[] args) throws InterruptedException {
Thread serverThread = new Thread(() -> server());
Thread clientThread = new Thread(() -> client());
serverThread.start();
clientThread.start();
serverThread.join();
clientThread.join();
}
private static void server() {
try (
ServerSocket listener = new ServerSocket( 1234 );
Socket client = listener.accept()){ // wait for connection
while (true) {
InputStream in = client.getInputStream();
// read a newline or carriage-return-delimited string
BufferedReader bin =
new BufferedReader( new InputStreamReader( in ) );
String someString = bin.readLine();
//process
Thread.sleep(1000);
System.out.println(someString);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void client () {
try (Socket server = new Socket(InetAddress.getLocalHost(), 1234))
{
while (true) {
OutputStream out = server.getOutputStream();
// write a newline or carriage return delimited string
PrintWriter pout = new PrintWriter(out, true);
pout.println("Hello!");
// send the the string
pout.flush();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I ran the program I got the following output:
Hello!
Hello!
llo!
o!
ello!
lo!
!
Hello!
llo!
o!
ello!
lo!
!
Hello!
llo!
o!
ello!
lo!
!
Hello!
llo!
o!
ello!
...
Now I am not sure I understand it 100%...
But I did run the experiment of using an input the size of a power of 2 (including /n) and the output was not cut off.
Can someone explain to me:
What's going on internally?
Why no error is thrown?
What would you do to overcome this problem?
Thanks!!
private static void server() {
...
while (true) {
InputStream in = client.getInputStream();
// read a newline or carriage-return-delimited string
BufferedReader bin =
new BufferedReader( new InputStreamReader( in ) );
String someString = bin.readLine();
This creates a new BufferedReader for each run of while loop. But readline will not only read a line from the socket. It will instead read a larger amount of data, check if there is a line end in it, read more if no line end yet etc and finally return the line. The rest of the read data is kept in the BufferedReader. By implicitly abandoning the BufferedReader at the end of loop run and creating a new one at the beginning of a new loop run you abandon all data in the buffer which were already read from the socket.
Instead you should create your BufferedReader outside the loop and use it there so that no data gets abandoned:
private static void server() {
...
InputStream in = client.getInputStream();
BufferedReader bin =
new BufferedReader( new InputStreamReader( in ) );
while (true) {
// read a newline or carriage-return-delimited string
String someString = bin.readLine();
I have a situation like, I am provided with a log file that consists of Strings. What I have to do is , I need to retrieve each string from the file and pass through a Socket and when the End of the File reaches it has to go again to the beginning of the file and send again the Strings. I have written a simple code using an infinite thread that sends the strings and when the EOF comes I am closing the file and again re-opening the file using new BufferedReader object. And I am also giving a small amount of 5ms of thread sleep, but after some time my Process is entering into Pause state (Like a Dead Lock). Is there anyway to improve the speed of transfer? or else can I eliminate the Pause state.
Below is my Simple code:
public class Write extends Thread{
private static final String FileName = "Messages.txt";
private static final int port = 8080;
private final int time = 5;
ServerSocket serverSocket;
Socket writeSocket;
#Override
public void run()
{
try
{
serverSocket = new ServerSocket(port);
System.out.println("Server listening on port " + port+ " ...");
Socket writeSocket = serverSocket.accept();
System.out.println("Connected to Client : "+ writeSocket.getLocalSocketAddress());
OutputStream outStream = writeSocket.getOutputStream();
PrintWriter out = new PrintWriter(outStream, true);
BufferedReader input = new BufferedReader(new FileReader(FileName));
String str = "";
while(true)
{
str = input.readLine();
if(str==null ){
input.close();
input = new BufferedReader(new FileReader(FileName));
}
else{
System.out.println("Outgoing Message>>"+str);
out.println(str);
Thread.sleep(time);
}
}
}
catch(IOException e) {System.out.println(e); } catch (InterruptedException ex) {
Logger.getLogger(Write.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Let me give you a simple explanation. Consider the above code is in a Server code. And when I run a client machine in the same PC, I can able to send the messages at some(high) speed but after sometime, both the client and the Server are entering into a Pause state. I feel this like a Dead Lock. The client is showing like the Server is disconnected and again Connected. When I close the Client then again Server is starting. Can anyone tell me is there a way to process the strings at a very high speed?
Re the program blocking, I would suggest:
put a System.out.print("A") before out.println() and a System.out.print("B") after. If it blocks with "A" as the last message in the output, then the problem is at the client side (they're not consuming the data, causing eventually the sender to block).
If the previous situation happens, write your own simple client which just reads data from the socket and throws it away, so you can demonstrate the problem is at the other side.
Re speed, you want to remove the sleep and System.out.println.
Why not use java nio to read all lines?
https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#readAllLines-java.nio.file.Path-java.nio.charset.Charset-
Or is the file too big to do this?
your code that reads the log file is just fine. no need to make it faster. see below (I commented the parts of the code that deal with the socket and the code works well at reading the log file multiple times. there is no sign of slowing down or deadlocks) :
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Write extends Thread {
private static final String FileName = "/tmp/Messages.txt";
private static final int port = 8080;
private final int time = 5;
ServerSocket serverSocket;
Socket writeSocket;
public static void main(String[] args) {
Write write = new Write();
Thread thread = new Thread(new Write());
thread.start();
}
#Override
public void run() {
try {
// serverSocket = new ServerSocket(port);
// System.out.println("Server listening on port " + port + " ...");
// Socket writeSocket = serverSocket.accept();
// System.out.println("Connected to Client : " + writeSocket.getLocalSocketAddress());
//
// OutputStream outStream = writeSocket.getOutputStream();
// PrintWriter out = new PrintWriter(outStream, true);
BufferedReader input = new BufferedReader(new FileReader(FileName));
String str = "";
while (true) {
str = input.readLine();
if (str == null) {
input.close();
input = new BufferedReader(new FileReader(FileName));
} else {
System.out.println("Outgoing Message>>" + str);
//out.println(str);
Thread.sleep(time);
}
}
} catch (IOException e) {
System.out.println(e);
} catch (InterruptedException ex) {
Logger.getLogger(Write.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I am working on a web server (done), and thought I would make my own little text-based browser, the only problem is that I can't actually get the browser to read the responses. Here is the code:
import java.io.*;
import java.net.*;
class client
{
static Socket socket = null;
static BufferedReader in = null;
static PrintWriter out = null;
public static void main(String args[])
{
int fromServer;
try
{
socket = new Socket("localhost", 8001);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter( new BufferedOutputStream(socket.getOutputStream()));
out.println("GET /Library/WebServer/Documents/index.html.en HTTP/1.0");
out.flush();
while ((fromServer = in.read()) != -1)
{
System.out.write(fromServer);
System.out.flush();
}
}
catch (UnknownHostException e)
{
System.out.println("Unknown host");
}
catch (IOException e)
{
System.out.println("IO error");
}
}
}
You haven't completely finished the request. You need two newlines, as otherwise it just looks like you're still writing out the request headers.
Add an extra println and you may be okay, although as HTTP specifies CRLF for the line ending, I would actually use print rather than println, and put \r\n at the end of each line explicitly.
(I'd also avoid using PrintWriter, personally - swallowing exceptions is bad...)
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();
}
}