0% found this document useful (0 votes)
22 views

Lab 04

This document discusses network programming in C using the Berkeley Sockets API. It covers concepts like sockets, streams, and datagrams. It explains how to create and bind sockets, listen for connections, connect to servers, and handle errors. Code examples are provided for key socket functions like socket(), bind(), listen(), connect(), and addressing structures like sockaddr, sockaddr_in, and sockaddr_in6. The goal is to teach the fundamentals of concurrent network programming using the Berkeley Sockets API.
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)
22 views

Lab 04

This document discusses network programming in C using the Berkeley Sockets API. It covers concepts like sockets, streams, and datagrams. It explains how to create and bind sockets, listen for connections, connect to servers, and handle errors. Code examples are provided for key socket functions like socket(), bind(), listen(), connect(), and addressing structures like sockaddr, sockaddr_in, and sockaddr_in6. The goal is to teach the fundamentals of concurrent network programming using the Berkeley Sockets API.
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/ 33

Network Programming in C

Networked Systems 3
Laboratory Sessions and Problem Sets
Lab Timetable, Aims, and Objectives
Teaching Week
14
Activity
Introduction
• Aims and objectives
15 Warm-up exercise
• To demonstrate how the world-wide
web works, at a protocol level
16 • To teach concurrent network
17 Web client programming in C

18
19
20
Web server
21
22
23 -

2
Relation Between Labs and Lectures

Layer

7 Lab
6
Lecture
5
4
3
2
1
Week
14 15 16 17 18 19 20 21 22 23

3
Network Programming in C:
The Berkeley Sockets API

4
The Berkeley Sockets API

• Widely used low-level C networking API


• First introduced in 4.3BSD Unix
• Now available on most platforms: Linux, MacOS X, Windows, FreeBSD,
Solaris, etc.
• Largely compatible cross-platform

• Recommended reading:
• Stevens, Fenner, and Rudoff, “Unix Network Programming
volume 1: The Sockets Networking API”, 3rd Edition,
Addison-Wesley, 2003.

5
Concepts

Application • Sockets provide a standard


interface between network
and application

Socket • Two types of socket:


• Stream – provides a virtual circuit service
• Datagram – delivers individual packets

• Independent of network type:


• Commonly used with TCP/IP and UDP/IP,
but not specific to the Internet protocols
Network
• Only discuss TCP/IP sockets today

6
What is a TCP/IP Connection?

• A reliable byte-stream connection between two


computers
• Most commonly used in a client-server fashion:
• The server listens on a well-known port
• The port is a 16-bit number used to distinguish servers
• E.g. web server listens on port 80, email server on port 25

• The client connects to that port


• Once connection is established, either side can write data into the
connection, where it becomes available for the other side to read

• The Sockets API represents the connection using a


file descriptor

7
TCP/IP Connection
Client Server

fd
fd connfd

Network ?
?
Socket Socket

int fd = socket(...) int fd = socket(...)


bind(fd, ..., ...)
listen(fd, ...)
connect(fd, ..., ...) connfd = accept(fd, ...)

write(fd, data, datalen) read(connfd, buffer, buflen)

read(fd, buffer, buflen) write(connfd, data, datalen)

close(fd) 8 close(connfd)
TCP/IP Connection

Server fd = socket(…);

Client bind(fd, …);


Specify well-known
port

fd = socket(…); listen(fd, …); Begin listening

TCP/IP connection established


connect(fd, …); connfd = accept(fd, …);
Block until connection
Send request established
write(fd, …); read(connfd, …);
Wait for response
read(fd, …); write(connfd, …);

TCP/IP connection shutdown


close(fd, …); read(connfd, …); EOF read

close(connfd, …);
9
Creating a socket

#include <sys/types.h>
<sys/socket.h>
#include <sys/socket.h> AF_INET for IPv4
AF_INET6 for IPv6
int fd;
...
fd = socket(family, type, protocol); SOCK_STREAM for TCP
if (fd == -1) { SOCK_DGRAM for UDP
// Error: unable to create socket
... 0 (not used for Internet sockets)
}
...

