Socket Programming

Download Report

Transcript Socket Programming

Socket Programming
UNIX Network Programming,
Socket Programming Tutorial:
http://beej.us/guide/bgnet/
2: Application Layer
1
Socket basics
 Socket: a door between application process and end-end-transport
protocol (UDP or TCP)
 Each host has 65,536 ports
 Some ports are reserved, for example:



HTTP: 80
FTP: 20, 21
Telnet: 23
 sender explicitly attaches destination IP address and destination
port number to each packet
 server extracts IP address, port of sender from received packet
2: Application Layer
2
High Level View of a Socket: 5-tuple
 Type of socket: TCP or UDP
 Local Port
 Local IP address
 Peer’s port (optional for UDP)
 Peer’s IP address (optional for UDP)
2: Application Layer
3
Struct sockaddr
Generic:
struct sockaddr {
u_short sa_family; /* which address family */
char sa_data[14]; /* the remaining 14 bytes */
};
For the Internet:
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct in_addr {
u_long s_addr;
};
/* AF_INET */
/* port 0-65535 */
/* IP-address */
/* unused */
/* 32-bit netid/hostid */
/* network byte ordered */
2: Application Layer
4
Byte Ordering: Address and Port
 Different Machines use different byte order for storing integers


u_short sin_port is 16 bits
in_addr sin_addr is 32 bits
 Big Endian Notation


Most Significant Byte (MSB) to Least Significant Byte (LSB)
The IP address 164.107.112.44 will be stored as 164 107
112
44
107
164
 Little Endian Notation


LSB to MSB
The IP address 164.107.112.44 will be stored as
44
112
 Internet messages must follow Big Endian ordering
2: Application Layer
5
Byte Ordering Functions
for handling byte order differences between Internet and some OSes
host
network
 u_long htonl (u_long hostlong);
 u_short htons (u_short hostshort);
 u_long ntohl (u_long netlong);
 u_short ntohs (u_short netshort);
These functions implicitly assume that short is 16 bits and long is 32 bits
If host order is same as network order, the function simply returns the
argument
2: Application Layer
6
Socket System Calls for UDP
Server
socket()
application viewpoint
UDP provides unreliable data delivery
service between client and server
bind()
Client
recvfrom()
socket()
Time
blocks until data
received from client
bind()
data (request)
process data
sendto()
sendto()
data (reply)
recvfrom()
2: Application Layer
7
socket():
returns socket descriptor for use by later system calls, or -1 on error.
 int socket (int family, int type, int protocol);
 family: set to AF_INET
 type



SOCK_STREAM : for TCP
SOCK_DGRAM : for UDP
SOCK_RAW
: for IP (bypasses transport layer)
 protocol to "0" to have socket() choose the correct protocol based
on the type
 Example

sockfd = socket(AF_INET, SOCK_STREAM, 0);
2: Application Layer
8
bind():
assigns a port to an unnamed socket
 int bind (int sockfd, struct sockaddr *myaddr, int addrlen);
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(5000); // short, network byte order
my_addr.sin_addr.s_addr = inet_addr("10.12.110.57");
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
2: Application Layer
9
sendto(), recvfrom():
send and receive through UDP sockets
 int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct
sockaddr *to, int tolen);

Returns number of bytes sent
 int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr
*from, int *fromlen);

Returns number of bytes received
 flag is normally set to 0
