Threads and Handlers in server socket - java

How is the new Handler(clientSocket); instantiated without an object?. Can somebody give some insight?
public class Server1 {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(15897);
while (true) {
Socket clientSocket = serverSocket.accept();
new Handler(clientSocket);
}
} catch (IOException e)
{
System.out.println("problem here 1");
}
}
}
class Handler implements Runnable {
int red;
int reads, r;
Socket clientSocket;
Handler(Socket s)
{
this.clientSocket = s;
new Thread(this).start();
}
public void run(){
BufferedReader bufferedReader;
try {
bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine = bufferedReader.readLine();

In you code Server is made to keep listening the incoming Clients.
Socket clientSocket = serverSocket.accept();
serverSocket.accept() waits until a connection or a client is found.
If client is found then accept() function returns a local socket which is connected to another socket at the client which is given to clientSocket in you code.
new Handler(clientSocket);
Now clientSocket is given to Handler class in which you are using thread for reading the data given by that clientSocket.
The purpose of thread here is to handle each incoming clientSocket seprately.

Your code is incomplete, so it's difficult to say with certainty, but observe that in the Handler's constructor a thread is created and started, which executes run().
Inside that function (and therefore in a separate thread), the input stream is read from the socket into a BufferedReader, from which the first line is obtained.
The thread will block until a line is received over the socket connection.
Because your code is cut off from that point, I can't say what else it does.

I am not sure what exactly does the code do but explaining it to you as per the concept of OOPs, it creates an instance of the Handler class everytime the while loop is executed.
Warning: The while(true) loop is bad code and when the project is run, it will run in an infinite loop.

Related

My java multi-thread (client-server) program throws a NullPointerException when socket object instance is created using the accept() method

I am trying to create a multi-threaded client-server communication program that uses 2 threads to connect to multiple clients (but only 2 at a time).
The characteristics of the program are:
The clients can terminate the communication program from their side but the server thread does not exit.
The threads in the server do not close ServerSocket until the exit condition is fulfilled by the server program, i.e. the server keeps running continuously connecting to various clients if requested.
Every time a client terminates the program only the communication (related) streams are closed.
Now the problem is the line of code where the Socket object is created. After calling the accept() method of ServerSocket object, a NullPointerException is thrown. Any insight as to where I am going wrong would be very helpful.
My Server side code:
class Clientconnect implements Runnable
{
ServerSocket ss;
Socket s;
String n;
int f;
Clientconnect() throws Exception
{
new ServerSocket(776);
new Socket();
}
public void run()
{
n = Thread.currentThread().getName();
while(true) // thread iteration
{
try
{
System.out.println("Thread "+Thread.currentThread().getName()+" is ready to accept a
connection.....");
s = ss.accept(); // ------**The NullPointerException occurs here**
System.out.println("Thread "+Thread.currentThread().getName()+" has accepted a connection:\n----------");
PrintStream ps = new PrintStream (s.getOutputStream());
BufferedReader cl = new BufferedReader (new InputStreamReader (s.getInputStream()));
BufferedReader kb = new BufferedReader (new InputStreamReader (System.in));
String in, out;
ps.println("you are connected via thread "+n);
ps.println("----------------------");
while (true)
{
in = cl.readLine();
if( in.equalsIgnoreCase("system_exit"))
{
break;
}
System.out.println("Client : "+in);
System.out.print("Server "+n+" :");
out = kb.readLine();
ps.println(out);
}
s.close();
ps.close();
cl.close();
System.out.print("do you want to close the server socket\n1:close\n2:continue\nenter");
f = Integer.parseInt(kb.readLine());
if(f == 1)
{
ss.close();
break;
}
else
{
continue;
}
}
catch (Exception e){e.printStackTrace();}
}
}
}
class test2g
{
public static void main (String args[]) throws Exception
{
Clientconnect cc = new Clientconnect();
Thread t1 = new Thread (cc, "t1");
Thread t2 = new Thread (cc, "t2");
t1.start();
t2.start();
}
}
It is a fairly simple communications program with no complex resource accessing or retrieval. I am running the client end on the same machine so it's "localhost".
My client side code is merely a reciprocation of the try{} block.
P.S. I have tried declaring the ServerSocket & Socket objects as static in the Clientconnect class but it did not help.
I believe ss needs to be assigned in the constructor:
Clientconnect() throws Exception
{
ss = new ServerSocket(776);
new Socket(); // Not needed because it creates a Socket that is immediately thrown away.
}

problem with connecting multiple clients to a server

hey I'm writing a simple code with a server socket and multiple clients which the server gets every client's username and stores them in a hashmap.the server accepts a socket client and the client enters the username but again the server accept the same socket client and it wants its username and the code stops here.i want it to work for multiple clients not just one.
server class:
public class Server implements Serializable{
// [..]
public void serverConnect() throws IOException, ClassNotFoundException
{
listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true)
{
System.out.println("Waiting ...");
socket=listener.accept();
for (Socket socket:socketList.keySet())
{
if (this.socket==socket)
{
checkSocket=false;
}
}
if (checkSocket)
{
socketList.put(socket,socketNumber);
System.out.println("Client is connected");
inputReader = new InputStreamReader(socket.getInputStream());
reader = new BufferedReader(inputReader);
user = reader.readLine();
Server.userList.add(user);
socketNumber++;
}
checkSocket=true;
}
}
}
client class:
public class Client {
public Client() {
}
public void clientConnect() throws UnknownHostException, IOException {
System.out.println("enter your username");
Scanner scanner = new Scanner(System.in);
String msg = scanner.nextLine();
Socket socket = new Socket("localhost", 9090);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.println(msg);
}
}
In principle you have the workings of single thread server (which means it can accept only one client connection at a time). The main issue is that you have over-complicated how you receive a connection.
You can simplify your current code by dealing by moving the client connection socket and readers into the local scope and dealing with the socket directly.
public void serverConnect() throws IOException {
listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true) {
System.out.println("Waiting ...");
Socket socket = listener.accept();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String user = reader.readLine();
Server.userList.add(user);
} catch (IOException ignore) {
} finally {
socket.close();
}
}
}
As you can see you don't need to keep hold of the socket beyond reading the value sent. If you are only expecting the one line of data from the client, you should also close the socket otherwise the client can hold the server hostage by not sending any data until the socket timeout is reached.
Further to this you also want to wrap the code inside the while loop with a try/catch block to prevent an exception terminating the server.
As I mentioned in the opening paragraph this code works as a single threaded server and it can only respond to a single request at a time. If you want to accept and process multiple requests you will need to spawn a new thread to handle the response. I would recommend constructing your code as below but for the sake of brevity you could do something like below:
public void serverConnect() throws IOException {
int MAX_WORKERS = 100;
ExecutorService service = Executors.newFixedThreadPool(MAX_WORKERS);
ServerSocket listener = new ServerSocket(9090);
System.out.println("Server is running...");
while (true) {
System.out.println("Waiting ...");
Socket socket = listener.accept();
service.submit(() -> {
System.out.println("Client is connected");
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String user = reader.readLine();
Server.userList.add(user);
} finally {
socket.close();
}
} catch (Throwable ignore) {
}
});
}
}
So all that is happening above is that we are creating a thread pool of 100 threads using the ExecutorService. This means in theory we can accept 100 concurrent connections.
When a connection is accepted, we submit the socket and worker code to a thread which means that the main thread can return to listening for a new connections.

