I've got a simple client and server that I've written to teach myself a bit of networking. The way it's set up is I've got a main server class which will deal with creating/destroying sockets, and the ConnectionThread class that represents each connection (each of which is given its own thread). The client is super simple.
The problem lies in creating the input/output streams in the ConnectionThread class. I'm not sure exactly what the problem is, but it crashes when the simple test client tries to connect, giving me this:
~~MMO Server Alpha .1~~
Constructed Server
Server Initialized, preparing to start...
Server preparing to check if it should be listening...
Server should be listening, continuing as planned.
ServerSocket passed to ConnectionThread: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=6969]
Constructing ConnectionThread.
Socket[addr=/10.0.1.10,port=55332,localport=6969]
ConnectionThread constructed.
Exception in thread "main" java.lang.NullPointerException
at ConnectionThread.init(ConnectionThread.java:65)
at Server.listen(Server.java:98)
at Server.start(Server.java:62)
at Server.main(Server.java:122)
ConnectionThread added to queue.
Establishing in and out streams:
null
Here are the classes (amended for brevity):
public class Server {
int PORT;
boolean shouldListen;
ArrayList<ConnectionThread> connections = new ArrayList<ConnectionThread>();
ServerSocket serverSocket;
public Server() {
try {
PORT = 6969;
shouldListen = true;
serverSocket = new ServerSocket(PORT);
}
catch (IOException e) {
System.out.println("Error in server constructor.");
System.exit(1);
}
}
public void start() {
System.out.println("Server preparing to check if it should be listening...");
listen();
System.out.println("Server finished listening.");
}
public void listen() {
while (shouldListen) {
ConnectionThread conn = null;
System.out.println("Server should be listening, continuing as planned.");
try {
conn = new ConnectionThread(serverSocket);
}
catch (Exception e) {
System.out.println("____Error constructing ConnectionThread. Could there be another instance of the server running?");
System.exit(1);
}
System.out.println("ConnectionThread constructed.");
connections.add(conn);
System.out.println("ConnectionThread added to queue.");
conn.init();
System.out.println("Finished ConnectionThread initialization, verifying...");
if (conn.isInitialized) {
System.out.println("ConnectionThread Initialized, preparing to start new thread.");
(new Thread(conn)).start();
}
}
}
public static void main(String[] args) {
System.out.println("~~MMO Server Alpha .1~~");
Server server = new Server();
System.out.println("Constructed Server");
server.init();
System.out.println("Server Initialized, preparing to start...");
server.start();
}
}
Here's the ConnectionThread class:
public class ConnectionThread implements Runnable {
boolean shouldBeListening = true;
boolean isThereAnUnsentOutgoingMessage = false;
String outgoingMessage = "OUTGOING UNINITIALIZED";
boolean IsThereAnUnsentIncomingMessage = false;
String incomingMessage = "INCOMING UNITIALIZED";
boolean isInitialized = false;
PrintWriter out;
BufferedReader in;
String currentInputMessage = "Test Input Message from the Server ConnectionThread";
String previousInputMessage = null;
Socket socket;
public ConnectionThread(ServerSocket s) {
System.out.println("ServerSocket passed to ConnectionThread: " + s);
/*
* The purpose of the constructor is to establish a socket
* as soon as possible. All transmissions/logic/anything else
* should happen in init() and/or run().
*/
System.out.println("Constructing ConnectionThread.");
try {
Socket socket = s.accept();
System.out.println(socket);
}
catch (IOException e) {
System.out.println("Error in ConnectionThread constructor");
System.exit(1);
}
}
public void init() {
/*
* Everything should be set up here before run is called.
* Once init is finished, run() should be set to begin work.
* This is to ensure each packet is efficiently processed.
*/
try {
System.out.println("Establishing in and out streams:");
System.out.println(socket);
out = new PrintWriter(socket.getOutputStream(), true);
System.out.println("ConnectionThread: Output Stream (PrintWriter) Established");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("ConnectionThread: InputStream (BufferedReader) Established");
}
catch (IOException e) {
System.out.println("Error in ConnectionThread method Init.");
System.exit(1);
}
isInitialized = true;
}
And optionally, here's the test client:
public class TestClient {
static PrintWriter out;
BufferedReader in;
public final int PORT = 6969;
Socket socket = null;
InetAddress host = null;
public TestClient() {
out = null;
in = null;
socket = null;
host = null;
}
public void connectToServer() {
System.out.println("Connecting to server...");
try {
host = InetAddress.getLocalHost();
socket = new Socket(host.getHostName(), PORT);
}
catch (Exception e) {
System.out.println("Error establishing host/socket");
System.exit(1);
}
try {
System.out.println("Establishing I/O Streams");
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch (Exception e) {
System.out.println("Error establishing in/out streams");
System.exit(1);
}
}
public static void main(String[] args) {
System.out.println("~~TestClient Alpha .1~~");
TestClient c = new TestClient();
c.connectToServer();
System.out.println("Should be connected to server. Sending test message...");
while (true) {
System.out.println("here");
out.println("Hello there");
}
}
}
The 'socket' variable in the constructor of ConnectionThread shouldn't be local. It is shadowing the member variable.
It is customary to call accept() in the listen() loop, and pass the accepted socket to the ConnectionThread.
As EJP said, in your ConnectionThread constructor you think that you are assigning the value to the socket field, however you are actually assigning the value to the socket method variable, thus the socket field remains null, and in init() you see socket as null.
In addition to EJP answer: you did not provide ConnectionThread.run() method, but I assume you are going to use fields in, out and socket in your run() method. Since these fields are not marked as volatile or final, depending on your luck and number of core on your computer, you may also get NullPointerException at run() method.
This is because new variable value may be not propagated between caches and new thread will not see value of changed.
Explanation of this possible problem is here - The code example which can prove "volatile" declare should be used
Related
I'm trying to make a connection between a server and multiple clients, but it doesn't work even for one. All I want to do is to send from the client an object using the ObjectOutputStream class. The connection is made successfully at the beginning but when I try to send the object to the server it fails.
This is the client part which is written in the main method of a class:
Socket socket;
OutputStream out;
ObjectOutputStream fout;
boolean connected=false;
if (!connected) {
try {
socket = new Socket("localhost", 8000);
out = socket.getOutputStream();
fout = new ObjectOutputStream(out);
fout.flush();
connected = true;
fout.writeObject(ac1);//ac is an object of Plane class
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
This is the server:
public class server {
static class ServerThread implements Runnable {
Socket client = null;
public ServerThread(Socket c) {
this.client = c;
}
public void run() {
try {
System.out.println("Connected to client : "+client.getInetAddress().getHostName());
Plane ac=null;
InputStream in=client.getInputStream();
ObjectInputStream fin=new ObjectInputStream(in);
while(client.isConnected()){
ac = (Plane)fin.readObject();
System.out.println(ac.toString());
}
client.close();
} catch (Exception e) {
// System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
public static void main(String args[]) {
try {
ServerSocket server = new ServerSocket(8000);
while (true) {
Socket p = server.accept();
new Thread(new ServerThread(p)).start();
}
} catch (Exception ex) {
System.err.println("Error : " + ex.getMessage());
}
}
}
Could anyone tell me what is the problem?
Your client never closes the socket, and presumably exits, so the connection is reset. So close the socket.
NB isConnected() is not a valid loop condition. It will never become false. Your loop should terminate when EOFExceprion is caught.
I'm new in Java Sockets, I have seen so many examples but I can't understand how to pass an argument from server to client and vice versa. My destination is to pass an Object that's why I'm using Object I/O Stream.
I have to classes Server and Player.
public class Server extends Thread{
public static final int TEST = 165;
ServerSocket serverSocket;
InetAddress address;
Player playerWhite;
public Server() {
start();
}
#Override
public void run() {
try
{
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
playerWhite = new Player();
System.out.println("server waits for players");
playerWhite.socket = serverSocket.accept();
playerWhite.start();
sendTestMessage(playerWhite);
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void sendTestMessage(Player player) throws IOException
{
ObjectOutputStream testToClient = new ObjectOutputStream(player.socket.getOutputStream());
testToClient.write(TEST);
testToClient.flush();
}
And the Player class:
public class Player extends Thread {
Socket socket;
Player() throws IOException
{
socket = new Socket(InetAddress.getLocalHost(), 6000);
}
#Override
public void run() {
try {
listenTestStream();
}
catch (IOException | ClassNotFoundException ex)
{
Logger.getLogger(CheckerPlayer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void listenTestStream() throws IOException, ClassNotFoundException
{
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
int message = ois.readInt();
//To test
System.out.println("Server listened: " + message);
}
I execute it as create a Server object in the other class.
When I have testing this application I saw that sometimes client is faster than Server. Is it possible to make him "wait" for server response?
Thanks for your response.
EDIT 1: PROBLEM SOLUTION:
From outside we should create:
Player player = new Player(); // (class player extends from Thread)
player.start();
and delete the Player variable - is not necessary, we need only Socket so:
Server:
Socket playerWhiteSocket
public void run() {
try
{
serverSocket = new ServerSocket(PORT);
playerWhiteSocket = serverSocket.accept();
sendMessage(playerWhiteSocket, "Hello");
}
catch(IOException | ClassNotFoundException ex)
{}
public void sendMessage(Socket socket, String message) throws IOException
{
ObjectOutputStream testToClient = new ObjectOutputStream(socket.getOutputStream());
testToClient.writeObject(message);
testToClient.flush();
}
In Player class we need get method:
public String receiveMessage() throws IOException, ClassNotFoundException
{
//socket is a variable get from Player class socket = new Socket("severHost", PORT);
ObjectInputStream messageFromServer = new ObjectInputStream(socket.getInputStream());
String message = (String) messageFromServer.readObject();
return message;
}
I would recomment doing this public void start(){
try {
ServerSocket = new ServerSocket(this.port,10,this.localAddress);
// set timeout if you want
//this.clientServerSocket.setSoTimeout(timeout);
// infinity loop
while(true)
{
//wait for a client connection
Socket socket = ServerSocket.accept();
// start thread for every new client
Thread t = new Thread(new AcceptClients(this.socket));
t.start();
System.out.println(L"new client connected");
// call garbage collector and hope for the best
System.gc();
}
} catch (IOException e) {
System.out.println("IO Error");
e.printStackTrace();
}
}
and then in another class
public class AcceptClients implements Runnable{
// socket
private Socket socket;
public AcceptClients (Socket socket){
this.socket = socket;
}
#Override
public void run() {
// what happens if a client connect
}
}
I always use this and it works fine
Suggested changes.
Create ServerSocket only once. If you have done it, you won't get "Address already in use" error
After creating Server Socket, you thread should be in while (true) loop to accept connection from client.
Once you create a client socket, pass that socket to thread.
Now Player is used to send communication from server to client socket. So You need one more class like PlayerClient which create a socket to Server IP and Port. Now PlayerClient should create one more thread to handle IO operations like you have done from server. In this case, creating a socket is not in while loop from client side. It create a socket to server once. Now you can run this PlayerClient program from multiple machines.
If you are just sending just primitive type, use DataOutputStream & DataInputStream instead of ObjectStreams
This code will become like this
try
{
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
System.out.println("server waits for players");
while ( true){
Socket socket = serverSocket.accept();
Player playerWhite = new Player(socket);
sendTestMessage(socket);// Move this method to Player thread and change the signature of this method accordingly to accept a socket
}
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
Player.java
Player(Socket socket) throws IOException
{
this.socket = socket;
start();
}
Have a look at this chat example for better understanding.
Yep it is.
It should work if you put it in a endlees loop like that:
try
{
while(true){
address = InetAddress.getLocalHost();
serverSocket = new ServerSocket(6000);
playerWhite = new Player();
System.out.println("server waits for players");
playerWhite.socket = serverSocket.accept();
playerWhite.start();
sendTestMessage(playerWhite);
}
}
catch (IOException ex)
{
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
But I would not recommend to put this in a thread. Instead I would put the connection of a new client in a thread, so multiple clients can connect to the server
public class Main {
public static void main(String[] args) {
Server server = new Server(9008);
}
}
public class Server {
private ServerSocket server;
private Socket client;
public Server(int port) {
try {
// Create out server with our desired port
server = new ServerSocket(port);
// Server started, let the user know
System.out.println("Server started at port " + port + "...");
} catch (IOException e) {
// Unable to start server, print error
System.out.println("Unable to start server on port " + port + "...");
}
// Start our main server method
runServer();
}
public void runServer() {
while (true) {
try {
// Wait for new clients and accept them
client = server.accept();
// Let the user know - print
System.out.println("New user connected - " + client.getLocalAddress().getHostAddress());
// Start thread for our client
Thread clientThread = new Thread(new ClientConnection(client));
clientThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
So at this points everything is going fine, now inside my clientThread the problem starts
public class ClientConnection implements Runnable {
private Socket socket;
public ClientConnection(Socket client) {
// Set client socket
this.socket = client;
}
public void run() {
try {
// Read from our client input
BufferedReader readClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = readClient.readLine()) != null) {
System.out.println("Client says - " + readClient.readLine());
}
} catch(IOException e) {
}
}
}
Is there a better way to handle this?
My actual client
public class Main {
public static void main(String args[]) {
try {
Socket socket = new Socket("localhost", 9008);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Hello\n");
writer.flush();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I will get "Client says - null" displayed
UPDATE: The way to read in an InputStream/Reader is somethink like
while ((myString = readClient.readLine()) != null) {
System.out.println(myString);
}
this way the loop will exit when the connection is closed.
Also, move the try/catch outside the loop, or do some error control. If you get an exception, you do not want to just try get again in the loop.
UPDATE2: In case my comment was not clear enough, over your updated code do
String line;
while ((line = readClient.readLine()) != null) {
System.out.println("Client says - " + line);
}
Just one read per iteration, at the while, so the loop can exit if line is null (that means the connection has been closed).
I'm using a server socket to accept clients on the main thread, when a thread is accepted,the clients socket is given to a handler which is started in a new thread to process communications. However, before I start running my server to access clients, it connects to a second server which it must list to and be able to respond to and pass on the messages it gets to it's clients.
Hopefully this image illustrate what I mean:
The small server must be continuously listening for input from the big server, and also able to output responses.
//Default constructor
private smallServer(){}
//method to initialise and start the server
public static void StartServer(int port) throws IOException {
smallServer ss = new smallServer();
ss.bs= new bigServerClient(ss);
Thread nsc_Thread = new Thread(ss.bsc);
bsc_Thread.start();
//accepts clients and starts new thread for them
ss.ServerRun(port);
}
private void ServerRun(int port) throws IOException {
ServerSocket server = new ServerSocket(port);
server.setSoTimeout(50);
while (run) {
Socket client = null;
try {
client = server.accept();
} catch (SocketTimeoutException e) {
}
if (client != null) {
ClientHandler handler = new ClientHandler(client, this);
Thread handleThread = new Thread(handler);
handleThread.start();
}
}
if (!run) {
synchronized (ClientHandler.handlers) {
for (ClientHandler handler : ClientHandler.handlers) {
handler.terminateHandler();
}
}
System.exit(0);
}
}
public void processBigServerCommand(String toProcess) {
System.out.println("RESEAVED: " + toProcess);
}
The big server client(on the small server) then does this:
public class bigServerClient implements Runnable {
private smalsServer ss;
private PrintWriter printer;
private BufferedReader reader;
private Socket socket;
public bigServerClient(smallServer _ss) throws IOException {
ss = _ss;
socket = new Socket("Localhost", 5000);
printer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printer.flush();
SendBigServerMessage("Starting String");
}
private void SendBigServerMessage(String toSend) {
printer.print(toSend);
printer.flush();
}
#Override
public void run() {
try {
while (ss.state()) {
String inputLine;
while ((inputLine = reader.readLine()) != null) {
ss.processBigServerCommand(inputLine);
System.out.println(inputLine);
}
}
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
From what's above, can anyone see why the big server client isn't responding to the big server when a message is sent? I'm guessing it's something to do with the main thread blocking the second thread, but I'm not sure... Any help would be greatly appreciated.
You lost me in your code...
Simplify it.
Your smallServer (see class names conventions) should have persistent connection to BigServer (effectively it is BigServer client) - you can implement it in your smallServer class, it should connect (once) and open I/O to BigServer (once) and close everything once the connection is terminated.
As your smallServer will handle multiple clients and pass their requests to BigServer there is no guarantee of the order of BigServer responses - you should do something to handle that (maybe pass UUID with requests?)
Simplify your smallServer and make sure that it runs...
I'm trying to make a simple ECHO server that can manage more client.
Server Class:
public class EchoServer {
protected int port ;
protected ServerSocket socket;
private Socket acceptedSocket;
public EchoServer(int port) throws IOException {
this.port = port;
socket = new ServerSocket(port);
}
public void start() throws AcceptingClientException {
while(!socket.isClosed()) {
try {
acceptedSocket = socket.accept();
}
catch (IOException e){
throw new AcceptingClientException();
}
ClientHandler ch = new ClientHandler(acceptedSocket);
ch.run();
}
}
}
Runnable client handler:
public class ClientHandler implements Runnable {
Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
PrintWriter From_Server = null;
BufferedReader To_Server = null;
String to_server_string = null;
try {
From_Server = new PrintWriter(socket.getOutputStream());
To_Server =
new BufferedReader(
new InputStreamReader( socket.getInputStream()));
System.out.println("Stream opened.\n");
while(true) {
if(To_Server.ready()){
System.out.println("Reading input line.\n");
to_server_string = To_Server.readLine();
if(to_server_string.equalsIgnoreCase("quit")) {
System.out.println("Connection closed on user request.\n");
From_Server.print("Bye :)\n");
From_Server.close();
To_Server.close();
socket.close();
}
else {
System.out.println(
"String '" +
to_server_string+"' is not 'quit', echoing.\n");
From_Server.print("ECHO: "+to_server_string+"\n");
System.out.println("String written on stream, flushing.\n");
From_Server.flush();
}
}
}
}
catch (IOException e) {
System.out.println("Stream error (connection closed?).\n");
}
}
}
Main Class
public static void main(String[] args) {
try {
EchoServer server= new EchoServer(9999);
server.start();
}
catch (IOException ex) {
System.out.println("Unable to start server (port is busy?)\n");
Logger.getLogger(SimpleServer.class.getName()).log(Level.SEVERE, null, ex);
}
catch (AcceptingClientException e){
System.out.println("Unable to accept client\n");
}
}
More than one client is able to connect to the server, but the ECHO will works only with one client at the time (if I close the connection with one client the server will start to handle another one automatically), but I can't understand why: when a client connects to the server, the associated socked created with server.accept() is passed to a new instance of a runnable client handler which is started with handler.run() and the server should go back on waiting in server.accept() (unless the ServerSocket is closed).
I'm assuming the issue should be with this method of the server class:
public void start() throws AcceptingClientException {
while(!socket.isClosed()) {
try {
acceptedSocket=socket.accept();
}
catch (IOException e){
throw new AcceptingClientException();
}
ClientHandler ch = new ClientHandler(acceptedSocket);
ch.run();
}
}
But I can't figure out what is wrong with it...what am I missing?
Your code:
ClientHandler ch = new ClientHandler(acceptedSocket);
ch.run();
doesn't start a new thread, it delegates to ClientHandler.run() in the same thread.
To start a thread, use new Thread( ch ).start(); since ch is of class ClientHandler which implements Runnable.