Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
9 views43 pages

Compnet Labsheets Merged

This document outlines a lab exercise on packet sniffing using Wireshark and measuring packet delay with Traceroute, emphasizing hands-on learning without external resources. It details how to use Wireshark to capture and analyze network packets, including HTTP messages, and provides instructions for conducting experiments to observe network behavior. Additionally, it explains the functionality of the Traceroute program for identifying the path of IP datagrams across networks.

Uploaded by

aryan1iitdelhi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views43 pages

Compnet Labsheets Merged

This document outlines a lab exercise on packet sniffing using Wireshark and measuring packet delay with Traceroute, emphasizing hands-on learning without external resources. It details how to use Wireshark to capture and analyze network packets, including HTTP messages, and provides instructions for conducting experiments to observe network behavior. Additionally, it explains the functionality of the Traceroute program for identifying the path of IP datagrams across networks.

Uploaded by

aryan1iitdelhi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

COMPUTER NETWORKS (CS F303)

LAB-SHEET – 1
Topic: Packet Sniffing using Wireshark and Packet Delay Measurement using Traceroute

Objectives
● This is an exercise in learning by doing and thinking.
● Do NOT consult a book or a website or a senior – if you do so, you are not learning.
● However, you are encouraged to consult/discuss/argue with other students in your class.
● Some of the material is taken up from Wikipedia and the Wireshark labs which come along with
your textbook, i.e. Computer Networking: A Top Down Approach by Kurose and Ross.

One’s understanding of network protocols can often be greatly deepened by “seeing protocols in action”
and by “playing around with protocols” – observing the sequence of messages exchanged between two
protocol entities, delving down into the details of protocol operation, and causing protocols to perform
certain actions and then observing these actions and their consequences. This can be done in simulated
scenarios or in a “real” network environment such as the Internet.

In the Wireshark labs you’ll be doing in this course, you’ll be running various network applications in
different scenarios using your own computer. You’ll observe the network protocols in your computer “in
action,” interacting and exchanging messages with protocol entities executing elsewhere in the Internet.
Thus, you and your computer will be an integral part of these “live” labs. You’ll observe, and you’ll learn,
by doing. The basic tool for observing the messages exchanged between executing protocol entities is called
a packet sniffer. As the name suggests, a packet sniffer captures (“sniffs”) messages being sent/received
from/by your computer; it will also typically store and/or display the contents of the various protocol fields
in these captured messages.

A packet sniffer itself is passive. It observes messages being sent and received by applications and protocols
running on your computer, but never sends packets itself. Similarly, received packets are never explicitly
addressed to the packet sniffer. Instead, a packet sniffer receives a copy of packets that are sent/received
from/by application and protocols executing on your machine.

Figure 1 shows the structure of a packet sniffer. At the right of Figure 1 are the protocols (in this case,
Internet protocols) and applications (such as a web browser or ftp client) that normally run on your
computer. The packet sniffer, shown within the dashed rectangle in Figure 1 is an addition to the usual
software in your computer, and consists of two parts.

1|Page
The packet capture library receives a copy of every link-layer frame that is sent from or received by your
computer. You know that that messages exchanged by higher layer protocols such as HTTP, FTP, TCP,
UDP, DNS, or IP all are eventually encapsulated in link-layer frames that are transmitted over physical
media such as an Ethernet cable. In Figure 1, the assumed physical media is an Ethernet, and so all upper-
layer protocols are eventually encapsulated within an Ethernet frame. Capturing all link-layer frames thus
gives you all messages sent/received from/by all protocols and applications executing in your computer.

packet sniffer

packet application (e.g., www


application
analyzer browser, ftp client)

operating
system Transport (TCP/UDP)
packet Network (IP)
capture copy of all Ethernet
frames sent/received
Link (Ethernet)
(pcap)
Physical

to/from network to/from network


Figure 1: Packet sniffer structure

The second component of a packet sniffer is the packet analyzer, which displays the contents of all fields
within a protocol message. In order to do so, the packet analyzer must “understand” the structure of all
messages exchanged by protocols. For example, suppose we are interested in displaying the various fields
in messages exchanged by the HTTP protocol in Figure 1.

The packet analyzer understands the format of Ethernet frames, and so can identify the IP datagram within
an Ethernet frame. It also understands the IP datagram format, so that it can extract the TCP segment (as
HTTP uses TCP as underlying transport layer protocol) within the IP datagram. Finally, it understands the
TCP segment structure, so it can extract the HTTP message contained in the TCP segment. Finally, it
understands the HTTP protocol.