Unblocking a UDP thread

I have this runnable receiver which I want to stop. but as it is a constantly receiving socket it's thread is in blocking mode.
I found that I had to stop the socket from outside the thread itself, using socket.close()
So i defined a public static socket. (which itself is bad, i guess?) then i start new threads and try stopping them with this code, (have not changed anything)
public static DatagramSocket socket;
Starting each thread seperatly works fine. but as the socket now is global, I can't stop them individually. How do I make the socket var global but individual? Or what do I need to make this possible?
public void startSls () throws SocketException{
try{
socket = new DatagramSocket(parseInt(port));
}catch (SocketException e) {
Log.e("CCSstream", e.toString());
}
slst = new Thread(new slss(port));
slst.start();
}
public void stopSls(){
socket.close();
stopSLS = true;
slst.interrupt();
runThreads1 = false;
}
If anything is unclear I can explain.
Thanks

Create ObjectInputStream according to a socket

I'm trying to create an ObjectInputStream according to a Socket and add this stream into a List.
The client is connected in the main class of my program, and the socket is sent in an other method in a Thread. Then the socket is used to create the stream.
The problem is that the stream is never create. I don't get why...
Below is my code :
In my Thread :
public void addClient(Socket socket){
try{
streamList.add(new ObjectInputStream(socket.getInputStream()));
}catch(IOException e){
e.printStackTrace();
}
}
And in my main class :
ServerSocket serverSocket = new ServerSocket(PORT);
Socket socket;
ClientThread clientThread = new ClientThread();
//start the thread
try{
socket = serverSocket.accept();
clientThread.addClient(socket);
}
catch(IOException e){
e.printStackTrace();
}
Thanks in advance.
The peer needs to create his ObjectOutputStream immediately on connection. Otherwise new ObjectInputStream will block until he does so.
It would be better if you could defer creation of the ObjectInputStream to the run() method of the thread that handles the accepted socket. You shouldn't do any I/O in the accept loop, just the accept itself. Otherwise you can block subsequent clients.

app get stuck at serverSocket.accept() and gives bind exception address already in use on the second call for the thread

