0% found this document useful (0 votes)
84 views28 pages

C++ Sockets TCP

The document summarizes the Berkeley Sockets API, a widely used low-level C networking API. It describes key concepts like sockets, which provide an interface between applications and the network. It also covers functions for creating and configuring sockets like bind(), listen(), connect(), and accept() to establish TCP/IP connections between clients and servers. Address structures like sockaddr_in and sockaddr_in6 are used to specify server addresses and ports.

Uploaded by

MaestroUTN
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
84 views28 pages

C++ Sockets TCP

The document summarizes the Berkeley Sockets API, a widely used low-level C networking API. It describes key concepts like sockets, which provide an interface between applications and the network. It also covers functions for creating and configuring sockets like bind(), listen(), connect(), and accept() to establish TCP/IP connections between clients and servers. Address structures like sockaddr_in and sockaddr_in6 are used to specify server addresses and ports.

Uploaded by

MaestroUTN
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 28

Network Programming in C:

The Berkeley Sockets API

Networked Systems 3
Laboratory Sessions
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.

2
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

3
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

4
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) 5 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, …);
6
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

7
Handling Errors

Socket functions return -1 and set the global integer


variable errno on failure

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


if (fd == -1) {
// Error occurred; look at possible errors that can
// errno to determine what occur for each function
// to do.
...
} E.g. do “man 2 socket”
in a terminal, and read the
ERRORS section

8
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

9
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

10
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

11
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

12
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

13
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

14
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

15
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) {
...

16
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) {


...

17
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) {


...

18
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
};

19
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;
}
...success, use the connection
break;
}
if (ai == NULL) {
// Connection failed, handle the failure...
}

20
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)
21
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

22
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]);
}

23
Handling Multiple Sockets
#include <sys/select.h> The select() call tells you which of a
...
int fd1, fd2;
group of sockets has data available to read
fd_set rfds;
struct timeval timeout;
...
timeout.tv_sec = 1; // 1 second timeout
timeout.tv_usec = 0;

FD_ZERO(&rfds);
FD_SET(fd1, &rfds);
FD_SET(fd2, &rfds);

int rc = select(max(fd1, fd2) + 1, &rfds, NULL, NULL, &timeout);


if (rc == 0) ... // timeout
if (rc > 0) {
if (FD_ISSET(fd1, &rfds)) {
// Data available to read on fd1
}
if (FD_ISSET(fd2, &rfds)) {
// Data available to read on fd2
}
}
if (rc < 0) ... // error

24
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


25
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;
}

26
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

27
Questions?

28

You might also like