Vous êtes sur la page 1sur 18



&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

C++ Chat Server Tutorial Part I


Intro
Click here for Part II
Tutorial Assumes Boost Version >= 1.53
We'll be making use of the Boost C++ libraries for this
tutorial so before we begin make sure you have read
through the installation documentation on the Boost
website on. Below I have included some links for each
operating system on how to install a recent version of Boost;
its not extremely difficult but sometimes installing Boost can
be tricky for those of us not familiar with compiling C++
projects from source code or the difference between the
header-file only libraries and the rest of Boost.
Windows users Boost Installation Guide
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

Ubuntu/Debian Linux can use the aptitude Boost


Ubuntu/Debian Linux can also use the Upstream Boost
which is recommended
Mac OS X should use Homebrew
If you need extra help installing the Boost C++ libraries or
making sure that you can compile a project using Boost and
properly link the libraries Google and or Stackoverflow are
your best bets. Once you're comfortable building projects
and or compiling single files with Boost we're ready to begin.

Part I: The Chat Client Code

Our client code for the Chat application will rely upon the
use of threads to divide our code into three distinct subroutines.
A thread for displaying chat messages
Another thread for sending messages to the Chat server
And a third thread for receiving messages routed by the
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

server from other connected clients


There are many approaches to designing multi-threaded
applications and its a big topic that often rears its head
during interviews with top tech companies but for the sake
of this tutorial we'll only need to concern ourselves with just
a small subset of concurrent programming. For the purposes
of the application we're going to build in this tutorial series
we're going to be using what is known as the "Producer-

Consumer" pattern for organizing our code. As a side note


for the pedantics reading this article I'm not claiming that
this code will follow Producer-Consumer to the exact
sepcification but for the most part it will resemble a typical

Producer-Consumer setup.

Producer-Consumer Overview For The Chat Client


Quoting from the Wikipedia page on the pattern

In computing, the producerconsumer's problem


(also
as the
bounded-buffer
Blogknown
Archive
Projects
About RSSproblem) is a
classic example of a multi-process synchronization
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

problem. The problem describes two processes, the


producer and the consumer, who share a common,
fixed-size buffer used as a queue.
Thus the following is a list of C++ objects used by our Client
to implement the Producer-Consumer pattern.
boost::thread_group to address multi-processing
std::queue< std::string > to represent the boundedbuffer of messages
boost::thread objects for adding and removing messages
from the queue

Preprocessor Directives And Function Prototypes


Lets start off, create a new working directory called
chat_app wherever you want on your system. Next change
into the chat_app directory and create a new file, name it
boostChatClient.cpp. First we'll need to include a few
libraries; some from the C++ standard template library and
others from Boost.
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

/*boostChatClient.cpp*/
#include
#include
#include
#include
#include
#include
#include
#include
#include

The above library includes are fairly basic for a C++ console
application but unfamiliar to most are probably the Boost
includes.
boost/thread Multithreading support
boost/bind A library for functional programming but
used here to create sub-rountines for threads
boost/asio System socket and network programming
library
boost/algorithm/string Pretty self-explainatory; gives
use some new string methods
I will be using namespace aliasing in this application, it can be
a pain sometimes to read code without namespace aliasing
so lets at least make an effort to strive for clean human
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

readable code. So add the lines below to the current file


right after the preprocessor library includes.
/*boostChatClient.cpp*/
usingnamespace
usingnamespace
usingnamespace
usingnamespace

Next we define some typedefs for quickly describing some


boost shared pointers. Shared pointers are now apart of the
C++ standard but there are problems abound when you try
and mix and match C++ std shared pointers with Boost
library shared pointers. Not so much for performance but
more from the fact that using Boost shared pointers
introduces a dependency on the Boost libraries; so to keep
your code Boost friendly just stick with the Boost versions
of the smart pointer collection.
/*boostChatClient.cpp*/
typedef
typedef
typedef

In order to initialize the boost::asio networking methods we


need to create a special object called io_service. The best
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

way to think of io_service is as shared queue which only


accepts functions that deal with asynchronous I/O. Thus you
can represent a socket bound to a network port within your
application and in order to send the socket a method such as
connect() the method must get enqueued within the
io_service before its sent down to the operating system.

The documentation on the anatomy of Boost::asio is


the most helpful for understanding the architecture
of the library. Basic Boost.Asio Anatomy
/*boostChatClient.cpp*/
//BoostAsioio_service
new//Queueforproducerconsumerpattern

//TCPsocketforconnectingtos
constint//Maximumsizeforinputbuffer
//Terminalpromptdisplayedtochatusers

Add the following function prototypes; we'll discuss the


functions as they get implemented. As you can already guess
by the descriptive names of each function the function's
with the suffix Loop will be ran on threads and interact with
the messageQueue we defined earlier.
KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

/*boostChatClient.cpp*/
//FunctionPrototypes
bool
void
void
void
string
//EndofFunctionPrototypes

The main() Function, Thread Creation And Socket


Initialization
From the explaination earlier in the article we create a
thread_group facilitate the all of our async functions. In
regards to the producer-consumer pattern,
inboundLoop() Will push items from the socket to our
messageQueue; i.e producer
displayLoop() Removes items from messageQueue to
display on the client terminal; i.e consumer
/*boostChatClient.cpp*/
intintchar



