Coder Social home page Coder Social logo

slopchat's Introduction

๐Ÿ‘‰ Documentazione in Italiano

slopchat

An exercise in socket programming in the Java programming language: Implementing a no-frills, telnet-compatible online chat system!

This project includes a basic implementation of the SLOP protocol in Java.

The SLOP protocol

SLOP stands for Simple Line Oriented Protocol.

A slopchat server listens to multiple connections on a given TCP port.

A slopchat client connects to a server and can exchange SLOP messages with other clients.

Each chat message is represented as a single line string, i.e. a string of variable length terminated by a LF character.

When a client sends a message to a server, the server sends a copy of the message to all the other connected clients.

A copy of the message is never sent back to the sender client.

No attempt is made to re-send a failed communication, and no history is kept on the server: Messages sent before a client has connected cannot be received by the client. Likewise, messages sent after a client has disconnected are not available for a future reconnection.

A received message has no sender information. This is left to higher-level protocols (or human interaction) to implement.

How to use slopchat to chat with your LAN friends

Let's see how to start a server and a client on one or more machines in your Local Area Network.

Starting a server

Make sure you have Java (v. >= 1.8) and Maven installed on your development machine.

On Linux/Unix/Mac please use the provided startServer.sh script.

> cd slopchat
> ./startServer.sh 10000

The command above will compile the code and start a server on port 10000. Remember to open your firewall and give the JVM process the permission to receive incoming connections to the port.

On any platform (e.g., Windows) you can compile and run the code manually with the following commands.

To compile the code:

> mvn clean package

To start the server:

> java -Djava.util.logging.config.file=./src/main/resources/logging.properties -cp ./target/slopchat-1.0-SNAPSHOT.jar io.github.googlielmo.slopchat.app.server.SlopchatServer 10000

You can edit the sample logging.properties file in the project under src/main/resources/logging.properties or provide your own.

Starting a client

Did you know SLOP is telnet-compatible? You can use the telnet command to chat.

> telnet localhost 10000

Fancy trying the original slopchat client? On Linux/Unix/Mac please use the provided startClient.sh script.

> cd slopchat
> ./startClient.sh localhost 10000

The command above will compile the code and start a client for the service on localhost port 10000.

On any platform (e.g., Windows) you can start the client manually with the following command.

> java -Djava.util.logging.config.file=./src/main/resources/logging.properties -cp ./target/slopchat-1.0-SNAPSHOT.jar io.github.googlielmo.slopchat.app.client.Slopchat localhost 10000

Using the client and/or the server from your own code

You can embed a slopchat server or client in your own project.

Instantiating a server

This is all you need to start serving slopchat clients:

new ChatServer(port).serve();

The serve() method is not meant to return, therefore you may want to execute it in a separate thread.

This implementation uses a thread-per-client approach, where a new dedicated thread is created to handle each connection for receiving and dispatching incoming messages.

Customizing the server

Do you need a customized server? Perhaps you want to change or otherwise process incoming messages, e.g., so to implement a higher-level protocol or to add new functionalities, such as chatrooms, private messages, nicknames, etc. In order to do so, you just need to implement the MessageProcessor interface, which allows you to control all inbound and outbound messages:

    /**
     * Process an incoming message.
     * This method is invoked once per incoming message, before message dispatching.
     * @param message the original wire message
     * @param sender the sender ClientHandler
     * @return An optional string: the (possibly new) message to dispatch if present, or empty to ignore the message
     */
    Optional<String> processIncomingMessage(String message, ClientHandler sender);

    /**
     * Process an outgoing message.
     * This method is called during message dispatching, once for each connected client as recipient.
     * @param message the message to send, already processed by {@link #processIncomingMessage(String, ClientHandler)}.
     * @param sender the sender ClientHandler
     * @param recipient the recipient ClientHandler
     * @return An optional string: the (possibly new) message to send if present, or empty to suppress the sending
     */
    Optional<String> processSend(String message, ClientHandler sender, ClientHandler recipient);

You can pre-process each incoming message with the processIncomingMessage method. It has to return an Optional<String> that โ€“ if present โ€“ represents the message to dispatch to other clients. If for any reason the incoming message must be discarded (not dispatched), return Optional.empty().

Likewise, each outgoing message can be processed by implementing the processSend method, which is called once for each connected client as a recipient. An Optional<String> is returned that โ€“ if present โ€“ represents the message to send to the recipient. If empty the sending is cancelled.

The default implementation for these methods is what you would expect. The processIncomingMessage method just returns the incoming message (no pre-processing). The processSend method checks that the sender and the recipient are different instances, and if so it returns the message unchanged. If sender and recipient are one and the same, an empty value is returned and the sending is cancelled.

To instantiate a server with your custom MessageProcessor, just pass it to the appropriate constructor.

new ChatServer(port, myMessageProcessor).serve();

Implementing a client

To turn your app into a slopchat client you instantiate a ChatClient:

    ChatClient client = new ChatClient(serverName, port, eventHandler);
    client.connect();

In the snippet above eventHandler is your own implementation of the ChatEventHandler interface:

    /**
     * Server connection event
     */
    void onConnect();

    /**
     * Incoming message event
     * @param message the message
     */
    void onMessage(String message);

    /**
     * Server disconnection event
     */
    void onDisconnect();

When your client receives a message the onMessage method is invoked on your handler to pass it the incoming message. The onConnect and onDisconnect methods notify your handler about connection and disconnection events, respectively.

After a successful connection with the server, your app can send a message by invoking the sendMessage method:

    client.sendMessage(message);

Putting it all together, our console-based client looks like the following, error handling and all.

    @Override
    public void onConnect() {
        System.out.println("Connected! ^C to quit");
    }

    @Override
    public void onMessage(String message) {
        // print incoming message to console
        System.out.println(message);
    }

    @Override
    public void onDisconnect() {
        System.out.println("Disconnected from server, bye");
        System.exit(0);
    }

    /**
     * Connect to server and handle console input
     * @throws IOException
     */
    private void execute() throws IOException {
        BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));

        ChatClient client = new ChatClient(serverName, port, this);
        try {
            client.connect();
        } catch (IOException e) {
            System.out.println("Cannot connect to server, bye");
            System.exit(1);
        }

        while (true) {
            // read message from console
            String message = consoleReader.readLine();
            // send it to server
            client.sendMessage(message);
        }
    }

That's it. Have fun with slopchat!

slopchat's People

Contributors

googlielmo avatar

Stargazers

 avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.