I want to make a game (jungle speed), where players click totem and it changes position on screen (I'm using swing, it's not important) and information about localisation change should be sent to everyone.
I want to make a server which gets player's click, verifies it and send update info to all.
In this scenario, client listens to server if someone has clicked totem and meanwhile is ready to send info about his own click.
Server listens to everyone and meanwhile is ready to send information to all.
I try to implement it like this:
Server generates thread for each player, listens inside for click and is ready to be interrupted to send new totem localisation (I use method shutdownNow on ExecutorService, which should cause IOException in threads which will made them to stop doing loop and send information about new localisation) then client-side gets it.
Same for client side if he clicks, thread is interrupted and instead of waiting for new localisation it sends his click.
The problem is that I can't create streams. Here is output and code
Client side:
2017-05-22T23:04:06.417Connected
2017-05-22T23:04:06.417Trying to make output
2017-05-22T23:04:06.417Trying to make input
Server side:
2017-05-22T23:04:03.278Server Thread :Socket created
2017-05-22T23:04:03.294Server Thread :Waiting for client!
2017-05-22T23:04:06.385Server Thread :Correct, connected!
2017-05-22T23:04:12.239Trying to make input
Client side code :
package client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ServerConnection implements Runnable {
MainWindow frame;
Socket toServ;
Socket fromServ;
ServerSocket myServ;
ObjectOutputStream out;
ObjectInputStream reader;
public int x, y, totemx, totemy;
int i = 0;
public ServerConnection(MainWindow frame) {
try {
this.frame = frame;
myServ = new ServerSocket(1338);
toServ = new Socket("localhost", 1337);
fromServ = myServ.accept();
System.out.println(LocalDateTime.now() + "Connected");
try {
System.out.println(LocalDateTime.now() + "Trying to make output");
out = new ObjectOutputStream(new BufferedOutputStream(toServ.getOutputStream()));
} catch (IOException ex) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(LocalDateTime.now() + "Trying to make input");
reader = new ObjectInputStream(new BufferedInputStream(fromServ.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
System.out.println(LocalDateTime.now() + "Running");
while (true) {
try {
int xGot, yGot;
System.out.println(LocalDateTime.now() + "Waiting for params");
xGot = (int) reader.readInt();
yGot = (int) reader.readInt();
System.out.println(LocalDateTime.now() + "I got new params");
frame.refresh(xGot, yGot);
} catch (IOException ex) {
{
try {
System.out.println(LocalDateTime.now() + "Sending click thread: Sending my click");
out.writeInt(x);
out.writeInt(y);
System.out.println(LocalDateTime.now() + "Sent");
} catch (IOException ex1) {
Logger.getLogger(ServerConnection.class.getName()).log(Level.SEVERE, null, ex1);
}
}
}
}
}
}
Server side code
First file:
package javaapplicationserwer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Japko
*/
public class Server{
public int x, y;
ServerSocket serv = null;
ExecutorService executor;
Server()
{
x = 10;
y = 50;
executor = Executors.newFixedThreadPool(4);
try {
serv = new ServerSocket(1337);
System.out.println(LocalDateTime.now() + "Server Thread :Socket created");
while (true) {
System.out.println(LocalDateTime.now() + "Server Thread :Waiting for client!");
Socket fromSocket = serv.accept();
Socket toSocket=new Socket(fromSocket.getInetAddress(),1338);
System.out.println(LocalDateTime.now() + "Server Thread :Correct, connected!");
ClientConnection temp = new ClientConnection(fromSocket,toSocket, this);
executor.submit(temp);
}
} catch (IOException ex) {
Logger.getLogger(JavaApplicationSerwer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void updateIt(int x, int y) {
System.out.println(LocalDateTime.now() + "Updating");
if (x == this.x && y == this.y) {
Random rand = new Random();
this.x = rand.nextInt(300);
this.y = rand.nextInt(300);
System.out.println(LocalDateTime.now() + "Updated");
executor.shutdownNow();
}
System.out.println(LocalDateTime.now() + "I notify");
}
}
Second file (Class implementing runnable which is created for each player by server):
package javaapplicationserwer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClientConnection implements Runnable {
Socket fromSocket, toSocket;
InetAddress IP;
Server serv;
ObjectOutputStream out;
ObjectInputStream reader;
public ClientConnection(Socket fromSocket, Socket toSocket, Server serwer) {
this.fromSocket = fromSocket;
this.toSocket = toSocket;
this.serv = serwer;
try {
System.out.println(LocalDateTime.now() + "Trying to make input");
reader = new ObjectInputStream(new BufferedInputStream(fromSocket.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(LocalDateTime.now() + "Trying to make output");
try {
out = new ObjectOutputStream(new BufferedOutputStream(toSocket.getOutputStream()));
} catch (IOException ex) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
while (true) {
System.out.println(LocalDateTime.now() + "Starting");
try {
int xGot, yGot;
while (true) {
System.out.println(LocalDateTime.now() + "Waiting for params");
try {
xGot = reader.readInt();
yGot = reader.readInt();
System.out.println(LocalDateTime.now() + "Got this");
//serv.wait();
System.out.println(LocalDateTime.now() + "Waited");
serv.updateIt(xGot, yGot);
System.out.println(LocalDateTime.now() + "Verified");
} catch (IOException ex) {
try {
out.writeInt(serv.x);
out.writeInt(serv.y);
} catch (IOException ex1) {
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex1);
}
Logger.getLogger(ClientConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
} finally {
System.out.println(LocalDateTime.now() + "I'm not serving for you");
}
}
}
}
It sounds like client has mate output (which means that server has input), then client wants to create input, but server escapes from constructor and doesn't even try to make its output.
Thanks in advance for help.
Sockets are a two (2) way connection. You only need one socket in the client connection.
here is some code that does simple tcp:
package p;
import java.io.*;
import java.net.*;
import java.util.function.*;
public class Tcp {
static class Acceptor extends Thread {
Acceptor(ServerSocket serverSocket,Consumer<Socket> consumer) {
super("Acceptor");
this.serverSocket=serverSocket;
this.consumer=consumer;
}
#Override public void run() {
p("acceptor running on: "+serverSocket);
while(true)
try {
Socket socket=serverSocket.accept();
if(consumer!=null) consumer.accept(socket);
} catch(IOException e) {
p(getName()+" caught: "+e);
break;
}
}
final ServerSocket serverSocket;
final Consumer<Socket> consumer;
}
static class Connection implements Runnable {
Connection(Socket socket) throws IOException {
this.socket=socket;
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
out=new OutputStreamWriter(socket.getOutputStream());
}
boolean send(String string) {
try {
p("sending: "+string+" on: "+socket);
out.write(string+'\n'/*System.getProperty("line.separator")*/);
out.flush();
return true;
} catch(IOException e) {
e.printStackTrace();
}
return false;
}
void process(String string) {
p("connection on: "+socket+" received: "+string);
}
#Override public void run() {
p("connection on: "+socket+" is runing.");
String string=null;
try {
p("connection on: "+socket+" is trying to read.");
while((string=in.readLine())!=null) {
process(string);
}
} catch(IOException e) {
e.printStackTrace();
}
process(null);
p("connection on: "+socket+" is exiting run()");
}
final Socket socket;
final BufferedReader in;
final Writer out;
}
public static void p(String string) {
System.out.println(string);
}
Tcp(String host,Integer service) throws IOException {
ServerSocket serverSocket=new ServerSocket();
SocketAddress socketAddress=new InetSocketAddress(host,service);
serverSocket.bind(socketAddress);
Consumer<Socket> socketConsumer=(socket)-> {
p("accepted from: "+socket);
try {
final Connection connection=new Connection(socket) {
#Override void process(String string) {
super.process(string);
send(string.toUpperCase());
}
};
new Thread(connection,"incoming").start();
} catch(IOException e2) {
e2.printStackTrace();
}
};
new Acceptor(serverSocket,socketConsumer).start();
}
public static void main(String[] args) throws UnknownHostException,IOException,InterruptedException {
final String host="localhost";
final Integer service=1237;
Tcp tcp=new Tcp(host,service);
Socket socket=new Socket(host,service);
Connection c1=new Connection(socket);
new Thread(c1,"c1").start();
socket=new Socket(host,service);
Connection c2=new Connection(socket);
Thread.sleep(500);
new Thread(c2,"c2").start();
c1.send("foo");
c2.send("bar");
}
}
out.flush() helped in this case.
Related
I have a client-server app.
It opens a socket on client side, then I input data to send, it's also sent to other clients, but then the socket is closed. Why? I have tried many different approaches, like shifting din and dout to thread itself, adding some handlers, etc. But no progress yet.
I saw some other problems like this, but the solutions there are not applicable to my problem (I am not so experienced in sockets). Would like a solution to my specific problem.
Errors:
java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getInputStream(Socket.java:927)
at com.uniqueapps.network.ClientThread.lambda$run$1(ClientThread.java:23)
at java.base/java.lang.Thread.run(Thread.java:833)
java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getOutputStream(Socket.java:998)
at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:28)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at com.uniqueapps.network.ClientThread.lambda$run$0(ClientThread.java:27)
at java.base/java.lang.Thread.run(Thread.java:833)
Server.java codes:
package com.uniqueapps.network;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
public class Server {
final static int PORT = 5555;
static ServerSocket serverSocket;
static ArrayList<ClientThread> clients = new ArrayList<>();
public static void main(String[] args) {
try {
serverSocket = new ServerSocket(PORT);
new Thread(() -> {
while (true) {
try {
Socket clientSocket = serverSocket.accept();
ClientThread client = new ClientThread(clientSocket);
client.run();
clients.add(client);
System.out.println("New client joined: " + client.socket.getLocalPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread.java codes:
package com.uniqueapps.network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread implements Runnable {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
new Thread(() -> {
boolean run = true;
while (run) {
try (DataInputStream din = new DataInputStream(socket.getInputStream())) {
String text = din.readUTF();
if (!text.equals("")) {
new Thread(() -> {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getLocalPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
Client.java codes:
package com.uniqueapps.network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 5555);
socket.setKeepAlive(true);
new Thread(() -> {
try {
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
Scanner scn = new Scanner(System.in);
while (true) {
String text = scn.nextLine();
if (!text.equals("")) {
try {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
DataInputStream din = new DataInputStream(socket.getInputStream());
while (true) {
try {
String text = din.readUTF();
if (!text.equals("")) {
System.out.println(text);
}
} catch (EOFException ignored) {
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Edit:
Thanks to Michael Lee, i understood the problem i have been trying to understand for weeks. I remade the code, but i am stuck a place.
I got to know that the .run(); method of "runnable" halts the current thread, but .start(); of "thread" doesn't. So i removed threads from all places, except one. This place is still getting the "Socket closed" error (If i keep runnable here, then the thread is halted, and the message not relayed to other clients). How can i overcome this?
Server.java:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
public class Server {
final static int PORT = 8686;
static ServerSocket serverSocket;
static ArrayList<ClientThread> clients = new ArrayList<>();
public static void main(String[] args) {
try {
serverSocket = new ServerSocket(PORT);
System.out.println("Server ready! Running on port " + PORT);
while (true) {
try {
Socket clientSocket = serverSocket.accept();
System.out.println("New client joined: " + clientSocket.getPort());
ClientThread client = new ClientThread(clientSocket);
System.out.println("Created thread for client.");
clients.add(client);
System.out.println("Added client to list.");
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
this.start();
System.out.println("Started thread for client.");
}
#Override
public void run() {
try {
boolean run = true;
DataInputStream din = new DataInputStream(socket.getInputStream());
while (run) {
try {
String text = din.readUTF();
if (!text.equals("")) {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
this.start();
System.out.println("Started thread for client.");
}
#Override
public void run() {
try {
boolean run = true;
DataInputStream din = new DataInputStream(socket.getInputStream());
while (run) {
try {
String text = din.readUTF();
if (!text.equals("")) {
for (ClientThread clientThread : Server.clients) {
try (DataOutputStream dout = new DataOutputStream(clientThread.socket.getOutputStream())) {
dout.writeUTF(text);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (EOFException ignored) {
} catch (SocketException e) {
e.printStackTrace();
Server.clients.remove(this);
run = false;
System.out.println("Client left: " + socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
In your ClientThread, after din.readUTF(); if (!text.equals("")) { ..., you should directly start processing the incoming data in current thread, rather than initializing a new thread to handle them.
Because in you current thread, the one holding the connected socket, probably closed before the new thread has not even started up. As Java Docs says:
void close() throws Exception
Closes this resource, relinquishing any underlying resources. This method is invoked automatically on objects managed by the try-with-resources statement.
That is why you got Socket Closed exceptions.
One more thing is that, there are too many threads in either Server or Client. Most of time such things are unnecessary, say, for a rather simple application. Because they are not quite managed well in your codes, which more likely makes your program behave unexpectedly in the future. Try use threads only if necessary, instead of using them as much as possible.
My program works fine and many users can connect and send commands to the server.
But when a user spams the server with commands the server blocks out all other clients and the server doesn't receive messages from clients other than the one that spammed.
Why is this?
TCPAccept Connections
package game.server;
import java.io.IOException;
import java.net.Socket;
public class TCPAcceptConnections implements Runnable
{
public static Socket clientSocket = null;;
int clientID = -1;
public void run()
{
while(Main.TCP)
{
try
{
clientSocket = TCPServer.serverSocket.accept();
System.out.println("Client Connected.");
clientID++;
new TCPClientManager(clientSocket, clientID).run();
}
catch (IOException e)
{
System.out.println("Couldn't create client socket.");
System.exit(-1);
}
}
}
}
TCPClientManager:
package game.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TCPClientManager implements Runnable
{
Socket client;
int clientID;
static PrintWriter out;
static BufferedReader in;
String inputLine, outputLine;
boolean destroy = false;
public TCPClientManager(Socket cs, int id)
{
try
{
client = cs;
clientID = id;
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch(IOException e)
{
e.printStackTrace();
}
}
public void run()
{
System.out.println("Created TCPManager for client.");
String command;
while(!destroy)
{
try
{
if((command = in.readLine()) != null) //If received something
{
System.out.println("Commad received: " + command);
System.out.println(" " + Commands.proccessCommand(command));
System.out.println("Command proccessed");
}
else
{
client.close();
destroy = true;
}
} catch (IOException e)
{
try
{
client.close();
} catch (IOException e1)
{
e1.printStackTrace();
destroy = true;
}
System.out.println("Client lost connection.");
destroy = true;
}
}
System.out.println("TCPManager for client destroyed.");
}
}
Commands:
package game.server;
public class Commands
{
public static String proccessCommand(String command)
{
if(command.equalsIgnoreCase("cp"))
{
System.out.println("Creating player...");
System.out.println(" Retrieved client");
return "Player Created";
}
else
{
return "Unkown command: " + command;
}
}
}
If you get an unknown command, you should log it and close the connection.
But you have a more severe problem. You aren't stopping the client handler when it reads null. So once a client disconnects the read will spin futilely forever. If readLine() returns null you must close the socket and exit the loop. If you get any IOException you must also close the socket.
I'm trying to handle multiple connections on the same port of my server. I'm doing this by instantiating an Object and passing it into the constructor for another class, which implements Runnable. Then I set up a socket in the Runnable class and call notify() on the passed Object after a Client connects on the port. This should then allow the server to restart its loop, creating another instance of the Runnable class after being notified. However, currently the wait() isnt being reached until after the client is closed. Here are the 3 relevant classes I have:
Server class:
package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.HashMap;
public class Server {
public static void main(String[] args){
HashMap<String, PortDummy> portDummies = new HashMap<String, PortDummy>();
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8000);
} catch (IOException e1) {
e1.printStackTrace();
}
for(;;){
Object block = new Object();
PortDummy dummy = new PortDummy(serverSocket, block, portDummies);
System.out.println("Running dummy port...");
dummy.start();
try {
synchronized(block){
System.out.println("Waiting...");
block.wait();
System.out.println("Block notified.");
}
} catch (InterruptedException e) {
System.out.println("Can't be interrupted!");
e.printStackTrace();
}
}
}
}
PortDummy (Runnable) class:
package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class PortDummy extends Thread {
private Object block;
private HashMap<String, PortDummy> portDummies;
private String clientName = null;
ServerSocket serverSocket;
BufferedReader socketIn;
PrintWriter socketOut;
public PortDummy(ServerSocket serverSocket, Object block, HashMap<String, PortDummy> portDummies){
this.block = block;
this.portDummies = portDummies;
this.serverSocket = serverSocket;
}
#Override
public void run() {
try {
System.out.println("Starting dummy port...");
Socket clientSocket = serverSocket.accept();
System.out.println("Connection made.");
synchronized(block){
System.out.print("Notifying...");
block.notify();
System.out.println("...done.");
}
socketIn = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
String inContent;
boolean loggedIn = false;
while((inContent = socketIn.readLine()) != null){
socketOut.println("Server Echo: " + inContent);
if(inContent.startsWith("/exit")){
if(loggedIn){
portDummies.remove(clientName);
System.out.println(clientName + " signed out. Removed from portDummies.");
}
else{
System.out.println("Closing...");
}
}
else if(inContent.startsWith("/register")){
System.out.println("/register accepted");
if(!loggedIn){
if(registerUser(inContent)){
System.out.println("Successfully registered.");
socketOut.println(clientName + " successfully registered.");
loggedIn = true;
}else{
socketOut.print("That user already exists.");
}
}
else{
socketOut.print("Already logged in.");
}
}
else if(inContent.startsWith("/tell")){
if(!loggedIn){
socketOut.println("You need to log in.");
}
else{
String[] parts = inContent.split("\\w");
String[] withoutCommand = new String[parts.length-1];
for(int i = 1; i<parts.length-1; i++){
withoutCommand[i] = parts[i];
}
String[] messageParts = new String[withoutCommand.length-1];
String message = "";
for(int j = 1; j<withoutCommand.length-1; j++){
message += withoutCommand[j] + " ";
}
String recipient = withoutCommand[0];
sendMessage(recipient, message);
}
}
else if(inContent.startsWith("/help")){
socketOut.print("/help ~~~~~~~ List all commands. \n " +
"/register <username> ~~~~~~~ Register a new user with 'username'. \n " +
"/tell <username> <message> ~~~~~~~ Send 'username' text 'message'. \n " +
"/exit ~~~~~~~ Log out.");
}
}
System.out.println("Shutting down client connections...");
socketOut.close();
socketIn.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
System.out.println("IOException!");
e.printStackTrace();
}
}
private boolean registerUser(String text){
System.out.println("Registering user...");
String user = text.substring(10);
if((user != null) && !(portDummies.containsKey(user))){
portDummies.put(user, this);
clientName = user;
System.out.println(user + " registered.");
return true;
}
return false;
}
private void sendMessage(String username, String message){
if(portDummies.containsKey(username)){
PortDummy recip = portDummies.get(username);
recip.getSocketOutput().println(clientName + ": " + message);
}
else{
socketOut.write("User " + username + " doesn't exist.");
}
}
public PrintWriter getSocketOutput(){
return socketOut;
}
}
Client class:
package client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.io.IOException;
public class Client {
protected String username;
public static void main(String[] args){
try{
Socket serverSocket = new Socket("localhost", 8000);
BufferedReader socketIn = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
PrintWriter socketOut = new PrintWriter(serverSocket.getOutputStream(), true);
Scanner keyboardInputScanner = new Scanner(System.in);
String keyboardInput, serverInput;
System.out.println("Welcome to Chris Volkernick's Server IM Client! \n" +
"Type '/register <username>' to register, '/list' to list connected users," +
"\n or '/tell <username> <message>' to send a user a message. '/help' lists these commands. (Type '/exit' to sign out.)");
while((keyboardInput = keyboardInputScanner.nextLine()) != null){
System.out.println("Input '" + keyboardInput + "' read on client side.");
if(keyboardInput.equals("/exit")){
socketOut.println("/exit");
socketOut.close();
socketIn.close();
serverSocket.close();
}else{
socketOut.println(keyboardInput);
while((serverInput = socketIn.readLine()) != null){
System.out.println(serverInput);
}
}
}
keyboardInputScanner.close();
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
Am I doing something wrong with the wait() and/or notify()?
EDIT: I also tried changing the implements Runnable to extends Thread then changing the .run() in the server to .start(), but that gives me this error:
java.net.BindException: Address already in use: JVM_Bind
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:365)
at java.net.ServerSocket.bind(ServerSocket.java:319)
at java.net.ServerSocket.<init>(ServerSocket.java:185)
at java.net.ServerSocket.<init>(ServerSocket.java:97)
at server.PortDummy.run(PortDummy.java:28)
EDIT 2: It seems to be working the way it should now in terms of starting new threads. However, I'm now running into another problem: After I enter a command on the client side of any given client, I can't enter additional commands. The first command will work fine (minus /exit; haven't quite figured out how that should work yet), just can't do anything after that. For example, I can register (sign in) but after that nothing else. I can go into another instance of Client and list all the current users (works), but again, after that I cannot enter additional commands. Any idea what may be happening to cause this?
The problem is that your child threads are trying to listen on port 8000, but the parent thread is already doing that. What you need to do is pass accept a connection from the original socket and then give it to the child thread. I'm not exactly sure how to do this in Java, but I suspect it's just..
Put this in your main thread:
ServerSocket serverSocket = new ServerSocket(8000);
Socket clientSocket = serverSocket.accept();
And then once you get that, pass clientSocket to your Thread.
That way there's only one socket listening on port 8000, but you can make child threads handle each connection.
When using wait and notify, realize that notifies aren't queued, so if the notify happens before the wait occurs, you will never exit the wait. Therefore you should never perform naked waits, that is there should always be some condition you test to see if you should wait.
sychronized(block) {
while (!available) {
block.wait();
}
}
and
synchronized(block) {
available = true;
block.notifyAll();
}
etc
package so_7775790;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;
/**
* barebones server -- ctl-C to kill it ;)
*/
public class Server implements Runnable {
final static Logger log = Logger.getLogger(Server.class.getSimpleName());
public static void main(String[] args) {
final int port = 8000;
final String tname = "my-server-thread";
final Server server = new Server(port);
try {
Thread tserver = new Thread(server, tname);
tserver.start();
tserver.join();
} catch (Exception e) {
log.severe(e.getMessage());
}
}
// -------------------------------------------------
// server
// -------------------------------------------------
final int port;
public Server(int port) {
this.port = port;
}
public void run() {
try{
final ServerSocket srvsocket = new ServerSocket(port);
log.info(String.format("Server started # %s\n", srvsocket));
while(!Thread.currentThread().isInterrupted()){
Socket newclient = srvsocket.accept();
// spawn thread and hand off new client to handler
new Thread(new ClientHandler(newclient)).start();
}
}
catch (Exception e) {
log.severe(e.getMessage());
}
log.info("server stopped");
}
// -------------------------------------------------
// client handler
// -------------------------------------------------
static class ClientHandler implements Runnable {
final Socket socket;
public ClientHandler(final Socket socket) {
assert socket != null : "serverthread is null";
this.socket = socket;
}
#SuppressWarnings("unused")
#Override final
public void run() {
log.info(String.format("new client # %s\n", socket.getRemoteSocketAddress()));
try {
final InputStream in = socket.getInputStream();
final OutputStream out = socket.getOutputStream();
// NOTE: this is just a stub busy loop!
for(;;) {
/* your protocol impl here .. */
}
} catch (Exception e) {
log.severe(e.getMessage());
}
finally {
try {
socket.close();
}
catch (Exception e) {
log.severe(e.getMessage());
}
}
}
}
}
I got simple socket based client - server application, each connection gets own thread.
Currently scheme is something like this:
Board - is the object to share between the clients, serialized, Plain Old Java object
ActiveSessions - all the connections are added into list
BroadCaster - when the board has changed, send the board to other clients
Problem is that each thread connects and recevies the board object but when it's sent again it sends again the same object, but on the serverside the object behaves correctly.
public static void main(String[] args) {
Board gameBoard = new Board();
ActiveSessions sessions = new ActiveSessions();
Broadcaster broadcaster = new Broadcaster(sessions, gameBoard);
try {
ServerSocket socket = new ServerSocket(1234);
// Timeout after what no more new connections are not accepted.
socket.setSoTimeout(30 * 1000);
logger.info("Server started on port " + socket.getLocalPort());
while (true) {
SessionHandler session = new SessionHandler(socket.accept(), gameBoard, broadcaster);
sessions.addSession(session);
session.start();
}
} catch (SocketTimeoutException e1) {
logger.info("No more new connecions are accpeted, start game or end");
gameBoard.setGameState(GameState.PLAYING);
logger.info("Set the gamestate to " + gameBoard.getGameState());
} catch (IOException e) {
logger.info("I/O error " + e.getMessage());
}
SessionHandler, each connection has own thread
package server;
import game.Board;
import game.Turn;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.logging.Logger;
public class SessionHandler extends Thread {
private Board gameBoard;
private Socket socket;
private Broadcaster broadcaster;
private boolean firstConnect = true;
private ObjectOutputStream out;
private ObjectInputStream in;
private static final Logger logger = Logger.getLogger(SocketServer.class.getName());
public SessionHandler(Socket socket) {
this.socket = socket;
}
public SessionHandler(Socket accept, Board gameBoard, Broadcaster broadcaster) {
this(accept);
this.gameBoard = gameBoard;
this.broadcaster = broadcaster;
}
#Override
public void run() {
try {
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
while (true) {
Turn turn = (Turn) in.readObject();
if (turn != null) {
if (firstConnect) {
gameBoard.addPlayer(turn.getWhoseTurn());
firstConnect = false;
}
// Add the turn to game board and make validation
gameBoard.increaseTurns();
broadcaster.send();
}
System.out.println("Turns made " + gameBoard.getTurns() + " players " + gameBoard.getPlayers() + " dice score " + turn.getDiceScore());
}
} catch (EOFException e1) {
logger.warning("Problem reading the object output");
} catch (SocketException e) {
if ("Connection reset".equals(e.getMessage())) {
System.out.println("Client disconnected, performing cleanup");
} else {
logger.warning("Connection between client lost " + Thread.currentThread());
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
public void sendTheGameBoard() {
try {
out.writeObject(this.gameBoard);
out.flush();
} catch (IOException e) {
logger.warning("Problem with sending game board object " + e.getMessage());
}
}
}
class Broadcaster {
private ActiveSessions activeSessions;
public Broadcaster(ActiveSessions aa, Board board) {
this.activeSessions = aa;
}
public void send() {
// Broadcast board forever
synchronized (activeSessions) {
Iterator<SessionHandler> active = activeSessions.iterator();
while (active.hasNext()) {
SessionHandler session = active.next();
if (!session.isAlive()) {
active.remove();
session.interrupt();
} else {
session.sendTheGameBoard();
}
}
}
}
}
Read http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#handle. The ObjectOutputStream has a cache in order to avoid sending the same object multiple times. You must reset the stream to send a copy again.
Hello Experts
can somebody please indentify the problem with this server why this is unable to connect more then one client
import java.io.*;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
public class MultithreadedServer extends Thread {
private ServerSocketChannel ssChannel;
private Thread tRunSer = new Thread(this, "ServerSelectThread");
public static void main(String argv[]) throws Exception {
new MultithreadedServer();
}
public MultithreadedServer() throws Exception {
this.start();
}
public void run() {
while (true) {
try {
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
int port = 2345;
ssChannel.socket().bind(new InetSocketAddress(port));
} catch (Exception e) {
}
}
}
}
class Connect extends Thread {
private ServerSocketChannel ssChannel;
private SimManager SM;
private BallState BS = new BallState(10, 5);
public Connect(ServerSocketChannel ssChannel) {
this.ssChannel = ssChannel;
SM = new SimManager(BS);
SM.start();
}
public void run() {
try {
SocketChannel sChannel = ssChannel.accept();
while (true) {
ObjectOutputStream oos = new ObjectOutputStream(sChannel
.socket().getOutputStream());
oos.writeObject(BS);
System.out.println("Sending String is: '" + BS.X + "'" + BS.Y);
oos.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
my intention is to send the objects on network.
please help
new code:
import java.io.*;
import java.net.*;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
public class MultithreadedServer extends Thread {
private ServerSocketChannel ssChannel;
private SimManager SM;
private BallState BS = new BallState(10, 5);
private Thread tRunSer = new Thread(this, "ServerSelectThread");
public static void main(String argv[]) throws Exception {
new MultithreadedServer();
}
public MultithreadedServer() throws Exception {
this.start();
}
public void run() {
// create the server socket once
try {
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.socket().bind(new InetSocketAddress(2345));
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
// accept new connections on the socket
SocketChannel accept;
try {
accept = ssChannel.accept();
ObjectOutputStream oos;
oos = new ObjectOutputStream(accept.socket().getOutputStream());
oos.writeObject(BS);
System.out.println("Sending String is: '" + BS.X + "'" + BS.Y);
oos.flush();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
You are creating a new server socket for each loop iteration (using the same port over and over). You must create the server socket only once, and then accept new incoming connections.
Something like:
public void run() {
// create the server socket once
ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.socket().bind(new InetSocketAddress(2345));
while (true) {
// accept new connections on the socket
try {
SocketChannel accept = ssChannel.accept();
System.out.println("new client: " + accept.getRemoteAddress());
} catch (Exception e) {
System.out.println("exception: " + e.getMessage());
}
}
}
If you put something in your catch block you will probably find it yourself. (e.printStackTracer() might help for the time being).
Here is the reason for your NPE:
If this channel is in non-blocking mode then this method will immediately return null if
there are no pending connections.
This is from ServerSocketChannel.accept().
Your accept call returns null, and you then try to call a method on this null object.