I have two problems with an app that i have built for socket communication, first I'll try to explain what the app does and then I'll go into the details of those two problems.
First I click on a button, which starts a thread, which sends a multicast massage "group address" through a UDP socket. Once any of the devices receive the massage, they will send a response through TCP socket and my device will act as a server to the one that sent the response. So after debugging I found out the first problem which is clientSocket = serverSocket.accept(); sometimes gets stuck and the app will block everything and keep executing it, which might happen because the udp massage might never arrive at the destination which means there is no client for the tcp server that I've created.
First question: Is there any way to make the serverSocket.accept(); non-blocking or set a time out? I've tried serverSocket.setTimeSoOut() method, but that didn't work. Maybe this problem comes from something other than the UDP message?
The second problem is that if I press the button that calls the thread twice it will throw a BindException address already in use: Which will happen because of the re execution of serverSocket.bind(new InetSocketAddress(4125));. Is there any way to fix/avoid that?
Here are the threads that I'm using:
This one is called after I press the button:
private class ChatClientThread extends Thread {
DatagramSocket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;
DataOutputStream outToServer;
BufferedReader inFromServer;
Socket clientSocket;
ServerSocket serverSocket;
#Override
public void run() {
/*Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream=null;*/
clientSocket=null;
try {
String data="NewTask_"+EmpPhoneNumber;
serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(4125));
socket = new DatagramSocket(52276);
socket.setBroadcast(true);
InetAddress group = InetAddress.getByName(
"224.0.1.2");
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
group, 52276);
socket.send(packet);
while(true){
clientSocket = serverSocket.accept();
ConnectThread ct=new ConnectThread(clientSocket);
ct.start();
}
} catch (UnknownHostException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}
});
} catch (IOException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}
});
} finally {
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
}
}
this one is called from the above thread as you can see:
private class ConnectThread extends Thread {
Socket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;
DataOutputStream outToServer;
BufferedReader inFromServer;
ConnectThread(Socket socket){
this.socket= socket;
}
#Override
public void run() {
DataInputStream dataInputStream = null;
DataOutputStream dataOutputStream = null;
Socket socket2 = null;
DataOutputStream dataOutputStream2= null;
DataInputStream dataInputStream2=null;
try {
while(true){
inFromUser = new BufferedReader( new InputStreamReader(System.in));
outToServer = new DataOutputStream(socket.getOutputStream());
inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sentence = inFromUser.readLine();
modifiedSentence = inFromServer.readLine();
socket2 = new Socket(socket.getInetAddress().getHostAddress(), 4125);
dataOutputStream2 = new DataOutputStream(
socket2.getOutputStream());
String[] parts = modifiedSentence.split("_");
String partGive = parts[0].substring(4); // 004
String partEmpId = parts[1];
if(partGive.equals("GiveMeATask")&&Integer.parseInt(partEmpId)==empId){
dataOutputStream2.writeUTF(" "+"SolveProblemOrder_2");
dataOutputStream2.flush();
}
System.out.println("FROM SERVER: " + modifiedSentence);
if(modifiedSentence!=null) break;}
outToServer.close();
inFromServer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Those are two very commmon problems. I'll answer the two in reverse order.
The button you are talking about is creating a ServerSocket and binding it to a specific port. In your case, the port is 4125. From looking at your code, you don't seem to be closing that serversocket anywhere. When you click the button a second time, a second instance of ServerSocket tries to bind to the same port - but that port is still in use by the first ServerSocket. In that case, you get a bind exception. One port cannot be used by more than one ServerSocket. The solution would be to close the existing ServerSocket before creating a new one using serverSocket.close();
If you read the documentation, it clearly states what ServerSocket.accept() does: "[...] The method blocks until a connection is made." This is the "getting stuck" that you described. The thread that executes that code is put into a waiting position and continues only when a connection is made, then returns that new connection. The classic approach is to start a new thread that waits for incoming connections so that your main thread continues to execute and your whole application does not "freeze". Another approach would be a non-blocking framework that encapsulates all that overhead away from you, one of those is Apache MINA.
I would highly suggest to look into small example projects that deal with basic client/server behaviour as you will most likely deal with threads here.
First problem: It is very likely that your application is not receiving the UDP packages. If serverSocket.accept() doesn't get any clients it'll wait indefinitely for someone to connect. You could avoid this by using yet another thread that just accepts connections to avoid freezing your application. Another way would be to use Java's NIO classes that provide non-blocking IO for pretty much anything. That would require you to use ServerSocketChannel and related classes. (Quick googling also gave me this guide which seems fairly easy to follow).
Second problem: You need to close your ServerSocket once you're done using it. Otherwise the port will never be free again to be used by another ServerSocket.
Alternatively you could just leave the Socket open and remember that you already openend it (e.g. with a boolean field in your class).

Categories