Vous êtes sur la page 1sur 64

EXPEREMENT-1

INTRODUCTION OF NETWORK PROGRAMMING LAB

1. LINUX:

1.1. HISTORY
1.1.1. UNIX
In order to understand the popularity of Linux, we need to travel back in time, about 30 years
ago...
Imagine computers as big as houses, even stadiums. While the sizes of those computers posed
substantial problems, there was one thing that made this even worse: every computer had a
different operating system. Software was always customized to serve a specific purpose, and
software for one given system didn't run on another system. Being able to work with one system
didn't automatically mean that you could work with another. It was difficult, both for the users
and the system administrators.
Computers were extremely expensive then, and sacrifices had to be made even after the original
purchase just to get the users to understand how they worked. The total cost per unit of
computing power was enormous.
Technologically the world was not quite that advanced, so they had to live with the size for
another decade. In 1969, a team of developers in the Bell Labs laboratories started working on a
solution for the software problem, to address these compatibility issues. They developed a new
operating system, which was

1. Simple and elegant.


2. Written in the C programming language instead of in assembly code.
3. Able to recycle code.
The Bell Labs developers named their project "UNIX."

The code recycling features were very important. Until then, all commercially available
computer systems were written in a code specifically developed for one system. UNIX on the
other hand needed only a small piece of that special code, which is now commonly named the
kernel. This kernel is the only piece of code that needs to be adapted for every specific system
and forms the base of the UNIX system. The operating system and all other functions were built
around this kernel and written in a higher programming language, C.

This language was especially developed for creating the UNIX system. Using this new
technique, it was much easier to develop an operating system that could run on many different
types of hardware.

The software vendors were quick to adapt, since they could sell ten times more software almost
effortlessly. Weird new situations came in existence: imagine for instance computers from
different vendors communicating in the same network, or users working on different systems
without the need for extra education to use another computer. UNIX did a great deal to help users
become compatible with different systems.

Throughout the next couple of decades the development of UNIX continued. More things
became possible to do and more hardware and software vendors added support for UNIX to their
products. UNIX was initially found only in very large environments with mainframes and
minicomputers (note that a PC is a "micro" computer). You had to work at a university, for the
government or for large financial corporations in order to get your hands on a UNIX system.

But smaller computers were being developed, and by the end of the 80's, many people had home
computers. By that time, there were several versions of UNIX available for the PC architecture,
but none of them were truly free and more important: they were all terribly slow, so most people
ran MS DOS or Windows 3.1 on their home PCs.

1.1.2. Linus and Linux

By the beginning of the 90s home PCs were finally powerful enough to run a full blown UNIX.
Linus Torvalds, a young man studying computer science at the university of Helsinki, thought it
would be a good idea to have some sort of freely available academic version of UNIX, and
promptly started to code.
He started to ask questions, looking for answers and solutions that would help him get UNIX on
his PC

From the start, it was Linus' goal to have a free system that was completely compliant with the
original UNIX. That is why he asked for POSIX standards, POSIX still being the standard for
UNIX. In those days plug-and-play wasn't invented yet, but so many people were interested in
having a UNIX system of their own, that this was only a small obstacle. New drivers became
available for all kinds of new hardware, at a continuously rising speed. Almost as soon as a new
piece of hardware became available, someone bought
It and submitted it to the Linux test, as the system was gradually being called, releasing more
free code for an ever wider range of hardware. These coders didn't stop at their PC's; every piece
of hardware they could find was useful for Linux.

Back then, those people were called "nerds" or "freaks", but it didn't matter to them, as long as
the supported hardware list grew longer and longer. Thanks to these people, Linux is now not
only ideal to run on new PC's, but is also the system of choice for old and exotic hardware that
would be useless if Linux didn't exist.

Two years after Linus' post, there were 12000 Linux users. The project, popular with hobbyists,
grew steadily, all the while staying within the bounds of the POSIX standard. All the features of
UNIX were added over the next couple of years, resulting in the mature operating system Linux
has become today. Linux is a full UNIX clone, fit for use on workstations as well as on middle-
range and high-end servers. Today, a lot of the important players on the hard- and software
market each have their team of Linux developers; at your local dealer's you can even buy pre-
installed Linux systems with official support - even though there is still a lot of hard- and
software that is not supported, too.

1.2. The user interface: Is Linux difficult?


Whether Linux is difficult to learn depends on the person you're asking. Experienced UNIX
users will say no, because Linux is an ideal operating system for power-users and programmers,
because it has been and is being developed by such people.

Everything a good programmer can wish for is available: compilers, libraries, development and
debugging tools. These packages come with every standard Linux distribution. The C-compiler
is included for free - as opposed to many UNIX distributions demanding licensing fees for this
tool. All the documentation and manuals are there, and examples are often included to help you
get started in no time. It feels like UNIX and switching between UNIX and Linux is a natural
thing.

In the early days of Linux, being an expert was kind of required to start using the system. Those
who mastered Linux felt better than the rest of the "lusers" who hadn't seen the light yet. It was
common practice to tell a beginning user to "RTFM" (read the manuals). While the manuals were
on every system, it was difficult to find the documentation, and even if someone did,
explanations were in such technical terms that the new user became easily discouraged from
learning the system.

The Linux-using community started to realize that if Linux was ever to be an important player on
the operating system market, there had to be some serious changes in the accessibility of the
system.

1.3. Does Linux have a future: Open Source?


The idea behind Open Source software is rather simple: when programmers can read, distribute
and change code, the code will mature. People can adapt it, fix it, debug it, and they can do it at a
speed that dwarfs the performance of software developers at conventional companies. This
software will be more flexible and of a better quality than software that has been developed using
the conventional channels, because more people have tested it in more different conditions than
the closed software developer ever can.
The Open Source initiative started to make this clear to the commercial world, and very slowly,
commercial vendors are starting to see the point. While lots of academics and technical people
have already been convinced for 20 years now that this is the way to go, commercial vendors
needed applications like the Internet to make them realize they can profit from Open Source.
Now Linux has grown past the stage where it was almost exclusively an academic system, useful
only to a handful of people with a technical background.

Now Linux provides more than the operating system: there is an entire infrastructure supporting
the chain of effort of creating an operating system, of making and testing programs for it, of
bringing everything to the users, of supplying maintenance, updates and support and
customizations, etcetera. Today, Linux is ready to accept the challenge of a fast-changing world.

1.4. Properties of Linux

1.4.1. Linux Pros

A lot of the advantages of Linux are a consequence of Linux' origins, deeply rooted in UNIX,
except for the first advantage, of course:
Linux is free:
As in free beer, they say. If you want to spend absolutely nothing, you don't even have to
pay the price of a CD. Linux can be downloaded in its entirety from the Internet
completely for free. No registration fees, no costs per user, free updates, and freely
available source code in case you want to change the behaviour of your system.
Most of all, Linux is free as in free speech:
The license commonly used is the GNU Public License (GPL). The license says that
anybody who may want to do so has the right to change Linux and eventually to
redistribute a changed version, on the one condition that the code is still available after
redistribution. In practice, you are free to grab a kernel image, for instance to add support
for teletransportation machines or time travel and sell your new code, as long as your
customers can still have a copy of that code.
Linux is portable to any hardware platform:
A vendor who wants to sell a new type of computer and who doesn't know what kind of
OS his new machine will run (say the CPU in your car or washing machine), can take a
Linux kernel and make it work on his hardware, because documentation related to this
activity is freely available.