There are many packet sniffers available, for example Wireshark packet sniffer, Ethereal Network
Analyzer, Snoop Analyzer Standard, Network Probe, etc. We will be using the Wireshark packet sniffer
[https://www.wireshark.org/] for these labs, allowing us to display the contents of messages being
sent/received from/by protocols at different levels of the protocol stack. (Technically speaking, Wireshark
is a packet analyzer that uses a packet capture library in your computer).

Wireshark is a free network protocol analyzer that runs on Windows, Linux/Unix, and Mac computers. It
operates in computers using Ethernet, serial (PPP and SLIP), 802.11 wireless LANs, and many other link-
layer technologies (if the OS on which it's running allows Wireshark to do so).

2|Page
Running Wireshark

When you run the Wireshark program, you’ll get a startup screen, as shown in Figure-2:

Figure-2: Start up screen of Wireshark.

Take a look at the screen – you’ll see an “Interface list”. This is the list of network interfaces on your
computer. Once you choose an interface, Wireshark will capture all packets on that interface. In the
example above, there is an Ethernet interface (Gigabit network Connection) along with some other. Use is
for this lab.

Click on “Ethernet” interface to start packet capture (i.e., for Wireshark to begin capturing all packets being
sent to/from that interface), a screen like the one shown in Figure-3 will be displayed, showing information
about the packets being captured. Once you start packet capture, you can stop it by using the Capture pull
down menu and selecting Stop.

3|Page
command
menus

display filter
specification

listing of
captured
packets

details of
selected
packet
header

packet content
in hexadecimal
and ASCII

Figure 3: Wireshark Graphical User Interface, during packet capture and analysis

The Wireshark interface has five major components:

● The command menus are standard pulldown menus located at the top of the window. Of interest
to us now are the File and Capture menus. The File menu allows you to save captured packet data
or open a file containing previously captured packet data, and exit the Wireshark application. The
Capture menu allows you to begin packet capture.

● The packet-listing window displays a one-line summary for each packet captured, including the
packet number (assigned by Wireshark; this is not a packet number contained in any protocol’s
header), the time at which the packet was captured, the packet’s source and destination addresses,
the protocol type, and protocol-specific information contained in the packet. The packet listing can
be sorted according to any of these categories by clicking on a column name. The protocol type
field lists the highest-level protocol that sent or received this packet, i.e., the protocol that is the
source or ultimate sink for this packet.

● The packet-header details window provides details about the packet selected (highlighted) in the
packet-listing window. (To select a packet in the packet-listing window, place the cursor over the
packet’s one-line summary in the packet-listing window and click with the left mouse button.).
These details include information about the Ethernet frame (assuming the packet was sent/received
over an Ethernet interface) and IP datagram that contains this packet. The amount of Ethernet and
IP-layer detail displayed can be expanded or minimized by clicking on the plus minus boxes to the
left of the Ethernet frame or IP datagram line in the packet details window. If the packet has been
carried over TCP or UDP, TCP or UDP details will also be displayed, which can similarly be

4|Page
expanded or minimized. Finally, details about the highest-level protocol that sent or received this
packet are also provided.

● The packet-contents window displays the entire contents of the captured frame, in both ASCII
and hexadecimal format.

Towards the top of the Wireshark graphical user interface, is the packet display filter field, into which a
protocol name or other information can be entered in order to filter the information displayed in the packet-
listing window (and hence the packet-header and packet-contents windows). In the example below, we’ll
use the packet-display filter field to have Wireshark hide (not display) packets except those that correspond
to HTTP messages.

Taking Wireshark for a Test Run


Experiment-1

The best way to learn about any new piece of software is to try it out! Do the following

1. Start up your favorite web browser.

2. Start up the Wireshark software. You will initially see a window similar to that shown in Figure 2.
Wireshark has not yet begun capturing packets. Select the desired network interface. Packet capture
will now begin - Wireshark is now capturing all packets being sent/received from/by your
computer!

3. Once you begin packet capture, a window similar to that shown in Figure 3 will appear. This
window shows the packets being captured. By selecting Capture pulldown menu and selecting
Stop, you can stop packet capture. But don’t stop packet capture yet. Let’s capture some
interesting packets first. To do so, we’ll need to generate some network traffic. Let’s do so using
a web browser, which will use the HTTP protocol.

4. While Wireshark is running, enter the URL: http://demo.testfire.net/login.jsp


and have that page displayed in your browser. In order to display this page, your browser will
contact the HTTP server and exchange HTTP messages with the server in order to download this
page. The Ethernet frames containing these HTTP messages (as well as all other frames passing
through your Ethernet adapter) will be captured by Wireshark.
5. After your browser has displayed the login.jsp page, stop Wireshark packet capture by selecting
stop in the Wireshark capture window. The main Wireshark window should now look similar to
Figure 3. You now have live packet data that contains all protocol messages exchanged between
your computer and other network entities! The HTTP message exchanges with the web server
should appear somewhere in the listing of packets captured. But there will be many other types of
packets displayed as well (see, e.g., the many different protocol types shown in the Protocol column
in Figure 3). Even though the only action you took was to download a web page, there were
evidently many other protocols running on your computer that are unseen by the user. We’ll learn
much more about these protocols as we progress through the text! For now, you should just be
aware that there is often much more going on than “meets the eye”!

6. Type in “http” (without the quotes, and in lower case – all protocol names are in lower case in
Wireshark) into the display filter specification window at the top of the main Wireshark window.
Then select Apply (to the right of where you entered “http”). This will cause only HTTP message
to be displayed in the packet-listing window.

5|Page
7. Find the HTTP GET message that was sent from your computer to the webserver. When you select
the HTTP GET message, the Ethernet frame, IP datagram, TCP segment, and HTTP message
header information will be displayed in the packet-header window. Recall that the HTTP GET
message that is sent to the testfire web server is contained within a TCP segment, which is contained
(encapsulated) in an IP datagram, which is encapsulated in an Ethernet frame. By clicking on ‘+’
and ‘-‘ right-pointing and down-pointing arrowheads to the left side of the packet details window,
minimize the amount of Frame, Ethernet, Internet Protocol, and Transmission Control Protocol
information displayed. Maximize the amount information displayed about the HTTP protocol.
Your Wireshark display should now look roughly as shown in Figure 4. (Note, in particular, the
minimized amount of protocol information for all protocols except HTTP, and the maximized
amount of protocol information for HTTP in the packet-header window).

Figure-4: GET message details

8. Save the packet capture and Exit Wireshark

6|Page
Now try to answer these questions:
1. What does \r\n mean after each line?
2. What indicates the end of HTTP message?
3. What is the version of HTTP used? Is it necessary to pass it in message? Why?
4. What type of connection it is: persistent or non-persistent?
5. What is the source IP address and destination IP address?
6. Which Transport layer protocol does HTTP use?
7. What is the source and destination port number?
8. How long did it take from when the HTTP GETT message was sent until HTTP OK reply was
received?
9. What is the difference between date header and Last-modified header in HTTP OK reply?
10. Although URL specifies the host, why do you think that it is again the part of HTTP GET message?
11. Does HTTP work on specific port? How can it be verified from GET and OK messages?
12. You can see a line “Response in Frame: some_number”. What does it mean? Verify your answer.
Experiment-2

1. Clear browsing history. You can do it using tools menu of your Brower.
2. Start Wireshark and apply filter “http” (without quotes) as we are interested in http packets.
3. Type the following URL in your web browser and press enter:
4. http://demo.testfire.net/login.jsp
5. Stop capturing packets and observe different HTTP packets. Observe that there are two embedded
images in the web page.
Q1. How many HTTP GET requests are generated?
Q2. What can be concluded from your answer of Q1 above?
Q3. What is the status code returned in all HTTP response packets?
Q4. When were the objects embedded in web page last modified at the server?
Q5. How many bytes of content are being returned to your browser in each HTTP response
packet?
6. Now, start Wireshark packet capture again and refresh the webpage, i.e., enter URL:
http://demo.testfire.net/login.jsp
Stop capturing packets and observe different HTTP packets again.
Q1. What is the date header value and Last Modified value in HTTP response packets?
Q2. Are two embedded images fetched from the server or were locally cached? How to verify
your answer? Justify the answer to yourself.
In all the above experiments see whether response from the server was in one single packet or multiple
packets. You will have to observe TCP packets for it in each case.

7|Page
Part 2: Traceroute Program- A handy debugging tool for network administrators

The Traceroute program, written by Van. It lets us see the route that IP datagrams follow from one host to
another.

Although there are no guarantees that two consecutive IP datagrams from the same source to the same
destination follow the same route, most of the time they do.

Traceroute uses ICMP (don’t worry if you do not understand the ICMP protocols at this point in time) and
the TTL field in the IP header. The TTL field (time-to-live) is an 8-bit field that the sender initializes to
some value. The sender initializes to some value. Each router that handles the packet (datagram) is required
to decrement the TTL by either one. The purpose of the TTL field is to prevent datagrams from ending up
in infinite loops, which can occur during routing transients.

When a router gets an IP datagram, whose TTL is either 0 or 1 it must not forward the datagram. (A
destination host that receives a datagram like this can deliver it to the application, since the datagram does
not have to be routed. Normally, however, no system should receive a datagram with a TTL of 0.) Instead
the router throws away the datagram and sends back to the originating host an ICMP "time exceeded"
message. The key to Traceroute is that the IP datagram containing this ICMP message has the
router's IP address as the source address.

We can now guess the operation of Traceroute. It sends an IP datagram with a TTL of 1 to the destination
host. The first router to handle the datagram decrements the TTL, discards the datagram, and sends back
the ICMP time exceeded. This identifies the first router in the path. Traceroute then sends a datagram with
a TTL of 2, and we find the IP address of the second router. This continues until the datagram reaches the
destination host. But even though the arriving IP datagram has a TTL of 1, the destination host won't throw
it away and generate the ICMP time exceeded, since the datagram has reached its final destination. How
can we determine when we've reached the destination?

Traceroute sends UDP datagrams to the destination host, but it chooses the destination UDP port number
to be an unlikely value (larger than 30,000), making it improbable that an application at the destination is
using that port. This causes the destination host's UDP module to generate an ICMP "port unreachable"
error when the datagram arrives. All Traceroute needs to do is differentiate between the received ICMP
messages-time exceeded versus port unreachable-to know when it's done.

8|Page
We are now ready to run traceroute and see the output. To perform the experiment, We'll use a Traceroute
available online at the website https://www.ultratools.com/tools/traceRoute or you can visit to
http://www.traceroute.org/ and choose a traceroute service.

Following is the output we got when, we performed the traceroute for “google.com”. You can directory
write the domain name (like google.com) or the IP address of that domain to run the Traceroute program.

traceroute to 172.217.23.238 (172.217.23.238), 30 hops max, 60 byte packets


1 praha-4d-c1-vl55.masterinter.net (77.93.199.253) 3.650 ms 3.718 ms 3.838 ms
2 vl1387.cr3.r1-8.dc1.4d.prg.masterinter.net (83.167.254.150) 0.148 ms 0.357 ms 0.366 ms
3 72.14.214.168 (72.14.214.168) 0.387 ms 0.376 ms 0.375 ms
4 108.170.245.49 (108.170.245.49) 0.285 ms 0.295 ms 108.170.245.33 (108.170.245.33) 0.274 ms
5 108.170.238.155 (108.170.238.155) 0.365 ms 108.170.238.157 (108.170.238.157) 0.337 ms
108.170.238.155 (108.170.238.155) 0.313 ms
6 prg03s06-in-f14.1e100.net (172.217.23.238) 0.192 ms 0.185 ms 0.235 ms

Lab Exercise-6: Once you run the Traceroute from your computer, the output received by you may not be
exactly same as above. (Note: It is suggested that you try it yourself.)
Now try to answer the following.
1. Explain the meaning of first line of the output.
2. The next two lines in the output begin with the TTL, followed by the name of the host or router its
IP address and three different time values. What these time values signifies?
3. How we can calculate the per hop time value?

Repeat the above experiment for the BITS Pilani web site and iitd.ac.in and observe the output

Lab Exercise-7:
Answer the following:

1. Did you observe the character * in few lines of the output for any of the trace route? If yes, then
what does it mean?
2. Did you see the last hop in your output as the destination you are looking for? If no, then what
could be the reason for this?
*****

9|Page
Department of Computer Science & Information Systemsfessor,

COMPUTER NETWORKS (CS F303)


LAB-SHEET – 2
Topic: Learning FTP and DNS using Wireshark

Objectives:
● To learn the working of FTP protocol using Wireshark
● To understand use and working of DNS protocol.
-------------------------------------------------------------------------------------------------------------------------------
This lab is divided into three parts.
In part one, we will continue doing the experiments with Wireshark to analyze and understand various
application layers’ protocols. In this lab our focus would be on another very important application layer
protocol called File Transfer Protocol.
In the second part of the lab, we will try to understand the working principles of domain name system with
the help of Wireshark capture and useful networking command called “nslookup”.
Finally, in the third part, we will learn another useful networking tool called traceroute, which is very much
required by any networking professional to manage the network and also to troubleshoot the problems
during the time when the network is down or some site is not accessible.
Part 1: Understanding the functioning of File Transfer Protocol (FTP) using Wireshark

FTP: File Transfer Protocol


FTP is a commonly used application over the Internet for file transfer. The file transfer provided by FTP
copies a complete file from one system to another system. To use FTP, we need an account to login on the
FTP server.

Figure 1, shows the arrangement of the client and server and the two connections between them.

Fig. 1

1 | Page
Department of Computer Science & Information Systemsfessor,

FTP Commands
The commands and replies sent across the control connection between the client and server are in NVT
ASCII (7 bit ASCII). This requires a CR (carriage return), LF (line feed) pair at the end of each line (i.e.,
each command or each reply). The commands are 3 or 4 bytes of uppercase ASCII characters, some with
optional arguments. More than 30 different FTP commands can be sent by the client to the server. Table
below shows some of the commonly used commands.

Command Description
ABOR abort previous FTP command and any data
transfer
LIST filelist list files or directories
PASS password password on server
PORT n1,n2,n3,n4,n5,n6 client IP address (nl.n2.n3.n4) and port (n5 x 256
+ n6)
QUIT logoff from server
RETR filename retrieve (get) a file
STOP filename store (put) a file

You will find that sometimes there is a one-to-one correspondence between what the user types and the
FTP command sent across the control connection, but for some operations a single user command (what
you type in the terminal) results in multiple FTP commands across the control connection.

The FTP server sends file listings back across the data connection, rather than as multiline replies across
the control connection. Unlike control connection which stays up for the duration of the client-server
connection, the data connection can come and go, as required.

The usual procedure is as follows:

1. The creation of the data connection is under control of the client, because it's the client that issues
the command that requires the data connection (get a file, put a file, or list a directory).
2. The client normally chooses an ephemeral port number on the client host for its end of the data
connection. The client issues a passive open from this port or starts listening on this port
3. The client sends this port number to the server across the control connection using the PORT
command.
4. The server receives the port number on the control connection, and issues an active open (try to
connect) to that port on the client host. The server's end of the data connection always uses port
20.

Lab Exercise-1: An Interactive FTP Session

1. To start an FTP interactive session type "ftp" from a DOS Command window.

C:\> ftp

The DOS prompt should be replaced with the FTP prompt. The FTP program is now running on the local
system. A connection (or session) to a remote system has not been established.

2 | Page
Department of Computer Science & Information Systemsfessor,

2. The help command or ? (question mark) may be executed without being attached to a remote system
and will do a print (usually to the screen) of the FTP commands. The following is an example of an
FTP Command to display the FTP Help information.

ftp> help

3. The following FTP Command will perform the FTP OPEN (make the connection) and display the
following messages.

ftp> open ftp.bits-pilani.ac.in


Username: csis, Password: csis

4. The following FTP Command will copy a file from the local system to the remote system and display
the information.

ftp> put C:\Users\Dell\Documents\readme.txt (This file could be anything from your local computer)

ftp> quit

Lab Exercise-2: Understanding FTP protocol details using Wireshark

Identify TCP Header Fields and Operation Using a Wireshark FTP Session Capture

Step 1: Start a Wireshark capture.

a) Close all unnecessary network traffic, such as the web browser, to limit the amount of traffic
during the Wireshark capture.
b) Start the Wireshark capture.

