NS3 Lab 1 TCP/IP Network Programming in C

Similar documents
Porting applications & DNS issues. socket interface extensions for IPv6. Eva M. Castro. ecastro@dit.upm.es. dit. Porting applications & DNS issues UPM

Tutorial on Socket Programming

Introduction to Socket programming using C

INTRODUCTION UNIX NETWORK PROGRAMMING Vol 1, Third Edition by Richard Stevens

Introduction to Socket Programming Part I : TCP Clients, Servers; Host information

Lab 4: Socket Programming: netcat part

CSE 333 SECTION 6. Networking and sockets

The POSIX Socket API

Socket Programming. Request. Reply. Figure 1. Client-Server paradigm

Socket Programming. Kameswari Chebrolu Dept. of Electrical Engineering, IIT Kanpur

Unix Network Programming

Socket Programming. Srinidhi Varadarajan

Socket Programming in C/C++

ELEN 602: Computer Communications and Networking. Socket Programming Basics

Best practices in IPv6 enabled networking software development.

TCP/IP - Socket Programming

Application Architecture

UNIX. Sockets. mgr inż. Marcin Borkowski

Implementing Network Software

Network Programming with Sockets. Anatomy of an Internet Connection

IT304 Experiment 2 To understand the concept of IPC, Pipes, Signals, Multi-Threading and Multiprocessing in the context of networking.

Writing a C-based Client/Server

Networks class CS144 Introduction to Computer Networking Goal: Teach the concepts underlying networks Prerequisites:

IBM i Version 7.2. Programming Socket programming IBM

Computer Networks Network architecture

UNIX Sockets. COS 461 Precept 1

Communication Networks. Introduction & Socket Programming Yuval Rochman

Programmation Systèmes Cours 9 UNIX Domain Sockets

Session NM059. TCP/IP Programming on VMS. Geoff Bryant Process Software

Lecture 17. Process Management. Process Management. Process Management. Inter-Process Communication. Inter-Process Communication

ICT SEcurity BASICS. Course: Software Defined Radio. Angelo Liguori. SP4TE lab.

VMCI Sockets Programming Guide VMware ESX/ESXi 4.x VMware Workstation 7.x VMware Server 2.0

Generalised Socket Addresses for Unix Squeak

Hostnames. HOSTS.TXT was a bottleneck. Once there was HOSTS.TXT. CSCE515 Computer Network Programming. Hierarchical Organization of DNS

BSD Sockets Interface Programmer s Guide

Operating Systems Design 16. Networking: Sockets

SMTP-32 Library. Simple Mail Transfer Protocol Dynamic Link Library for Microsoft Windows. Version 5.2

DESIGN AND IMPLEMENT AND ONLINE EXERCISE FOR TEACHING AND DEVELOPMENT OF A SERVER USING SOCKET PROGRAMMING IN C

Network Programming with Sockets. Process Management in UNIX

Implementing and testing tftp

Overview. Socket Programming. Using Ports to Identify Services. UNIX Socket API. Knowing What Port Number To Use. Socket: End Point of Communication

Networks. Inter-process Communication. Pipes. Inter-process Communication

sys socketcall: Network systems calls on Linux

Limi Kalita / (IJCSIT) International Journal of Computer Science and Information Technologies, Vol. 5 (3), 2014, Socket Programming

IPv6 Enabling CIFS/SMB Applications

Domain Name System (1)! gethostbyname (2)! gethostbyaddr (2)!

Packet Sniffing and Spoofing Lab

Client / Server Programming with TCP/IP Sockets

Software changes for Website and Application IPv6 Readiness

System calls. Problem: How to access resources other than CPU

Writing Client/Server Programs in C Using Sockets (A Tutorial) Part I. Session Greg Granger grgran@sas. sas.com. SAS/C & C++ Support

Windows Socket Programming & IPv6 Translation Middleware

CS 213, Fall 2000 Lab Assignment L5: Logging Web Proxy Assigned: Nov. 28, Due: Mon. Dec. 11, 11:59PM

Project 1: Implement a simple hosts framework using UNIX TCP Sockets to demonstrate the concept of Mobile Agents

Concurrent Server Design Alternatives

System Calls Related to File Manipulation

Hardware Prerequisites Atmel SAM W25 Xplained Pro Evaluation Kit Atmel IO1 extension Micro-USB Cable (Micro-A / Micro-B)

Division of Informatics, University of Edinburgh

Socket = an interface connection between two (dissimilar) pipes. OS provides this API to connect applications to networks. home.comcast.

KATRAGADDA INNOVATIVE TRUST FOR EDUCATION NETWORK PROGRAMMING. Notes prepared by D. Teja Santosh, Assistant Professor, KPES, Shabad, R.R. District.

Elementary Name and Address. Conversions