Linux was made to keep on running:


As with UNIX, a Linux system expects to run without rebooting all the time. That is why
a lot of tasks are being executed at night or scheduled automatically for other calm
moments, resulting in higher availability during busier periods and a more balanced use
of the hardware. This property allows for Linux to be applicable also in environments
where people don't have the time or the possibility to control their systems night and day.

Linux is secure and versatile:


The security model used in Linux is based on the UNIX idea of security, which is known
to be robust and of proven quality. But Linux is not only fit for use as a fort against
enemy attacks from the Internet: it will adapt equally to other situations, utilizing the
same high standards for security. Your development machine or control station will be as
secure as your firewall.

Linux is scalable:
From a Palmtop with 2 MB of memory to a pet byte storage cluster with hundreds of
nodes: add or remove the appropriate packages and Linux fits all. You don't need a
supercomputer anymore,
Because you can use Linux to do big things using the building blocks provided with the
system. If you want to do little things, such as making an operating system for an
embedded processor or just recycling your old 486, Linux will do that as well.

The Linux OS and most Linux applications have very short debug-times:
Because Linux has been developed and tested by thousands of people, both errors and
people to fix them are usually found rather quickly. It sometimes happens that there are
only a couple of hours between discovery and fixing of a bug.

1.4.2. Linux Cons

There are far too many different distributions:


"Quot capites, tot rationes", as the Romans already said: the more people, the more
opinions. At first glance, the amount of Linux distributions can be frightening, or
ridiculous, depending on your point of view. But it also means that everyone will find
what he or she needs. You don't need to be an expert to find a suitable release.
When asked, generally every Linux user will say that the best distribution is the specific
version he is using. So which one should you choose? Don't worry too much about that:
all releases contain more or less the same set of basic packages. On top of the basics,
special third party software is added making, for example, TurboLinux more suitable for
the small and medium enterprise, RedHat for servers and SuSE for workstations.
However, the differences are likely to be very superficial. The best strategy is to test a
couple of distributions; unfortunately not everybody has the time for this. Luckily, there
is plenty of advice on the subject of choosing your Linux. A quick search on Google,
using the keywords "choosing your distribution" brings up tens of links to good advice.
The Installation HOWTO also discusses choosing your distribution.
Linux is not very user friendly and confusing for beginners:
It must be said that Linux, at least the core system, is less user-friendly to use than MS
Windows and certainly more difficult than MacOS, but... In light of its popularity,
considerable effort has been made to make Linux even easier to use, especially for new
users. More information is being released daily, such as this guide, to help fill the gap for
documentation available to users at all levels.
Is an Open Source product trustworthy?
How can something that is free also be reliable? Linux users have the choice whether to
use Linux or not, which gives them an enormous advantage compared to users of
proprietary software, who don't have that kind of freedom. After long periods of testing,
most Linux users come to the conclusion that Linux is not only as good, but in many
cases better and faster that the traditional solutions. If Linux were not trustworthy, it
would have been long gone, never knowing the popularity it has now, with millions of
users. Now users can influence their systems and share their remarks with the community,
so the system gets better and better every day. It is a project that is never finished, that is
true, but in an ever changing environment, Linux is also a project that continues to strive
for perfection.

1.5. Linux Flavors

1.5.1. Linux and GNU

