Search This Blog

Showing posts with label TCP/IP. Show all posts
Showing posts with label TCP/IP. Show all posts

Saturday, 21 February 2015

Chat server implemented in Perl, based on AnyEvent

Event-driven implementation of a chat server, with one main processing thread.

Uses tcp_server method from AnyEvent::Socket for easy creation of a non-blocking TCP connection. Inside the connection callback, the connecting client is informed about other already connected clients and client information (host:port identifier and the client socket handle) is stored in a hash. The client file/socket handle, available in the tcp_server callback after a client connects to the server, is wrapped in a AnyEvent::Handle object to allow event-driven access and manipulation. The on_read handler of the client socket handle deals with the client message, sending it to all other connecting servers. The client can send a message either directly, or first send OK, followed by the message itself. 

#!/usr/bin/perl
 
=head2 chat_server.pl

Perl chat server based on AnyEvent

Server:     perl $0
Clients:    telnet 127.0.0.1 8888 (run in several terminals)
            clients communicate by:
                                    a) sending message terninated with carriage return
                                    b) sending OK, followed by carriage return
                                       sending  message terninated with carriage return  

=cut

use strict;
use warnings;
use utf8;
use v5.018;

use AnyEvent;                           # creates event driven loop
use AnyEvent::Socket qw(tcp_server);    # provides high level function to create tcp server
use AnyEvent::Handle;                   # creates non-blocking (socket) handle

use Data::Dumper qw(Dumper);

sub _inform_clients;

=head2 Store connected clients in a hash structure

key:    $host:$port ..... uniquely identifies a connected client
value:  socket handle ... so we can continue communication with individual clients

=cut

my %client = ();

=head2 Create TCP server

allow connection from everywhere, on a specified port

=cut

tcp_server undef, 8888, sub {
    my ($fh, $host, $port) = @_;

    say "[$host:$port] connected";

=head3 On connection, tell the client how many are already connected

=cut

    syswrite $fh, "Hello friend. There are currently " . scalar(keys %client) . 
                  " connected friends.\015\012";

    _inform_clients(\%client, "Friend [$host:$port] joined us!");

=head3 Create nonblocking socket handle for the client

=cut

    my $hdl = AnyEvent::Handle->new(
        fh => $fh,
    );

=head3 Store client information

=cut

    my $client_key = "$host:$port";
    $client{$client_key} = $hdl;

=head3 On error, clear the read buffer

=cut

    $hdl->on_error (sub {
        my $data = delete $_[0]{rbuf};
    });

=head3 On receiving a message from a client

We expect:

    sending a regular message
        either "OK\n", then a message
        or      directly a message
    disconnecting
        send quit/QUIT followed by carriage return

=cut

    my $writer; 
    $writer = sub {
        my ($hdl, $line) = @_;
        say "Reading from client: [$line]";

        my @clients = keys %client;
        say Dumper(\@clients);

        # The client cannot disconnect until we release its handle
        if ($line =~ /\Aquit|bye|exit\z/i) {

            my $client_count = (scalar keys %client) - 1;       # exclude the leaving client
            say "REMAINING (apart from this): $client_count";

            # Send message to each client
            for my $key (@clients) {

                if ($key eq $client_key) {
                    $hdl->push_write("Bye\015\012");
                }
                else {
                    my $message = ($client_count > 1) ? "only $client_count of us left\015\012" : 
                                                         "You are the only one left :(. Send quit/QUIT to disconnect\015\012";
                    $client{$key}->push_write("Friend $client_key is leaving us, $message");
                }

            }

            $hdl->push_shutdown;
            delete $client{$client_key};
            
        }
        # if we got an "OK", we have to _prepend_ another line,
        # so it will be read before the second request reads the 64 bytes ("OK\n")
        # which are already stored in the queue when this callback is called
        elsif ($line eq "OK") {
            $_[0]->unshift_read (line => sub {
                my $response = $_[1];
                for my $key (grep {$_ ne $client_key} @clients) {
                    $client{$key}->push_write("$response from $client_key\015\012");
                }
            });
        }
        elsif ($line) {
            for my $key (grep {$_ ne $client_key} @clients) {
                my $response = $line;
                $client{$key}->push_write("$response from $client_key\015\012");
            }
        }
    };

=head3  Enter the request handling loop

=cut

    $hdl->on_read (sub {
        my ($hdl) = @_;

        # Read what was sent, when request/message received
        # (then distribute the message)
        $hdl->push_read (line => $writer);
    });

};

