I'm building something here and I found myself in a pickle. Just some introduction first. I'm developing a client-server game. One of the functions it has is a chat that players can use to talk to another.
Player1 send a message to the server and the server forwards it to the respective Player2. My problemas is: how can I access classes from another thread so I can get the Socket object to relay the message to Player2.
while (listening)
{
try
{
//this is how I start a thread for each connection
//do I need to use identifiers or something?
new Client(serverSocket.accept()).start();
}
catch(IOException A)
{
reportError(A.toString()); //reportError is a function of mine
}
}
there are many ways to achieve this, the easiest would be:
public void start(){
try {
ServerSocket ss = new ServerSocket(port);
System.out.println("Starting server on port: " + port);
while (serverState) {
Socket socket = ss.accept();
//stop server
if (!serverState) {
break;
}
Client handler = new Client(this, socket);
handler.start();
}
//when server is stopped, close all connections
for (Client client : clients.values()) {
client.closeConnection();
}
} catch (IOException e) {
}
}
if you send "this" inside the constructor of client and set it as a private variable you could Access it from the run function(other thread)
Related
I have to implement (in the server side) the quit command which disconnects any clients still connected and closes the server.
Here the server code.
public class Server {
public static void main (String args []) {
if (args.length < 1) {
System.err.println("Usage: java Server <port>");
return;
}
int port = Integer.parseInt(args[0]);
try {
ServerSocket listener = new ServerSocket(port);
Files input = new Files();
while (true) {
System.out.println("Listening...");
Socket s = listener.accept();
System.out.println("Connected");
Thread clientHandlerThread = new Thread(new ClientHandler(s,input));
clientHandlerThread.start();
}
} catch (IOException e) {
System.err.println("Error during I/O operation:");
e.printStackTrace();
}
}
}
how can the server accept command line instructions while it is running?
First of all, you have to keep track of all the clients that you create by putting their instances in a list so that when you're going to shutdown everything, you could access them and tell them to finish their job.
And about how to tell the thread instances to do that, you should call their interrup() method to inform them that they should finish/stop whatever it's doing. Calling the interrupt() method on a thread leads an InterruptedException in the thread that you should handle and gracefully finish whatever you're doing.
For example if you have something like this in the run method of your ClientHandler:
while (true) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
Thread.currentThread().interrupt();
System.out.println(
"We've been asked to finish up the communication. Bye! ;)");
}
// do your business
}
This was of course a very simplified scenario to demonstrate the overall approach. You should be able to find tons of tutorials online about how to use the interrupt.
am currently working on a project where I have to build a multi thread server. I only started to work with threads so please understand me.
So far I have a class that implements the Runnable object, bellow you can see the code I have for the run method provided by the Runnable object.
public void run() {
while(true) {
try {
clientSocket = serversocket.accept();
for (int i = 0; i < 100; i++) {
DataOutputStream respond = new DataOutputStream(clientSocket.getOutputStream());
respond.writeUTF("Hello World! " + i);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
//
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
Bellow is the main method that creates a new object of the server class and creates a threat. initializing the Thread.
public static void main(String args[]) {
new Thread(new Server(1234, "", false)).start();
}
I know this creates a new thread but it does not serve multiple clients at once. The first client need to close the connection for the second to be served. How can I make a multi threated server that will serve different client sockets at once? Do I create the thread on the clientSocket = serverSocket.accept();
yes.
from the docs:
Supporting Multiple Clients
To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads—one thread per each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
The thread reads from and writes to the client connection as necessary.
https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
I'm trying to get a threaded chatserver working. But my socket is closing and I have no clue why it is.
In the server class I create a new ClientHandler
addHandler(new ClientHandler(this, incoming));
addHandler starts the thread and adds the new ClientHandler to an ArrayList in server.
incoming is the client socket.
public ClientHandler(Server serverArg, Socket sockArg) {
server = serverArg;
client = sockArg;
System.out.println(client.isClosed());
}
There is nothing called between
public void run() {
try {
System.out.println(client.isClosed());
in = new Scanner(client.getInputStream());
out = new PrintWriter(client.getOutputStream(), true);
announce();
System.out.println("Waiting for input");
boolean done = false;
while(!done && in.hasNextLine()) {
System.out.println("There is input!");
server.broadcast(clientName + ": " + in.nextLine());
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
When I run this code. This is the output:
false
true
java.net.SocketException: Socket is closed
Why is it closing immediately after creating this class / before starting it?
The connection is being closed by your code between when you add the handler and when the run() method is called. I suggest you add a breakpoint to the close method in the JDK and see where it is called. Or have a look at the code after you add the handler.
You can use a networking sniffer like wireshark or tcpdump.
To find out that if the connection broke due to the server side.
I guess that maybe the client side close the connection.
So, I have the following code that catches a new connection, then hands that connection to its own thread to handle the client.
private void loop(int port) {
// Opens a port for connections.
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("Server running in port " + port);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Listens for a connection
while (onlineState == true && serverSocket != null) {
Socket clientSocket = new Socket();
try {
clientSocket = serverSocket.accept();
System.out.println(clientSocket.getInetAddress() + " has connected to the port " + clientSocket.getPort());
new Thread(new SocketThread(clientSocket)).run();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
So, my problem here is that when I try to connect with multiple client apps to the server, the server only seems to either accept one connection at any given time. The client itself is a very simple application of the basic tutorial: it simply repeats any string that the server sends to it.
I have two guesses as to why this is happening: a) there's something wrong with my handling code, b) it's because both connections are from the same IP.
However, neither case is a good thing. Any ideas what I'm doing wrong? (Except everything)
Two things:
You want to call start(), not run() on your Thread object. The difference is that start() actually goes and does threaded stuff, like running it in the background. Calling run() from where you call it there will handle all the client communication right there, inline. That's why you only ever accept one connection - you won't accept any more until you've serviced that client.
You don't want to call clientSocket.close() in your main thread. In your implementation of SocketThread, call clientSocket.close() at the end of your run() method, probably inside a finally block.
Also, does SocketThread extend Thread? If so, you don't need new Thread(), just do
new SocketThread(clientSocket).start();
If it doesn't extend Thread, why not name it SocketRunnable or ClientRunnable or something like that.
I have developed a java swing client-server application. The server has many services like database service, cache service and client service talks to the clients.
The client service opens a socket on a port and listens to incoming connections. It spawns a new thread for every client connection, creates a session and reads the incoming serialized object. It maintains this session (keeps the thread alive) till the client issues a 'CLOSE_SESSION' command.
What i would like to know is if its correct to spawn a new thread for every new client-socket session. Thanks.
My client service code is as below.
Code to create server socket:
try {
ServerSocket socket = new ServerSocket(serverPort);
Socket listener = socket.accept();
Thread client = new Thread(new ClientHandler(listener));
client.start();
} catch (IOException ex) {
log.error(new Throwable(ex));
}
Code to spawn new thread for every client
class ClientHandler implements Runnable {
private static Logger log = Logger.getLogger(ClientHandler.class);
private Socket listener;
public ClientHandler(Socket listener) {
this.listener = listener;
}
public void run() {
try {
ObjectInputStream inStream = new ObjectInputStream(
listener.getInputStream());
try {
ServiceRequestResponse request = (ServiceRequestResponse) inStream
.readObject();
if (request != null && request.getServiceCommand() != null) {
ServiceCommand command = request.getServiceCommand();
log.debug("command : " + command.getCommand());
log.debug("is session alive? " + request.isAlive());
log.debug("ServiceCommand.CREATE_SESSION : "
+ ServiceCommand.CREATE_SESSION.getCommand());
if (!request.isAlive()
&& command.getCommand().equals(
ServiceCommand.CREATE_SESSION.getCommand())) {
// No session yet, and service command issued is login.
// Call login service, check credentials and create
// session.
request.setSessionId(UUID.randomUUID());
log.debug("Created user session with id : "
+ request.getSessionId());
} else {
if (command.getCommand().equals(
ServiceCommand.CLOSE_SESSION)) {
// Close session and do clean up here
}
// Here session is alive.
while (!ServiceCommand.CLOSE_SESSION.equals(command
.getCommand())) {
// Read the service command from the request
// response and
// Hand it over to the appropriate handler.
}
}
}
} catch (ClassNotFoundException ex) {
log.error(new Throwable(ex));
}
} catch (IOException ex) {
}
}
}
If your client session request can last long then thread-per-connection is a good solution.
Alternatives are:
Using NIO;
Using thread pool if client requests are short.