Although there are a large number of Linux implementations, you will find a lot of similarities in
the different distributions, if only because every Linux machine is a box with building blocks
that you may put together following your own needs and views. Installing the system is only the
beginning of a long-term relationship. Just when you think you have a nice running system,
Linux will stimulate your imagination and creativeness, and the more you realize what power the
system can give you, the more you will try to redefine its limits.
Linux may appear different depending on the distribution, your hardware and personal taste, but
the fundamentals on which all graphical and other interfaces are built, remain the same. The
Linux system is based on GNU tools (Gnu's Not UNIX), which provide a set of standard ways to
handle and use the system. All GNU tools are open source, so they can be installed on any
system. Most distributions offer pre-compiled packages of most common tools, such as RPM
packages on Red Hat and Debian packages (also called deb or dpkg) on Debian, so you needn't
be a programmer to install a package on your system. However, if you are and like doing things
yourself, you will enjoy Linux all the better, since most distributions come with a complete set of
development tools, allowing installation of new software purely from source code. This setup
also allows you to install software even if it does not exist in a pre-packaged form suitable for
your system.
A list of common GNU software:
Bash: The GNU shell
GCC: The GNU C Compiler
GDB: The GNU Debugger
Coreutils: a set of basic UNIX-style utilities, such as ls, cat and chmod
Findutils: to search and find files
Fontutils: to convert fonts from one format to another or make new fonts
The Gimp: GNU Image Manipulation Program
Gnome: the GNU desktop environment
Emacs: a very powerful editor
Ghostscript and Ghostview: interpreter and graphical frontend for PostScript files.
GNU Photo: software for interaction with digital cameras
Octave: a programming language, primarily intended to perform numerical computations
and image processing.
GNU SQL: relational database system
Radius: a remote authentication and accounting server

1.5.2. GNU/Linux

The Linux kernel (the bones of your system, see Section 3.2.3.1) is not part of the GNU project
but uses the same license as GNU software. A great majority of utilities and development tools
(the meat of your system), which are not Linux-specific, are taken from the GNU project.
Because any usable system must contain both the kernel and at least a minimal set of utilities,
some people argue that such a system should be called a GNU/Linux system.
In order to obtain the highest possible degree of independence between distributions, this is the
sort of inux that we will discuss throughout this course. If we are not talking about a
GNU/Linux system, the specific distribution, version or program name will be mentioned.

1.6. Introduction to UNIX Systems

When learning about the shells, you will find they are often associated with different versions of
the UNIX/Linux operating systems. For example, the Bourne and Korn shells are associated with
AT&T UNIX, the C shell with Berkeley UNIX, and the Bash shell with Linux. Before delving
into the particulars of the shells, this section is provided to give you a little background
information about the operating systems on which they reside.
1.6.1 A Little Bit about UNIX

UNIX is a multiuser, multitasking operating system initiated by Ken Thompson in 1969 at AT&T
Bell Labs. UNIX was designed to allow a large number of programmers to access the computer
at the same time, sharing its resources. It was to be simple and powerful, versatile and portable.
It could run on computer systems ranging from microcomputers to super minicomputers and
mainframes.

At the heart of UNIX is the kernel, a program loaded when the system boots. The kernel talks to
the hardware and devices, schedules tasks, and manage memory and storage. Due to the Spartan
nature of UNIX, a large number of small simple tools and utilities were developed, and because
these tools (commands) could be easily combined to perform a variety of larger tasks, UNIX
quickly gained popularity. One of the most important utilities developed was the shell, a program
that allows the user to communicate with the operating system. This book explores the features
of the most prominent shells available today.

At first UNIX was adopted, at nominal cost, by scientific research institutions and universities
and later spread to computer companies, government bodies, and manufacturing industries. In
1973, the U.S. Defense Advanced Research Projects Agency (DARPA) initiated a research
program to develop a way to link computers together transparently across multiple networks
using UNIX. This project, and the system of networks that emerged from the research, resulted
in the birth of the Internet!

By the late 1970s many of the students who had pioneered and experimented with UNIX in
college were now working in industry and demanded a switch to UNIX, claiming that it was the
most suitable operating system for a sophisticated programming environment. Soon a large
number of vendors, large and small, started marketing their own versions of UNIX, optimizing it
for their individual computer architectures. The two most prominent versions of UNIX were
System V from AT&T and BSD UNIX, which was derived from AT&T's version and developed
at the University of California, Berkeley, in the early 1980s.

(To see a chart of the many different versions of UNIX, over 80 flavors. With so many versions
of UNIX, applications and tools running on one system often could not run on another without
considerable time and energy spent in making them compatible. This lack of uniformity fueled
the rhetoric of competing vendors to abandon UNIX and stay with the older, non-UNIX
proprietary systems, such as VMS, that had proven to be more consistent and reliable.

It was time to standardize UNIX. A group of vendors got together and started the concept of
"open systems," whereby those participating would agree to conform to certain standards and
specifications. UNIX was chosen as the basis for the new concept. A company called X/Open
was formed to define the open systems platform, and many organizations began using X/Open as
a basis for system design. X/Open is now a part of The Open Group and continues to develop a
Single UNIX Specification.

In early 1993, AT&T sold its UNIX System Laboratories to Novell. In 1995 Novell transferred
the rights to the UNIX trademark and the specification (which subsequently became the Single
UNIX Specification) to The Open Group (at the time X/Open), and sold SCO the UNIX system
source code. Today UNIX-based systems are sold by a number of companies. The systems
include Solaris from Sun Microsystems, HP-UX and Tru64 UNIX from Hewlett-Packard, and
AIX from IBM. In addition there are many freely available UNIX and UNIX-compatible
implementations, such as Linux, FreeBSD, and NetBSD.

1.6.2 Definition and Function of a Shell

The shell is a special program used as an interface between the user and the heart of the
UNIX/Linux operating system, a program called the kernel. The kernel is loaded into memory at
boot-up time and manages the system until shutdown. It creates and controls processes, and
manages memory, file systems, communications, and so forth. All other programs, including
shell programs, reside on the disk. The kernel loads those programs into memory, executes them,
and cleans up the system when they terminate. The shell is a utility program that starts up when
you log on. It allows users to interact with the kernel by interpreting commands that are typed
either at the command line or in a script file.
Figure 1.1: operating system architecture

When you log on, an interactive shell starts up and prompts you for input. After you type a
command, it is the responsibility of the shell to (a) parse the command line; (b) handle wildcards,
redirection, pipes, and job control; and (c) search for the command, and if found, execute that
command. When you first learn UNIX/Linux, you spend most of your time executing commands
from the prompt. You use the shell interactively.

If you type the same set of commands on a regular basis, you may want to automate those tasks.
This can be done by putting the commands in a file, called a script file, and then executing the
file. A shell script works much like a batch file: A list of UNIX/Linux commands is typed into a
file, and then the file is executed. More sophisticated scripts contain programming constructs for
making decisions, looping, file testing, and so forth. Writing scripts not only requires learning
programming constructs and techniques, but also assumes that you have a good understanding of
UNIX/Linux utilities and how they work. There are some utilities, such as grep, sed, and awk,
that are extremely powerful tools used in scripts for the manipulation of command output and
files. After you have become familiar with these tools and the programming constructs for your
particular shell, you will be ready to start writing useful scripts. When executing commands from
within a script, you are using the shell as a programming language.

1.6.3 Uses of the Shell

When running interactively, one of the major functions of a shell is to interpret commands
entered at the command-line prompt. The shell parses the command line, breaking it into words
(called tokens) separated by whitespace, which consists of tabs, spaces, or a newline. If the
words contain special meta characters, the shell evaluates them. The shell handles file I/O and
background processing. After the command line has been processed, the shell searches for the
command and starts its execution.

Another important function of the shell is to customize the user's environment, normally done in
shell initialization files. These files contain definitions for setting terminal keys and window
characteristics; setting variables that define the search path, permissions, prompts, and the
terminal type; and setting variables that are required for specific applications such as window
managers, text-processing programs, and libraries for programming languages. The Korn/Bash
shells and C/TC shells also provide further customization with the addition of history, aliases,
and built-in variables set to protect the user from clobbering files, or inadvertently logging out,
or to notify the user when a job has completed.

The shell can also be used as an interpreted programming language. Shell programs, also called
scripts, consist of commands listed in a file. The programs are created in an editor (although
online scripting is permitted). They consist of UNIX/Linux commands interspersed with
fundamental programming constructs such as variable assignment, conditional tests, and loops.
You do not have to compile shell scripts. The shell interprets each line of the script as if it had
been entered from the keyboard. Because the shell is responsible for interpreting commands.
1.6.4 Responsibilities of the Shell

The shell is ultimately responsible for making sure that any commands typed at the prompt get
executed properly. Included in those responsibilities are:

1. Reading input and parsing the command line

2. Evaluating special characters, such as wildcards and the history character

3. Setting up pipes, redirection, and background processing

4. Handling signals

5. Setting up programs for execution


2. Network Programming

2. 1 The OSI Model


OSI stands for Open Systems Interconnection Reference Model. In short it is termed as OSI
model or OSI reference model or 7-layer model or Layered Model or OSI seven layer
models. OSI layer consists of seven layers: Physical layer, Data link layer, Network layer,
Transport layer, Session layer, Presentation layer and Application layer

Figure 1.1: OSI model

OSI mode is a layered, abstract description for communications & computer network protocol
design which consists of 7 layers and has two major components (i) an abstract model of
networking (the Basic Reference Model) (ii) a set of concrete protocols
In the following paragraphs, you will find summarize description of OSI layers:

Functionality of Application Layer

Application layer is the 7th layer of OSI model and sometimes referred as Layer Seven of OSI
model. The functionality of application layer is described below:

Network processes to applications.

Provides network services to application processes, such as e-mail, file transfer &
terminal emulation.

Functionality of Presentation Layer

Presentation layer is the 6th layer of OSI model and sometimes referred as Layer Six of OSI
model. The functionality of presentation layer is described below:

Data representation and encryption

Ensure data is readable by receiving system.

Format of data

Data structures

Negotiates data transfer syntax for application layer.

Functionality of Session Layer

Session Layer is the 5th layer of OSI model and sometimes referred as Layer Five of OSI model.
The functionality of session layer is described below:

Interhost communication

Establish, manages & terminates session between applications.

Functionality of Transport Layer


Transport Layer is the 4th layer of OSI model and sometimes referred as Layer Four of OSI
model. The functionality of transport layer is described below:

End-to-end connections and reliability (TCP)

Concerned with transportation issues between hosts.

Data transport reliability.

Establish, maintain, and terminate virtual circuits.

Fault detection & recovery information flow control.

Controls the reliability of a given link through flow control,


segmentation/desegmentation, and error control.

Functionality of Network Layer

Network Layer is the 3rd layer of OSI model and sometimes referred as Layer Three of OSI
model. The functionality of Network layer is described below:

Path determination and logical addressing (IP)

Logical addressing

Best effort delivery

Functionality of Data link Layer

Data link layer is the 2nd layer of OSI model and sometimes referred as Layer Two of OSI
model. The functionality of Data link layer is described below:

Physical addressing (MAC & LLC)

Provides reliable transfer of data across media

Physical addressing, network topology, line discipline, error notification, ordered delivery
to frames, flow control
Functionality of Physical Layer

Physical Layer is the 1st layer of OSI model and sometimes referred as Layer One of OSI model.
The functionality of physical layer is described below:

Media, signal and binary transmission

Figure 2.2. Layers with protocols

In this lab we will concentrate more on the Transport and Network layer of the TCP/IP stack.
More detail TCP/IP stack with typical applications is shown below.

Figure 2.3. Layers with protocols

The following figure is a TCP/IP architectural model. Frame, packet and message are same entity
but called differently at the different layer because there are data encapsulations at every layer.
Figure 2.4. Layers with protocols

Protocol
In computing field, a protocol is a convention or standard rules that enables and controls
the connection, communication and data transfer between two computing endpoints.
Protocols may be implemented by hardware, software, or a combination of the two. At
the lowest level, a protocol defines the behaviour of a hardware connection.
In term of controls, protocol may provide data transfer reliability, resiliency and integrity.
An actual communication is defined by various communication protocols. In the
context of data communication, a network protocol is a formal set of rules, conventions
and data structure that governs how computers and other network devices exchange
information over a network.
In other words, protocol is a standard procedure and format that two data communication
devices must understand, accept and use to be able to talk to each other.
A wide variety of network protocols exist, which are defined by many standard
organizations worldwide and technology vendors over years of technology evolution and
developments.
One of the most popular network protocol suites is TCP/IP, which is the heart of
internetworking communications.

2.2 Client/Server Computing


2.2.1 User Datagram Protocol (UDP)
UDP provides an unreliable packet delivery system built on top of the IP protocol. As with IP,
each packet is an individual, and is handled separately. Because of this, the amount of data that
can be sent in a UDP packet is limited to the amount that can be contained in a single IP packet.
Thus, a UDP packet can contain at most 65507 bytes (this is the 65535-byte IP packet size minus
the minimum IP header of 20 bytes and minus the 8-byte UDP header).
UDP packets can arrive out of order or not at all. No packet has any knowledge of the preceding
or following packet. The recipient does not acknowledge packets, so the sender does not know
that the transmission was successful. UDP has no provisions for flow control--packets can be
received faster than they can be used. We call this type of communication connectionless because
the packets have no relationship to each other and because there is no state maintained.
The destination IP addresses and port number is encapsulated in each UDP packet. These two
numbers together uniquely identify the recipient and are used by the underlying operating system
to deliver the packet to a specific process (application).
One way to think of UDP is by analogy to communications via a letter. You write the letter (this
is the data you are sending); put the letter inside an envelope (the UDP packet); address the
envelope (using an IP address and a port number); put your return address on the envelope (your
local IP address and port number); and then you send the letter. Like a real letter, you have no
way of knowing whether a UDP packet was received. If you send a second letter one day after
the first, the second one may be received before the first. Or, the second one may never be
received.
So why use UDP if it unreliable? Two reasons: speed and overhead. UDP packets have almost no
overhead--you simply send them then forget about them. And they are fast, since there is no
acknowledgement required for each packet. Keep in mind the degree of unreliability we are
talking about. For all practical purposes, an Ethernet breaks down if more than about 2 percent of
all packets are lost. So, when we say unreliable, the worst-case loss is very small. UDP is
appropriate for the many network services that do not require guaranteed delivery. An example
of this is a network time service. Consider a time daemon that issues a UDP packet every second
so computers on the LAN can synchronize their clocks. If a packet is lost, it's no big deal--the
next one will be by in another second and will contain all necessary information to accomplish
the task. The following figure illustrates the example of client/server relationship of the socket
APIs for a connectionless protocol (UDP).

Figure 2.5. Client/server relationship for UDP

Another common use of UDP is in networked, multi-user games, where a player's position is sent
periodically. Again, if one position update is lost, the next one will contain all the required
information. A broad class of applications is built on top of UDP using streaming protocols. With
streaming protocols, receiving data in real-time is far more important than guaranteeing delivery.
Examples of real-time streaming protocols are RealAudio and RealVideo which respectively
deliver real-time streaming audio and video over the Internet. The reason a streaming protocol is
desired in these cases is because if an audio or video packet is lost, it is much better for the client
to see this as noise or "drop-out" in the sound or picture rather than having a long pause while the
client software stops the playback, requests the missing data from the server. That would result in
a very choppy, burst playback which most people find unacceptable, and which would place a
heavy demand on the server.

2.2.2 Transmission Control Protocol (TCP)


We saw in the previous section that UDP provides an unreliable packet delivery system--each
packet is an individual, and are handled separately. Packets can arrive out of order or not at all.
The recipient does not acknowledge them, so the sender does not know that the transmission was
successful. There are no provisions for flow control--packets can be received faster than they can
be used. Packet size was limited by the underlying IP protocol. TCP, Transmission Control
Protocol, was designed to address these problems. TCP packets are lost occasionally, just like
UDP packets. The difference is that the TCP protocol takes care of requesting retransmits to
ensure that all packets show up, and tracks packet sequence numbers to be sure that they are
delivered in the correct order. While UDP required us to send packets of byte arrays, with TCP
we can use streams along with the standard Java file I/O mechanism. Unlike UDP, the
Transmission Control Protocol, TCP, establishes a connection between the two endpoints.
Negotiation is performed to establish a socket, and the socket remains open throughout the
duration of the communications. The recipient acknowledges each packet, and packet
retransmissions are performed by the protocol if packets are missed or arrive out of order. In this
way TCP can allow an application to send as much data as it desires and not be subject to the IP
Packet size limit. TCP is responsible for breaking the data into packets, buffering the data,
resending lost or out of order packets, acknowledging receipt, and controlling rate of data flow
by telling the sender to speed up or slow down so that the application never receives more than it
can handle.
Again, unlike UDP, the destination host and port number is not sufficient to identify a recipient
of a TCP connection. There are five distinct elements that make a TCP connection unique:
IP address of the server
IP address of the client
Port number of the server
Port number of the client
Protocol (UDP, TCP/IP, etc...)
Where each requested client socket is assigned a unique port number whereas the server port
number is always the same. If any of these numbers is different, the socket is different. A server
can thus listen to one and only one port, and talk to multiple clients at the same time. So a TCP
connection is more like a telephone connection than a letter; you need to know not only the
phone number (IP address), but since the phone may be shared by many people at that location,
you also need the name of the user you want to talk to at the other end (port number). The
analogy can be taken a little further. If you don't hear what the other person has said, a simple
request ("What?") will prompt the other end to resend or repeat the phrase. And, the connection
remains open until someone hangs up. The following figure illustrates the example of
client/server relationship of the socket APIs for connection-oriented protocol (TCP).

Figure 2.5. Client/server relationship for TCP

2.3 LINUX Socket Programming


A "socket" is a loose term used to describe "an end point for communication." The traditional
Berkley Socket API is a set of C function calls used to support network communication. The
Sockets API is not specific to TCP/IP. Therefore, developing TCP/IP network applications
requires slightly more overhead of programming and understanding to account for the generic
parameters of the library's function calls. Once understood, Socket programming is as easy as
reading and writing to disk files.
Include Files

When writing C or C++ programs that use the socket library go ahead and include all these
header files:

UNIX:

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

#include <fcntl.h>

#include <errno.h>

#include <sys/time.h>

#include <stdlib.h>

#include <memory.h>

Compiling and Linking

To compile and run this program, type


$ gcc hello.c -o hello
$ ./hello
Hello, Linux programming world!
The first command tells gcc to compile and link the source file hello.c, creating an executable,
specified using the -o argument, hello. The second command executes the program, resulting in
the output on the third line.
A lot took place under the hood that you did not see. gcc first ran hello.c through the
preprocessor, cpp, to expand any macros and insert the contents of #included files. Next, it
compiled the preprocessed source code to object code. Finally, the linker, ld, created the hello
binary.
You can re-create these steps manually, stepping through the compilation process. To tell gcc to
stop compilation after preprocessing, use gccs -E option:

$ gcc -E hello.c -o hello.cpp

Examine hello.cpp and you can see the contents of stdio.h have indeed been inserted into the file,
along with other preprocessing tokens. The next step is to compile hello.cpp to object code. Use
gccs -c option to accomplish this:

$ gcc -x cpp-output -c hello.cpp -o hello.o

In this case, you do not need to specify the name of the output file because the compiler creates
an object filename by replacing .c with .o. The -x option tells gcc to begin compilation at the
indicated step, in this case, with pre-processed source code.
2.3.1 Socket Address Structures

From an application programming point of view, the only differences between network protocols
are the address schemes used. Otherwise, operations such as connect, send, receive, and
disconnect are probably the only things a developer has to think about when designing a
network application. For TCP/IP, an ideal API would be one that understood IP addresses and
port numbers. Since the socket library is designed to be used for multiple protocols, addresses
are referenced by a generic structure as follows:
struct sockaddr {

unsigned short sa_family;

char sa_data[14];

};

The sa_family field specifies the type of protocol. For TCP/IP, this field is always set to
AF_INET. The remaining 14 bytes (sa_data) of this structure are always protocol dependent. For
TCP/IP, IP addresses and port numbers are placed in this field. To facilitate operating with these
fields, a specific type of socket address structure is used instead of the one above.

struct sockaddr_in{

short sin_family;

unsigned short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

If it's not already apparent, these structures are compatible with each other. They both are 16
bytes in size. It is also readily seen that the first two bytes of each structure are the family field.
Thus, a struct sockaddr_in can always be cast to a struct sockaddr.

A sockaddr_in structure contains an in_addr structure as a member field. It has the following
form

struct in_addr {

unsigned long s_addr;


};

Browsing the header file reveals that this really isn't the form of the structure. It's really a very
complicated union designed to hold an IP address in a variety of ways. Regardless, the in_addr
struct is exactly 4 bytes long, which is the same size as an IP address. In the sockaddr_in
structure, the sin_port field is a 16-bit unsigned value used to represent a port number. It's
important to remember that these fields always need to be set and interpreted in network byte
order. For example:

struct sockaddr_in sin;

sin.sin_family = AF_INET;

sin.sin_port = htons(9999)

sin.sin_addr.s_addr = inet_addr("128.227.224.3");

In the above code example, the structure sin, holds the IP address, 128.227.224.3, and references
the port number 9999. Two utility functions are used to set these values. The function htons
returns the integer argument passed into it in network byte order. The function inet_addr
converts the string argument from a dotted-quad into a 32-bit integer. Its return value is also in
network byte order.

The structure above could be used to reference a host and application in which a datagram is to
be delivered. The uses of the sockaddr_in structure will be covered in more detail below.

2.3.2 Socket

The socket library call has the following prototype:

int socket(int family, int type, int protocol);


In short, this function creates "an end point for communication". The return value from this
function is a handle to a socket. This number is passed as a parameter to almost all of the other
library calls.

Since the focus of this document is on TCP/IP based sockets, the family parameter should be set
to AF_INET. The type parameter can be either SOCK_STREAM (for TCP), or SOCK_DGRAM
(for UDP). The protocol field is intended for specifying a specific protocol in case the network
model support different types of stream and datagram models. However, TCP/IP only has one
protocol for each, so this field should always be set to 0.

Examples: To create a UDP socket:

int s;

s = socket(AF_INET, SOCK_DGRAM, 0);

To create a TCP socket:

int s;

s = socket(AF_INET, SOCK_STREAM, 0);

bind

Before sending and receiving data with a socket, it must first be associated with a local source
port and a network interface address. The mapping of a socket to a TCP/UDP source port and IP
address is called a "binding". It may be the case where the socket is being used as a server, and
thus must be able to listen for client requests on a specific port. It can also be the case that a
client program doesn't need a specific source port, since all it's concerned about doing is sending
and receiving messages with a specific port on the remote host.

Further complications arise when there are more than one network devices on the host running
the program. So the question of sending through "which network" must be answered as well. The
bind function call is used to declare the mapping between the socket, the TCP/UDP source port,
and the network interface device.

The prototype for bind is as follows:

bind(int socket, struct sockaddr *address, int address_length);

The first argument is a socket handle (the number returned from the socket function call). The
second argument is a socket address structure. With TCP/IP, this is really a sockaddr_in structure.
The sin_port field of the address argument is the local source port number associated with this
socket. That is, for every "send" operation with this socket, the source port field in the TCP/UDP
header gets set with this value. If specifying an exact source port is not required, setting this
value to INADDR_ANY (0) allows the operating system to pick any available port number. The
sin_addr field specifies which network interface device to use. Since most hosts only have one
network interface and only one IP address, this field should be set with the host's own IP address.
However, the socket library provides no immediate way of for a host to determine its own IP
address! However, specifying the value of INADDR_ANY (0) in this field tells the operating
system to pick any available interface and address.

The address of the sockaddr_in structure is passed into the bind call, so that the socket will now
be ready to communicate with remote hosts. The third parameter passed to bind is the length of
the sockaddr_in structure.

Example:

struct sockaddr_in sin;

int s;

s = socket(AF_INET, SOCK_DGRAM, 0);

sin.sin_family = AF_INET;

sin.sin_port = htons(9999);
sin.sin_addr.s_addr = INADDR_ANY;

bind(s, (struct sockaddr *)&sin, sizeof(sin));

/* s is now a usable UDP socket. Source port is 9999 */

It is recommended that the return from bind be checked. Bind will fail by returning -1 if the port
that is being requested for use is already taken. When bind is called on a UDP socket, the socket
is now ready to send and receive datagrams. For TCP sockets, the socket is now ready for the
connect or accept calls.

2.3.3 UDP Sockets

Once a UDP socket has been created and bound to a local source port, it is now capable of being
used for sending and receiving datagrams. The functions for sending and receiving datagrams are
sendto and recvfom. Sendto has the following prototype:

int sendto(int socket, char *buffer, int length, int flags, struct sockaddr *destination_address, int
address_size);

Where socket is a UDP socket that has been created and bound to a source port. buffer is a
pointer to an array of bytes that are to be sent over the network. The length field specifies how
long this array is. The flags field is normally 0.

The destination address is also a sockaddr structure. A sockaddr_in structure can be casted into
this field. Use the sin_addr field to specify the destination IP address and sin_port for the
destination port.

For example:

struct sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_port = htons(12345); // htons for network byte order

sin.sin_addr.s_addr = inet_addr("128.227.22.43");

char *msg = "Hello, World";

sendto(s, msg, strlen(msg)+1, 0, (struct sockaddr *)sin, sizeof(sin));

In the above example, s is assumed to be a created UDP socket that has already bound to a local
port. When sendto is called, a UDP datagram is sent to the host at 128.227.22.43. It's assumed
there is a process with a socket bound to port 12345 waiting on a recvfrom call to receive the
contents of the message being sent. The sendto function returns the number of bytes sent, or -1 if
an error occurred. With UDP sockets, it's not usually necessary to check to see how many bytes
were sent because this information is specified in the length field.

Recvfrom has the following prototype:

int recvfrom(int socket, char *buffer, int length, int flags, struct sockaddr *sender_address, int
*address_size);

Recvfrom is similar to sendto. Buffer is a pointer to a byte array that is to be filled with the
contents of the datagram. The length argument specifies the maximum length to copy into buffer.
This is to prevent buffer over-run errors in case the datagram is larger than expected. The flags
field is normally 0. The sender_address argument is a pointer to a socket address structure that
gets filled with a copy of the sender's IP address and source port. The address_size parameter
must be initialized to the size of the sockaddr structure being used. On return it will hold the
number of bytes that were copied into the sender_address structure.

Recvfrom returns the number of bytes copied into the byte array pointed to by buffer. If the buffer
space specified in length is less than that of the original datagram, only length bytes will be
copied into buffer, and the rest will be lost.

For example:
struct sockaddr_in sin;

char msg[10000];

int ret;

int sin_length;

sin_length = sizeof(sin);

ret = recvfrom(s, msg, 10000, 0, (struct sockaddr *)sin, &sin_length);

printf("%d bytes received from %s (port %d)\n",

ret, inet_ntoa(sin.sin_addr), sin.sin_port);

In the above example, recvfrom will wait until it receives a datagram on the local port associated
with the socket s. The printf statement will list information regarding the size, source IP address,
and source port of the datagram received.

For any open socket that has been successfully binded to a port, the application may call sendto
and recvfrom using that socket as many times as it needs to.

Fragmentation is completely transparent to the applications that are sending and receiving
datagrams.

2.3.4 TCP Sockets

<TO BE ADDED SOMETIME LATER>

connect()

listen() / accept()

send()
recv()

close

When the data transfer session is over, simply call close on the socket as you would a file:

close(s); // s is a created socket

For UDP sockets, this will release the ownership on the local port that is bound to this socket.
For TCP, this will initiate a two-way shutdown between both hosts before giving up port
ownership.

If a TCP socket calls close, any pending or subsequent recv calls by the remote host will result in
recv returning 0 to indicate a connection shutdown on the other end has occurred. Attempting to
call send on a socket that is connected to a host that has called close will result in send returning
-1. Unless it's known a priori that the remote host has only called shutdown, it is recommended
that the application call close on it's socket so that the TCP connection will be properly
terminated on both sides.

shutdown

TCP sockets can also engage in a half-close operation using the shutdown function call. It's
prototype is as follows:

shutdown(int socket, int how);

If the how field is 0, this will disallow further reading (recv) from the socket. If the how field is
1, subsequent writes (send) will be disallowed. The socket will still need to be passed to close.

2.3.5 Relationship between Sockets and File Descriptors

Socket handles are integer values. In UNIX, socket handles can be passed to most of the low-
level POSIX I/O functions. For example:

read(s, buffer, buffer_len);


In the above example, s could be either a socket or file handle. Calling read on an open socket is
equivalent to recv and recvfrom. However, if the socket is UDP, then information about the
sender of the datagram will not be returned. Similarly the write function call is equivalent to
send and sendto. UDP sockets may call connect to use send and write. It's always recommended
that the socket library functions be used instead of the file I/O equivalents.
EXPERIMENT NO. 2

Objective: Write two programs in C : tcpserver and tcpclient to implement TCP/IP protocol
using socket programming in LINUX in which client connects to the server, sends a string say
hello, world, then closes the connection and in turn server listen, accept ,read and print that
string on screen and close the connection.

ALGORITHM: CLIENT
1. Start the program
2. To create a socket in client to server.
3. The client connection accepts to the server and sends a string to server.
4. Close the socket.
5. Stop the program.
ALGORITHM: SERVER
1. Start the program
2. To create a socket in server to client.
3. To print the string sends by the client.
4. Close the socket.
5. Stop the program.
/* tcpserver.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define BUFSIZE 1024


int main()
{
int sock, connected, bytes_recieved , true = 1;
char send_data [1024] , recv_data[1024];

struct sockaddr_in server_addr,client_addr;


int sin_size;

if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {


perror("Socket");
exit(1);
}

if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
perror("Setsockopt");
exit(1);
}

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);

if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))


== -1) {
perror("Unable to bind");
exit(1);
}

if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}

printf("\nTCPServer Waiting for client on port 5000");


fflush(stdout);

while(1)
{

sin_size = sizeof(struct sockaddr_in);

connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);

printf("\n I got a connection from (%s , %d)",


inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));

while (1)
{
printf("\n SEND (q or Q to quit) : ");
gets(send_data);

if (strcmp(send_data , "q") == 0 || strcmp(send_data , "Q") == 0)


{
send(connected, send_data,strlen(send_data), 0);
close(connected);
break;
}

else
send(connected, send_data,strlen(send_data), 0);

bytes_recieved = recv(connected,recv_data,1024,0);

recv_data[bytes_recieved] = '\0';

if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)


{
close(connected);
break;
}

else
printf("\n RECIEVED DATA = %s " , recv_data);
fflush(stdout);
}
}

close(sock);
return 0;
}

/* tcpclient.c */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main()

int sock, bytes_recieved;


char send_data[1024],recv_data[1024];
struct hostent *host;
struct sockaddr_in server_addr;

host = gethostbyname("127.0.0.1");

if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)


{
perror("Socket");
exit(1);
}

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);

if (connect(sock, (struct sockaddr *)&server_addr,


sizeof(struct sockaddr)) == -1)
{
perror("Connect");
exit(1);
}

while(1)
{

bytes_recieved=recv(sock,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';

if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)


{
close(sock);
break;
}

else
printf("\nRecieved data = %s " , recv_data);

printf("\nSEND (q or Q to quit) : ");


gets(send_data);

if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0)


send(sock,send_data,strlen(send_data), 0);

else
{
send(sock,send_data,strlen(send_data), 0);
close(sock);
break;
}

}
return 0;
}
EXPERIMENT NO.3

