I have this simple multi-threaded java socket application. Using classes Client.java
public class Client {
private static Socket socket;
private static boolean waitForServer = false;
public static void main(String[] args) throws IOException {
while(true){
socket = new Socket("localhost", ServerPortInfo.getPort());
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
BufferedReader bufferedReader = new java.io.BufferedReader(new InputStreamReader(System.in));
while(true){
PrintWriter.println(name + " Hello");
waitForServer = true;
if (waitForServer){
BufferedReader inputBufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String inputString = null;
while((inputString = inputBufferedReader.readLine()) != null){
System.out.println(inputString);
break;
}
}
}
}
}
}
And Server.java
public class Server {
public static ArrayList<ServerThread> connections = new ArrayList<ServerThread>();
public static void main(String[] args) throws IOException, SQLException, ClassNotFoundException {
// Init server functionality
new Server().runServer();
}
// Implementing server functionality
public void runServer() throws IOException{
ServerSocket serverSocket = new ServerSocket(ServerPortInfo.getPort());
System.out.println("Server is running... Waiting for connections");
while (true){
Socket socket = serverSocket.accept();
// After connection handle clients in threads
ServerThread newThread = new ServerThread(socket);
connections.add(newThread);
newThread.start();
}
}
}
And then a Thread that handles that connection...
public class ServerThread extends Thread {
private static Socket socket;
public static boolean alive = true;
ServerThread(Socket socket){
this.socket = socket;
}
public void run(){
if (alive) {
//DO STUFF NOW
}
}
And now when I have multiple connections. It creates a different Thread for every connection.
What should i do when a user wants to disconnect from this server?
Should i kill the thread, socket?
I tried just saying to the thread
alive = false; so the run would just stop running. But this breaks other connections as well.
EDIT
ServerThread ->
private Socket socket;
And a function ->
void closeConnection() throws IOException{
this.socket.close();
}
works like a charm.
public static variables are a recipe for disaster (as I'm sure you've
just found out the hard way). But as #cktang said, close the socket,
then kill that thread (not the others). -#JoeC
Changed private static Socket socket; to private Socket socket;.
Closed the socket and then Thread.
The problem is with
public static boolean alive = true;
private static Socket socket;
As it is static, it influences all your ServerThread's, but each ServerThread (aka connected client) should have its own socket and flag indicating if it's alive or not.
Remove the static modifier from both attributes and
make the flag private volatile boolean alive = true;
At first close the socket a then stop the thread (and remove it from the list).
Related
I am trying to implement a java command line chat server and client. I am using 4 classes, the Server.java sets up a ServerSocket and accepts all connections. The Client.java can connect to the Server, then 2 threads for both client and server are created using the SendMessages.java and ReceiveMessages.java. The threads are responsible for taking the input from stdin and sending it to the output stream of the socket, and taking the incoming input stream to print it to stdout. Everything works when launching the server and connecting the client, the chat also works. However, when either client or server is terminated a resource leak is caused. I want the SendMessages class and ReceiveMessages class to be able to detect when the connection of client or server is terminated and close all resources to avoid resource leaks. Here is the code:
Server.java
import java.net.*;
import java.io.*;
import java.util.*;
public class Server{
public static void main(String[] args) throws SocketException,IOException{
ServerSocket s = new ServerSocket(8000);
s.setSoTimeout(10000000);
while(true){
Socket clientSocket = s.accept();
handle(clientSocket);
}
}
static void handle(Socket clientSocket) throws IOException{
System.out.println("connection accepted from " + clientSocket.getRemoteSocketAddress());
receiveMessages(clientSocket);
sendMessages(clientSocket);
}
static void receiveMessages(Socket clientSocket) throws IOException{
(new Thread(new ReceiveMessages(clientSocket))).start();;
}
static void sendMessages(Socket clientSocket)throws IOException{
(new Thread(new SendMessages(clientSocket))).start();
}
}
Client.java
import java.net.*;
import java.io.*;
import java.util.*;
public class Client{
public static void main(String[] args) throws IOException, UnknownHostException, ConnectException{
String hostname = args[0];
int port = Integer.parseInt(args[1]);
Socket s = null;
s = connect(hostname, port);
handle(s);
}
public static Socket connect(String hostname, int port) throws UnknownHostException, IOException, ConnectException{
Socket s = null;
try{
s = new Socket(hostname, port);
} catch(ConnectException e){
System.out.println("Connect Exception caught!");
}
return s;
}
static void handle(Socket clientSocket) throws IOException, UnknownHostException{
receiveMessages(clientSocket);
sendMessages(clientSocket);
}
static void receiveMessages(Socket clientSocket) throws IOException, NullPointerException{
(new Thread(new ReceiveMessages(clientSocket))).start();
}
static void sendMessages(Socket clientSocket)throws IOException, NullPointerException{
(new Thread(new SendMessages(clientSocket))).start();
}
}
SendMessages.java
import java.io.*;
import java.net.*;
import java.util.*;
public class SendMessages implements Runnable{
Socket clientSocket;
public SendMessages(Socket clientSocket){
this.clientSocket = clientSocket;
}
public void run(){
System.out.println("SendMessages thread has started.");
Scanner sc = new Scanner(System.in);
PrintWriter out = null;
try{
out = new PrintWriter(clientSocket.getOutputStream(), true);
}
catch(IOException | NullPointerException e){}
String message;
while(true){
message = sc.nextLine();
out.println(message);
if(out.checkError()){
out.close();
sc.close();
System.out.println("SendMessages closed");
}
}
}
}
ReceiveMessages.java
import java.io.*;
import java.net.*;
import java.util.*;
public class ReceiveMessages implements Runnable{
Socket clientSocket;
public ReceiveMessages(Socket clientSocket){
this.clientSocket = clientSocket;
}
public void run(){
System.out.println("ReceiveMessages thread has started.");
BufferedReader in = null;
try{
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}catch(IOException|NullPointerException e){}
String message;
try{
while(true){
while((message = in.readLine())!= null){
System.out.println(message);
}
}
} catch(IOException|NullPointerException e){
System.out.println("ReceiveMessages resources closed.");
try{
in.close();
clientSocket.close();
}
catch(IOException f){}
}
}
}
Thank you!
So I have recently delt myself with such an issue.
The problem is, that by shutting one side of the connection down, a "half-open" connection remains (which isn't a real connection anymore).
The Socket API does not have an option to check, if the partnered service/device is still alive.
So what to do about that? I myself prefer the concept of heartbeats.
Every 10 seconds (or any other timeframe, it's up to you) a heartbeat is send to the output stream of the socket. This operation throws a IOException, when the stream is no longer avaiable. Therefore you can catch the the exception and handle all "close" operations within the catch block.
Example:
public class Heartbeater
implements Runnable
{
private OutputStream os;
private ServerHandler servhand;
private Logger logger = Logger.getLogger( Logger.GLOBAL_LOGGER_NAME );
//NOTE: ServerHandler is my class which handles the socket of the server after ServerSocket.accept();
public Heartbeater( OutputStream os, ServerHandler servhand )
{
this.servhand = servhand;
this.os = os;
}
#Override
public void run()
{
try
{
Thread.currentThread().setName( "Heartbeater" );
// while the handler's connection is alive
while ( servhand.isConnectionAlive() )
{
Thread.sleep( 10000 );
// dummy write to trigger the exception if the client does not respond properly
os.write( "_HEARTBEAT_".getBytes() );
}
}
catch ( InterruptedException e )
{
logger.log( Level.SEVERE, "HEARTBEATER GOT INTERRUPTED", e );
Thread.currentThread().interrupt();
}
catch ( IOException e )
{
logger.log( Level.INFO, "The connection to the client has been lost." );
// Here you would define the resource close operation.
servhand.setConnectionAlive( false );
}
}
}
Can someone look at my code and tell me what's wrong?
I am trying to make a client server chat program and want server to accept endless connections requested from the clients. It runs successfully. At First run, server and client are able to chitchat properly but when the client is closed(quit) and again came back, client is able to connect with
server and even it can send messages to server and messages are also received by the server BUT there is issue at server side, At Server side server messages are not reach to client properly. Some messages are skipped and are not able to reached to client immediately as it was before in the first run.Please help me if anyone can find this solution.
SERVER CODE:
//packages
import java.io.*;
import java.net.*;
import java.lang.*;
public class Server1 {
public static void main(String[] args) throws IOException {
// Instance variable fields
ServerSocket listener=null;
Socket clientSocket=null;
final int port = 444;
System.out.println("Server waiting for connection on port "+port);
try
{
listener = new ServerSocket(port);
// Creates a server socket bound to the specified port.
}
catch(IOException e)
{
e.printStackTrace();
}
while(true)
{
try
{
clientSocket = listener.accept(); //Listens for a connection to be made to this socket and accepts it.
//clientsocket is now the route through which we can communicate with the client.
//if we reach here, the server got a call already...
System.out.println("You have succesfully connected");
/*Returns local address of this serversocket and
Returns the remote port number to which this socket is connected. */
System.out.println("Recieved connection from "+clientSocket.getInetAddress() +" on port "+clientSocket.getPort());
new echoThread(clientSocket).start(); //new thread for a client
}
catch( IOException e)
{
System.out.println("I/O error "+e);;
}
}
}
}
class echoThread extends Thread{
Socket clientSocket; // instance variable field
//For every client we need to start separate thread.
public echoThread(Socket clientSocket) //constructor
{
this. clientSocket = clientSocket;
}
//create two threads to send and recieve from client
public void run()
{
RecieveFrmClientThread recieve = new RecieveFrmClientThread(this.clientSocket);
Thread thread = new Thread(recieve);
thread.start();
SndToClientThread send = new SndToClientThread(this.clientSocket);
Thread thread2 = new Thread(send);
thread2.start();
}
}
//INCOMING
class RecieveFrmClientThread implements Runnable
{
Socket clientSocket=null;
BufferedReader br = null;
public RecieveFrmClientThread(Socket clientSocket)
{
this.clientSocket = clientSocket;
} //end constructor
public void run() {
try{
br = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
//returns the input stream through which the server can hear the client.
String messageString="";
System.out.println("Please enter something to send back to client..");
while(true){
while((messageString = br.readLine())!= null)
{//assign message from client to messageString
if(messageString.equals("EXIT"))
{
System.out.println("you have been logout from it");
//break;//break to close socket if EXIT
}
System.out.println("From Client: " + messageString);//print the message from client
messageString="";
}
}
}
catch(Exception ex){System.out.println(ex.getMessage());}
}
}//end class RecieveFromClientThread
//OUTGOING
class SndToClientThread implements Runnable
{
//instance field variables
PrintWriter pwPrintWriter;
Socket clientSock = null;
public SndToClientThread(Socket clientSock)
{
this.clientSock = clientSock;
}
public void run() {
try{
pwPrintWriter =new PrintWriter(this.clientSock.getOutputStream(),true);//returns the output stream through which the server can talk to the client,
while(true)
{
String msgToClientString = null;
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));//get input from server
msgToClientString = input.readLine();//read message from server to send it to client
if(msgToClientString.equals("EXIT"))
{
System.out.println("Disconnecting Client!!");
//System.exit(0);
}
pwPrintWriter.println(msgToClientString);//send message to client with PrintWriter
pwPrintWriter.flush();//flush the PrintWriter
}//end while
}
catch(Exception ex){System.out.println(ex.getMessage());}
}//end run
}//end class SendToClientThread
CLIENT CODE :
import java.io.*;
import java.net.*;
public class Client1 {
//Instance variable field
//private ServerSocket ss;
public static void main(String[] args)
{
try {
Socket sock = new Socket("localhost",444);
/*//create two threads to send and recieve from client
RecieveFromServer recieveThread = new RecieveFromServer(sock);
System.out.println("SOCK=" +sock);
Thread thread2 =new Thread(recieveThread);
thread2.start();
SendToServer sendThread = new SendToServer(sock);
Thread thread = new Thread(sendThread);
thread.start();*/
new echoThread1(sock).start(); //new thread for a client
}
catch (Exception e) {System.out.println(e.getMessage());}
}
}
class echoThread1 extends Thread {
Socket sock;
public echoThread1(Socket sock) {
this.sock = sock;
}
//create two threads to send and recieve from client
public void run()
{
RecieveFromServer recieveThread = new RecieveFromServer(this.sock);
Thread thread = new Thread(recieveThread);
thread.start();
SendToServer sendThread = new SendToServer(this.sock);
Thread thread2 = new Thread(sendThread);
thread2.start();
}
}
class RecieveFromServer implements Runnable
{
Socket sock=null;
BufferedReader recieve=null;
public RecieveFromServer(Socket sock) {
this.sock = sock;
}//end constructor
public void run() {
try{
recieve = new BufferedReader(new InputStreamReader(sock.getInputStream()));//get inputstream for this socket
String msgRecieved = null;
while((msgRecieved = recieve.readLine())!= null)
{
System.out.println("From Server: " + msgRecieved);
}
}catch(Exception e){System.out.println(e.getMessage());}
}//end run
}//end class RecieveFromServer
class SendToServer implements Runnable
{
Socket sock=null;
PrintWriter print=null;
BufferedReader brinput=null;
public SendToServer(Socket sock)
{
this.sock = sock;
}//end constructor
public void run(){
try{
if(this.sock.isConnected()) //Returns TRUE if the socket is successfuly connected to a server
{
System.out.println("Client connected to "+this.sock.getInetAddress() + " on port "+this.sock.getPort());
this.print = new PrintWriter(sock.getOutputStream(), true);
System.out.println("Type your message to send to server..type 'EXIT' to exit");
while(true){
brinput = new BufferedReader(new InputStreamReader(System.in)); // input from client
String msgtoServerString=null;
msgtoServerString = brinput.readLine();
this.print.println(msgtoServerString);
this.print.flush();
if(msgtoServerString.equals("EXIT"))
{
System.out.println("you have logged out of server...Thanks for your visit");
sock.close();
break;}
}
}//end while
}
catch(Exception e){System.out.println(e.getMessage());}
}//end run method
}//end class SendToServer
I have been asked to take this post down, and in particular the code, by a superior of mine
Problem 1: Client did not receive message
Solution: Make sure port matches sending's port
Problem 2: Could not broadcast message
Solution: Use a broadcast address
// Client REceive
DatagramSocket socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress("127.0.0.1", 4002));
// ClientSEnd
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
socket = new DatagramSocket();
socket.setReuseAddress(true);
Just add the port number to the Datagram socket in the receive. it will work fine.
Class - ClientReceive:
DatagramSocket socket = new DatagramSocket(4001);
Set the reuse address to true ..
that will make use of the address whatever it is 4001 4002..etc
socket.setReuseAddress(true);
The problem seems to be that DatagramSocket allows you to send a datagram to a given destination. In your case you are sending to localhost, so that all messages are sent to the local machine only and not to other clients. If you want to reach all network clients should use a broadcast address or use the MulticastSocket class instead DatagramSocket.
import java.net.*;
import java.io.*;
public class ClientSend implements Runnable
{
private Thread t;
private DatagramSocket socket;
private String name;
private String sendingMessage;
private int port;
public ClientSend(int port)
{
this.port = port;
}
public void run()
{
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
socket = new DatagramSocket();
socket.setReuseAddress(true);
while(true)
{
sendingMessage = br.readLine();
byte sendingData[] = sendingMessage.getBytes();
InetAddress clientAddress = InetAddress.getByName("224.0.0.3");
DatagramPacket sendingPacket = new DatagramPacket(sendingData, sendingData.length, clientAddress, 4011);
socket.send(sendingPacket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void start()
{
t = new Thread(this);
t.start();
}
public static void main(String args[]) throws Exception
{
ClientSend CS = new ClientSend(4011);
CS.start();
}
}
import java.net.;
import java.io.;
public class ClientReceive implements Runnable
{
private Thread t;
public ClientReceive()
{
}
public void run()
{
try {
// DatagramSocket socket = new DatagramSocket(null);
MulticastSocket socket = new MulticastSocket(4011);
InetAddress group = InetAddress.getByName("10.10.222.120");
socket.joinGroup(group);
//socket.setReuseAddress(true);
//socket.bind(new InetSocketAddress("10.10.222.120", 4011));
while(true)
{
byte receivingData[] = new byte[1024];
DatagramPacket receivingPacket = new DatagramPacket(receivingData, receivingData.length);
socket.receive(receivingPacket);
String receivingMessage = new String(receivingPacket.getData(), 0, receivingPacket.getLength());
System.out.println("Received: " + receivingMessage);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void start()
{
t = new Thread(this);
t.start();
}
public static void main(String args[]) throws Exception
{
ClientReceive CR = new ClientReceive();
CR.start();
}
}
I am currently trying to take an ArrayList and fill it with sockets using .add, when the socket is passed into the constructor. When i run the debug, it looks like there is only ever 1 socket filling the ArrayList, and no more, even though I've opened like 6 client threads.
Server class
public static void main(String[] args) throws IOException
{
final int PORT = 8888;
ServerSocket server = new ServerSocket(PORT);
System.out.println("Waiting...");
while(true)
{
Socket s = server.accept();
System.out.println("Client connected");
Service service = new Service(s);
Thread t = new Thread(service);
t.start();
}
Service class
public class Service implements Runnable
{
private Socket s;
private Scanner in;
private PrintWriter out;
private ArrayList<Socket> sockets = new ArrayList<Socket>();
public Service(Socket aSocket)
{
s = aSocket;
sockets.add(s);
}
It's because you create a new Service every loop => you will have 6 Service objects with one arrayList in each containing each objects socket. If you want your arrayList to contain all clients / sockets, you will have to have this list in your server class. Also it's rarely a good idea for your clients to know about all other clients.
I also suggest putting in a Thread.sleep(100) in your main method (server), otherwise it will take up a lot of your precessing power.
public static void main(String[] args) throws IOException
{
final int PORT = 8888;
ServerSocket server = new ServerSocket(PORT);
System.out.println("Waiting...");
private ArrayList<Socket> sockets = new ArrayList<Socket>();
while(true)
{
Thread.sleep(100);
Socket s = server.accept();
System.out.println("Client connected");
Service service = new Service(s);
Thread t = new Thread(service);
t.start();
sockets.add(s);
}
I am trying to adapt my simple socket server so that it can have multiple TCP connections, via multithreading, but I can't seem to get it to work. My code so far is as follows, I'm not really sure where to go from here :
import java.net.*;
import java.io.*;
public class DoSomethingWithInput implements Runnable {
private final Socket clientSocket; //initialize in const'r
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String nextline;
while ((nextline = in.readLine())!=null) {
System.out.println(nextline);
} //... close socket, etc.
}
}
public class Socket{
public Socket() {
}
#Override
public void run() {
try {
ServerSocket serverSocket = null;
serverSocket = new ServerSocket(5432);
for (;;) {
ServerSocket serverSocket = null;
serverSocket = new ServerSocket(5432);
for (;;) {
Socket clientSocket = null;
clientSocket = serverSocket.accept();
//delegate to new thread
new Thread(new DoSomethingWithInput(clientSocket)).start();
}
}
}catch (IOException e) {
System.err.println("Could not listen on port: 5432.");
System.exit(1);
}
}
}
Would anyone be able to give me some pointers on how I could do this, and why my current implementation will not work ? I was running through the tips in the Java tutorial http://download.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServerThread.java here, but the example they give here seems to use a lot of outside sources and classes like KnockKnockProtocol etc etc.
Would anyone be able to help me out with this?
Thank you very much!
The problem is that currently you're accepting the connection, but then immediately performing blocking reads on it until it's closed:
// After a few changes...
Socket clientSocket = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String nextLine;
while ((nextLine = in.readLine()) != null) {
System.out.println(nextline);
}
That means the same thread which accepts the connection is trying to handle the connection. That won't let you use multiple connections at the same time.
Instead, create a class (e.g. ConnectionHandler) which implements Runnable, and has a constructor taking a Socket. Its run method should handle the connection. Then change your code to:
Socket clientSocket = serverSocket.accept();
Runnable connectionHandler = new ConnectionHandler(clientSocket);
new Thread(connectionHandler).start();
That will leave your "main" thread free to wait for the next connection.
(By the way, the KnockKnockProtocol class isn't really "external" - it's part of the example. They just didn't make it very clear that the source is here...)
You're not multithreading. You're creating a thread which binds on a port and then reads from any client socket until the connection is closed.
You need to pass the socket to a new thread and have it read.
public class DoSomethingWithInput implements Runnable {
private final Socket clientSocket; //initialize in const'r
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String nextline;
while ((nextline = in.readLine())!=null) {
System.out.println(nextline);
} //... close socket, etc.
}
}
//...
ServerSocket serverSocket = null;
serverSocket = new ServerSocket(5432);
for (;;) {
Socket clientSocket = null;
clientSocket = serverSocket.accept();
//delegate to new thread
new Thread(new DoSomethingWithInput(clientSocket)).start();
} //...