Step 2: Log on to the FTP server

a) From the command prompt, enter ftp ftp.bits-pilani.ac.in


b) Enter Username: csis
c) Enter Password: csis

Step 3: Locate and download the readme.txt file from the server.

Step 4: ftp quit

Step 5: Stop the Wireshark capture.

Step 6: View the Wireshark Main Window.

Wireshark would have captured many packets during the FTP session. To limit the amount of data for
analysis, type tcp and ip.addr = = 172.22.1.29 in the Filter: entry area and click Apply. The IP address,
172.22.1.29, is the address for our FTP server.

3 | Page
Department of Computer Science & Information Systemsfessor,

Analyze the TCP header fields:

After the TCP filter has been applied, the first three frames in the packet list pane (top section) displays the
transport layer protocol TCP creating a reliable session. The sequence of [SYN], [SYN, ACK], and [ACK]
illustrates the three-way handshake. (Let us not get into details of SYN, SYN, ACK…., we will learn about
them in due course of time!!!)

TCP is routinely used during a session to control datagram delivery, verify datagram arrival, and manage
window size. For each data exchange between the FTP client and FTP server, a new TCP session is started.
At the conclusion of the data transfer, the TCP session is closed. Finally, when the FTP session is finished,
TCP performs an orderly shutdown and termination.

In Wireshark, detailed TCP information is available in the packet details pane (middle section).

Highlight the first TCP datagram from the host computer, and expand the record.

Lab Exercise-3: Understand the working of FTP

Answer the following questions.


1. Did you see an OPTS request going from client to server? What is the purpose of this command?
2. Locate the PORT command in the Wireshark trace and try to correlate it with the command entered by
you in the ftp terminal. Analyze the parameters of PORT command.
3. How the server is able to send PORT command successful, even when the three-way handshake
required to complete the TCP connection that got initiated due to PORT command has not been
completed.
4. The FTP server sends file listings back across the data connection, rather than as multiline replies across
the control connection. Try to verify this fact by listing the remote directory using “dir” command and
analyzing the Wireshark packet capture.

4 | Page
Department of Computer Science & Information Systemsfessor,

Part 2: Understanding the functioning of Domain Name System DNS Protocol using
Wireshark and nslookup command.

DOMAIN NAME SERVICE (DNS)

The Domain Name System (DNS) is a hierarchical decentralized naming system for computers, services,
or other resources connected to the Internet or a private network. It associates various information with
domain names assigned to each of the participating entities. Most prominently, it translates more readily
memorized domain names to the numerical IP addresses needed for locating and identifying computer
services and devices with the underlying network protocols. By providing a worldwide, distributed
directory service, the Domain Name System is an essential component of the functionality on the Internet
that has been in use since 1985.

The Domain Name System also specifies the technical functionality of the database service that is at its
core. It defines the DNS protocol, a detailed specification of the data structures and data communication
exchanges used in the DNS, as part of the Internet Protocol Suite. Historically, other directory services
preceding DNS were not scalable to large or global directories as they were originally based on text files,
prominently the hosts file.A DNS name server is a server that stores the DNS records for a domain; a DNS
name server responds with answers to queries against its database.