2: Application Layer
10
#define PORT_NUM
1050 // Port number used
void main(void)
{
unsigned int
server_s;
// Server socket descriptor
struct sockaddr_in server_addr; // Server1 Internet address
struct sockaddr_in client_addr; // Client1 Internet address
int
addr_len;
// Internet address length
char
out_buf[100]; // 100-byte buffer for output data
char
in_buf[100]; // 100-byte buffer for input data
long int
i;
// Loop counter
server_s = socket(AF_INET, SOCK_DGRAM, 0);
UDP
server
// Fill-in my socket's address information
server_addr.sin_family
= AF_INET;
// Address family to use
server_addr.sin_port
= htons(PORT_NUM); // Port number to use
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Listen on any IP address
bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr));
addr_len = sizeof(client_addr);
recvfrom(server_s, in_buf, sizeof(in_buf), 0,
(struct sockaddr *)&client_addr, &addr_len);
printf("Message received is: '%s' \n", in_buf);
strcpy(out_buf, "Reply message from server1 to client1");
sendto(server_s, out_buf, (strlen(out_buf) + 1), 0,
(struct sockaddr *)&client_addr, sizeof(client_addr));
close(server_s);
}
2: Application Layer
11
#define PORT_NUM
1050 // Port number used
#define IP_ADDR "131.247.166.56" // IP address of server1
void main(void)
{
unsigned int
client_s;
// Client socket descriptor
struct sockaddr_in
server_addr;
// Server Internet address
int
addr_len;
// Internet address length
char
out_buf[100];
// 100-byte buffer for output data
char
in_buf[100];
// 100-byte buffer for input data
client_s = socket(AF_INET, SOCK_DGRAM, 0);
// Fill-in server1 socket's
server_addr.sin_family
server_addr.sin_port
server_addr.sin_addr.s_addr
UDP
client
address information
= AF_INET;
// Address family to use
= htons(PORT_NUM);
// Port num to use
= inet_addr(IP_ADDR); // IP address to use
// Assign a message to buffer out_buf
strcpy(out_buf, "Test message from client1 to server1");
sendto(client_s, out_buf, (strlen(out_buf) + 1), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr));
addr_len = sizeof(server_addr);
recvfrom(client_s, in_buf, sizeof(in_buf), 0,
(struct sockaddr *)&server_addr, &addr_len);
printf("Message received is: '%s' \n", in_buf);
close(client_s);
}
2: Application Layer
12
Socket-programming using TCP
TCP service: reliable transfer of bytes from one
process to another
controlled by
application
developer
controlled by
operating
system
process
process
socket
TCP with
buffers,
variables
socket
TCP with
buffers,
variables
host or
server
internet
controlled by
application
developer
controlled by
operating
system
host or
server
2: Application Layer
13
Socket System Calls for TCP
Server
socket()
bind()
listen()
Client
accept()
Time
blocks until connection
from client
socket()
connection establishment
data (request)
recv()
send()
connect()
send()
data (reply)
recv()
2: Application Layer
14
listen():
sets limit on the maximum number of unprocessed incoming requests
 int listen (int sockfd, int backlog);
 backlog is the number of connections allowed
on the incoming queue
 typical default is 20
2: Application Layer
15
accept():
takes the first queued connection request and creates a new socket call
blocks if no pending requests
 int accept (int sockfd, void *peer, int *addrlen);
 sockfd is the socket descriptor
 peer will usually be a pointer to a local struct sockaddr_in to find out which
host is calling from which port
listen(sockfd, 10);
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
2: Application Layer
16
accept():
for (; ;) {
newsockfd = accept (sockfd, …); /* blocks */
if (newsockfd < 0) {
fprintf(stderr,“accept error”);
exit(0);
}
do_something(newsockfd); /*process the request */
close (newsockfd);
Iterative
Server
}
for (; ;) {
Concurrent
Server
}
newsockfd = accept (sockfd, …); /* blocks */
if (newsockfd < 0) {
fprintf(stderr,“accept error”);
exit(0);
}
if (fork() == 0) {
close(sockfd); /* child */
do_something(newsockfd); /*process the request */
exit(0);
}
close (newsockfd);
2: Application Layer
17
connect():
establishes connection with the server
does not return till connection is established or fails to connect
 int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);
 serv_addr is a struct sockaddr containing the destination port and IP address,
 addrlen is set to sizeof(struct sockaddr)
 Handshake messages are exchanged between the peers
 If called before bind(), OS automatically assigns a port
 If sockfd is a UDP socket, OS stores peer specific information from serv_addr
 Subsequent calls for reading and writing do not require destination address or port
number
sockfd = socket(AF_INET, SOCK_STREAM, 0);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(DEST_PORT); // short, network byte order
dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
memset(&(dest_addr.sin_zero), '\0', 8); // zero the rest of the struct
connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
2: Application Layer
18
send(), recv():
to send and recv data through TCP sockets or connect-ed UDP sockets
 int send (int sockfd, const void *msg, int len, int flags);

Returns the number of bytes sent
 int recv (int sockfd, void *buf, int len, unsigned int flags);

Returns the number of bytes received
 flag is normally set to 0
2: Application Layer
19
select()
to enable a process to wait for events on multiple sockets
 int select (int maxfdpl, fd_set *readfds, fd_set *writefds, fd_set






*execptfds, struct timeval * timeout);
Returns the number of ready descriptors or, -1 if none
maxfdpl: 1+ largest file descriptor to check
readfds: List of descriptors for checking if ready to read
writefds: List of descriptors for checking if ready to write
exceptfds: List of descriptors for checking if any exceptions
timeout: timeout value to wait, NULL for infinite timeout
struct timeval {
long tv_set;
long tv_usec;
}
/* seconds */
/* microseconds */
2: Application Layer
20
select() (contd.)
Macros for setting/resetting/checking bits corresponding to sockets
 FD_ZERO (int fd, fd_set *fd_set);
/* clear all bits in fdset */
 FD_SET (int fd, fd_set *fd_set);
/* turn on the bit for fd */
 FD_CLR (int fd, fd_set *fd_set);
/* turn off the bit for fd */
 FD_ISSET (int fd, fd_set *fdset);
