Java application with TCP sockets is using 100% of CPU - java

The server has to continuously listen for incoming connections and perform some logic on the data received. Every time I run the application, the CPU usage is more than 90%. Earlier I thought that the while loop might be spinning (busy waiting), but the readLine() is supposed to be a blocking call, so I don't think that is the case. Any help is appreciated!
The following is the server code:
public void listen() throws IOException
{
try( ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();
DataOutputStream outputStream = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));)
{
String data = null;
while((data = bufferedReader.readLine()) != null)
{
Message message = Message.deserializeMessage(data);
synchronized (PeerNode.requestHistory)
{
if(PeerNode.requestHistory.keySet().contains(message))
{
continue;
}
}
if(message.getType() == 0 && message.getHopCount() < 1) {
continue;
}
switch(message.getType()) {
case 0:
synchronized (PeerNode.sharedRequestBuffer){
PeerNode.sharedRequestBuffer.offer(message);
}
break;
case 1:
synchronized (PeerNode.sharedReplyBuffer) {
PeerNode.sharedReplyBuffer.offer(message);
}
break;
case 2:
synchronized (PeerNode.numberOfItems) {
if(PeerNode.numberOfItems > 0) {
PeerNode.numberOfItems -= 1;
}
outputStream.writeBytes("0" + "\n");
}
break;
}
synchronized (PeerNode.requestHistory) {
PeerNode.requestHistory.put(message, 0);
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Edit: Added deserialize() method
public static Message deserializeMessage(String s)
{
Message m = new Message();
String[] objArray = s.split("#");
String[] list = objArray[2].split(",");
m.setProductName(objArray[0]);
m.setProductId(Integer.parseInt(objArray[1]));
List<Integer> tempList = new ArrayList();
for(int i=0; i<list.length; i++)
{
if(list[i].length() == 0)
continue;
tempList.add(Integer.parseInt(list[i]));
}
m.setMessagePath(tempList);
m.setHopCount(Integer.parseInt(objArray[3]));
m.setType(Integer.parseInt(objArray[4]));
m.setRequestId(Integer.parseInt(objArray[5]));
m.setSourcePeerId(Integer.parseInt(objArray[6]));
m.setDestinationSellerId(Integer.parseInt(objArray[7]));
m.setDestinationSellerLocation(Integer.parseInt(objArray[8]));
return m;
}
Edit 2: Changed deserialize() to use Scanner():
public static Message deserializeMessage(String s)
{
Message m = new Message();
Scanner sc = new Scanner(s);
sc.useDelimiter("#");
m.setProductName(sc.next());
m.setProductId(Integer.parseInt(sc.next()));
List<Integer> tempList = new ArrayList();
Scanner sct = new Scanner(sc.next());
sct.useDelimiter(",");
while(sct.hasNext())
{
tempList.add(Integer.parseInt(sct.next()));
}
m.setMessagePath(tempList);
m.setHopCount(Integer.parseInt(sc.next()));
m.setType(Integer.parseInt(sc.next()));
m.setRequestId(Integer.parseInt(sc.next()));
m.setSourcePeerId(Integer.parseInt(sc.next()));
m.setDestinationSellerId(Integer.parseInt(sc.next()));
m.setDestinationSellerLocation(Integer.parseInt(sc.next()));
return m;
}
Edit: Updated Server Code:
private ExecutorService executor = Executors.newFixedThreadPool(15);
public void listen() throws IOException
{
serverSocket = new ServerSocket(port);
while (!Thread.interrupted()) {
try
{
//Server, Listening........
clientSocket = serverSocket.accept();
ServerExecutor serverExecutor = new ServerExecutor(peerID, clientSocket);
executor.submit(serverExecutor);
}
catch (IOException e)
{
e.printStackTrace();
}
}
serverSocket.close();
}
ServerExecutor class:
public ServerExecutor(int _peerID, Socket _clientSocket)
{
this.peerID = _peerID;
this.clientSocket = _clientSocket;
}
public void run()
{
try( DataOutputStream outputStream = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));)
{
String data = null;
while((data = bufferedReader.readLine()) != null)
{
Message message = Message.deserializeMessage(data);
synchronized (PeerNode.requestHistory)
{
if(PeerNode.requestHistory.keySet().contains(message))
{
continue;
}
}
if(message.getType() == 0 && message.getHopCount() < 1) {
continue;
}
switch(message.getType()) {
case 0:
synchronized (PeerNode.sharedRequestBuffer){
PeerNode.sharedRequestBuffer.offer(message);
}
break;
case 1:
synchronized (PeerNode.sharedReplyBuffer) {
PeerNode.sharedReplyBuffer.offer(message);
}
break;
case 2:
synchronized (PeerNode.numberOfItems) {
if(PeerNode.numberOfItems > 0) {
PeerNode.numberOfItems -= 1;
}
outputStream.writeBytes("0" + "\n");
}
break;
}
synchronized (PeerNode.requestHistory) {
PeerNode.requestHistory.put(message, 0);
}
}
clientSocket.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Updated deserialize():
public static Message deserializeMessage(String s)
{
Message m = new Message();
Scanner sc = new Scanner(s);
sc.useDelimiter("#");
m.setProductName(sc.next());
m.setProductId(sc.nextInt());
List<Integer> tempList = new ArrayList();
Scanner sct = new Scanner(sc.next());
sct.useDelimiter(",");
while(sct.hasNext())
{
tempList.add(sct.nextInt());
}
m.setMessagePath(tempList);
m.setHopCount(sc.nextInt());
m.setType(sc.nextInt());
m.setRequestId(sc.nextInt());
m.setSourcePeerId(sc.nextInt());
m.setDestinationSellerId(sc.nextInt());
m.setDestinationSellerLocation(sc.nextInt());
return m;
}

Are you using different thread for each new client connection and also this kinda code will never occupy such a high % of CPU load. Is there some other functionality that's running in the background as well?
Edit:
Maybe you can try something like this?
while (true)
{
Socket s = null;
ServerSocket serverSocket = new ServerSocket(5555);
try
{
s = ss.accept(); //ss is the server socket object
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader int = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//create a new Thread for the client
Thread t = new TaskHandler(s, in, out); //run method of Task Handler can have the code you want to execute for each connected client
t.start();
}
catch (Exception e){
s.close();
e.printStackTrace();
}
}
Does this help?

Related

Socket client blocks forever

I'm coding socket client in Java.
In the program, I want to get information from server.
When the server receives "GET_LIGHTS" command, it sends back data in JSON format.
But in my code, bw.write() and bw.flush() doesn't work before socket.close().
So, the BufferedReader object is not ready: br.ready() returns false.
Is there any mistake in my code?
The client code is shown bellow.
package monitor;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
public class SocketClient {
static private int port;
static private String hostName;
private Socket socket;
public SocketClient(String host, int port) {
this.hostName = host;
this.port = port;
}
// get lights by JSON
public void getLights() {
try {
// generate socket
InetSocketAddress endpoint = new InetSocketAddress(hostName, port);
socket = new Socket();
socket.connect(endpoint);
// setting
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
BufferedWriter bw = new BufferedWriter(out);
InputStreamReader in = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(in);
// send command
bw.write("GET_LIGHTS");
bw.flush();
// receive message from server
System.out.println(br.readLine());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void initLights(ArrayList<Light> lights) {
getLights();
}
}
Edited:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class SocketServer extends Thread{
static final int PORT = 44344;
static private ILS ils;
private ServerSocket serverSocket;
private Socket socket;
public SocketServer(ILS ils) {
this.ils = ils;
}
#Override
public void run() {
serverSocket = null;
System.out.println("Server: listening");
try {
serverSocket = new ServerSocket(PORT);
while(true){
socket = serverSocket.accept();
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
ArrayList<String> cmd = new ArrayList<>();
String in;
while( (in = br.readLine()) != null ){
cmd.add(in);
}
command(cmd);
if( socket != null){
socket.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
if( serverSocket != null){
try {
serverSocket.close();
serverSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
// send message to client
private void sendMessage(String str) {
System.out.println(str);
try {
OutputStream output = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(output));
bw.write(str + "¥n");
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// error
private void printError(String err) {
String str = "ERROR; ";
str += err;
sendMessage(str);
}
public void command(ArrayList<String> cmd) {
String mode = cmd.get(0);
if(mode == null){
}else switch(mode){
case "MANUAL_SIG-ALL":
System.out.println("全照明一括 信号値指定調光");
manualSigAll(cmd.get(1));
break;
case "MANUAL_SIG-INDIVIDUAL":
System.out.println("全照明独立 信号値指定調光");
manualSigIndividual(cmd.get(1));
break;
case "MANUAL_ID-SIG":
System.out.println("照明ID・信号値指定調光");
manualIDSig(cmd.get(1));
break;
case "MANUAL_ID-RELATIVE":
System.out.println("照明ID・相対信号値指定調光");
break;
case "DOWNLIGHT_ALL":
System.out.println("Downlight: All Control");
downlightAll(cmd.get(1));
break;
case "DOWNLIGHT_INDIVIDUAL":
System.out.println("Downlight: Individual control");
downlightIndividual(cmd.get(1));
break;
case "GET_LIGHTS":
System.out.println("Sending lights via JSON");
sendLights();
break;
default:
System.out.println("Error: 不明なmode command");
}
}
// 全照明一括 信号値指定調光
private void manualSigAll(String sigs) {
if(sigs == null) {
System.out.println("信号値のフォーマットを確認してください");
} else {
ArrayList<Integer> s = new ArrayList<>();
String[] buf = sigs.split(",");
for(String i:buf) s.add(Integer.parseInt(i));
for(Light l: ils.getLights()) {
l.setLumPct((double)s.get(0)/255.0*100.0);
l.setSignal(s.get(0), s.get(1));
}
}
// 調光
ils.downlightDimmer.send();
}
// 全照明独立 信号値指定調光
private void manualSigIndividual(String sigs) {
if(sigs == null) {
System.out.println("信号値のフォーマットを確認してください");
} else {
ArrayList<Integer> s = new ArrayList<>();
String[] buf = sigs.split(",");
for(String i:buf) s.add(Integer.parseInt(i));
for(int i=0; i<ils.getLights().size(); i++) {
ils.getLights().get(i).setSignal(s.get(0), s.get(1));
s.remove(0);
s.remove(0);
}
}
ils.downlightDimmer.send();
}
// 照明ID・信号値指定調光
private void manualIDSig(String sigs) {
if(sigs == null) {
System.out.println("信号値のフォーマットを確認してください");
} else {
ArrayList<Integer> s = new ArrayList<>();
String[] buf = sigs.split(",");
for(String i:buf) s.add(Integer.parseInt(i));
System.out.println(s.get(0));
ils.getLight(s.get(0)).setSignal(s.get(1), s.get(2));
}
ils.downlightDimmer.send();
}
private void downlightAll(String cmd) {
if(cmd == null) {
printError("Check for data command.");
} else {
ArrayList<Double> data = new ArrayList<>();
String[] buf = cmd.split(",");
for(String i:buf) data.add(Double.parseDouble(i));
for(Light l: ils.getLights()) {
l.setLumPct(data.get(0));
l.setTemperature(data.get(1));
}
}
// dimming
ils.downlightDimmer.send();
}
private void downlightIndividual(String cmd) {
if(cmd == null) {
printError("Check for data command.");
} else {
ArrayList<Integer> id = new ArrayList<>();
ArrayList<Double> lumPct = new ArrayList<>();
ArrayList<Integer> temp = new ArrayList<>();
String[] buf = cmd.split(",");
if(buf.length % 3 != 0) {printError("invalid number of data.");}
for(int i=0; i<buf.length/3; i++) {
int n = i*3;
try {
id.add(Integer.parseInt(buf[n]));
lumPct.add(Double.parseDouble(buf[n + 1]));
temp.add(Integer.parseInt(buf[n + 2]));
} catch (Exception e) {
printError(e.getMessage());
return;
}
}
while (id.size() > 0) {
// update light object
Light light = ils.getLight(id.get(0));
light.setLumPct(lumPct.get(0));
light.setTemperature(temp.get(0));
// remove data from array list
id.remove(0);
lumPct.remove(0);
temp.remove(0);
}
// dimming
ils.downlightDimmer.send();
}
}
private void sendLights() {
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(ils.getLights());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// output
sendMessage(json);
}
}
If your server is using readLine(), as is probable, it will block until you close the connection, because you aren't sending a line.
Add bw.newLine() before the flush().
EDIT As predicted, your server isn't sending lines, so it needs the same treatment as above. However there is an anterior problem:
while( (in = br.readLine()) != null ){
cmd.add(in);
}
This loop in the server cannot possibly exit until the client closes the connection. You should process a line at a time in the server, or else moderate your expectations of the client's behaviour.

How to access a string called "numberPart" from a different file (multithreaded java socket programming)

There is a string called numberPart inside a thread class called ServerRecieve. The location where .start() is being called is inside of a different class called Server.
The 'numberPart' will eventually be used as a port for file transferring later on.
My question is: How do I access the numberPart variable inside of the class called Server?
Screenshot of code running (server on left window, client on the right):
server on left window, client on the right
In the left window of the screenshot (server) you can see the that the first port number of the right window's command line argument which is 4021 being sent via a text message, and the server successfully receives it with the message "File transfer port found: 4021". Unfortunately this variable is located inside a different class. I would like to know how to access that variable inside the class called Server.
ServerRecieve code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerRecieve extends Thread
{
Socket servSocket;
boolean m_bRunThread = true;
boolean ServerOn = true;
public ServerRecieve(Socket s)
{
super();
servSocket = s;
}
public void run()
{
while(true)
{
try
{
BufferedReader readFromClient = new BufferedReader(new InputStreamReader(servSocket.getInputStream()));
String fromClient = readFromClient.readLine();
String a = fromClient;
int i;
for(i = 0; i < a.length(); i++)
{
char c = a.charAt(i);
if( '0' <= c && c <= '9' )
{
break;
}
}
String alphaPart = a.substring(0, i);
String numberPart = a.substring(i);
System.out.println("Recieved from client: " + alphaPart +"\n");
System.out.println("File transfer port found: " + numberPart + "\n");
//String[] filePortNumber = null;
//filePortNumber[0] = numberPart;
// Server thing = new Server(filePortNumber);
if(fromClient.equals(null))
{
System.exit(0);
}
OutputOptions();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
}
}
}
void OutputOptions()
{
System.out.println("Enter an option ('m', 'f', 'x'): ");
System.out.println("(M)essage (send)");
System.out.println("(F)ile (request) ");
System.out.println("e(X)it ");
}
}
Server source:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.imageio.IIOException;
public class Server
{
private String[] serverArgs;
public Socket socket;
public Socket fileSocket;
public boolean keepRunning = true;
public int ConnectOnce = 0;
public String option = "";
public boolean isConnected = false;
public String FILE_TO_SEND = "/Users/nanettegormley/Documents/workspace/assignment2/src/servers/cdm.jpg";
public Server(String[] args) throws IOException
{
// set the instance variable
this.serverArgs = args;
if(ConnectOnce == 0)
{
int port_number1 = Integer.valueOf(serverArgs[1]);
ServerSocket serverSocket = new ServerSocket(port_number1);
socket = serverSocket.accept();
ConnectOnce = 4;
isConnected = true;
}
}
public String[] serverRun2(String[] args) throws IOException
{
serverArgs = args;
serverArgs = Arrays.copyOf(args, args.length);
serverSend.start();
return serverArgs;
}
Thread serverSend = new Thread()
{
public void run()
{
OutputOptions();
while(isConnected)
{
try
{
ServerRecieve serverThread = new ServerRecieve(socket);
serverThread.start();
// input the message from standard input
BufferedReader input2= new BufferedReader(new InputStreamReader(System.in));
option = input2.readLine();
if(option.equals("m") || option.equals("M"))
{
StandardOutput();
}
if(option.equals("f") || option.equals("F"))
{
FileTransferSend();
}
if(option.equals("x") || option.equals("X"))
{
System.exit(0);
}
}
catch ( Exception e )
{
System.out.println( e.getMessage() );
}
}
}
};
public void StandardOutput()
{
try
{
//Send the message to the server
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
//creating message to send from standard input
String newmessage = "";
try
{
System.out.println("Enter your message: ");
// input the message from standard input
BufferedReader input2= new BufferedReader(new InputStreamReader(System.in));
String line = "";
line= input2.readLine();
newmessage += line + " ";
}
catch ( Exception e )
{
System.out.println( e.getMessage() );
}
String sendMessage = newmessage;
bw.write(sendMessage + "\n");
bw.newLine();
bw.flush();
System.out.println("Message sent to client: "+sendMessage);
StandardInput();
//run();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
}
}
void FileTransferSend()
{
//connect to the filetransfer
try
{
System.out.println("Which file do you want? ");
Scanner scanner = new Scanner(System.in);
String filename = scanner.nextLine();
FileInputStream fis = new FileInputStream(new File(filename));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(fileSocket.getOutputStream()));
int element;
while((element = fis.read()) !=1)
{
dos.write(element);
}
byte[] byteBuffer = new byte[1024]; // buffer
while(fis.read(byteBuffer)!= -1)
{
dos.write(byteBuffer);
}
OutputOptions();
// dos.close();
// fis.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
}
}
void OutputOptions()
{
System.out.println("Enter an option ('m', 'f', 'x'): ");
System.out.println("(M)essage (send)");
System.out.println("(F)ile (request) ");
System.out.println("e(X)it ");
}
public void StandardInput()
{
OutputOptions();
while(true)
{
try
{
// input the message from standard input
BufferedReader input2= new BufferedReader(new InputStreamReader(System.in));
String line2 = "";
option= input2.readLine();
if(option.equals("m") || option.equals("M"))
{
StandardOutput();
}
if(option.equals("f") || option.equals("F"))
{
FileTransferSend();
}
if(option.equals("x") || option.equals("X"))
{
System.exit(0);
}
}
catch ( Exception e )
{
System.out.println( e.getMessage() );
}
finally
{
}
}
}
}
Full code with all files:
https://www.dropbox.com/s/0yq47gapsd3dgjp/folder33.zip?dl=0
My question is: What changes can I make to the code that would allow me to access numberPart while being inside Server?
EDIT: Is there a way to bump a question that hasn't gotten any answers or should I just delete this one and repost it somewhere?
I would think that you could use either a listener or callback pattern to solve this.
(I'm losing my Java memory now that I'm doing C# so please bear with me..)
interface PortAssignable {
public assignPort(int port);
}
Then have the Server class implement that interface
public Server implements PortAssignable {
...
}
And ServerReceive
// Constructor
public ServerRecieve(Socket s, PortAssignable portNotifyListener) {
_portNotifyListener = portNotifyListener;
... your other code ...
}
Make sure when you create an instance of ServerReceive, you pass in your Server instance, via this.
ServerRecieve serverThread = new ServerRecieve(socket, this);
Now, when you get your numberPart, your next line can be
_portNotifyListener.assignPort(numberPart);
How you choose to implement the assignPort method in your Server class is up to you.
P.S. I saw this question from /r/programming.

SocketException recv failed, but why?

I've got a Client and a Server. The client simply sends 1 line of input to the server and then prints the response.
I'm getting a
SocketException (Software caused connection abort: recv failed)
[...]
at java.io.InputStreamReader.read(InputStreamReader.java:168)
at hw3.Client.readLine(Client.java:37)
at hw3.Client.main(Client.java:28)
The debugger tells me that the socket is not closed at the time of the read, what else can cause this exception?
I think I'm running into issues because of the threading, does anything stick out as "doing it wrong"?
public class Client
{
public static final int PORT = ReversingEchoServerDispatcher.PORT;
private static final String host = "localhost";
private static Socket sock;
public static void main(String[] args)
throws IOException
{
try(Socket sock = new Socket(host, PORT);
InputStreamReader clin = new InputStreamReader(sock.getInputStream());
OutputStream clout = sock.getOutputStream();
Scanner sc = new Scanner(System.in))
{
Client.sock = sock;
byte[] cl = sc.nextLine().getBytes("UTF-8");
clout.write(cl);
System.out.println(readLine(clin));
}
}
private static String readLine(InputStreamReader in)
throws IOException
{
StringBuilder sb = new StringBuilder();
for(int i = in.read(); i != -1; i = in.read())
{
char c = (char) i;
if(c != '\n') sb.append(c);
else break;
}
return sb.toString();
}
}
public class ServerDispatcher
{
public static final int PORT = 8034;
public static void main(String[] args)
{
try (ServerSocket serversock = new ServerSocket(PORT))
{
while(true)
{
Socket socket = serversock.accept();
ServerLogic sv = new ServerLogic(socket);
new Thread(() -> {
try {
sv.run();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}).start();
}
}
catch(IOException e)
{
e.printStackTrace(System.err);
}
}
}
For the record, the ServerLogic class looks something like the following. My exit code is 1, not -999, so it's not that socket.close() is failing
class ServerLogic
{
Socket socket;
public
ServerLogic(Socket s)
{
this.socket = s;
}
public void run()
throws IOException
{
try(InputStreamReader in = new InputStreamReader(socket.getInputStream());
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream()))
{
StringBuilder sb = new StringBuilder();
while(in.ready()) {
char c = (char) in.read();
if(c == '\n') {
String str = process(sb);
if(str != null) out.write(str);
else return;
} else {
sb.append(in.read());
}
}
} finally {
try {
socket.close();
} catch(IOException ex) {
ex.printStackTrace(System.err);
System.exit(-999);
}
}
}
private static String process(StringBuilder sb)
{ /* ... */ }
The server is expecting a newline \n to terminate the input but you never send one from the client. sc.nextLine() returns the input line but does not include the terminating newline. The while(in.ready()) loop eventually ends and the server closes the socket without ever sending a response.

Multithreading echo server

Hello it is my first topic here.
I wrote some code to making connection client-server by sockets. As a client I mean opening terminal window and connection to this server by telnet. Application works as a server listening for requests from client on specified port. Every single connection is treat as a new thread. Once the connection is bound the client can send a message and gets an answer back as an echo.
The problem is I want to be informed when the client closes the terminal window (finish thread). I want to know id of this closed thread.
This is full code:
public class MultithreadEchoServer
{
public static void main(String[] args) throws IOException
{
int count=0;
long[] ids = new long[10];
try (ServerSocket ss = new ServerSocket(1234))
{
System.out.println("Listening...");
while(true)
{
count++;
Socket s = ss.accept();
Runnable r = new MyThread(s, count);
Thread t = new Thread(r);
t.start();
ids[count-1] = t.getId();
if(Thread.activeCount() != count+1)
{
count = Thread.activeCount();
System.out.println("Client "+/*??thread's id??*/" left the session. Now connected: "+count);
}
System.out.println("Clients connected: "+count);
System.out.println(ids[count-1]);
}
}
}
}
class MyThread implements Runnable
{
private Socket s;
private int count;
private long id;
InputStream io;
OutputStream os;
private PrintWriter pw;
MyThread(Socket s, int count)
{
this.s = s;
this.count = count;
}
public long getId()
{
id = Thread.currentThread().getId();
return id;
}
#Override
public void run()
{
try
{
io = s.getInputStream();
os = s.getOutputStream();
}
catch (IOException e) {System.err.println(e);}
try (Scanner sc = new Scanner(io))
{
pw = new PrintWriter(os, true);
pw.println("Connected");
while(sc.hasNextLine())
{
String line = sc.nextLine();
System.out.println("Client "+count+": "+line);
pw.println("Echo: "+line);
}
}
}
}
Why you donn't print Thread ID inside Thread execution with a finally statement after your try with resource statement :
try (Scanner sc = new Scanner(io))
{
pw = new PrintWriter(os, true);
pw.println("Connected");
while(sc.hasNextLine())
{
String line = sc.nextLine();
System.out.println("Client "+count+": "+line);
pw.println("Echo: "+line);
}
}
finally {
System.out.println("Client " + this.id + " left the session."");
}
MultithreadEchoServer
public class MultithreadEchoServer
{
public static void main(String[] args) throws IOException
{
int count=0;
long[] ids = new long[10];
try (ServerSocket ss = new ServerSocket(1234))
{
System.out.println("Listening...");
while(true)
{
count++;
Socket s = ss.accept();
Runnable r = new MyThread(s, count);
Thread t = new Thread(r);
t.start();
ids[count-1] = t.getId();
if(Thread.activeCount() != count+1)
{
count = Thread.activeCount();
System.out.println("Now connected: "+count);
}
System.out.println("Clients connected: "+count);
System.out.println(ids[count-1]);
}
}
}
}
MyThread
class MyThread implements Runnable
{
private Socket s;
private int count;
private long id;
InputStream io;
OutputStream os;
private PrintWriter pw;
MyThread(Socket s, int count)
{
this.s = s;
this.count = count;
}
public long getId()
{
id = Thread.currentThread().getId();
return id;
}
#Override
public void run()
{
try
{
io = s.getInputStream();
os = s.getOutputStream();
}
catch (IOException e) {System.err.println(e);}
try (Scanner sc = new Scanner(io))
{
pw = new PrintWriter(os, true);
pw.println("Connected");
while(sc.hasNextLine())
{
String line = sc.nextLine();
System.out.println("Client "+count+": "+line);
pw.println("Echo: "+line);
}
}
finally {
System.out.println("Client " + this.id + " left the session."");
}
}
}

Multithreading with client server program

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.

Categories