Create an unbound socket, not connected to network;


can be used as either a client or a server

10
Handling Errors

Socket functions return -1 and set the global variable


errno on failure

fd = socket(family, type, protocol); The Unix man pages list


if (fd == -1) {
switch (errno) { possible errors that can
case EPROTONOSUPPORT : occur for each function
// Protocol not supported
...
case EACCES: E.g. do “man 2 socket”
// Permission denied
...
in a terminal, and read the
case ... ERRORS section
default:
// Other error...
...
}
11
Binding a Server Socket

• Bind a socket to a port #include <sys/types.h>


#include <sys/socket.h>
on a network interface ...
if (bind(fd, addr, addrlen) == -1) {
• Needed to run servers on a
// Error: unable to bind
well-known port - with addr
specified as INADDR_ANY ...
}
• Not generally used on clients, ...
since typically don’t care
which port used

12
Listening for Connections

#include <sys/types.h>
#include <sys/socket.h>

if (listen(fd, backlog) == -1) {


// Error
...
}
...

Tell the socket to listen for new connections

The backlog is the maximum number of connections the


socket will queue up, each waiting to be accept()’ed

13
Connecting to a Server

#include <sys/types.h>
Pointer to a struct sockaddr
#include <sys/socket.h>
Size of the struct in bytes
if (connect(fd, addr, addrlen) == -1) {
// Error: unable to open connection
...
}
...

Tries to open a connection to the server


Times out after 75 seconds if no response

14
Specifying Addresses & Ports

• Must specify the address and port when calling


bind() or connect()
• The address can be either IPv4 or IPv6
• Could be modelled in C as a union, but the designers of the sockets API
chose to use a number of structs, and abuse casting instead

15
struct sockaddr

• Addresses specified via


struct sockaddr
• Has a data field big enough to struct sockaddr {
hold the largest address of any uint8_t sa_len;
family sa_family_t sa_family;
• Plus sa_len and sa_family
};
char sa_data[22];
to specify the length and type
of the address
• Treats the address as an opaque
binary string

16
struct sockaddr_in

struct in_addr {
• Two variations exist for };
in_addr_t s_addr;

IPv4 and IPv6


addresses struct sockaddr_in {
uint8_t sin_len;
• Use struct sockaddr_in to sa_family_t sin_family;
hold an IPv4 address in_port_t sin_port;
• Has the same size and memory struct in_addr
char
sin_addr;
sin_pad[16];
layout as struct sockaddr,
but interprets the bits differently };
to give structure to the address

17
struct sockaddr_in6

struct in6_addr {
• Two variations exist for };
uint8_t s6_addr[16];

IPv4 and IPv6


addresses struct sockaddr_in6 {
uint8_t sin6_len;
• Use struct sockaddr_in6 sa_family_t sin6_family;
to hold an IPv6 address in_port_t sin6_port;
• Has the same size and memory uint32_t
struct in6_addr
sin6_flowinfo;
sin6_addr;
layout as struct sockaddr,
but interprets the bits differently };
to give structure to the address

18
Working with Addresses

• Work with either struct sockaddr_in or


struct sockaddr_in6
• Cast it to a struct sockaddr before calling
the socket routines

struct sockaddr_in addr;


...
// Fill in addr here
...
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
...

19
Creating an Address: Manually (Client)

#include <sys/types.h>
#include <sys/socket.h> inet_pton() to convert address
#include
#include
<netinet/in.h>
<arpa/inet.h>
htons() to convert port

struct sockaddr_in addr;


...
inet_pton(AF_INET, “130.209.240.1”, &addr.sin_addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(80);

if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {


...

20
Creating an Address: Manually (Server)

#include <sys/types.h>
#include <sys/socket.h> Usually specify INADDR_ANY
#include <netinet/in.h> htons() to convert port
#include <arpa/inet.h>

struct sockaddr_in addr;


...
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(80);

if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {


...

21
Creating an Address: DNS

• Prefer using DNS names to raw IP addresses


• Use getaddrinfo() to look-up name in DNS
• Returns a linked list of struct addrinfo values, representing
addresses of the host

struct addrinfo {
int ai_flags; // input flags
int ai_family; // AF_INET, AF_INET6, ...
int ai_socktype; // IPPROTO_TCP, IPPROTO_UDP
int ai_protocol; // SOCK_STREAM, SOCK_DRAM, ...
socklen_t ai_addrlen; // length of socket-address
struct sockaddr *ai_addr; // socket-address for socket
char *ai_canonname; // canonical name of host
struct addrinfo *ai_next; // pointer to next in list
};

22
Connecting via a DNS Query
struct addrinfo hints, *ai, *ai0;
int i;

memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((i = getaddrinfo(“www.google.com”, "80", &hints, &ai0)) != 0) {
printf("Unable to look up IP address: %s", gai_strerror(i));
...
}

for (ai = ai0; ai != NULL; ai = ai->ai_next) {


fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (fd == -1) {
perror("Unable to create socket");
continue;
}

if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {


perror("Unable to connect");
close(fd);
continue;
}
...
}
23
Accepting Connections

#include <sys/types.h>
#include <sys/socket.h>

int connfd;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
...
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
// Error
...
}
...

Accepts a connection, returns new file descriptor for the


connection (connfd) and client address (cliaddr)
24
Accepting Connections

• A TCP/IP server may have multiple connections


outstanding
• Can accept() connections one at a time, handling each request in
series
• Can accept() connections and start a new thread for each, allowing it to
process several in parallel

• Each call to accept() returns a new file descriptor

25
Reading and Writing Data

#define BUFLEN 1500


...
Read up to BUFLEN bytes of
ssize_t i; data from connection; blocks
ssize_t rcount; until data available
char buf[BUFLEN];
...
rcount = read(fd, buf, BUFLEN); Returns actual number of
if (rcount == -1) {
// Error has occurred bytes read, or -1 on error
...
}
... Data is not null terminated
for (i = 0; i < rcount; i++) {
printf(“%c”, buf[i]);
}

26
Reading and Writing Data

char data[] = “Hello, world!”;


int datalen = strlen(data);
...
if (write(fd, data, datalen) == -1) {
// Error has occurred
...
}
...

Send data on a TCP/IP connection; blocks until all data


can be written

Returns actual number of bytes written, or -1 on error


27
Reading and Writing Data

#include <stdio.h>
#include <stdlib.h> What gets printed?
#include <string.h>

int main()
{
char x[] = "Hello, world!";
char *y = malloc(14);

sprintf(y, "Hello, world!");

printf("x = %s\n", x);


printf("y = %s\n", y);

printf("sizeof(x) = %d\n", sizeof(x));


printf("sizeof(y) = %d\n", sizeof(y)); Why?
printf("strlen(x) = %d\n", strlen(x));
printf("strlen(y) = %d\n", strlen(y));

return 0;
}

28
Closing a Socket

#include <unistd.h>

close(fd);

Close and destroy a socket

Close the file descriptor for each connection, then the file
descriptor for the underlying socket

29
Programming Exercises

30
Assessment

• Laboratory work is assessed, total weighting 20%

Exercise Date set Date due* Weighting

26 January,
Warm-up 13 January 4%
12:00pm
16 February,
Web client 27 January 6%
12:00pm
12 March,
Web server 17 February 10%
12:00pm
* Note: these are hard deadlines; late submissions will receive a mark of zero unless
accompanied by a valid special circumstances form.

• All students are required to attend Wednesday labs

31
Warm-up Exercise

• Write two programs in C: hello_client and


hello_server
• The server listens for, and accepts, a single TCP connection; it reads all
the data it can from that connection, and prints it to the screen; then it
closes the connection
• The client connects to the server, sends the string “Hello, world!”, then
closes the connection

• Details on the handout…

32
Questions?

33

You might also like