First Team Share -- Chat Room
I have built a chat room application before by using fifo on Linux. Today, I am going to build a little TCP ruby chat application using the ruby standard library Socket. I'm using ruby 2.1.0 and Mac OS.
First we need to take a short overview of TCP:
TCP is one of the core protocols of the Internet protocol suite (IP), and is so common that the entire suite is often called TCP/IP. Web browsers use TCP when they connect to servers on the World Wide Web, and it is used to deliver email and transfer files from one location to another. For more detaled information visit TCP Wikipedia
This is how our TCP chat room is going to work:
We will create a server that receives the client connections and stores them in data dictionaries. These dictionaries will keep track of what room the client is located in, receive messages, and relay the messages to other users. Each user MUST have a different username, which will be our primary key to look up our connections in the data dictionary so we can keep track of connected users.
Once completed, we’ll test our chat by opening different command terminals, one for each simulated user.
First we are going to create the necessary files: ‘server.rb’ and ‘client.rb’
In server.rb and client.rb we have to require the Socket library.
Then create the respective classes with some attributes to handle users.
The client receives a server instance so it can establish a connection with the server. We need to initialize a request and response to send and receive messages through the server. Right now our @response and @request objects are null, but later on we are going to build two threads and assign them to our objects to read and write at the same time.
The server receives a port which will be our channel for establishing a connection between users. The server listens to the port for any event and sends a response to everyone who is interested. The initializer also creates three 3 hashes:
@connections is a pool of users connected to server.
@rooms is keyed on room name and holds the users in each room.
@clients are our connected client instances
Now we can track which user is in which room. It’s important to reiterate that the client name/username must be unique. Here is what our hashes will look like with some data:
Then we need to create two threads on the client side so it can read/write messages at the same time. Without this functionality, our chat would be very boring. Imagine typing your message and only after finishing being able to look for an answer without the posibility of doing both at the same time. This is how most chat clients work basically.
To sum up, here is the client.rb file:
On the server side we need something similar, basically one thread per connected user. This way, we can handle as many users as possible without any concurrency issues.
For our test, the IP ip is local. The port MUST be the same on the client and server side and, in this case. Remember, ports are virtual:
A port is not a physical device, but an abstraction to facilitate communication between a server and a client. A machine can have a maximum of 65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports. – Brief Description of TCP and UDP
We’ll also clean up all of the extra characters at the end of a message, such as the end of the line, tabs, etc.
The implementation is quite simple. All we need is to finish up with the run method, and verify the uniqueness of the username provided. If the username is taken, tell the client with an error message and kill the connection. Otherwise, give the client a successfull connection message.
Right now our chat is almost finished, but there is one method left for handling all the messages between all connected users. Without it, our users won’t be able to send messages to each other.
All the listen_user_messages method does is listen to the user messages and send them to all the other users. Now, call this method inside the run method in the server instance and that’s it.
To sum up, here is the entire server.rb file:
Finally, we can run our chat on the terminal.