Objective: Write two programs in C : udperver and udpclient to implement UDP protocol
using socket programming in LINUX in which client connects to the server, sends a string say
hello, world, then closes the connection and in turn server listen, accept ,read and print that
string on screen and close the connection.
ALGORITHM: CLIENT
1. The client establishes a connection to the server.
2. The client accept the connection and to send the data from client to server and vice versa
3. The client communicate the server to send the end of the message
4. Stop the program.
ALGORITHM: SERVER
1. The server establishes a connection to the client.
2. The server accept the connection and to send the data from server to client and vice versa
3. The server communicate the client to send the end of the message
4. Stop the program.

/*
* udpclient.c - A simple UDP client
* usage: udpclient <host> <port>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define BUFSIZE 1024


/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(0);
}

int main(int argc, char **argv) {


int sockfd, portno, n;
int serverlen;
struct sockaddr_in serveraddr;
struct hostent *server;
char *hostname;
char buf[BUFSIZE];

/* check command line arguments */


if (argc != 3) {
fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);

/* socket: create the socket */


sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");

/* gethostbyname: get the server's DNS entry */


server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
exit(0);
}

/* build the server's Internet address */


bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);

/* get a message from the user */


bzero(buf, BUFSIZE);
printf("Please enter msg: ");
fgets(buf, BUFSIZE, stdin);