The most common types of records stored in the DNS database are for Start of Authority (SOA), IP
addresses (A and AAAA), SMTP mail exchangers (MX), name servers (NS), pointers for reverse DNS
lookups (PTR), and domain name aliases (CNAME).

In this experiment you will sniff DNS packets.

Experiment 4

1. Clear Browsing history.


2. Start Wireshark and type filter name “dns” to see DNS packets.
3. Start browser and type URL:
https://icms.bits-pilani.ac.in/lab-1-webpages/lab1_second_page.htm
4. Understand that the first task to be done by your system is to get IP address corresponding to the
server. See if there is any DNS packet shown in Wireshark to resolve server hostname. Chances
are that no DNS packet is shown in Wirehasrk. WHY ?? Think before reading ahead.
5. Probably you must have thought that DNS resource records are cached locally and clearing
browsing history does not clear DNS records. You were right! So, now follow the following steps.
6. Open command prompt (or terminal) and type
C:\ ipconfig/displaydns
You will see all the cached DNS resource records. Now you need to clear all this. So type
C:\ ipconfig/flushdns
7. Now, repeat steps 2 to 4 above and observe DNS packets exchanged. Answer the following
questions with respect to DNS query message:
Q1. Which transport layer protocol is used?
Q2. What is the transaction ID of the message?

5 | Page
Department of Computer Science & Information Systemsfessor,

Q3. What is the query section? What is the type of query and what does it signify about the
type of query? Is there any other type of query you can recall?
Q4. What is the IP address of DNS server?
Q5. What is the destination port number? Remember that it is fixed for all DNS messages.

8. See the DNS response message and answer the following:


Q1. What is the transport layer protocol?
Q2. What is the transaction ID of this message? Is it same as that of corresponding DNS query
message?
Q3. Along with the answer, is there any authoritative name server also. What is its type and
what does it signifies?
Q4. Is there any other field (for example additional records, etc.)? What it signifies?
9. Verify that when the webpage in step 3 above was fetched, DNS query and response was generated
first then HTTP query and response.

To understand the process of IP address resolution in DNS with the help of Wireshark lets perform the
following experiment.

Lab Exercise-4:

Step 1: Start a Wireshark capture.

a) Close all unnecessary network traffic, such as the web browser, to limit the amount traffic during
the Wireshark capture.
b) Start the Wireshark capture.

Step 2: Run the following command from the command prompt

nslookup bits-pilani.ac.in

Step 3: Stop the Wireshark capture.

Step 4: View the Wireshark Main Window.

Answer the following questions by observing traffic captured using Wireshark:

1. Locate the DNS query and response messages. Are they sent over UDP or TCP?
2. To what IP address is the DNS query message sent?
3. What is the destination port for the DNS query message?
4. What is the source port of DNS response message?
5. Examine the DNS response message.

6 | Page
Department of Computer Science & Information Systemsfessor,

Repeat the same experiment by running the following command at step 2


nslookup -type=NS bits-pilani.ac.in and try to answer the same questions.

Lab Exercise-5:
Run the following commands from the command prompt. We have provided here the corresponding output
for each command. The output in your terminal may not be exactly same as the output provided here.
Understand and describe the meaning/purpose of the commands and their corresponding output. (e.g.,
Different DNS records, i.e. A, NS, MX, CNAME and their purpose.)

Command Output
C:\Users\Dell>nslookup Server: UnKnown
bits-pilani.ac.in Address: 199.7.87.1
a0.in.afilias-nst.info Name: bits-pilani.ac.in
Served by:
ns1.bits-pilani.ac.in
202.78.175.200
C:\Users\Dell>nslookup Server: UnKnown
google.com Address: 172.24.2.71
Non-authoritative answer:
Name: google.com
Addresses: 2404:6800:4009:807::200e
216.58.199.174
C:\Users\Dell>nslookup Server: UnKnown
-type=NS google.com Address: 172.24.2.71
Non-authoritative answer:
google.com nameserver = ns2.google.com
google.com nameserver = ns3.google.com
google.com nameserver = ns4.google.com
google.com nameserver = ns1.google.com
ns3.google.com internet address = 216.239.36.10
C:\Users\Dell>nslookup Server: ns2.google.com
google.com Address: 216.239.34.10
ns2.google.com Name: google.com
Addresses: 2404:6800:4009:807::200e
216.58.199.174

C:\Users\Dell>nslookup Server: UnKnown


8.8.8.8 Address: 172.24.2.71
Name: google-public-dns-a.google.com
Address: 8.8.8.8

7 | Page
Department of Computer Science & Information Systemsfessor,

C:\Users\Dell>nslookup Server: google-public-dns-a.google.com


bits-pilani.ac.in google- Address: 8.8.8.8
public-dns-a.google.com
Non-authoritative answer:
Name: bits-pilani.ac.in
Address: 202.78.175.227

*****

8 | Page
Department of Computer Science & Information
Systemsfessor,
COMPUTER NETWORKS (CS F303)
LAB-SHEET – 3
TOPIC: Socket Programming using TCP Sockets
Objectives:
a) To learn the concept of socket to create network applications
b) To learn Socket creation using LINUX system calls
c) Writing a simple TCP client and TCP server program to achieve communication between
two processes running on same machine and on two different machines

What is a Socket…?

A socket is an abstraction through which an application may send and receive data, in much the same way
as an open file allows an application to read and write data to stable storage. A socket allows an application
to "plug in" to the network and communicate with other applications that are also plugged in to the same
network.

Sockets come in different flavors, corresponding to different underlying protocol families and different
stacks of protocols within a family. In this course we deal only with the TCP/IP protocol family. The main
flavors of sockets in the TCP/IP family are stream sockets and datagram sockets. Stream sockets use TCP
as the end-to-end protocol (with IP underneath) and thus provide a reliable byte-stream service. Datagram
sockets use UDP (again, with IP underneath) and thus provide a best-effort datagram service that
applications can use.

A socket using the TCP/IP protocol family is uniquely identified by:


a) An Internet address,
b) An end-to-end protocol (TCP or UDP)
c) A port number.

Creating and Destroying Sockets


To communicate using TCP or UDP, a program begins by asking the operating system to create an instance
of the socket abstraction. The function that accomplishes this is socket()

int socket(int protocolFamily, int type, int protocol)

The first parameter determines the protocol family of the socket. The constant PF_INET specifies a socket
that uses protocols from the Internet protocol family. The second parameter specifies the type of the socket.
The type determines the semantics of data transmission with the socket--for example, whether transmission
is reliable, whether message boundaries are preserved, and so on. The constant SOCK_STREAM specifies
a socket with reliable byte-stream semantics, whereas SOCK_DGRAM specifies a best-effort datagram
socket. The third parameter specifies the particular end-to-end protocol to be used. For the PF_INET
protocol family, we want TCP (identified by the constant IPPROTO_TCP) for a stream socket and UDP
(identified by IPPROTO_UDP) for a datagram socket. Supplying the constant 0 as the third parameter
requests the default end-to-end protocol for the specified protocol family and type.

Page 1 of 8
Department of Computer Science & Information
Systemsfessor,
The return value of socket () is an integer: a nonnegative value for success and -1 for failure. A nonfailure
value should be treated as an opaque handle, which we call a socket descriptor, and is passed to other API
functions to identify the socket abstraction on which the operation is to be carried out.

When an application is finished with a socket, it calls close(), giving the descriptor for the socket that is no
longer needed.

int close (int socket)

close() returns 0 on success or -1 on failure.

Specifying Addresses
Applications using sockets need to be able to specify Internet addresses and ports to the kernel. The sockets
API defines a generic data type--the sockaddr structure--for specifying addresses associated with sockets:
struct sockaddr
{
unsigned short sa_family; /* Address family (e. g. AF_INET) */
char sa_data[14] ; /* Family-specific address information */
};

The first part of this address structure defines the address family--the space to which the address belongs.
For our purposes, we will always use the constant AF_INET, which specifies the Internet address family.
The second part is a blob of bits whose exact form depends on the address family.
The particular form of the sockaddr structure that is used for TCP/IP socket addresses is the sockaddr_in
structure.