Network Programming. Chapter The Client-Server Programming Model

A Client Server Transaction. Introduction to Computer Systems /18 243, fall th Lecture, Nov. 3 rd

Network-Oriented Software Development. Course: CSc4360/CSc6360 Instructor: Dr. Beyah Sessions: M-W, 3:00 4:40pm Lecture 2

Programming with TCP/IP Best Practices

Teldat Router. DNS Client

Computer Networks/DV2 Lab

AT12181: ATWINC1500 Wi-Fi Network Controller - AP Provision Mode. Introduction. Features. Atmel SmartConnect APPLICATION NOTE

Chapter 2: Remote Procedure Call (RPC)

Socket programming. Socket Programming. Languages and Platforms. Sockets. Rohan Murty Hitesh Ballani. Last Modified: 2/8/2004 8:30:45 AM

3.5. cmsg Developer s Guide. Data Acquisition Group JEFFERSON LAB. Version

Goal: learn how to build client/server application that communicate using sockets. An interface between application and network

15-441: Computer Networks Homework 1

Programming OpenSSL. The Server Perspective. by Sean Walton. Copyright 2001 Sean Walton

Network Programming using sockets

Network Programming TDC 561

Unix System Administration

Ethernet. Ethernet. Network Devices

University of Amsterdam

Introduction to Computer Networks

Direct Sockets. Christian Leber Lehrstuhl Rechnerarchitektur Universität Mannheim

What is CSG150 about? Fundamentals of Computer Networking. Course Outline. Lecture 1 Outline. Guevara Noubir noubir@ccs.neu.

DNS Domain Name System

Chapter 3. Internet Applications and Network Programming

Chapter 11. User Datagram Protocol (UDP)

Porting and Deploying VoIP to IPv6: Lessons Learned

TFTP Usage and Design. Diskless Workstation Booting 1. TFTP Usage and Design (cont.) CSCE 515: Computer Network Programming TFTP + Errors

transmission media and network topologies client/server architecture layers, protocols, and sockets

Application Development with TCP/IP. Brian S. Mitchell Drexel University

Project 4: IP over DNS Due: 11:59 PM, Dec 14, 2015

Beej's Guide to Network Programming

Name and Address Conversions

RPG Does TCP/IP (Socket Progamming in RPG IV)

The difference between TCP/IP, UDP/IP and Multicast sockets. How servers and clients communicate over sockets

Transcription:

NS3 Lab 1 TCP/IP Network Programming in C Dr Colin Perkins School of Computing Science University of Glasgow http://csperkins.org/teaching/ns3/ 13/14 January 2015 Introduction The laboratory exercises for Networked Systems 3 (NS3) will introduce you to network programming in C on Unix/Linux systems, and help you understand how to use the network. There are weekly laboratory sessions for this course, during which you will complete several exercises. These exercises will build on your knowledge of C programming from the Advanced Programming 3 (AP3) course last semester, and introduce you to network programming in C. There are a mixture of formative and summative exercises. The formative exercises are intended to give you practice in programming networked systems in C; they are not assessed. The summative exercise tests your ability to use the network by developing a networked system. They are designed to complement the lectures, which explain how the network operates. This is NS3 lab 1, an introduction to TCP client/server programming in C. It comprises one formative C programming exercise that is expected to take about 2 hours and should be completed in the first two laboratory sessions. This laboratory exercise is not assessed, but is important to help you understand network programming, and also the principles of networked systems. Background The standard API for network programming in C is Berkeley Sockets. This API was first introduced in 4.3BSD Unix, and is now available on all Unix-like platforms including Linux, MacOS X, FreeBSD, and Solaris. A very similar network API is available on Windows. The standard reference book for the Berkeley Sockets API is W. R. Stevens, B. Fenner, and A. M. Rudoff, Unix Network Programming volume 1: The Sockets Networking API, 3rd Edition, Addison Wesley, 2003, ISBN 978-0131411555. Creating a Socket Sockets provide a standard interface between the network and application. There are two types of socket: a stream socket provides a reliable byte stream transport service, while a datagram socket provides unreliable delivery of individual data packets. When used in the Internet environment, stream sockets correspond to TCP/IP connections and datagram sockets to UDP/IP datagrams. This exercise will only consider TCP/IP stream sockets, as they are by far the most widely used. To use the sockets API, you must first include the appropriate header files: #include <sys/types.h> #include <sys/socket.h> 1

