I'm working on this:
//
// Application: Golf App Server
// Author: Andres Martinez
// Year: 2016
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package com.andress.golfappserver.listener;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import com.andress.golfappserver.beans.Client;
import com.andress.golfappserver.client.ClientHandler;
import com.andress.golfappserver.client.ClientStatus;
/**
* This class has two main goals. First, start to listening the server in a certain port and
* second, accepting incoming connections from clients. It runs as a Thread. The server
* Administrator should provide the number of the port. When the Listener object is initialized
* the ServerSocket will be listening to the port provided. To start to accept new connections
* the Thread should be started. The Listener will create a new Client object every time when accepts
* a new connection. The new Client will have the Socket accepted and a ClientStatus by default of
* Connected. Then, a ClientHandler will be created with the Client as an argument.
* The ClientController will be notified every time a new ClientHandler Thread is created.
*/
public class Listener implements Runnable {
private final int port;
private final ServerSocket serverSocket;
/**
* The Listener is instantiated and initialized with a port number
* supplied by the Server Administrator. Then, the constructor
* creates a new SeverSocket with this port ready to start to listen
* for new connections.
* #param port Integer to identify port.
*/
public Listener(final int port) {
this.port = port;
this.serverSocket = listen();
}
public int getPort() {
return port;
}
public ServerSocket getServerSocket() {
return serverSocket;
}
/**
* Creates Client objects for accepted connections and spawns
* a new ClientHandler for each of the new Client connections.
*/
#Override
public void run() {
Client client = createClient(accept(this.serverSocket));
ClientHandler clientHandler = new ClientHandler(client);
//clientHandler.start();
}
/**
* Binds the port provided by the Server Administrator to a new
* ServerSocket.
* #return ServerSocket listening to the port provided.
*/
private final ServerSocket listen() {
try (ServerSocket serverSocket = new ServerSocket(port)) {
return serverSocket;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Starts to listen for connections to the port specified.
* #param serverSocket ServerSocket to listen for.
* #return Socket of the accepted connection.
*/
private final Socket accept(final ServerSocket serverSocket) {
try (Socket clientSocket = serverSocket.accept()) {
return clientSocket;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Creates a new Client Bean with ClientStatus by default
* of Connected and the Socket of the new connection.
* #param clientSocket Socket for the new connection.
* #return Client object with ClientStatus of Connected by default.
*/
private final Client createClient(final Socket clientSocket) {
Client client = new Client();
client.setSocket(clientSocket);
client.setStatus(ClientStatus.CONNECTED);
return client;
}
}
I'm having an error with the socket but, I'm not interested in this particular error. What I would like to know if a thread always need the code to be executed inside the run() method or is there a way to do it like I'm attempting to do it?
Error:
Exception in thread "Thread-0" java.lang.RuntimeException: java.net.SocketException: Socket is closed
at com.andress.golfappserver.listener.Listener.accept(Listener.java:85)
at com.andress.golfappserver.listener.Listener.run(Listener.java:58)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketException: Socket is closed
at java.net.ServerSocket.accept(ServerSocket.java:509)
at com.andress.golfappserver.listener.Listener.accept(Listener.java:82)
... 2 more
Process finished with exit code 0
a thread always need the code to be executed inside the run() method
Yes. That's what a Java Thread does.
or is there a way to do it like I'm attempting to do it?
You're actually calling some methods inside run(), so it should work altogether.
UPDATE
In accept() method:
private final Socket accept(final ServerSocket serverSocket) {
try (Socket clientSocket = serverSocket.accept()) {
return clientSocket;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
You are accepting the socket in a try-with-resources construction. It means that as soon as this method ends, the socket closes. I bet that's not what you want to be done. Try this instead:
private final Socket accept(final ServerSocket serverSocket) {
try {
return serverSocket.accept();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Related
I'm implementing a Java multi threaded server that receive messages from a client and broadcast them to the other clients, but it's not working. The server receives the client messages only when the client application closes (the client socket closes). The application is divided in two modules: client and the server. The code is a little bit long, I know that is annoying to read all, but please help me to solve this problem.
Here is the GitHub application link to facilitate the reading. Please checkout the test branch.
The server module classes:
GameServer.java
/*
* This file contains the application core server responsible to wait and accept clients connections requests.
* */
package server;
import com.sun.istack.internal.NotNull;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* #author Michael Pacheco <b>pacheco#decom.ufop.br</b>
* #version 1.0
*
* This class is responsible to receive clients connections and send messages to them.
* */
public class GameServer implements Runnable {
/**
* The port number used to start the server.
* */
private int port;
/**
* The socket used to accept clients connections.
* */
private ServerSocket serverSocket;
/**
* A {#link Logger} used to print messages for debug purpose.
* */
private final static Logger LOGGER = Logger.getLogger(GameServer.class.getName());
/**
* A hash set to store the clients sockets
* */
private HashSet<Socket> clientsSockets;
private GameServer() {
clientsSockets = new HashSet<>();
}
/**
* Instantiates a new {#link GameServer} with a given port number.
* #param port the port number used to start the server.
* */
public GameServer(int port) {
this();
this.port = port;
}
/**
* Override method from Runnable. This method is called when an attempt to close the application occur.
* */
#Override
public void run() {
Scanner s = new Scanner(System.in);
while (s.hasNext()) s.nextLine();
shutdown();
}
/**
* Start the server and listen for clients connections requests.
* */
public void start () {
try {
LOGGER.log(Level.INFO, "Trying to start the server...\n");
serverSocket = new ServerSocket(this.port);
final String ip = InetAddress.getLocalHost().getHostAddress();
LOGGER.log(Level.INFO, "Server started!\n\tPort: {0}\n\t IP: {1}\n", new Object[] {port, ip});
LOGGER.log(Level.INFO, "Press Ctrl-D to shutdown the server!\n");
waitForConnections();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to initialize the server! {0}\n", e.getMessage());
e.printStackTrace();
}
}
/**
* Wait for clients connections requests
* */
private void waitForConnections() {
new Thread(this).start();
try {
//noinspection InfiniteLoopStatement
while (true) {
Socket clientSocket = serverSocket.accept();
LOGGER.log(Level.INFO, "New client connected! {0}\n", clientSocket);
clientSocket.getOutputStream().write("You're now connected to the server\n".getBytes());
clientSocket.getOutputStream().flush();
allocateClient(clientSocket);
}
} catch (IOException e) {
// No need for printing stacktrace if the serverSocket was closed by the shutdown method
if (!serverSocket.isClosed())
e.printStackTrace();
}
}
/**
* This method is responsible to delegate the communication with the client to the {#link ClientListener}.
* #param clientSocket the client socket to delegate.
* */
private void allocateClient(#NotNull Socket clientSocket) {
clientsSockets.add(clientSocket);
new Thread(new ClientListener(clientSocket, this)).start();
}
/**
* Shutdown the server
* */
private void shutdown () {
try {
LOGGER.log(Level.INFO, "Trying to shutdown the server...\n");
// TODO Clear resources
for (Socket soc : clientsSockets) removeClient(soc);
serverSocket.close();
LOGGER.log(Level.INFO, "Server successfully shut down!\n");
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to shutdown the server! {0}\n", e.getMessage());
e.printStackTrace();
}
}
/**
* Send a message to a single client.
* #param message the message to be sent.
* #param clientSocket the socket of the client that will receive the message
* */
private void sendMessage (#NotNull Object message, #NotNull Socket clientSocket) {
try (PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true)) {
writer.println(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Send a message to all clients except the given one.
* #param message the message to be sent.
* #param excludedClient the client that won't receive the message.
* */
void broadcast (#NotNull Object message, #NotNull Socket excludedClient) {
for (Socket client : clientsSockets) {
if (excludedClient == client)
continue;
sendMessage(message, client);
}
}
/**
* Remove the given client from server.
* #param clientSocket the client to be removed.
* */
void removeClient (#NotNull Socket clientSocket) {
try {
clientSocket.close();
clientsSockets.remove(clientSocket);
LOGGER.log(Level.INFO, "Client removed! {0}\n", clientSocket);
// TODO broadcast the client disconnection
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientListener.java
package server;
import com.sun.istack.internal.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* #author Michael Pacheco <b>pacheco#decom.ufop.br</b>
* #version 1.0
*
* This class is responsible to listen messages of a single client and send them to the server and then to the other clients.
* */
public class ClientListener implements Runnable {
/**
* The socket used to communicate with the delegated client.
* */
private Socket clientSocket;
/**
* A reference to the {#link GameServer} used to call the {#link GameServer} broadcast method.
* #see GameServer
* */
private GameServer server;
/**
* A {#link Logger} used to print messages for debug purpose.
* */
private final static Logger LOGGER = Logger.getLogger(ClientListener.class.getName());
/**
* Instantiate a new {#link ClientListener} with a given client socket.
*
* #param clientSocket the socket of the delegated client.
* #param server the server reference used to call the broadcast method.
* */
ClientListener(#NotNull Socket clientSocket, #NotNull GameServer server) {
this.clientSocket = clientSocket;
this.server = server;
}
/**
* Listen for client messages and send it to the server.
* */
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
String message;
while ((message = reader.readLine()) != null) {
// send received message to the server
LOGGER.log(Level.INFO, "Message received!\n\t From: {0}\n\tMessage: {1}\n",
new Object[]{clientSocket, message});
server.broadcast(message, clientSocket);
}
} catch (IOException e) {
if (!clientSocket.isClosed())
e.printStackTrace();
} finally {
// send the client to server to be disconnected
server.removeClient(clientSocket);
}
}
}
The client module classes:
GameClient.java
package client;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GameClient {
public static void main(String[] args) {
final String serverAddress = args.length == 2 ? args[0] : "localhost";
final int port = args.length == 2 ? Integer.parseInt(args[1]) : 5000;
final Logger LOGGER = Logger.getLogger(GameClient.class.getName());
try {
Socket serverSocket = new Socket(serverAddress, port);
LOGGER.log(Level.INFO, "Connection successful! {0}\n", serverSocket);
new Thread(new ClientWriterThread(serverSocket)).start();
new Thread(new ClientReaderThread(serverSocket)).start();
} catch (IOException e) {
LOGGER.log(Level.SEVERE,"Failed to connect with the server\n", e);
e.printStackTrace();
}
}
}
ClientWriterThread.java
package client;
import com.sun.istack.internal.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* #author Michael Pacheco
* #version 1.0
* This class is responsible to read client messages and send it to the server.
* */
public class ClientWriterThread implements Runnable {
/**
* The socket used to send messages to the server.
* */
private Socket serverSocket;
/**
* Instantiate a new {#link ClientReaderThread} with a given server socket.
* #param serverSocket the socket used to send messages to the server.
* */
ClientWriterThread(#NotNull Socket serverSocket) {
this.serverSocket = serverSocket;
}
/**
* Read messages typed by the client and send it to the server.
* */
#Override
public void run() {
try {Thread.sleep(1000);}
catch (InterruptedException e) {e.printStackTrace();}
BufferedReader keyboardReader = null;
try (PrintWriter socketWriter = new PrintWriter(serverSocket.getOutputStream(), true)) {
keyboardReader = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = keyboardReader.readLine()) != null) socketWriter.write(line);
} catch (IOException e) {
if (!serverSocket.isClosed())
e.printStackTrace();
} finally {
try {
if (keyboardReader != null) keyboardReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ClientReaderThread.java
package client;
import com.sun.istack.internal.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* #author Michael Pacheco
* #version 1.0
* This class is responsible to read messages sent by the server and show them to the client.
*/
public class ClientReaderThread implements Runnable {
/**
* The socket used to read messages sent by the server.
*/
private Socket serverSocket;
ClientReaderThread(#NotNull Socket serverSocket) {
this.serverSocket = serverSocket;
}
/**
* Read messages sent by the server.
* */
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()))) {
String message;
while ((message = reader.readLine()) != null) System.out.println(message);
} catch (IOException e) {
if (!serverSocket.isClosed())
e.printStackTrace();
}
}
}
Be sure to PrintWriter.flush() the messages you send after each write() in ClientWriterThread.java.
As a side note, in order to make the code clearer change your serverSocket variable name to clientSocket in the appropriate classes (GameClient.java and ClientWriterThread.java).
You use PrintWriter with autoflush, but you don't use println(...) or format(...). The .write() is not subject to the autoflush.
FYI, clientsSockets is not thread safe, you add/remove on distinct threads. Not necessarily the bug, but careful. Also, spinning non-daemon threads without keeping a reference is risky; always keep threads under control and don't count too much on interrupt()/InterruptedException/InterruptedIOException...
I have a technogical question regarding Java Sockets.
For example lets assume I have one Java Sockets Server and n multiple clients.
Is it possible to send data from the Server to any or all Clients in nearly realtime?
More precisely:
Is there kind of Listener which can be implemented in a Sockets Client?
or do I need a loop in the client code where I ask every x milliseconds if there is a task for me?
Can somebody tell me what approach would be the best one?
And in addition if somebody has a code example I would be happy too.
Thanks!
You can establish a Thread in your client which listens to the socket and waits. It will continue when it gets data from the server.
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
public class ResponseThread extends Thread {
private final Socket socket;
/**
* Client is a selfmade interface which has no direct connection to socket communication.
* i build it to provide start(), stop() and isRunning() methods.
*/
private final Client client;
/**
* #param client encapsulated methods to check and manage the client status itself.
* #param socket the socket which is connected to the server.
*/
public ResponseThread(final Client client, final Socket socket) {
this.client = client;
this.socket = socket;
}
#Override
public void run() {
ObjectInputStream reader = null;
try(ObjectInputStream reader = new ObjectInputStream(socket.getInputStream())) {
while (client.isRunning()) {
try {
// The thread will wait here until the server sends data.
final String line = (String) reader.readObject();
if (null == line || line.isEmpty()) {
client.stop();
} else {
System.out.println(line);
}
} catch (IOException | ClassNotFoundException e) {
client.stop();
}
}
} catch (IOException ex) {
System.out.println("ERROR Abort reading. Could not establish InputStream from Socket.");
} finally {
try {
reader.close();
} catch (IOException ex) {
System.out.println("FATAL Could not close Socket.InputStream.");
}
}
}
public Socket getSocket() {
return socket;
}
}
I've searched stackoverflow for an answer to my question, but I can't get my answer from those threads. My question is why a ServeerSocket Object's accept() method returns a Socket object listening on a different port on the server machine, while the port that the server is listening to is another.
JAVA Code:
package chat.server;
import java.io.*;
import java.net.*;
public class ServerApp {
public String[] advices = {"Take smaller bites",
"Go for the tight jeans. No they do NOT make you look fat.",
"One word: inappropriate",
"Just for today, be honest. Tell your boss what you *really* think",
"You might want to rethink that haircut."};
public ServerSocket serverSocket;
public ServerApp()
{
try
{
serverSocket = new ServerSocket(4245);
System.out.println("Server Started.");
}catch (Exception exception)
{
exception.printStackTrace();
}
}
public static void main(String[] args) {
ServerApp server = new ServerApp();
while(true)
{
server.sendMessage();
}
}
public void sendMessage()
{
String advice;
try
{
Socket socket = serverSocket.accept();//here comes my question
System.out.println(socket.getPort());
PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
advice = getAdvice();
printWriter.write(advice);
printWriter.close();
System.out.println(advice);
}catch (Exception exception)
{
exception.printStackTrace();
}
}
private String getAdvice() {
int random = (int) (Math.random() * advices.length);
return advices[random];
}
}
Isn't that normal that the server listens and answers the client from the same port number?
If you're looking to get back the value 4245 (the port your server socket is listening on) from the connected socket, you want getLocalPort, not getPort.
getPort:
Returns the remote port number to which this socket is connected.
getLocalPort:
Returns the local port number to which this socket is bound.
(My emphasis)
why a ServeerSocket Object's accept() method returns a Socket object listening on a different port on the server machine
It doesn't. What you're looking at is the remote port, at the client end. The local port is given by getLocalPort(), and it is the same as the ServerSocket's.
NB Only the ServerSocket is 'listening'. The accepted Socket is connected, and ready for I/O.
Hey guys i've just recently been getting a hang of sockets but ran into an issue with posting to multiple clients. Ive made it multithreaded to handle this and am attempting to hold all client data the server needs to send to in a hashmap, however when cycling and adding to the hashmap. it seems to only ever add one person. Heres the code..
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
public class HostMain extends Thread {
/**
* The set of all names of clients in the chat room. Maintained
* so that we can check that new clients are not registering name
* already in use.
*/
private static HashMap<String, ConnectedUsers> users = new HashMap<String, ConnectedUsers>();
public HostMain() throws IOException
{
}
public void run()
{
try
{
System.err.println("SERVER:The chat server is running.");
ServerSocket listener = new ServerSocket(PORT);
System.err.println("SERVER:socket created");
Constants.getInstance().getStatusLabel().setText("Server is running. Join when ready");
try {
while (true) {
System.err.println("SERVER:New handler being created");
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
catch(Exception e)
{
Constants.getInstance().getStatusLabel().setText("SERVER:A HOST IS ALREADY RUNNING ON THIS PORT!");
System.err.println("SERVER:A HOST IS ALREADY RUNNING ON THIS PORT!");
}
}
/**
* The port that the server listens on.
*/
private static final int PORT = 1337;
/**
* The appplication main method, which just listens on a port and
* spawns handler threads.
*/
/**
* A handler thread class. Handlers are spawned from the listening
* loop and are responsible for a dealing with a single client
* and broadcasting its messages.
*/
private static class Handler extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private ObjectInputStream oin;
private ObjectOutputStream oout;
/**
* Constructs a handler thread, squirreling away the socket.
* All the interesting work is done in the run method.
*/
public Handler(Socket socket) {
this.socket = socket;
}
/**
* Services this thread's client by repeatedly requesting a
* screen name until a unique one has been submitted, then
* acknowledges the name and registers the output stream for
* the client in a global set, then repeatedly gets inputs and
* broadcasts them.
*/
public void run() {
try {
// Create object streams for the socket.
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
oin = new ObjectInputStream(socket.getInputStream());
oout = new ObjectOutputStream(socket.getOutputStream());
//add socket to a list
users.put(name,new ConnectedUsers(name,oout));
System.err.println(users.size());
// Accept messages from this client and broadcast them.
// Ignore other clients that cannot be broadcasted to.
while (true) {
Object obj = oin.readObject();
Messages message = (Messages)obj;
if(obj.getClass().equals(Messages.class))
{
for(Map.Entry<String, ConnectedUsers> entry:users.entrySet())
{
ConnectedUsers user = entry.getValue();
user.objectWriter.writeObject(message);
}
}
}
} catch (IOException | ClassNotFoundException e) {
System.out.println(e);
} finally {
// This client is going down! Remove its name and its print
// writer from the sets, and close its socket.
if (name != null) {
users.remove(name);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}
name seems to be always null so you keep using the same key (null) which would explain why there is only one user in your map.
Also note that HashMap is not thread safe - unless you add some form of synchronization when accessing the map from your threads it could yield surprising results.
You could instead use a thread safe map, for example a ConcurrentHashMap.
Do I have to close all the sockets after using it? Where should I put them in this code? My program just works normally when I run it. However, when I re-run it, it said "Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind". Therefore, I think I did not close all the socket after using it.
import java.io.*;
import java.net.*;
import java.util.*;
public class Server2 {
public static void main(String args[]) throws Exception {
int PORT = 5555; // Open port 5555
//open socket to listen
ServerSocket server = new ServerSocket(PORT);
Socket client = null;
while (true) {
System.out.println("Waiting for client...");
// open client socket to accept connection
client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
}
}
}
Call server.close() in a finally block.
ServerSocket server = new ServerSocket(PORT);
try {
while (true) {
System.out.println("Waiting for client...");
// open client socket to accept connection
Socket client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
}
} finally {
server.close();
}
Address already in use: JVM_Bind - means, that you operation system is not closed socket after previous use. It closes on timeout about 30-180 seconds.
I don't realy know how to do this in java, but in C code it may be done like this, before bind system function call:
int yes = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
That mean: set the flag (option) SO_REUSEADDR to sockfd socket.
In java must exists appropriate mechanism for do the same.
You are running an infinite while loop , have a boolean variable to say when to stop , i think you are not exiting gracefully, that is why port is not closed.
May be you can try like this
import java.io.*;
import java.net.*;
import java.util.*;
public class Server2 {
static int NUM_CONN_TO_WAIT_FOR=15;
boolean exitServer =false;
public static void main(String args[]) throws Exception {
int PORT = 5555; // Open port 5555
//open socket to listen
ServerSocket server = new ServerSocket(PORT);
Socket client = null;
static int connections =0;
try
{
while (!exitServer ) {
System.out.println("Waiting for client...");
// open client socket to accept connection
if ( connections < NUM_CONN_TO_WAIT_FOR )
{
client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
} else
{
exitServer =true;
}
connections++;
}
} catch (Exception e)
{
System.out.println(e.printStackTrace());
}
finally
{
if ( client != null)
client.close();
if ( server!= null)
server.close();
}
}
}