Introduction To Network Programming
Introduction To Network Programming
CSC 343643
WAKE FOREST
U N I V E R S I T Y
E. W. Fulp
Fall 2007
E. W. Fulp
Fall 2007
sa_family identies the address family (AF_INET) sa_data contains a network address Prefer something more IP specic, which is sockaddr_in
E. W. Fulp
Fall 2007
// // // //
E. W. Fulp
Fall 2007
sa_family
sa_data
sockaddr
8 bytes unused
sin_zero
sockaddr_in
family
sin_family sin_port
Socket calls are generic (sockaddr) but we will use Internet addresses (sockaddr_in) Since the structs are the same size (parallel) cast
E. W. Fulp
Fall 2007
Byte Order
As you may recall... There are two types of byte orderings Most signicant byte rst (also called network byte order) Least signicant byte rst Computers (based on architecture) will use one or the other Therefore we need to be consistent... remember to convert How do we convert? Use the following functions htons() is host to network short htonl() is host to network long ntohs() is network to host short ntohl() is network to host long
E. W. Fulp
Fall 2007
Address Example
Create an address for www.cs.wfu.edu web server
#include<arpa/inet.h> // for sockaddr_in and inet_addr #include<string.h> // for memset struct sockaddr_in wfuAddr; // address for www.cs.wfu.edu wfuAddr.sin_family = AF_INET; // Internet address wfuAddr.sin_port = htons(80); // port (network byte order) // copy IP address (ascii to network byte order) inet_aton("152.17.140.92", &(wfuAddr.sin_addr)); // zero the rest of the struct memset(&(wfuAddr.sin_zero), \0, 8); // print the address to the screen cout << inet_ntoa(wfuAddr.sin_addr) << \n;
E. W. Fulp
Fall 2007
Creating a Socket
Before sending/receiving must create a socket Must specify, protocol family (PF_INET), type (SOCK_DGRAM or SOCK_STREAM), and protocol (0 for default)
#include <sys/socket.h> // for socket() int sock; // stores the socket descriptor if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) { cerr << "Could not create socket \n"; exit(1); }
Returns the socket number, -1 if error Once done with the socket, your program must close it (like a le)
close(sock);
E. W. Fulp
Fall 2007
TCP or UDP
There are two types of services available in the Internet User Datagram Procotol (UDP) is an unreliable transmission Transport Control Protocol (TCP) is a reliable stream Service must be specied once the socket is created Creating the socket with SOCK_DGRAM uses UDP
sock = socket(PF_INET, SOCK_DGRAM, 0)
E. W. Fulp
Fall 2007
10
/ /
bind
/ /
listen
/ /
accept close
recv/send E
/ close
connect
send/recv E
E. W. Fulp
Fall 2007
11
TCP Client
TCP client must perform the following four steps 1. Create a TCP socket using socket 2. Establish connection to server using connect 3. Communicate using send and recv 4. Close the connection with close / connect / send/recv socket E Already discussed how to create a socket Be certain the socket is SOCK_STREAM for TCP / close
E. W. Fulp
Fall 2007
12
Connect will perform three-way handshake Once connected, client and server can send and recv data Would UDP use the connect function?
E. W. Fulp
Fall 2007
13
TCP send
To send data (TCP only) the program must supply Socket, pointer to data, data length, and ags
int send(int sock, const void *msg, unsigned int msgLength, int flags);
send() will return the number of bytes sent How does send know which address and port to send to?
E. W. Fulp
Fall 2007
14
TCP recv
To recv data (TCP only) the program must supply Socket, pointer to buer, maximum buer length, and ags
int recv(int sock, void *buffer, unsigned int bufferLength, int flags);
recv() returns the number of bytes read Blocks until data received or timeout Data is placed in the buffer
E. W. Fulp Fall 2007
15
Closing a Socket
Once communication over a socket is complete, you must close Specify the socket and use the close() function
#include<unistd.h> close(sock);
E. W. Fulp
Fall 2007
16
17
struct sockaddr_in srvAddr; // address of time server srvAddr.sin_family = AF_INET; // Internet address srvAddr.sin_port = htons(13); // port 13 srvAddr.sin_addr.s_addr = inet_addr("152.17.140.3"); memset(&(srvAddr.sin_zero), \0, 8); // set remaining to zero if(connect(sock, (struct sockaddr *) &srvAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not connect to server \n"; exit(2); } // to receive the time, just ask the question... char* msg = "What time is it?"; if(send(sock, msg, strlen(msg) + 1, 0) == -1) { cerr << "Could not send to socket \n"; exit(3); }
E. W. Fulp
Fall 2007
18
char buffer[256]; // stores the data received from socket // will block until datagram received from socket if(recv(sock, buffer, 256, 0) == -1) { cerr << "Could not receive from socket \n"; exit(4); } cout << buffer << \n; close(sock); return 0; }
2
> tcpTime Mon Nov 24 12:15:47 2003
Terminal
22
E. W. Fulp
Fall 2007
19
TCP Server
TCP server must complete the following six steps 1. Create a TCP socket using socket 2. Assign a port number to the socket using bind 3. Tell system to allow connections to port using listen 4. Accept connection request using accept 5. Communicate using recv and send via new socket 6. Close the connection using close x / accept
socket
/ bind
/ listen
/ recv/send E
/ close
E. W. Fulp
Fall 2007
20
TCP bind
To bind a port to an address the program must supply Socket, address, and address length
int bind(int sock, struct sockaddr *localAddr, unsigned int addrLength);
E. W. Fulp
Fall 2007
21
TCP listen
To listen for a connection request the program must supply Socket and queue limit
int listen(int sock, int queueLimit);
queueLimit is the maximum outstanding requests Assume we wanted to listen for incoming connections
#define MAX_PENDING 5 // maximum outstanding requests if(listen(sock, MAX_PENDING) < 0) { cerr << "Could not listen on socket \n"; exit(1); }
22
TCP accept
To accept an incomming connection the program must supply Socket, client address, and address length
int accept(int sock, struct sockaddr *clientAddress, unsigned int *addrLength);
E. W. Fulp
Fall 2007
23
accept() returns a descriptor for a new socket Dequeues the next connection on the socket queue Creates a new socket for arriving connection Sets the address and address length variables If the queue is empty, then block If error then accept returns -1 After accept() program can recv() and send() As described there are two sockets, one for receiving a connection request and another created for the connection Which socket is used for sending and which socket is used for receiving? The socket that has been bound to a port and marked listening is never used for sending and receiving in TCP
E. W. Fulp Fall 2007
24
E. W. Fulp
Fall 2007
25
E. W. Fulp
Fall 2007
26
// establish connection with server if(connect(sock, (struct sockaddr *) &srvAddr, sizeof(struct sockaddr)) < 0) { cerr << "Could not connect \n"; exit(2); } char* msg = "Hello from client"; // c-string to send if(send(sock, msg, strlen(msg) + 1, 0) == -1) { cerr << "Could not send to socket \n"; exit(3); } char buffer[256]; // stores the data received from socket unsigned int addrLength = sizeof(sockaddr); int numBytes = 0; if((numBytes = recv(sock, buffer, 256, 0)) <= 0) { cerr << "Could not receive from socket \n"; exit(4); } cout << buffer << \n; close(sock); return 0; }
E. W. Fulp
Fall 2007
27
E. W. Fulp
Fall 2007
28
if(bind(sock, (struct sockaddr*) &myAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not bind to port \n"; exit(2); } if(listen(sock, 0) < 0) { cerr << "Could not listen to socket \n"; exit(3); } int clientSock; // client socket struct sockaddr_in clientAddr; // client address unsigned int clientAddrLength = sizeof(struct sockaddr_in); if((clientSock = accept(sock, (struct sockaddr *) &clientAddr, &clientAddrLength)) < 0) { cerr << "Could not accept connection \n"; exit(4); } char buffer[256]; // data received from socket if(recv(clientSock, buffer, 256, 0) == -1) { cerr << "Could not receive from socket \n"; exit(3); } cout << buffer << \n;
E. W. Fulp
Fall 2007
29
char *reply = new char[strlen("Hello ") + strlen(inet_ntoa(destAddr.sin_addr)) + 1]; strcpy(reply, "Hello "); strcat(reply, inet_ntoa(clientAddr.sin_addr)); if(send(clientSock, reply, strlen(reply) + 1, 0)) == -1) { cerr << "Could not send to socket \n"; exit(4); } close(sock); return 0; }
Terminal
22 2
3
Terminal
22
4
E. W. Fulp
Fall 2007
30
UDP Sockets
Datagram sockets are connectionless and do not have connection setup Client socket, create new end point sendto and recvfrom, transmit data Server socket, creates a new end point bind, binds an address to the connection sendto and recvfrom, transmit data
server client socket socket
/ /
bind
/ /
recvfrom recvfrom
/ /
sendto close
close
sendto Z
E. W. Fulp
Fall 2007
31
Client does not establish a connection connect is not needed Server does not accept a connection listen is not needed accept is not needed What is the implication of no established connection? Does the server still wait for datagrams? In TCP accept assigned a new socket to the incoming data, how will communication take place in UDP?
E. W. Fulp
Fall 2007
32
Datagram sendto()
To sendto() the program must specify Socket, data, data length, ags, to address, to address length
int sendto(int sock, const void *msg, int len, unsigned int flags, const struct sockaddr *toAddr, int toLength);
E. W. Fulp
Fall 2007
33
Datagram recvfrom()
Similarly, to recvfrom() the program must specify Socket, buer (to store data), buer length, ags, from address, and from address length
int recvfrom(int sock, void *buffer, int bufferLength, unsigned int flags, struct sockaddr *fromAddr, int *fromLength);
recvfrom() returns the number of data bytes, -1 if error fromAddr stores the datagram address addrLength stores the address length must be initialized
E. W. Fulp Fall 2007
34
35
struct sockaddr_in srvAddr; // address of time server srvAddr.sin_family = AF_INET; // Internet address srvAddr.sin_port = htons(13); // port 13 srvAddr.sin_addr.s_addr = inet_addr("152.17.140.13"); memset(&(srvAddr.sin_zero), \0, 8); // set remaining to zero // to receive the time, just ask the question... char* msg = "What time is time?"; if(sendto(sock, msg, strlen(msg) + 1, 0,(struct sockaddr*) &srvAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not send to socket \n"; exit(2); }
E. W. Fulp
Fall 2007
36
char buffer[256]; // stores the data received from socket unsigned int addrLength = sizeof(sockaddr); // will block until datagram received from socket if(recvfrom(sock, buffer, 256, 0, (struct sockaddr*) &srvAddr, &addrLength) == -1) { cerr << "Could not receive from socket \n"; exit(3); } close(sock); cout << buffer << \n; return 0; }
2
> udpTime Mon Nov 24 12:15:47 2003
Terminal
22
E. W. Fulp
Fall 2007
37
E. W. Fulp
Fall 2007
38
39
char* msg = "Hello from client"; // c-string to send if(sendto(sock, msg, strlen(msg) + 1, 0, (struct sockaddr*) &srvAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not send to socket \n"; exit(2); } char buffer[256]; // stores the data received from socket unsigned int addrLength = sizeof(sockaddr); if(recvfrom(sock, buffer, 256, 0, (struct sockadddr*) &srvAddr, &addrLength) == -1) { cerr << "Could not receive from socket \n"; exit(3); } cout << buffer << \n; close(sock); return 0; }
E. W. Fulp Fall 2007
40
41
if(bind(sock, (struct sockaddr*) &myAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not bind to port \n"; exit(1); } struct sockaddr_in destAddr; // destination (client) address unsigned int destAddrLength = sizeof(struct sockaddr); char buffer[256]; // data received from socket if(recvfrom(sock, buffer, 256, 0, (struct sockadddr*) &destAddr, &destAddrLength) == -1) { cerr << "Could not receive from socket \n"; exit(3); } cout << buffer << \n;
E. W. Fulp
Fall 2007
42
char *reply = new char[strlen("Hello ") + strlen(inet_ntoa(destAddr.sin_addr)) + 1]; strcpy(reply, "Hello "); strcat(reply, inet_ntoa(destAddr.sin_addr)); if(sendto(sock, reply, strlen(reply) + 1, 0, (struct sockaddr*) &destAddr, sizeof(struct sockaddr)) == -1) { cerr << "Could not send to socket \n"; exit(4); } close(sock); return 0; }
Terminal
22 2
3
Terminal
22
4
E. W. Fulp
Fall 2007