struct in_addr
{
unsigned long s_addr; /* Internet address (32 bits) */
};

struct sockaddr_in
{
unsigned short sin_family; /* Internet protocol (AF_INET) */
unsigned short sin_port; /* Address port (16 bits) */
struct in_addr sin_addr; /* Internet address (32 bits) */
char sin_zero[8]; /* Not used */
}
As you can see, the sockaddr_in structure has fields for the port number and Internet address in addition
to the address family. It is important to understand that sockaddr_in is just another view of the data in a
sockaddr structure, tailored to sockets using the Internet protocols. Thus, we can fill in the fields of a
sockaddr_in and then cast it to a sockaddr to pass it to the socket functions, which look at the sa_family
field to learn how the rest of the address is structured.

Page 2 of 8
Department of Computer Science & Information
Systemsfessor,

TCP CLIENT
Its job is to initiate communication with a server that is passively waiting to be contacted. The typical TCP
client goes through four basic steps:

1. Create a TCP socket using socket().


2. Establish a connection to the server using connect ().
3. Communicate using send() and recv().
4. Close the connection with close().

A TCP socket must be connected to another socket before any data can be sent through it. The connection
establishment process is the biggest difference between clients and servers: The client initiates the
connection while the server waits passively for clients to connect to it. To establish a connection with the
server, we call connect () on the socket.

int connect ( int socket, struct sockaddr *foreignAddress, unsigned int addressLength)

socket is the descriptor created by socket (). foreignAddress is declared to be a pointer to a sockaddr
because the sockets API is generic; for our purposes, it will always be a pointer to a sockaddr_in containing
the Internet address and port of the server, addressLength specifies the length of the address structure and
is invariably given as sizeof(struct sockaddr_in).

When connect () returns successfully, the socket is connected and communication can proceed with calls
to send() and recv().

int send (int socket, const void *msg, unsigned int msgLength, int flags)

int recv (int socket, void *rcvBuffer, unsigned int bufferLength, int flags)

send () and recv() have very similar arguments, socket is the descriptor for the connected socket through
which data is to be sent or received. For send(), msg points to the message to send, and msgLength is the
length (in bytes) of the message. For recv(), rcvBuffer points to the buffer--that is, an area in memory such
as a character array--where received data will be placed, and bufferLength gives the length of the buffer,
which is the maximum number of bytes that can be received at once. The flags parameter in both send()
and recv() provides a way to change the default behavior of the socket call. Setting flags to 0 specifies the
default behavior. send() and recv() return the number of bytes sent or received or -1 for failure.

Page 3 of 8
Department of Computer Science & Information
Systemsfessor,
TCP Server
The server's job is to set up a communication endpoint and passively wait for a connection from the client.
As with clients, the setup for a TCP and UDP server is similar. For now, let’s focus on a TCP server. There
are four steps for TCP server communication:

1. Create a TCP socket using socket().


2. Assign a port number to the socket with bind().
3. Tell the system to allow connections to be made to that port, using listen() .
4. Repeatedly do the following:
● Call accept () to get a new socket for each client connection.
● Communicate with the client via that new socket using send() and recv().
● Close the client connection using close().

Creating the socket, sending, receiving, and closing are the same as in the client. The differences in the
server have to do with binding an address to the socket and then using the socket as a channel to "receive"
other sockets that are connected to clients. For the client to contact the server, the server's socket must have
an assigned local address and port; the function that accomplishes this is bind(). Notice that while the client
has to supply the server's address to connect(), the server has to specify its own address to bind(). It is this
piece of information (i.e., the server's address and port) that they have to agree on to communicate; neither
one really needs to know the client's address.

int bind (int socket, struct sockaddr *localAddress, unsigned int addressLength)

The first parameter is the descriptor returned by an earlier call to socket(). As with connect(), the address
parameter is declared as a pointer to a sockaddr, but for TCP/IP applications, it will actually point to a
sockaddr_in containing the Internet address of the local interface and the port to listen on. addressLength
is the length of the address structure, invariably passed as sizeof(struct sockaddr_in). bind() returns 0 on
success and - 1 on failure. If successful, the socket identified by the given descriptor (and no other) is
associated with the given Internet address and port. The Internet address can be set to the special wildcard
value INADDR_ANY, which means that connections to the specified port will be directed to this socket,
regardless of which Internet address they are sent to; this practice can be useful if the host happens to have
multiple Internet addresses.

Now that the socket has an address (or at least a port), we need to instruct the underlying TCP protocol
implementation to listen for connections from clients by calling listen() on the socket.

int listen(int socket, int queueLimit)

listen() causes internal state changes to the given socket, so that incoming TCP connection requests will be
handled and then queued for acceptance by the program. The queueLimit parameter specifies an upper
bound on the number of incoming connections that can be waiting at any time. listen() returns 0 on success
and - 1 on failure.

At first it might seem that a server should now wait for a connection on the socket that it has set up, send
and receive through that socket, close it, and then repeat the process. However, that is not the way it works.

Page 4 of 8
Department of Computer Science & Information
Systemsfessor,
The socket that has been bound to a port and marked "listening" is never actually used for sending and
receiving. Instead, it is used as a way of getting new sockets, one for each client connection; the server then
sends and receives on the new sockets. The server gets a socket for an incoming client connection by calling
accept ().

int accept(int socket, struct sockaddr *clientAddress, unsigned int *addressLength)

accept() de-queues the next connection on the queue for socket. If the queue is empty, accept() blocks until
a connection request arrives. When successful, accept() fills in the sockaddr structure, pointed to by
clientAddress, with the address of the client at the other end of the connection, addressLength specifies
the maximum size of the clientAddress address structure and contains the number of bytes actually used
for the address upon return. If successful, accept() returns a descriptor for a new socket that is connected
to the client. The socket sent as the first parameter to accept() is unchanged (not connected to the client)
and continues to listen for new connection requests. On failure, accept() returns -1.

The server communicates with the client using send() and recv(); when communication is complete, the
connection is terminated with a call to close().

Now, let’s implement a simple client and server program which can send one message to each other.

Read, understand, and save the following file as client.c.


#include <stdio.h>
#include <sys/socket.h> //for socket(), connect(), send(), recv()
functions
#include <arpa/inet.h> // different address structures are declared
here
#include <stdlib.h> // atoi() which convert string to integer
#include <string.h>
#include <unistd.h> // close() function
#define BUFSIZE 32
int main()
{
/* CREATE A TCP SOCKET*/
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) { printf ("Error in opening a socket"); exit (0);}
printf ("Client Socket Created\n");

/*CONSTRUCT SERVER ADDRESS STRUCTURE*/


struct sockaddr_in serverAddr;
memset (&serverAddr,0,sizeof(serverAddr));

/*memset() is used to fill a block of memory with a particular value*/


serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345); //You can change port number here

Page 5 of 8
Department of Computer Science & Information
Systemsfessor,
serverAddr.sin_addr.s_addr = inet_addr("A.B.C.D"); //Specify server's
IP address here
printf ("Address assigned\n");

/*ESTABLISH CONNECTION*/
int c = connect (sock, (struct sockaddr*) &serverAddr , sizeof
(serverAddr));
printf ("%d\n",c);
if (c < 0)
{ printf ("Error while establishing connection");
exit (0);
}
printf ("Connection Established\n");

/*SEND DATA*/
printf ("ENTER MESSAGE FOR SERVER with max 32 characters\n");
char msg[BUFSIZE];
gets(msg);
int bytesSent = send (sock, msg, strlen(msg), 0);
if (bytesSent != strlen(msg))
{ printf("Error while sending the message");
exit(0);
}
printf ("Data Sent\n");

/*RECEIVE BYTES*/
char recvBuffer[BUFSIZE];
int bytesRecvd = recv (sock, recvBuffer, BUFSIZE-1, 0);
if (bytesRecvd < 0)
{ printf ("Error while receiving data from server");
exit (0);
}
recvBuffer[bytesRecvd] = '\0';
printf ("%s\n",recvBuffer);

close(sock);
}