try



new

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH













catch



return 



Function Definitions
The first function buildPrompt is a function which handles
the display of the terminal input for clients. Its fairly simple
in that it takes a string of the clients name and assigns it to
the value of the prompt pointer we declared earlier.
/*boostChatClient.cpp*/
string

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

constint

char

char

stringnewstring





string

return

Following the buildPrompt() function the first of the


threaded functions is the inboundLoop().
/*boostChatClient.cpp*/
void



int

char

for

if



newstring





KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

Our code for the inboundLoop() is self-explainatory but in


particular it creates a loop which only inserts into the thread
when a message is available on the socket connected to the
server. Reading from the socket object is an operation which
may potentially interfere with writing to the socket so we
put a one second delay on checks for reading.
As for writting mesasges to the socket to send off to other
members of the Chat session we need a loop that will
constantly poll for user input. Once the user input is read
write the message to the socket wait for the next input.
Recall that this operation is threaded so in-comming
messages can still be displayed since that happens on an
entirely different thread.
/*boostChatClient.cpp*/
void



char

string

for



string

if

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

//Thestringforquittingtheapplication

//Ontheserversidethereisalsoacheckfor"quit"toterminatetheTCPsock

ifstring







exit//Replacewithcleanupcodeifyouwantbutforthistutorial

For the extra pedantic, you might be wondering why there is


no extraneous clean-up code and instead we just call exit(1);
for the sake of keeping this tutorial brief and to the point we
are not launching a production ready scalable service
oriented distributed ChatApplication to be used by
thousands of clients. Anyhow moving on the last of the
threaded funtions is for displaying the messages read from
the socket to the terminal.
/*boostChatClient.cpp*/
void



for

if

//Canyourefactorthiscodetohandlemultipleuserswiththesamepro

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

if







The displayLoop() function is fairly crude but it gets the job


done. We rely on the fact that every message begins with a
user prompt in order to determine if the message belonged
to the client or not. When I say crude I mean that a proper
chat application with tag each user with a specific id number
because our code fails to handle the error when multiple
users share the same prompt. Speaking of which here is the
last of the utility functions; the one which checks if the
prompt from buildPrompt() is found within the string
arriving from the socket.
bool



ifstring

else

returntrue
returnfalse

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

Thanks for reading my tutorial on how to setup a chat client


using C++ and the Boost Libraries; this code deserves a
refactor considering that many of the Boost code used is
now apart of the latest C++ standard. In addition the
introduction of a protocol could be useful for unique
identification of clients and other things as well. Stay tuned
for the second part of this tutorial where we code the server
side of the Chat applciation.

Full Source Code















KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH









 











 



















 




KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH



































KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH




















ERRVW&KDW&OLHQWFSSKRVWHGZLWKE\*LW+XE

YLHZUDZ

Click here for Part II

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO





&&KDW6HUYHU7XWRULDO3DUW,_7D\ZLOVPH

&RPPHQWV

WD\ZLOVPH

6KDUH

5HFRPPHQG

/RJLQ

6RUWE\%HVW

-RLQWKHGLVFXVVLRQ
/HOHN DPRQWKDJR

&RXOG\RXKHOSZLWKFRPSLOLQJ#8EXQWX"

5HSO\ 6KDUH

:DVHHP$KPDG1DHHP PRQWKVDJR

1RWXVHIXO,1HHG7XWRULDO1RW6RXUFH&RGH

5HSO\ 6KDUH

:+$7
67+,6"

$/62217$<:,/60(

5XE\&UDPSWXWRULDOEXLOGDQ566$3,ZLWK
5XE\DQG5HGLV

-DYD6SDUN)UDPHZRUN7XWRULDO
FRPPHQWV\HDUVDJR

FRPPHQWV\HDUVDJR

SDSDMWKLVDUWLFOHLVROGDQGWKLQJVKDYH

FKDQJHGVLQFHWKHQSOHDVHXSGDWHLWLI\RX
FRXOG7K[

$KPDG+DVDQ.KDQ1RSUREOHP

%XLOG$7H[W%DVHG0XOWLSOD\HU53*3DUW9
FRPPHQW\HDUVDJR

-RQ:KHQ,GRZQORDGDOOWKHILOHVSXWWKHP

,QVWDOO3\WKRQ1XPS\DQG3DQGDVRQ
:LQGRZV
FRPPHQWV\HDUVDJR

LQWKHVDPHIROGHUDQGRSHQPDLQFSSDQGWU\
WRFRPSLOH,JHWHUURUVDOORIWKHPVWDUWLQJ
XQGHILQHGUHIHUHQFHWR08'

6XEVFULEH

$GG'LVTXVWR\RXUVLWH

0DKDVLVK6KRPH:KDWDQDZHVRPH

7XWRULDO7KDQNVYHU\PXFKIRUVKDULQJ

3ULYDF\

Copyright 2015 Demetrious Taylor Wilson. All rights reserved.

KWWSZZZWD\ZLOVPHERRVWFKDWFOLHQWKWPO



Vous aimerez peut-être aussi