/* send the message to the server */


serverlen = sizeof(serveraddr);
n = sendto(sockfd, buf, strlen(buf), 0, &serveraddr, serverlen);
if (n < 0)
error("ERROR in sendto");

/* print the server's reply */


n = recvfrom(sockfd, buf, strlen(buf), 0, &serveraddr, &serverlen);
if (n < 0)
error("ERROR in recvfrom");
printf("Echo from server: %s", buf);
return 0;
}
/*
* udpserver.c - A simple UDP echo server
* usage: udpserver <port>
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFSIZE 1024

/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}

int main(int argc, char **argv) {


int sockfd; /* socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client's address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
struct hostent *hostp; /* client host info */
char buf[BUFSIZE]; /* message buf */
char *hostaddrp; /* dotted decimal host addr string */
int optval; /* flag value for setsockopt */
int n; /* message byte size */

/*
* check command line arguments
*/
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);

/*
* socket: create the parent socket
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");

/* setsockopt: Handy debugging trick that lets


* us rerun the server immediately after we kill it;
* otherwise we have to wait about 20 secs.
* Eliminates "ERROR on binding: Address already in use" error.
*/
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* build the server's Internet address
*/
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)portno);

/*
* bind: associate the parent socket with a port
*/
if (bind(sockfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");

/*
* main loop: wait for a datagram, then echo it
*/
clientlen = sizeof(clientaddr);
while (1) {

/*
* recvfrom: receive a UDP datagram from a client
*/
bzero(buf, BUFSIZE);
n = recvfrom(sockfd, buf, BUFSIZE, 0,
(struct sockaddr *) &clientaddr, &clientlen);
if (n < 0)
error("ERROR in recvfrom");
/*
* gethostbyaddr: determine who sent the datagram
*/
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
printf("server received datagram from %s (%s)\n",
hostp->h_name, hostaddrp);
printf("server received %d/%d bytes: %s\n", strlen(buf), n, buf);

/*
* sendto: echo the input back to the client
*/
n = sendto(sockfd, buf, strlen(buf), 0,
(struct sockaddr *) &clientaddr, clientlen);
if (n < 0)
error("ERROR in sendto");
}
}
EXPERIMENT-4
Objective: Simulate DSDV-destination sequenced distance vector routing algorithm.
ALGORITHM:

Step 1: Start the program.

Step 2: Include the necessary header files.

Step 3: Enter the number of vertices.

Step 4: Get the distance table as input.

Step 5: Calculate the cost of direct and indirect path from source to destination.

Step 6: Compare the cost of all path.

Step 7: Display the minimum cost of all path.

Step 8: Print out with the necessary details.

Step 9: Stop the program.

SOURCE CODE:
#include<stdio.h>
#include<string.h>
int main()
{
int count,src_router,i,j,k,w,v,min;
int cost_matrix[100][100],dist[100],last[100];
int flag[100];
printf("\nENTER THE NO OF ROUTERS:");
scanf("%d",&count);
printf("\nENTER THE COST MATRIX VALUES:");
for(i=0;i<count;i++)
{
for(j=0;j<count;j++)
{
printf("\n%d->%d:",i,j);
scanf("%d",&cost_matrix[i][j]);
if(cost_matrix[i][j]<0)
cost_matrix[i][j]=1000;
}
}
printf("\nENTER THE SOURCE ROUTER:");
scanf("%d",&src_router);
for(v=0;v<count;v++)
{
flag[v]=0;
last[v]=src_router;
dist[v]=cost_matrix[src_router][v];
}
flag[src_router]=1;
for(i=0;i<count;i++)
{
min=1000;
for(w=0;w<count;w++)
{
if(!flag[w])
if(dist[w]<min)
{
v=w;
min=dist[w];
}
}
flag[v]=1;
for(w=0;w<count;w++)
{if(!flag[w])
if((min+cost_matrix[v][w])<dist[w])
{
dist[w]=min+cost_matrix[v][w];
last[w]=v;
}
}
}
for(i=0;i<count;i++)
{
printf("\n%d==>%d:PATH TAKEN:%d",src_router,i,i);
w=i;
while(w!=src_router)
{
printf("\n<--%d",last[w]);
w=last[w];
}
printf("\nSHORTEST PATH COST:%d",dist[i]);
}
extern int getch(void);
}

OUTPUT:

ENTER THE NO OF ROUTERS:3


ENTER THE COST MATRIX VALUES:
0->0:100
0->1:1
0->2:1
1->0:3
1->1:100
1->2:1
2->0:1
2->1:1
2->2:100
ENTER THE SOURCE ROUTER:1
1==>0:PATH TAKEN:0
<--2
<--1
SHORTEST PATH COST:2
1==>1:PATH TAKEN:1
SHORTEST PATH COST:100
1==>2:PATH TAKEN:2
Jm <--1
SHORTEST PATH COST:1
EXPERIMENT-5
Objective: Write two programs in C: tcperver and tcpclient using TCP/IP protocol using
socket programming in LINUX to estimate the round trip time from client to server and
implement the server as concurrent server

ALGORITHM:
1. Start the program
2 To create a socket in client to server.
3. 3he client establishes a connection to the server.
4. The client accepts the connection and sends data to server and the server to replay the echo
message to the client and estimate the round trip time.
5. The client communicate the server to send the end of the message
6. Stop the program.

Server Program:
/************************************
* RTT *
************************************/
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#define MYPORT 3490


#define SIZE_TO_SEND 1000
#define MY_IP "127.0.0.1"

int main(int argc, char *argv[]) {


int sockfd,sockfd2;
char tosend = 's'; //a char (1byte) to send to receivers
char ack;
struct sockaddr_in my_addr,rcvr_addr;
struct timeval start,end;
int sin_size = sizeof(my_addr),i,k,num_packet_sent,optval;
double t1,t2;

//open TCP socket,bind and accept RECEIVERS connections


if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) ==-1){
perror("socket error");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = inet_addr(MY_IP);
memset(my_addr.sin_zero, '\0', sizeof(my_addr.sin_zero));
//allow reuse of port
optval = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//bind(socketfd, struct about my address,sizeofmy address);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1) {
perror("bind");
exit(1);
}
listen(sockfd,10);