Read, understand, and save the following file as server.c


#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>

Page 6 of 8
Department of Computer Science & Information
Systemsfessor,
#include <unistd.h>
#define MAXPENDING 5
#define BUFFERSIZE 32
int main ()
{
/*CREATE A TCP SOCKET*/
int serverSocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket < 0) { printf ("Error while server socket
creation"); exit (0); }
printf ("Server Socket Created\n");

/*CONSTRUCT LOCAL ADDRESS STRUCTURE*/


struct sockaddr_in serverAddress, clientAddress;
memset (&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(12345);
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
printf ("Server address assigned\n");

int temp = bind(serverSocket, (struct sockaddr*) &serverAddress,


sizeof(serverAddress));
if (temp < 0)
{ printf ("Error while binding\n");
exit (0);
}
printf ("Binding successful\n");
int temp1 = listen(serverSocket, MAXPENDING);
if (temp1 < 0)
{ printf ("Error in listen");
exit (0);
}
printf ("Now Listening\n");
char msg[BUFFERSIZE];

int clientLength = sizeof(clientAddress);


int clientSocket = accept (serverSocket, (struct sockaddr*)
&clientAddress, &clientLength);
if (clientLength < 0) {printf ("Error in client socket"); exit(0);}
printf ("Handling Client %s\n", inet_ntoa(clientAddress.sin_addr));
int temp2 = recv(clientSocket, msg, BUFFERSIZE, 0);
if (temp2 < 0)
{ printf ("problem in temp 2");
exit (0);
}
printf ("%s\n", msg);
printf ("ENTER MESSAGE FOR CLIENT\n");
gets (msg);
int bytesSent = send (clientSocket,msg,strlen(msg),0);
if (bytesSent != strlen(msg))
{ printf ("Error while sending message to client");
exit(0);

Page 7 of 8
Department of Computer Science & Information
Systemsfessor,
}
close (serverSocket);
close (clientSocket);
}

Once you have understood the above programs, execute them on the same machine on two different
terminals. Probably, both the client and server should be able to communicate with each other.
Exercises:
1. Run both client and server on the same machine with IP address as seen using ifconfig.
2. Now, run both client and server on the same machine with IP address 127.0.0.1. See if it works.
What does it mean?
3. Now, run server on different machine and client on different machine. You might require to change
the IP address accordingly.
4. In all the above steps, run wireshark and capture TCP packets. Observe the corresponding packets.
5. Modify the server program such that it can accept three simultaneous client connections. Run the
program and verify it.
6. Modify the client and server programs to implement the following functionality. Client sends one
real number (e.g., 4.40) to server and server returns the next higher integer corresponding to it.
*******

Page 8 of 8
Department of Computer Science & Information
Systemsfessor,

COMPUTER NETWORK (CS F303)


LAB-SHEET – 4
Topic: Socket Programming Part-II
-----------------------------------------------------------------------------------------------------------------------------------------
Learning Objectives:

a) Client-server program writing using UDP sockets


b) File Transfer Program (with partial file sending option) using TCP sockets
-----------------------------------------------------------------------------------------------------------------------------------------
a) A simple ECHO server using UDP sockets
In the last lab, we created a client/server based simple application using the TCP socket (or byte stream socket).
Today, as the first exercise, we will see how to create a simple ECHO server and the client using UDP (message
stream) sockets. By ECHO server, we mean that the server will reply the same message back, whatever it receives
from the client.

Read, understand, and save the following file as client_udp.c. You can also download this file from Nalanda. While
reading, try to locate and understand the specific differences with the TCP based client program that we did in the
previous lab.

/* Simple udp client */

#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUFLEN 512 //Max length of buffer

#define PORT 8888 //The port on which to send data

void die(char *s)


{
perror(s);
exit(1);
}

int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];

if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)


{
die("socket");

Page 1 of 9
Department of Computer Science & Information
Systemsfessor,
}

memset((char *) &si_other, 0, sizeof(si_other));


si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
si_other.sin_addr.s_addr = inet_addr("127.0.0.1");

while(1)
{
printf("Enter message : ");
gets(message);

//send the message


if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other,
slen)==-1)
{
die("sendto()");
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -
1)
{
die("recvfrom()");
}

puts(buf);
}

close(s);
return 0;
}

Read, understand, and save the following file as server_udp.c. You can also download this file from
Nalanda. While reading, try to locate and understand the specific differences with the TCP based server
program that we did in the previous lab.
/* Simple udp server */

#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUFLEN 512 //Max length of buffer


#define PORT 8888 //The port on which to listen for incoming data

Page 2 of 9
Department of Computer Science & Information
Systemsfessor,
void die(char *s)
{
perror(s);
exit(1);
}

int main(void)
{
struct sockaddr_in si_me, si_other;
int s, i, slen = sizeof(si_other) , recv_len;
char buf[BUFLEN];

//create a UDP socket


if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
die("socket");
}

// zero out the structure


memset((char *) &si_me, 0, sizeof(si_me));

si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);

//bind socket to port


if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
die("bind");
}

//keep listening for data


while(1)
{
printf("Waiting for data...");
fflush(stdout);

//try to receive some data, this is a blocking call


if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other,
&slen)) == -1)
{
die("recvfrom()");
}

//print details of the client/peer and the data received


printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr),
ntohs(si_other.sin_port));
printf("Data: %s\n" , buf);

//now reply the client with the same data


if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1)
{
die("sendto()");
}

Page 3 of 9
Department of Computer Science & Information
Systemsfessor,
}
close(s);
return 0;
}

The following diagram showing the sequence of function calls for the client and a server participating in a TCP
and UDP would help you understand the differences between TCP and UDP socket programming better.

Exercise #1
Modify the ECHO server and client programs to a guessing game, where the server will generate a
number (say between 1 to 6 or the name of a famous personality with some hint) and ask the client
to guess it. The user will enter the guessed number (or name) through the terminal. If the guess is
correct the client will win, otherwise it will lose. An appropriate message about the outcome can be
printed at the client side.

b) Designing and implementing simple FTP client and server with broken
download handling capability using TCP sockets.
In the second lab, we performed few experiments with Wireshark to understand functioning of standard
FTP protocol. Here, we will develop our own simple client/server based application to get a file from the
server. Currently, the program given here, simply downloads a predefined file from the server. It can be
extended to include many other functionalities such as directory listing, “get” and “put” commands, as
present in the standard FTP program. However, our program has the broken download capability which
allows the client to complete a file transfer by downloading the remaining portion of a file only, if the
file to be download is already present with the client partially. For example, if the client is already having
initial 100 bytes of a files then next time, instead of downloading the complete file from the server, the
client can request the server to send the file starting from byte number 101.

Read, understand, and save the following file as client_broken_ftp.c. You can also download this file
from Nalanda.

/* Client program Broken FTP */

#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>
#include <arpa/inet.h>

Page 4 of 9
Department of Computer Science & Information
Systemsfessor,

int main(void)
{
int sockfd = 0;
int bytesReceived = 0;
char recvBuff[256];
unsigned char buff_offset[10]; // buffer to send the File offset value
unsigned char buff_command[2]; // buffer to send the Complete File (0)
or Partial File Command (1).
int offset; // required to get the user input for
offset in case of partial file command
int command; // required to get the user input for command
memset(recvBuff, '0', sizeof(recvBuff));
struct sockaddr_in serv_addr;

/* Create a socket first */


if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}

/* Initialize sockaddr_in data structure */


serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5001); // port
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

/* Attempt a connection */
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}

/* Create file where data will be stored */


FILE *fp;
fp = fopen("destination_file.txt", "ab");
if(NULL == fp)
{
printf("Error opening file");
return 1;
}
fseek(fp, 0, SEEK_END);
offset = ftell(fp);
fclose(fp);
fp = fopen("destination_file.txt", "ab");
if(NULL == fp)
{
printf("Error opening file");

Page 5 of 9
Department of Computer Science & Information
Systemsfessor,
return 1;
}