=head3 Start the event loop

=cut

AnyEvent->condvar->recv; 

=head2 SUBROUTINES

_inform_clients

=cut

=head2 _inform_clients

sends a message to all known/stored clients

=cut

sub _inform_clients {
    my ($client_href, $message) = @_;

    for my $key (keys %$client_href) {
        $client{$key}->push_write("$message\015\012");
    }
}

Source code on github 

Sunday, 14 December 2014

Data Journey - HTTP, TCP, IP Protocol basics

Background

All the data sent here and there on the Internet - how does it work? The basis is synchronization of data transfer through an agreed upon procedure, ie adhering to a protocol of communication. There are different types of protocols. Machines/hosts/nodes communicate using lower level protocols, applications running on machines communicate using higher level protocols.

Communication happens between endpoints/sockets. Endpoints are entry points to a connection/process/service. Protocols are agreed upon rules, describing the format the communicated information, procedures that need to be followed.

Communication on the Internet depends on the Internet Protocol suite, a set of communication protocols making it possible to send bytes/octets between two networked computers, even if they are miles apart on different networks. Its alias is TCP/IP because the TCP (Transmission Control Protocol) and IP (Internet Protocol) protocols were formulated first.

How it works

We want to send a message from a browser on our local machine to a web application running a remote server, something we wrote in a form on a web page.

The remote web server is listening for HTTP requests on a socket described by the local IP address and a particular port. It directs requests for a dynamic resource to a web application. The client, sending the request, also creates a socket (web server IP address + the port on which the server is listening), through which it can now communicate with the web server. After establishing the physical connection, a several-step handshake follows , before data can be sent/received.

Browser and web server are applications communicating using the HTTP protocol. That way they know in what format they want receive the data, if they can deal with compression, whether it is possible to use a cached resource/page or need to retrieve it, etc. Browser will send the actual information we want to be sent, alongside with HTTP mandatory and optional headers.

How does the data travel to its destination? Thanks to the TCP, the sending application, browser in our case, does not need to worry about bytes and octets, but can send the whole message in one go, and let TCP tackle the problem.

TCP provides connection oriented, ie reliable transfer with error checking. It guarantees delivery but is not necessarily timely. It controls the data flow to avoid overwhelming the receiver, and network congestion, a situation when no or little data transfer is happening. When transfer reliability is not crucial, reduced latency (transfer delay) can be achieved with UDP, the connectionless User Datagram Protocol. While using TCP is important in e-commerce, for instance, UDP is used when streaming films, VOIP etc.

The message is divided into small pieces, each, a sequence of octets/bytes, each of which is then encapsulated with additional data (in a header/footer). The encapsulation - headers + payload - is called a packet or a datagram, and is a basic transfer unit. The headers (they gradually accumulate, as a protocol in each layer in the Internet Protocol suite, adds its own), contain, in the end, all the information needed to get the data across from one endpoint to the other one.  The TCP header holds information needed for reassembly of the message from individual packets (local and remote ports, sequence number etc).


 

http://books.msspace.net/mirrorbooks/snortids/0596006616/snortids-CHP-2-SECT-2.html

TCP operations have three phases. The first is about creating a connection using a multi-step handshake, to establish a reliable connection. A TCP connection is managed by the operating system through socket API (application programming interface) (Inter-process Communication). After that, the data transfer phase happens, followed by closure of the connection and release of resources.

IP protocol  deals with the actual packet transfer across different network boundaries, ie with routing. It prescribes the format of its associated header containing IP addresses of the local and remote hosts and other routing data.

When the collection of packets representing our message, arrives at the destination endpoint, they are reassembled to form the original data, according to the meta data in the TCP/IP/HTTP headers. The destination application receives the whole message instead of a bundle of little payloads. Impressive!