sockfd2 = accept(sockfd, (struct sockaddr *)&rcvr_addr, &sin_size);

//connections OK
//send 100 packet of size 1 byte and for each send wait for ack
t1=0.0; t2=0.0;
printf("Sending 100 messages 1 byte each and wait for ack.\n");
for(num_packet_sent=0;num_packet_sent<100;num_packet_sent++){
if(gettimeofday(&start,NULL)) {
printf("time failed\n");
exit(1);
}
send(sockfd2,&tosend,sizeof(char),0);
optval=recv(sockfd2,&ack,sizeof(char),0);
if(optval==-1) {
perror("Receive error");
exit(1);
}
else{
if(gettimeofday(&end,NULL)) {
printf("time failed\n");
exit(1);
}
t1+=start.tv_sec+(start.tv_usec/1000000.0);
t2+=end.tv_sec+(end.tv_usec/1000000.0);
}
}
//calculate and print mean rtt
printf("RTT = %g ms\n",(t2-t1)/100);
printf("close sockets and exit\n");
shutdown(sockfd2,2);
shutdown(sockfd,2);
exit(0);
}
Client Program:
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>

#define SENDER_PORT 3490


#define SENDER_IP "127.0.0.1"

int main(int argc, char *argv[]) {

int sockfd;
int rcv_num,loop_count,i;
char buf;
struct sockaddr_in sender_addr;

//open socket and connect


if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) ==-1){
perror("socket error"); // do some error checking!
exit(1);
}