printf("Enter (0) to get complete file, (1) to specify offset, (2)


calculate the offset value from local file\n");
scanf("%d", &command);
sprintf(buff_command, "%d", command);
write(sockfd, buff_command, 2);

if(command == 1 || command == 2) // We need to specify the offset


{

if(command == 1) // get the offset from the user


{
printf("Enter the value of File offset\n");
scanf("%d", &offset);
}
// otherwise offset = size of local partial file, that we have
already calculated
sprintf(buff_offset, "%d", offset);
/* sending the value of file offset */
write(sockfd, buff_offset, 10);
}

// Else { command = 0 then no need to send the value of offset }

/* Receive data in chunks of 256 bytes */


while((bytesReceived = read(sockfd, recvBuff, 256)) > 0)
{
printf("Bytes received %d\n",bytesReceived);
// recvBuff[n] = 0;
fwrite(recvBuff, 1,bytesReceived,fp);
// printf("%s \n", recvBuff);
}

if(bytesReceived < 0)
{
printf("\n Read Error \n");
}

return 0;
}

Page 6 of 9
Department of Computer Science & Information
Systemsfessor,
Read, understand, and save the following file as server_broken_ftp.c. You can also download this file from
Nalanda.

/* Server program for broken ftp */

#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>
#include <sys/types.h>

int main(void)
{
int listenfd = 0;
int connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
int numrv;

listenfd = socket(AF_INET, SOCK_STREAM, 0);

printf("Socket retrieve success\n");

memset(&serv_addr, '0', sizeof(serv_addr));


memset(sendBuff, '0', sizeof(sendBuff));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5001);

bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));

if(listen(listenfd, 10) == -1)


{
printf("Failed to listen\n");
return -1;
}

while(1)
{
unsigned char offset_buffer[10] = {'\0'};
unsigned char command_buffer[2] = {'\0'};
int offset;

Page 7 of 9
Department of Computer Science & Information
Systemsfessor,
int command;
connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);

printf("Waiting for client to send the command (Full File (0)


Partial File (1)\n");

while(read(connfd, command_buffer, 2) == 0);


sscanf(command_buffer, "%d", &command);

if(command == 0)
offset = 0;
else
{
printf("Waiting for client to send the offset\n");
while(read(connfd, offset_buffer, 10) == 0);
sscanf(offset_buffer, "%d", &offset);

/* Open the file that we wish to transfer */


FILE *fp = fopen("source_file.txt","rb");
if(fp==NULL)
{
printf("File opern error");
return 1;
}

/* Read data from file and send it */


fseek(fp, offset, SEEK_SET);
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[256]={0};
int nread = fread(buff,1,256,fp);
printf("Bytes read %d \n", nread);

/* If read was success, send data. */


if(nread > 0)
{
printf("Sending \n");
write(connfd, buff, nread);
}

/*
* There is something tricky going on with read ..
* Either there was error, or we reached end of file.
*/

Page 8 of 9
Department of Computer Science & Information
Systemsfessor,
if (nread < 256)
{
if (feof(fp))
printf("End of file\n");
if (ferror(fp))
printf("Error reading\n");
break;
}
}
close(connfd);
sleep(1);
}
return 0;
}

Exercise #2
So, now as you understand the programming with UDP sockets and the working of our simple broken
FTP application running over TCP socket, modify the above broken FTP client/server programs to make
it run using UDP sockets.

--------------------------------------------------------------Good Luck------------------------------------------------------------------------

Page 9 of 9
COMPUTER NETWORK (CS F303)
LAB-SHEET – 5
Topic: Socket Programming- Concurrent Server
-------------------------------------------------------------------------------------------------------------------------------
Learning Objectives:

Creating concurrent TCP server (handling multiple clients) using fork() and threads tem call

Handling multiple clients at the same time


There are two main classes of servers, iterative and concurrent. An iterative server iterates through
each client, handling it one at a time. A concurrent server handles multiple clients at the same time.
The simplest technique for a concurrent server is to call the fork function, creating one child process
for each client. An alternative technique is to use threads instead (i.e., light-weight processes).
TCPEchoServer_fork.c
A typical concurrent ECHO server (using fork has the following
structure).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8898


#define MAX_CONN 10
#define BUFFER_SIZE 1024

void handle_client(int client_sock) {


char buffer[BUFFER_SIZE];
ssize_t bytes_read;
// Echo data received from client
while ((bytes_read = read(client_sock, buffer, sizeof(buffer))) > 0) {
write(client_sock, buffer, bytes_read); // Send back the received
data
}
if (bytes_read == 0) {
printf("Client disconnected.\n");
} else if (bytes_read == -1) {
perror("Error reading from socket");
}
close(client_sock);
}