Once the headers have been included, you can create a socket by calling the socket function. This function returns an integer known as a file descriptor that identifies the newly created socket. int fd = socket(af_inet, SOCK_STREAM, 0); if (fd == -1) { (the shows that some application code has been omitted). The AF INET parameter to the socket() call indicates that the Internet address family (IPv4) is to be used; AF INET6 would create an IPv6 socket. The SOCK STREAM parameter indicates that a TCP stream socket is desired; use SOCK DGRAM to create a UDP datagram socket. The final parameter is not used with TCP or UDP sockets, and is set to zero. The socket that is created is unbound, and not yet connected to the network. If an error occurs, -1 is returned and the global variable errno is set to indicate the type of error. The Unix man page for the socket function lists the possible errors. A TCP/IP connection provides a reliable byte-stream connection between two computers. TCP/IP is most commonly used in a client-server fashion: the server creates a socket, binds it to a well-known port, and listens for connections; meanwhile, the client creates a socket, and connects to the specified port on the server. Ports are identified by 16-bit unsigned integers, and the IANA maintains a list of well-known ports for different applications. Once the connection is established, either client or server can write data into the connection, where it is available for the other party to read. TCP Server Sockets To make a newly created socket into a TCP server, it is first necessary to bind that socket to the appropriate well-known port. This is done using the bind() function, specifying the file descriptor, address, and port on which you wish to listen for connections: if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { As with the socket() function, -1 is returned and errno is set if an error occurs. The addr parameter to the bind() function is specified to be a pointer to a variable of type struct sockaddr. This structure is defined in the <sys/socket.h> header as follows: struct sockaddr { sa_family_t char sa_len; sa_family; sa_data[22]; The struct sockaddr is intended to be generic. The sa len and sa family fields hold the size and type of the address, while the sa data field is large enough to hold any type of address. It treats the address as an opaque piece of binary data. 2

Applications do not use a struct sockaddr directly. Rather, if they use IPv4 addresses, they instead use a struct sockaddr in: struct in_addr { in_addr_t s_addr; struct sockaddr_in { sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_pad[16]; or for IPv6 addresses, they use a struct sockaddr in6: struct in6_addr { s6_addr[16]; struct sockaddr_in6 { sin6_len; sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; These structures are defined in the <netinet/in.h> header, so you don t need to define them yourself. You will note that the struct sockaddr in is exactly the same size in bytes as the struct sockaddr, and has the sin len and sin family fields in exactly the same places as the sa len and sa family fields. The sa data field of the struct sockaddr is replaced by the sin port, sin addr and sin pad fields, which have the same total size. A struct sockaddr in can therefore be freely cast to a struct sockaddr, and vice versa, since they have the same size and the common fields are laid out in memory in the same way. The same is true for IPv6, with the struct sockaddr in6. These definitions allow for a primitive form on sub-classing, where the Sockets API takes a generic superclass (struct sockaddr) while the program uses a subclass specific to IPv4 (struct sockaddr in) or IPv6 (struct socaddr in6) and casts to/from struct sockaddr as appropriate. When creating a server, you need only specify the address family (IPv4 or IPv6) and the port to bind, allowing the system to listen on any available address. For example, an IPv4 server on port 80 would use: 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) { 3

Once a socket has been bound to a port, you can instruct the operating system to begin listening for connections on that port using the listen() function: int backlog = 10; if (listen(fd, backlog) == -1) {.. The value of the backlog parameter to the listen() function specifies how many simultaneous clients can be queued up waiting for their connections to be accepted by the server before the server returns a connection refused error to new clients (note: this is not the maximum number of clients that can be connected at once, but rather the maximum number of clients that can be waiting for the server to accept() their connection at once; a value of 10 is reasonable unless your server is very busy and also slow to accept connections). Finally, you can accept a new connection by calling the accept() function: int connfd; struct sockaddr_in cliaddr; socklen_t cliaddr_len = sizeof(cliaddr); connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen); if (connfd == -1) { If there are no clients waiting, then the accept() function will block until a client tries to connect. The cliaddr parameter will be filled in with the address of the client, and the cliaddrlen parameter will be set to the length of that address. The accept() function returns a new file descriptor, called connfd in this example, that represents the connection to this particular client (i.e., it s a new socket, connected to the client at the client at cliaddr). The original listening socket, and the corresponding file descriptor, remains untouched, and you can call accept() again on it to accept the next connection. A server application will call accept() in a loop to accept new connections from clients, then pass each connfd to a new thread for processing. Since there is only one listening socket, there s no benefit to calling accept() from multiple threads. TCP Client Sockets A TCP client can connect to a server by calling the connect() function. This function takes three parameters: the file descriptor of a newly created socket, the address and port of the server it should connect to (cast to a struct sockaddr), and the size of the address: struct sockaddr_in addr; // Or struct sockaddr_in6 if using IPv6 if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { 4

The difficulty with connect() comes with knowing the IP address of the server, to put into the struct sockaddr, since usually only the DNS name of the server is known and not the IP address. You can look up the IP address of a server given a DNS name using the getaddrinfo() function. This function takes as parameters the server name, port, and hints about the type of address required, and returns a linked list of possible IP addresses for the server (a server can have multiple IP addresses if it multiple network connections for robustness against network outages, or if it has both IPv4 and IPv6 addresses). You then need to iterate through the list of addresses, trying each in turn until you succeed in making a connection to the server. For example, to connect to a server called www.example.com on port 80, you would use code like: struct addrinfo hints; struct addrinfo *ai0; int i; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; // Can use either IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // Want a TCP socket if ((i = getaddrinfo("www.example.com", "80", &hints, &ai0))!= 0) { printf("error: unable to lookup IP address: %s", gai_strerror(i)); // ai0 is a pointer to the head of a linked list of struct addrinfo // values containing the possible addresses of the server; interate // through the list, trying to connect to each turn, stopping when // a connection succeeds: struct addrinfo *ai; int fd; for (ai = ai0; ai!= NULL; ai = ai->ai_next) { fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { // Unable to create socket, try next address in list continue; if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) { // couldn t connect to the address, try next in list close(fd); continue; break; // successfully connected if (ai!= NULL) { // Successfully connected: fd is a file descriptor of a socket // connected to the server; use the connection else { // Couldn t connect to any of the addresses, handle failure The Unix manual page for the getaddrinfo() function explains all the fields of the struct addrinfo, and explains how to use this function in more detail. 5

Sending and Receiving Data Once client and server are connected, you can send an receive data over the connection using the write() and read() functions. The write() function takes as arguments a file descriptor of a connected socket, a pointer to the data (char *), and the size of the data in bytes. It returns the number of bytes sent, or -1 if an error occurs: char *data; int datalen; if (write(fd, data, datalen) == -1) { // An error has occurred The read() function take as parameters a connected socket, a pointer to a buffer in which to store the data, and the size of the buffer. It returns the number of bytes read, or -1 if an error occurred: #define BUFLEN 1500 ssize_t rcount; char buf[buflen]; rcount = read(fd, buf, BUFLEN); if (rcount == -1) { // An error has occurred Note that the read() function does not add a terminating zero byte to the data it reads, so it is unsafe to use string functions on the data unless you add the terminator yourself. Note also that read() will silently overflow the buffer and corrupt memory if the buffer length passed to the function is too short. These are significant security risks, so care is needed. A TCP connection buffers data, so that data written with a single call to write() might be returned split across multiple read() calls. Alternatively, data from several write() requests might be combined and returned by a single read() call. Data will be delivered reliably and in-order when using TCP sockets, but the timing and record boundaries are not necessarily preserved. The read() call will block if there is nothing available to read from the socket. The write() call will block until it is able to send some data (write() may return after sending only some of the data requested, if the network is heavily congested). Closing the Connection Once you have finished with the connection, call the close() function to terminate it: close(fd); Remember to close both the client and server sockets. For the server socket, close the per-connection fd when you have finished with that connection, and the underlying fd when you have finished accepting new connections. 6

Formative Exercise 1: Networked Hello, World Application The first formative exercise demonstrates how to build the most simple client-server application using TCP/IP. You should write two programs: hello server The server should listen on TCP port 5000 for incoming connections. It should accept the first connection made, read all the data it can from that connection, print that data to the screen, close the connection, and exit. hello client Your client should connect to TCP port 5000 of a host named on the command line, send the text Hello, world!, then close the connection. The client should take the name of the machine on which the server is running as its single command line argument (i.e., if the server is running on machine bo720-1-01.dcs.gla.ac.uk you should run your client using the command hello client bo720-1-01.dcs.gla.ac.uk. Run your client and server, and demonstrate that you can send the text Hello, world! from one to the other. Try this with client and server running on the same machine, and with them running on two different machines. Once this is working, modify your client to send a much longer message (several thousand characters), and check that works too. When you have large messages working, modify your client and server so that the server can send a message back to the client. The client should send Hello, world!, then wait for and display the message sent back by the server. The contents of the message returned by the server are unimportant. Check that your server can handle connections from multiple clients without crashing, and without needing to be restarted. Write a simple Makefile to compile your code, rather than running the compiler by hand. You are strongly advised to enable all compiler warnings (at minimum, use gcc -W -Wall -Werror), and to fix your code so it compiles without warnings. Compiler warnings highlight code which is legal, but almost certainly doesn t do what you think it does (i.e., they show the location of bugs in your code). Use them to help you find problems. This exercise is not assessed, and you do not need to submit your code. The summative assessed web server exercise later in the course builds on the skills you will learn in completing this formative exercise, however, so you are advised to complete this exercise carefully, and seek help if you have any questions or problems in doing so, to ensure you understand the basics of network programming in C. A worked solution to this exercise will be provided at the start of the third laboratory session. 7