sender_addr.sin_family = AF_INET;
sender_addr.sin_port = htons(SENDER_PORT);
sender_addr.sin_addr.s_addr = inet_addr(SENDER_IP);
memset(sender_addr.sin_zero, '\0', sizeof(sender_addr.sin_zero));

if ((connect(sockfd,(struct sockaddr *)&sender_addr,sizeof(sender_addr))) ==-1){


perror("connect error"); // do some error checking!
exit(1);
}
//connection established
printf("Connection to sender established\n");
//reads 100 packets of 1 byte and sends them back as ack packets
printf("Receive 100 packets of 1 byte and send then back\n");
for(i=0;i<100;i++){
rcv_num = recv(sockfd,&buf,sizeof(char),0);
if(rcv_num!=0) {
//send ack
send(sockfd,&buf,sizeof(char),0);
}
else{
perror("Receive error");
exit(1);
}
}
printf("\tDone\nClose socket and exit\n");
close(sockfd);
exit(0);
}
EXPERIMENT-6

Objective: Write a program in C which acts like a simple multi-user chat server to exhibit
multiplexed I/O operations.
ALGORITHM: SERVER
1. Start the program
2. To create a socket in server to client
3. The server establishes a connection to the client.
4. The server accept the connection and to send the data from server to client and vice versa
5. The server communicate the client to send the end of the message
6. Stop the program.