int main() {

Page 1 of 9
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
// Create socket
if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket creation failed");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);

// Bind socket to address


if (bind(server_sock, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1) {
perror("Bind failed");
close(server_sock);
exit(1);
}
// Listen for incoming connections
if (listen(server_sock, MAX_CONN) == -1) {
perror("Listen failed");
close(server_sock);
exit(1);
}
printf("Server listening on port %d...\n", PORT);
// Accept incoming connections and handle them concurrently
while (1) {
client_sock = accept(server_sock, (struct sockaddr *)&client_addr,
&client_addr_len);
if (client_sock == -1) {
perror("Accept failed");
continue;
}

printf("Client connected from %s:%d\n", inet_ntoa(client_addr.sin_addr),


ntohs(client_addr.sin_port));
// Create a child process to handle the client
if (fork() == 0) {
// Child process
close(server_sock); // Child does not need the server socket
handle_client(client_sock);
exit(0);
}
close(client_sock); // Parent does not need the client socket

Page 2 of 9
}
close(server_sock);
return 0;
}
When a connection is established, accept returns, the server calls fork, and the child process services
the client (on the connected new socket). The parent process waits for another connection (on the
listening socket sockfd). The parent closes the connected socket since the child handles the new
client.

TCPEchoServer_threads.c
A typical concurrent ECHO server (using threads has the following
structure).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

#define PORT 8898


#define MAX_CONN 10
#define BUFFER_SIZE 1024

// Structure to pass client socket to the thread function


typedef struct {
int client_sock;
struct sockaddr_in client_addr;
} client_data_t;

// Thread function to handle each client


void *handle_client(void *arg) {
client_data_t *data = (client_data_t *)arg;
char buffer[BUFFER_SIZE];
ssize_t bytes_read;
// Handle client interaction
while ((bytes_read = read(data->client_sock, buffer, sizeof(buffer))) >
0) {
write(data->client_sock, buffer, bytes_read); // Echo the received
data
}
if (bytes_read == 0) {
printf("Client disconnected from %s:%d\n", inet_ntoa(data-
>client_addr.sin_addr), ntohs(data->client_addr.sin_port));
} else if (bytes_read == -1) {

Page 3 of 9
perror("Error reading from socket");
}
close(data->client_sock);
free(data); // Free allocated memory for client data
pthread_exit(NULL);
}
int main() {
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len = sizeof(client_addr);
pthread_t thread_id;

// Create server socket


if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket creation failed");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// Bind socket to the address
if (bind(server_sock, (struct sockaddr *)&server_addr,
sizeof(server_addr)) == -1) {
perror("Bind failed");
close(server_sock);
exit(1);
}
// Listen for incoming connections
if (listen(server_sock, MAX_CONN) == -1) {
perror("Listen failed");
close(server_sock);
exit(1);
}
printf("Server listening on port %d...\n", PORT);
// Accept and handle client connections concurrently using threads
while (1) {
client_sock = accept(server_sock, (struct sockaddr *)&client_addr,
&client_addr_len);
if (client_sock == -1) {
perror("Accept failed");
continue;
}
printf("Client connected from %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// Allocate memory for client data and pass it to the thread

Page 4 of 9
client_data_t *data = malloc(sizeof(client_data_t));
data->client_sock = client_sock;
data->client_addr = client_addr;
// Create a new thread for the client
if (pthread_create(&thread_id, NULL, handle_client, data) != 0) {
perror("Thread creation failed");
free(data); // If thread creation fails, free the allocated
memory
close(client_sock);
}
// Detach the thread so it can clean up resources when finished
pthread_detach(thread_id);
}
close(server_sock);
return 0;
}

 The server now uses pthreads to handle multiple client connections concurrently.
 Each time a client connects, a new thread is created with pthread_create(), and the
thread is responsible for handling communication with that specific client.
 client_data_t is used to store the client's socket and address information, which is
passed to the thread function.
 Threads are detached using pthread_detach() so that resources are automatically
cleaned up once the thread finishes execution.

The main difference between using fork() and pthreads in handling multiple client
connections is primarily in the concurrency model (process-based vs. thread-based), but there are
some additional considerations as well.
1. Concurrency Model: Process vs. Threads

 Using fork() (Process-based):

 Each time a client connects, the server creates a new child process using fork().
 Each process has its own memory space (each client gets a separate process, so no memory is
shared between them unless explicitly managed using inter-process communication like shared
memory or pipes).
 The operating system is responsible for managing separate processes, and each process has its
own stack, heap, and other resources.
 Process creation is heavier, requiring more system resources (e.g., separate memory for each
process, OS overhead for process scheduling).

Page 5 of 9
 Using pthreads (Thread-based):

 Instead of creating a new process, the server creates a new thread using
pthread_create().
 All threads in a process share the same memory space. This makes thread management faster
and more efficient in terms of memory and resource usage.
 Threads are lighter than processes. They share the same address space, so they can
communicate with each other easily (via shared memory).
 Thread creation is generally faster and more efficient than process creation because there’s no
need for duplication of memory, file descriptors, etc.

2. Code and Resource Management Differences

Here are the key differences in terms of code and resource management:

1. Memory and Resources:


 Forked Process:

 Each child process is independent with its own memory space, and the parent doesn’t directly
share data with the child unless explicitly handled via IPC mechanisms like pipes or shared
memory.
 Each process has a separate stack, and synchronization (if needed) must be handled through
inter-process mechanisms.
 Pthreads (Threads):

 Threads in a process share the same memory space, so they can easily communicate using
shared variables and structures.
 Synchronization (mutexes, condition variables) is needed to avoid data races when multiple
threads access shared memory.
 Threads are lighter in terms of resource usage compared to processes because they don’t
duplicate memory or system resources like file descriptors.

2. Thread/Process Lifecycle:
 Forked Process:
 A new process is created when a client connects, and it runs independently. The child process
exits once its task is done.
 You need to wait for the process to complete (using wait() or waitpid()), or simply let
the operating system clean up orphaned processes.
 Pthreads (Threads):
 A new thread is created for each client, and the main thread can continue accepting other
clients.
 Threads are joined or detached. If you use pthread_join(), you can wait for the thread to
complete; pthread_detach() allows threads to clean up automatically when done.

Page 6 of 9
3. Code Differences in Handling Clients:

Fork-based Server Code:


if (fork() == 0) { // Child process
// Handle client
handle_client(client_sock);
exit(0); // Child exits after handling client
}

 When you use fork(), the child process runs the code to handle the client, and the parent process
goes back to accepting new connections.
 The child process exits once it’s done, so there’s no need for cleanup (the OS will handle that).

Thread-based Server Code:


pthread_t thread_id;
client_data_t *data = malloc(sizeof(client_data_t));
data->client_sock = client_sock;
data->client_addr = client_addr;
pthread_create(&thread_id, NULL, handle_client, data);
pthread_detach(thread_id); // No need to join, thread will clean up itself

 Here, instead of forking, we create a thread using pthread_create(). The thread executes the
client-handling function (handle_client).
 pthread_detach() is used to automatically clean up the thread when it's done. If we used
pthread_join(), the parent would wait for the thread to finish.

4. Handling Synchronization:
 Fork-based Process Server:

 Since each process is independent, no explicit synchronization is needed between processes.


But if you're sharing data between processes (e.g., through shared memory), you will need
synchronization mechanisms (semaphores, shared memory locks, etc.).
 Thread-based Server:

 Because threads share the same address space, you must be cautious of race conditions.
Shared data (such as global variables or structures passed to threads) should be protected
using synchronization primitives like mutexes, semaphores, or condition variables.

3. Performance Considerations:

 Forking (Processes):

 Forking processes is more expensive in terms of time and system resources.


 Creating and managing processes involves more memory overhead (copy-on-write mechanism)
and context-switching is heavier compared to threads.

Page 7 of 9
 If the server needs to handle a large number of clients, forking might introduce performance
issues due to the overhead of creating and destroying processes.
 Pthreads (Threads):

 Threads are lightweight and faster to create and manage, with lower overhead.
 Since threads share memory, communication between threads is faster (they can directly
access shared variables).
 However, the developer must ensure thread safety, especially when modifying shared data.

4. Scalability:

 Forking:

 Scaling with fork() can be less efficient, especially with many clients, due to the overhead of
managing multiple processes.
 On systems with limited process resources (like file descriptors), you may hit system limits
more quickly.
 Pthreads:

 Threads are more scalable for a larger number of concurrent clients due to their lightweight
nature.
 Thread-based servers generally provide better performance and scalability for applications
requiring high concurrency.

5. Error Handling and Debugging:

 Forking:
 Each child process runs independently, so debugging and error handling can be trickier. You
need to handle errors across multiple processes, often using signals and inter-process
communication.
 Pthreads:
 Debugging is easier because threads share memory space, but the synchronization of threads
can lead to subtle issues like race conditions or deadlocks. Proper error handling mechanisms
(like checking pthread_create() returns) must be in place.

Switching from fork() to pthreads mainly affects how concurrency is handled. While both methods
achieve similar functionality in a TCP server (handling multiple clients concurrently), using threads
(pthreads) provides lower overhead and more efficient memory usage. Threads are typically preferred for
higher-performance and scalable server applications. However, they require more careful synchronization and
attention to shared memory access to avoid issues like data races.

To summarize:

Page 8 of 9
 Using fork(): Processes, heavier memory footprint, independent address spaces, suitable for lower
concurrency.
 Using pthreads: Threads, lighter memory footprint, shared memory, suitable for high concurrency
and better resource utilization.

Note: you need to use -pthread option while compiling the TCPEchoServer_threads.c code.
The -pthread option is necessary for:
1. Defining threading-related macros for thread safety during compilation.
2. Linking to the pthread library during the linking phase of the compilation process.

Thus, it ensures that the program is both compiled and linked correctly to support threads.
Exercise #1
a. Use and modify the TCP Echo client created in Lab3 to create a client which connects to either of the servers.
b. Use and modify to TCPEchoServer_fork.c and TCPEchoServer_threads.c to create a concurrent
TCPEchoServer_ft.c which can either run using fork or thread mode (you may use command line arguments to
specify the mode)
c. Test the server program created above using the TCP Echo client program.
d. Which server mode do you think is more efficient? Justify you answer.

Exercise#2
Develop a simple key-value () store using TCP sockets where clients connect simultaneously to the server for
inserting and retrieving the key. Your application must support the following features:
 The client takes user input to get/put/delete keys and passes these requests over the server.
 The server maintains a data structure of key-value pairs in a file (database.txt) as the persistent
database and returns a suitable reply to the server.
 When the request from the client is of the form "put key value", the server must store the key-value
pair in its data structures, provided the key does not already exist. Put requests on an existing key
must return an error message.
 When the client sends a request of the form "get key", the value stored against the key must be
returned to the client. If the key is not found, a suitable error message must be returned by the server.
 The client should be able to issue a delete request (on an existing key) as follows: "del key".
 For all requests that succeed, the server must either return the value (in case of get), or the string
"OK" (in case of put/del).
 You may assume that all keys are integers and the corresponding values are strings. When the user
inputs "Bye", the server should reply "Goodbye" and close the client connection.
 Upon receiving this message from the server, your client program terminates. However, the server
must keep the database in a file for subsequent run of client program.
 Note that your server must be able to communicate with multiple active clients at a time. When
multiple clients talk to the server, one client should be able to see the data stored by the other clients.
xx—oo—xx

Page 9 of 9

You might also like