Eli
Eli

Reputation: 337

Custom Java Socket class

This is my first time messing around with Sockets, and it was working up until now. Basically, I have a custom ServerSocket class named Server and a custom Socket class named Client.

When Client tries to connect to Server, Server performs a little check to make sure it is actually Client that it trying to make the connection, and not some other socket, because Client has certain methods that I need.

However, this check always returns false. Here is my Server connection code:

package me.eli.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import me.eli.client.Client;

public class Server extends ServerSocket {

private final Map<Client, IOPair> clients = new HashMap<Client, IOPair>();

public Server(final int port) throws IOException {
    super(port);
    System.out.println("Server started on " + getLocalPort() + "... Waiting for client!");
}

public Client waitOnClient() throws IOException {
    final Socket generalClient = accept();
    final Client client;
    if(!(generalClient instanceof Client)) {
        client = null;
        PrintWriter out = new PrintWriter(generalClient.getOutputStream(), true);
        out.println("Access denied: " + generalClient.getClass().getSimpleName());
        log("Invalid client: " + generalClient.getClass().getName() + " (" + generalClient.getInetAddress().getHostAddress() + ")");
        out.close();
    } else
        client = (Client) generalClient;
    if(client == null)
        return null;
    client.setServer(this);
    BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
    PrintWriter out = new PrintWriter(client.getOutputStream(), true);
    broadcast(client.getName() + " has joined.");
    clients.put(client, new IOPair(in, out));
    System.out.println("Client (" + client.getName() + ") connected from " + client.getInetAddress().getHostAddress());
    out.println("Connected! Welcome to the server.");
    return client;
}

@Override
public void close() throws IOException {
    for(Client c : getClients())
        kick(c, "Server closed");
    super.close();
}

public void kick(Client c, String reason) {
    try {
        c.message("disconnect", reason);
        c.close();
    } catch(IOException e) {
        log("Failed to kick " + c.getName() + ": " + e.getMessage());
        c.message("error", "Failed to disconnect");
    }
}

public void log(String message) {
    getServerOut().println(message);
}

public void log(String source, String message) {
    log("<" + source + "> " + message);
}

public void broadcast(String message) {
    log("broadcast", message);
    for(Client c : getClients())
        c.message("broadcast", message);
}

public Client[] getClients() {
    return clients.keySet().toArray(new Client[clients.keySet().size()]);
}

public BufferedReader getClientIn(Client c) {
    return clients.get(c).getIn();
}

public PrintWriter getClientOut(Client c) {
    return clients.get(c).getOut();
}


public InputStream getServerIn() {
    return System.in;
}

public PrintStream getServerOut() {
    return System.out;
}

public static boolean isServerRunningOn(final int port) {
    try {
        new ServerSocket(port).close();
        return false;
    } catch(IOException e) {
        return true;
    }
}

}

And here is my Client connection code:

package me.eli.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;

import me.eli.server.IOPair;
import me.eli.server.Server;

public class Client extends Socket {

private Server server;
private final IOPair serverio;
private final String name;

public Client(final String host, final int port) throws IOException {
    this(host, port, "Guest-" + (int) (Math.random() * 10000));
}

public Client(final String host, final int port, final String name) throws IOException {
    super(host, port);
    System.out.println("Connected to server on " + host + ":" + port);
    BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
    PrintWriter out = new PrintWriter(getOutputStream(), true);
    this.name = name;
    this.serverio = new IOPair(in, out);
    String input;
    if((input = in.readLine()) != null)
        System.out.println("<Welcome message> " + input);
    out.println("Yay! I'm connected!");
}

@Override
public synchronized void close() throws IOException {
    if(serverio != null) {
        if(server != null)
            server.broadcast(getName() + " has disconnected.");
        message("server", "Disconnected.");
        super.close();
        serverio.getIn().close();
        serverio.getOut().close();
    } else
        super.close();
}

public void message(String source, String message) {
    getClientOut().println("<" + source + "> " + message);
}

public String getName() {
    return name;
}

public void setServer(Server server) {
    this.server = server;
}

public Server getServer() {
    return server;
}

public BufferedReader getServerIn() {
    return serverio.getIn();
}

public PrintWriter getServerOut() {
    return serverio.getOut();
}

public InputStream getClientIn() {
    return System.in;
}

public PrintStream getClientOut() {
    return System.out;
}

}

I'm not the most experienced with networking, but this confuses me because I do indeed connect with my Client class. Thanks in advance!

Upvotes: 2

Views: 1270

Answers (1)

user207421
user207421

Reputation: 311002

Server performs a little check to make sure it is actually Client that it trying to make the connection

Impossible and nonsensical. The Client class is at the other end of the connection. It is not magically transmitted to your accept() method. If you want to validate your client you will have to build something into your application protocol.

Notes:

  • Calling Client.setServer() is similarly futile. It is not magically transmitted to the client.
  • It is possible to get your ServerSocket-derived class to create Client objects instead of Socket objects in its accept() method, but that doesn't actually solve the issue you're trying to solve.

Upvotes: 2

Related Questions