Server Program:
/*******select.c*********/
/*******Using select() for I/O multiplexing*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* port we're listening on */
#define PORT 2020
int main(int argc, char *argv[])
{
/* master file descriptor list */
fd_set master;
/* temp file descriptor list for select() */
fd_set read_fds;
/* server address */
struct sockaddr_in serveraddr;
/* client address */
struct sockaddr_in clientaddr;
/* maximum file descriptor number */
int fdmax;
/* listening socket descriptor */
int listener;
/* newly accept()ed socket descriptor */
int newfd;
/* buffer for client data */
char buf[1024];
int nbytes;
/* for setsockopt() SO_REUSEADDR, below */
int yes = 1;
int addrlen;
int i, j;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* get the listener */
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
/*just exit lol!*/
exit(1);
}
printf("Server-socket() is OK...\n");
/*"address already in use" error message */
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");
/* bind */
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
/* listen */
if(listen(listener, 10) == -1)
{
perror("Server-listen() error lol!");
exit(1);
}
printf("Server-listen() is OK...\n");
/* add the listener to the master set */
FD_SET(listener, &master);
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one*/
/* loop */
for(;;)
{
/* copy it */
read_fds = master;
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("Server-select() error lol!");
exit(1);
}
printf("Server-select() is OK...\n");
/*run through the existing connections looking for data to be read*/
for(i = 0; i <= fdmax; i++)
{
if(FD_ISSET(i, &read_fds))
{ /* we got one... */
if(i == listener)
{
/* handle new connections */
addrlen = sizeof(clientaddr);
if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
{
perror("Server-accept() error lol!");
}
else
{
printf("Server-accept() is OK...\n");
FD_SET(newfd, &master); /* add to master set */
if(newfd > fdmax)
{ /* keep track of the maximum */
fdmax = newfd;
}
printf("%s: New connection from %s on socket %d\n", argv[0], inet_ntoa(clientaddr.sin_addr),
newfd);
}}
else
{
/* handle data from a client */
if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
{
/* got error or connection closed by client */
if(nbytes == 0)
/* connection closed */
printf("%s: socket %d hung up\n", argv[0], i);
else
perror("recv() error lol!");
/* close it... */
close(i);
/* remove from master set */
FD_CLR(i, &master);
}
else
{
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++)
{
/* send to everyone! */
if(FD_ISSET(j, &master))
{
/*except the listener and ourselves */
if(j != listener && j != i)
{
if(send(j, buf, nbytes, 0) == -1)
perror("send() error lol!");
}}}}
}}}}
return 0;}
OUTPUT:-