/* test the bit for fd in fdset */
2: Application Layer
21
Select example
fd_set read_fd_set;
....
/* Initialize the set of active sockets. */
FD_ZERO (&read_fd_set);
FD_SET (sock1, &read_fd_set);
FD_SET (sock2, &read_fd_set);
while (1)
{
/* Block until input arrives on one or more active sockets. */
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
{
perror ("select");
exit (EXIT_FAILURE);
}
if (FD_ISSET (sock1, &read_fd_set))
{
// sock1 is ready to be read
}
if (FD_ISSET (sock2, &read_fd_set))
{
// sock2 is ready to be read
}
FD_ZERO (&read_fd_set);
FD_SET (sock1, &read_fd_set);
FD_SET (sock2, &read_fd_set);
}
}
2: Application Layer
22
close() :
to close a socket
 close (sockfd)


frees socket descriptor
frees the associated port
2: Application Layer
23
Address Conversion Routines
for conversion between dotted-decimal format and in_addr structure
 int
inet_aton(const char *cp, struct in_addr *inp)
 Dotted decimal string to internet address
 char * inet_ntoa (struct in_addr inaddr);
 Internet address to string format
2: Application Layer
24
Some other useful functions:
 Socket Address


getsockname: get IP and port of a socket
getpeername: get IP and port of the other end of the socket
 Host Name

Gethostname
 Host Information


gethostbyname: get IP address from machine name
gethostbyaddr: get machine name from IP address
 Other send recv functions

sendmsg/recvmsg
2: Application Layer
25
#define PORT_NUM
1050
// Arbitrary port number for the server
void main(void)
{
unsigned int
server_s;
// Server socket descriptor
struct sockaddr_in
server_addr;
// Server Internet address
unsigned int
connect_s;
// Connection socket descriptor
struct sockaddr_in
client_addr;
// Client Internet address
struct in_addr
client_ip_addr; // Client IP address
int
addr_len;
// Internet address length
char
out_buf[100];
// 100-byte output buffer for data
char
in_buf[100];
// 100-byte input buffer for data
server_s = socket(AF_INET, SOCK_STREAM, 0);
TCP
server
// Fill-in my socket's address information and bind the socket
server_addr.sin_family
= AF_INET;
// Address family to use
server_addr.sin_port
= htons(PORT_NUM);
// Port number to use
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Listen on any IP address
bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(server_s, 1);
// Accept a connection. The accept() will block and then return with
// connect_s assigned and client_addr filled-in.
addr_len = sizeof(client_addr);
connect_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len);
2: Application Layer
26
memcpy(&client_ip_addr, &client_addr.sin_addr.s_addr, 4);
printf("Accept completed!!! IP address of client = %s port = %d \n",
inet_ntoa(client_ip_addr), ntohs(client_addr.sin_port));
TCP
server
(contd.)
strcpy(out_buf, "Test message from server to client");
send(connect_s, out_buf, (strlen(out_buf) + 1), 0);
recv(connect_s, in_buf, sizeof(in_buf), 0);
printf("Received from client... data = '%s' \n", in_buf);
close(server_s);
close(connect_s);
}
2: Application Layer
27
#define
#define
PORT_NUM
1050
IP_ADDR "131.247.166.56"
void main(void)
{
unsigned int
struct sockaddr_in
char
char
// Port number used at the server
// IP address of server
client_s;
server_addr;
out_buf[100];
in_buf[100];
//
//
//
//
Server socket descriptor
Server Internet address
100-byte output buffer for data
100-byte input buffer for data
client_s = socket(AF_INET, SOCK_STREAM, 0);
// Fill-in the client socket's address information and do a connect with
// the listening server.
server_addr.sin_family
= AF_INET;
// Address family to use
server_addr.sin_port
= htons(PORT_NUM);
// Port num to use
server_addr.sin_addr.s_addr = inet_addr(IP_ADDR); // IP address to use
connect(client_s, (struct sockaddr *)&server_addr, sizeof(server_addr));
TCP
client
recv(client_s, in_buf, sizeof(in_buf), 0);
printf("Received from server... data = '%s' \n", in_buf);
strcpy(out_buf, "Test message from client to server");
send(client_s, out_buf, (strlen(out_buf) + 1), 0);
close(client_s);
}
2: Application Layer
28
MSG_WAITALL
 This flag is useful for blocking recv
 MSG_WAITALL requests blocking until all the requested bytes have
been read.

Unless a signal is caught or an error or disconnect happens
 Note that recv() by default does not wait for all the bytes specified in
the argument.
 But send() by default writes all the bytes to the local buffer in the
kernel. If space is not available, it keeps writing/copying as space
becomes available and returns when the entire buffer has been
written/copied to the local buffer in the kernel.
2: Application Layer
29