I am trying to implement multi threading with a client/server program I have been working on. I need to allow multiple clients to connect to the server at the same time. I currently have 4 classes: a Client, a Server, a Protocol and a Worker to handle the threads. The following code is what I have for those classes:
SocketServer Class:
public class SocketServer {
public static void main(String[] args) throws IOException {
int portNumber = 9987;
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
Thread thread = new Thread(new ClientWorker(clientSocket));
thread.start(); //start thread
String inputLine, outputLine;
// Initiate conversation with client
Protocol prot = new Protocol();
outputLine = prot.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = prot.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("quit"))
break;
}
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
SocketClient Class:
public class SocketClient {
public static void main(String[] args) throws IOException
{
String hostName = "localhost";
int portNumber = 9987;
try (
Socket socket = new Socket(hostName, portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
) {
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
System.out.println("Server: " + fromServer);
if (fromServer.equals("quit"))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + hostName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " +
hostName);
System.exit(1);
}
}
}
Protocol Class:
public class Protocol {
private static final int waiting = 0;
private static final int sentPrompt = 1;
private int status = waiting;
public String processInput(String theInput) {
String theOutput = null;
if (status == waiting) {
theOutput = "Please enter what you would like to retrieve: 'customer' or 'product' ";
status = sentPrompt;
}
else if ( status == sentPrompt ) {
if ( theInput.equalsIgnoreCase("product")) {
File f = new File("product.txt");
Scanner sc = null;
try {
sc = new Scanner(f);
} catch (FileNotFoundException ex) {
Logger.getLogger(Protocol.class.getName()).log(Level.SEVERE, null, ex);
}
while ( sc.hasNextLine() ) {
String line = sc.nextLine();
theOutput = "The current product entries are : " + line;
}
return theOutput;
}
else if ( theInput.equalsIgnoreCase("customer")) {
File f = new File("customer.txt");
Scanner sc = null;
try {
sc = new Scanner(f);
} catch (FileNotFoundException ex) {
Logger.getLogger(Protocol.class.getName()).log(Level.SEVERE, null, ex);
}
while ( sc.hasNextLine() ) {
String line = sc.nextLine();
theOutput = "The current customer entries are : " + line;
}
return theOutput;
}
else if ( theInput.equalsIgnoreCase("quit")) {
return "quit";
}
else {
return "quit";
}
}
return theOutput;
}
}
The ClientWorker Class:
public class ClientWorker implements Runnable {
private final Socket client;
public ClientWorker( Socket client ) {
this.client = client;
}
#Override
public void run() {
String line;
BufferedReader in = null;
PrintWriter out = null;
try {
System.out.println("Thread started with name:"+Thread.currentThread().getName());
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.out.println("in or out failed");
System.exit(-1);
}
while (true) {
try {
System.out.println("Thread running with name:"+Thread.currentThread().getName());
line = in.readLine();
//Send data back to client
out.println(line);
//Append data to text area
} catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
}
When I run the server and client, everything works fine as expected. Then when I try to run another client, it just hangs there and does not prompt the client to give a response. Any insight into what I am missing is greatly appreciated!
Your server code should address implement below functionalities.
Keep accepting socket from ServerSocket in a while loop
Create new thread after accept() call by passing client socket i.e Socket
Do IO processing in client socket thread e.g ClientWorker in your case.
Have a look at this article
Your code should be
ServerSocket serverSocket = new ServerSocket(portNumber);
while(true){
try{
Socket clientSocket = serverSocket.accept();
Thread thread = new ClientWorker(clientSocket);
thread.start(); //start thread
}catch(Exception err){
err.printStackTrace();
}
}
How many times does serverSocket.accept() get called?
Once.
That's how many clients it will handle.
Subsequent clients trying to contact will not have anybody listening to receive them.
To handle more clients, you need to call serverSocket.accept() in a loop.
Related
I am trying to implement a simple client-server application in Java.
Here is the code:
Client.java
public class Client implements Runnable {
private String hostName;
private int portNumber;
private String message;
private Socket socket;
private PrintWriter writer;
private BufferedReader reader;
public Client(String hostName, int portNumber, String message) {
this.hostName = hostName;
this.portNumber = portNumber;
this.message = message;
}
public void connect() {
try {
socket = new Socket(hostName, portNumber);
writer = new PrintWriter(socket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer.println(message);
} catch (UnknownHostException e) {
System.err.println("Could not resolve the host name '" + hostName + "'.");
} catch (IOException e) {
System.err.println("Could not get the I/O for the connection to '" + hostName + "'.");
}
}
private void listenForMessages() {
while (true) {
try {
System.out.println("In loop!");
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
public void run() {
connect();
listenForMessages();
}
}
Server.java
public class Server implements Runnable {
private int portNumber;
private String message;
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter writer;
private BufferedReader reader;
public Server(int portNumber, String message) {
this.portNumber = portNumber;
this.message = message;
}
private void listen() {
try {
serverSocket = new ServerSocket(portNumber);
} catch (IOException e) {
System.err.println(e.getMessage());
}
while (true) {
try {
clientSocket = serverSocket.accept();
writer = new PrintWriter(clientSocket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
writer.println(message);
} catch (IOException e) {
System.err.println(e.getMessage());
break;
}
}
}
public void run() {
listen();
}
}
And this is the main class:
public class Test {
public static void main(String[] args) {
Client client = new Client("localhost", 4444, "Hello from client!");
Server server = new Server(4444, "Hello from server!");
Thread serverThread = new Thread(server);
serverThread.start();
Thread clientThread = new Thread(client);
clientThread.start();
}
}
The logic of the code is simple: both the client and the server are waiting for messages inside a while(true) loop.
The while loop inside the server's listen method executes just fine. However, inside the listenForMessages method, the loop seems to be executed only once. I only see one "In loop" printed on the screen.
Can you figure out what the problem is?
Thank you in advance!
However, inside the listenForMessages method, the loop seems to be
executed only once. I only see one "In loop" printed on the screen.
Actually it is not because the loop is executed only once it is simply because reader.readLine() will make the current thread wait until it receives an entire line and here if you check the code of the Server, it reads first and it reads in an infinite loop as reader.readLine() will only return null at the end of the stream so when the socket will be closed in this case.
If you want to implement some kind of ping-pong between the client and the server, simply read then write on one side and write and read and the other side as next:
Client code:
public void connect() {
try {
socket = new Socket(hostName, portNumber);
writer = new PrintWriter(socket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Could not resolve the host name '" + hostName + "'.");
} catch (IOException e) {
System.err.println(
"Could not get the I/O for the connection to '" + hostName + "'."
);
}
}
private void listenForMessages() {
while (true) {
try {
System.out.println("In loop!");
// Write the message for the server
writer.println(message);
// Read the message from the server
System.out.println(reader.readLine());
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
Server code:
while (true) {
try {
clientSocket = serverSocket.accept();
writer = new PrintWriter(clientSocket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while (true) {
// Read the message from the client
System.out.println(reader.readLine());
// Write the message for the client
writer.println(message);
}
} catch (IOException e) {
System.err.println(e.getMessage());
break;
}
}
Output:
In loop!
Hello from client!
Hello from server!
In loop!
Hello from client!
Hello from server!
...
There are many tutorials where explains about socket server/client sides, but all them are very trivial. Is there any tutorial for production ready code? I'm new in sockets. There is a client, that sends strings to server. I must create the server side. in server side I read string from client and after some manipulation saves them in db. I must response to client only IF I get string like "Error" for example. and if there are no any daya from client in 30 secs, I must close client connection, but server side must works. this is my test Client side:
public class ClientSideSocket2 {
public static void main(String[] args) {
String serverName = "localhost";
int port = 5555;
String line = "";
Socket client = null;
try {
System.out.println("Connecting to " + serverName + " on port " + port);
client = new Socket(serverName, port);
System.out.println("Just connected to " + client.getRemoteSocketAddress());
PrintWriter toServer = new PrintWriter(client.getOutputStream(), true);
BufferedReader fromServer = new BufferedReader(new InputStreamReader(client.getInputStream()));
List<String> messages = new ArrayList<>();
for (int i = 0; i < 6; i++) {
messages.add("Message " + i+1);
}
messages.add("abc");
for (int i = 0; i < messages.size(); i++) {
toServer.println(messages.get(i));
if ((line = fromServer.readLine()) != null) {
System.out.println("Responce from server: " + line);
}
}
toServer.close();
fromServer.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
and my server side:
public class TRSServerInterface implements Runnable {
private ServerSocket serverSocket = null;
private Socket socket = null;
boolean runner = true;
String message = "";
public TRSServerInterface() {}
#Override
public void run() { // default run method of Thread class and Runnable interface
try {
int serverPort = 5555;
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) {
System.out.println("Waiting for connection...");
socket = serverSocket.accept();
System.out.println("Connected to " + socket.getRemoteSocketAddress());
//get the input and output streams
PrintWriter toClient = new PrintWriter(socket.getOutputStream(), true);
BufferedReader fromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do {
message = fromClient.readLine();
System.out.println("From client > " + message);
if (message.equals("abc")) {
toClient.println("Message from server");
}
else {
toClient.println("");
}
} while (!message.equals(""));
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
// try {
// objectOut.close();
// objectIn.close();
// socket.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
is my solution corrent and how I can close connection with client if there are no any data in 30 secs.
There are several production ready frameworks that should be used instead of rolling your own. Socket timeouts can be used to control how long different operations are allowed to take before an exception is thrown.
Right now my server only can handle one client at a time. I am trying to use a Thread so that the server can handle several clients, but I am doing it wrong. I have added the thread in the try/catch clause where the serverSocket accepts the client, but this makes no difference. I don't get an error or anything, but it just doesn't work.
So what I want to do, is make the server not freeze at one client, but still accept several clients.
Here is the server code:
import java.io.*;
import java.net.*;
public class Server {
private BufferedReader reader;
private PrintWriter writer;
private int port;
public Server(int port)
{
this.port = port;
}
private String getSeverAddress() {
String host = null;
try {
InetAddress adr = InetAddress.getLocalHost();
host = adr.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return host;
}
public void startServer() {
print("Contact this sever on address: " + getSeverAddress() + " port: " + port);
ServerSocket ss = null;
Socket socket = null;
Thread clientThread = null;
try {
ss = new ServerSocket(port);
socket = ss.accept();
clientThread = new Thread(new Client(socket));
clientThread.start();
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
String msg = null;
while (( msg = reader.readLine()) != null) {
print("System out: " + msg);
if(msg.equals("Bye")) {
print("Client left");
break;
}
}
ss.close();
socket.close();
reader.close();
writer.close();
} catch(SocketException e) {
e.printStackTrace();
} catch (IOException i ) {
i.printStackTrace();
return;
}
}
private void print(String msg) {
System.out.println(msg);
}
public static void main(String[] args) {
Server server = new Server(1111);
server.startServer();
}
}
Here is the client code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client implements Runnable{
private Socket client;
private BufferedReader reader;
private PrintWriter writer;
public Client(Socket socket)
{
client = socket;
try{
reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
writer = new PrintWriter(client.getOutputStream(), true);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
#Override
public void run() {
String msg = null;
BufferedReader r = null;
try {
r = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e1) {
e1.printStackTrace();
}
System.out.println("Write message to server");
while(true) {
try {
msg = r.readLine();
if(msg.equals("Quit") || msg == null) {
print("Disconnect");
break;
}
} catch (IOException e) {
e.printStackTrace();
}
writeToServer(msg);
}
try {
r.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeToServer(String msg) {
writer.println(msg);
}
private void print(String msg) {
System.out.println(msg);
}
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("localhost", 1111);
} catch (Exception e) {
e.printStackTrace();
}
Client client = new Client(socket);
client.run();
}
}
You are still trying to handle clients in your main thread. Main thread should just accept new connections and start new threads. You also have to do accept in a loop so multiple connections can be accepted:
ss = new ServerSocket(port);
while(true) {
Socket socket = ss.accept();
Thread clientThread = new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
String msg = null;
while (( msg = reader.readLine()) != null) {
print("System out: " + msg);
if(msg.equals("Bye")) {
print("Client left");
break;
}
}
socket.close();
reader.close();
writer.close();
}});
clientThread.start();
}
You need to put your ss.accept() into a while loop and create a new Thread for every client accepted, which handles the connection.
I have two Java applications, where an Android client connects to a server on a computer and sends a message using BufferedWriter over websockets.
The client:
try {
toast("Sending...");
Socket sock = new Socket(ip, PORT);
OutputStream os = sock.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.flush();
bw.write("Hello Server!");
toast("Connected!");
} catch (UnknownHostException e) {
toast(e.getMessage());
} catch (IOException e) {
toast(e.getMessage());
}
The server:
public static void main(String[] args) {
ServerSocket server;
ConnectionThread ct;
Socket s;
ExecutorService es = Executors.newSingleThreadExecutor();
try {
System.out.println("Starting server...");
server = new ServerSocket(1337);
s = server.accept();
ct = new ConnectionThread(s);
es.execute(ct);
} catch (IOException ex) {
ex.printStackTrace();
}
}
The ConnectionThread class:
public class ConnectionThread implements Runnable {
private Socket sock;
private InputStream is;
private BufferedReader br;
private boolean online;
public ConnectionThread(Socket s) {
System.out.println("Creating connection thread.");
this.sock = s;
online = true;
}
#Override
public void run() {
String input = "";
try {
System.out.println("Starting to read...");
is = sock.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while (online) {
input = br.readLine();
if(input != null){
System.out.print("Received message: ");
System.out.println(input);
}
}
br.close();
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When I run the server, and then the client, the client will show the "Connected!" toast, and the server's output will be:
Starting server...
Creating connection thread.
Starting to read...
So, it seems like the connection is actually being made, but the message does not arrive. Does anybody know why this could be happening?
Your server is expecting a complete line terminated by a newline. Try:
bw.write("Hello Server!");
bw.newLine();
Do it like this...
String s = new String();
while ((br.readLine())!=null) {
s = s+br.readLine();
System.out.print("Received message: ");
System.out.println(input);
}
}
And
bw.println("Hello Server");
I notice that you don't send an endline on your client, so the BufferedReader.readline() will never return, because it cannot match the \n-character. Try it again with
bw.write("Hello Server!\n");
on the client side.
I am making a console based java application - which will check the username and password of client. What I want is the data entered by client must enter to server in a line by line format i.e pressing enter must send username data and password for next enter press. But what the problem is - until I quit at the client side the data is not sent to the server. Meaning , when client hits 'Bye.' then the client is closed and server receives the data then. Help me in this regard as this is the first step - later I have to check database with this username and password on server. My codes are as follows :
Server :
import java.net.*;
import java.io.*;
public class EchoServer2 extends Thread
{
protected Socket clientSocket;
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2010);
System.out.println ("Connection Socket Created");
try {
while (true)
{
System.out.println ("Waiting for Connection");
new EchoServer2 (serverSocket.accept());
}
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
}
catch (IOException e)
{
System.err.println("Could not listen on port.");
System.exit(1);
}
finally
{
try {
serverSocket.close();
}
catch (IOException e)
{
System.err.println("Could not close port.");
System.exit(1);
}
}
}
private EchoServer2 (Socket clientSoc)
{
clientSocket = clientSoc;
start();
}
public void run()
{
System.out.println ("New Communication Thread Started");
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
PrintWriter out1 = new PrintWriter(clientSocket.getOutputStream(),
true);
BufferedReader in = new BufferedReader(
new InputStreamReader( clientSocket.getInputStream()));
BufferedReader in1 = new BufferedReader(
new InputStreamReader( clientSocket.getInputStream()));
String inputLine,u,p;
while ((u = in.readLine()) != null && (p = in.readLine()) != null)
{
System.out.println ("U: " + u);
out1.println(u);
System.out.println ("P: " + p);
out1.println(p);
if (u.equals("Bye."))
break;
}
out1.close();
out.close();
//in1.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
System.err.println("Problem with Communication Server");
System.exit(1);
}
}
}
Client :
import java.io.*;
import java.net.*;
import java.lang.*;
import java.io.Console;
public class EchoClient2 {
public static void main(String[] args) throws IOException {
String serverHostname = new String ("127.0.0.1");
if (args.length > 0)
serverHostname = args[0];
System.out.println ("Attemping to connect to host " +
serverHostname + " on port .");
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
BufferedReader in1 = null;
try {
echoSocket = new Socket(serverHostname, 2010);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverHostname);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: " + serverHostname);
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
BufferedReader std = new BufferedReader(
new InputStreamReader(System.in));
String upwd,uname,text;
Console console = System.console();
String username = console.readLine("Username:");
char[] pwd = console.readPassword("Password:");
upwd=new String(pwd);
while (username!=null && upwd!=null && (uname = stdIn.readLine()) != null)
{
out.println("Username:"+username);
out.println("Password:"+upwd);
// end loop
if (uname.equals("Bye."))
break;
}
out.close();
stdIn.close();
echoSocket.close();
}
}
On the client side, do out.flush() after writing the password to the stream.