Chapter 3
Advanced Sockets
Functions
By
En. Mohd Nizam bin Osman
(Senior Lecturer)
Department of Computer Science
Faculty of Computer and Mathematical Science, UiTM Perlis
Course Outline
• select
• getsockname
• getpeername
• getsockopt
• shutdown
• gethostname
• gethostbyaddr
• gethostbyname
• getservbyname
• getservbyport
Sockets Function
SOCKETS FUNCTIONS
Function Description
select Provides event notification of socket events
getsockname Returns the address of the local socket
getpeername Returns the address of the remote socket
getsockopt Returns the value of a socket option for a given socket
setsockopt Manipulates a socket option for a given socket
shutdown Closes a socket with more control
gethostname Retrieves the name of the host on which this stack operates
sethostname Sets the name of the host on which this stack operates
gethostbyaddr Returns the FQDN for a given IP address
gethostbyname Returns the IP address for a given FQDN
getservbyname Returns the port number for a given service string
getservbyport Returns the service string for a given port number
Function
select()
int select (int maxDescPlus1, fd_set *readDescs, fd_Set
*writeDescs, fd_set *exceptionDescs, struct timeval
*timeout);
maxDescsPlus1: integer, hint of the maximum number of descriptors
readDescs: fd_set, checked for immediate input availability
writeDescs: fd_set, checked for the ability to immediately write data
exceptionDescs: fd_set, checked for pending exceptions
timeout: struct timeval, how long it blocks (NULL -> forever)
Client/sever model
Provides a notification service for a
Purpose collection of events on one or more
socket
Function
select()
returns the total number of ready descriptors:
Value Description
>0 Number of descriptors that are contained within the descriptor set
0 Expiration of the timeout argument
-1 An error occurred in the select function
Changes the descriptor lists so that only the corresponding positions
Client/sever
are set. model
int FD_ZERO (fd_set *descriptorVector); /* removes all descriptors from vector */
int FD_CLR (int descriptor, fd_set *descriptorVector); /* remove descriptor from vector */
int FD_SET (int descriptor, fd_set *descriptorVector); /* add descriptor to vector */
int FD_ISSET (int descriptor, fd_set *descriptorVector); /* vector membership check */
struct timeval{
time_ttv_sec;/* seconds */
time_ttv_usec;/* microseconds */
};
Function
getsockname()
int getsockname(int sockfd, struct sockaddr *addr, socklen_t
Client/sever model
*addrlen);
To return the local address of a given
Purpose socket
returns the current address to which the socket
sockfd is bound, in the buffer pointed to by
addr
0 is returned on success; -1 otherwise
Function
getpeername()
int getpeername(int
Client/sever model sockfd, struct sockaddr *addr,
socklen_t *addrlen);
To return the peer address of a given
Purpose socket (foreign address)
returns the address (IP and port) of the peer connected
to the socket sockfd, in the buffer pointed to by addr
0 is returned on success; -1 otherwise
Function: Socket Options
getsockopt()/setsockopt()
int getsockopt
Client/sever model (int sockid, int level, int optName, void
*optVal, socklen_t optLen);
sockid: integer, socket descriptor
level: integer, the layers of the protocol stack (socket, TCP, IP)
optName: integer, option
optVal: pointer to a buffer; upon return it contains the value of the specified option
optLen: integer, in-out parameter
int setsockopt(int sockid, int level, int optName, void
*optVal,
socklen_t
optLen is now optLen);
only an input parameter
It returns -1 if an error occurred
getsockopt and setsockopt allow socket
Purpose options values to be queried and set, respectively.
Socket Options
(Table)
Client/sever model
Socket Options
(Example)
“Fetch and then double the current number of bytes in the
Client/sever
socket’s modelbuffer”
receive
int rcvBufferSize;
int sockOptSize;
…
/* Retrieve and print the default buffer size */
sockOptSize= sizeof(recvBuffSize);
if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize,
&sockOptSize) < 0)
DieWithError(“getsockopt() failed”);
printf(“InitialReceive Buffer Size: %d\n”, rcvBufferSize);
/* Double the buffer size */
recvBufferSize*= 2;
/* Set the buffer size to new value */
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvBufferSize,
sizeof(rcvBufferSize)) < 0)
DieWithError(“getsockopt() failed”);
Function
shutdown()
int shutdown (int socket, int direction);
socket – A socket descriptor created by the socket
system call.
direction – the direction in which shutdown is desired: 0
means terminate further input, 1 means terminate further
output, and 2 means terminate both input and output
Returns 0 if successful and -1 an error has occurred.
Terminates a TCP connection in one or
Purpose both directions.
Function
gethostname()
int gethostname(char
Client/sever model *hostname, size_t size);
hostname - is a pointer to an array of chars that will contain
the hostname upon the function's return,
size - is the length in bytes of the hostname array.
It returns the name of the computer that your program is running
on.
The function returns 0 on successful completion, and -1 on error.
Permits the application to identify the
Purpose name of the host
Function: Domain Name Service
gethostbyaddr()
struct hostent *gethostbyaddr(const void *addr,
socklen_t len, int type);
returns a structure of type hostent for the given host address
addr of length len and address type type.
Used to identify the fully qualified domain name
Purpose of a host given its IP address
type struct hostent{
char *h_name; /* official name of host */
char **h_aliases; /* alias list (strings) */
int h_addrtype; /* host address type (AF_INET) */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses (binary in network byte order)*/
}
#define h_addrh_addr_list[0] /* for backward compatibility */
Function: Domain Name Service
gethostbyname()
struct hostent
Client/sever model *gethostbyname(const char
*name);
returns a structure of type hostent for the given host name.
name is a hostname, or an IPv4 address in standard dot notation.
e.g. gethostbyname(“www.csd.uoc.gr”);
Used to identify the IP address given a fully qualified
Purpose domain name
type struct hostent{
char *h_name; /* official name of host */
char **h_aliases; /* alias list (strings) */
int h_addrtype; /* host address type (AF_INET) */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses (binary in network byte order)*/
}
#define h_addrh_addr_list[0] /* for backward compatibility */
Function: Domain Name Service
getservbyname()
struct servent *getservbyname(const char
*name, const char *proto);
returns a servent structure for the entry from the database that matches
the service name using protocol proto.
if proto is NULL, any protocol will be matched.
Example: getservbyname(“echo”, “tcp”) ;
Takes a service name and protocol and yields among
Purpose other things, the port to be used to either register the
service or find the service.
struct servent{
char *s_name; /*official service name*/
char **s_aliases; /*list of alternate names(strings)*/
int s_port; /*service port number*/
char *s_proto; /*protocol to use (“tcp” or “udp”)*/
}
Function: Domain Name Service
getservbyport()
struct servent *getservbyport(int port, const
Client/sever model
char *proto);
returns a servent structure for the entry from the database
that matches the service name using port port
To identify the service and its characteristics given a port
Purpose number
struct servent{
char *s_name; /*official service name*/
char **s_aliases; /*list of alternate names(strings)*/
int s_port; /*service port number*/
char *s_proto; /*protocol to use (“tcp” or “udp”)*/
}
Useful Functions
int atoi (const char *nptr);
Client/sever
Convertsmodel
the initial portion of the string pointed to by nptr to int
int inet_aton(const char *cp, struct in_addr *inp);
Converts the Internet host address cp from IPv4 numbers-and-dots
notation into binary form (in network byte order)
Stores it in the structure that inp ponts to.
It returns nonzero if the address is valid, and 0 if not
char *inet_ntoa(struct in_addr in);
Converts the Internet host address in, given in network byte order,
to a string in IPv4 dotted-decimal notation
typedef uint32_t in_addr_t;
struct in_addr{
int_addr_t s_addr;
};
Iterative Stream Socket Server
Handles one client at a time.
Client/sever model
Additional clients can connect while one is being
served.
Connections are established.
They are able to send requests.
But, the server will respond after it finishes with the first
client.
Works well if each client required a small, bounded
amount of work by the server.
× Otherwise, the client experience long delays.
Iterative Stream Socket Server
Handles one client at a time.
Client/sever model
Additional clients can connect while one is being
served.
Connections are established.
They are able to send requests.
But, the server will respond after it finishes with the first
client.
Works well if each client required a small,
bounded amount of work by the server.
Otherwise, the client experience long
delays.
Iterative Server
Example: “Echo Server” using stream socket
//Iterative Server
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/
#define LISTENQ 8 /*maximum number of client connections */
int main ()
{
int listenfd, connfd, n;
socklen_t clilen;
char buf[MAXLINE];
struct sockaddr_in cliaddr, servaddr;
//creation of the socket
listenfd = socket (AF_INET, SOCK_STREAM, 0);
Iterative Server
Example: “Echo Server” using stream socket
//preparation of the socket address
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
printf("%s\n","Server running...waiting for connections.");
for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
printf("%s\n","Received request...");
while ( (n = recv(connfd, buf, MAXLINE,0)) > 0) {
printf("%s","String received from and resent to the client:");
puts(buf);
send(connfd, buf, n, 0);
}
Iterative Server
Example: “Echo Server” using stream socket
if (n < 0) {
perror("Read error");
exit(1);
}
close(connfd);
}
//close listening socket
close(listenfd);
}
Iterative Server
Example: “Echo Server” using stream socket
//Client
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define MAXLINE 4096 /*max text line length*/
#define SERV_PORT 3000 /*port*/
int main()
{
int sockfd;
struct sockaddr_in servaddr;
char sendline[MAXLINE], recvline[MAXLINE];
//Create a socket for the client
//If sockfd<0 there was an error in the creation of the socket
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) {
perror("Problem in creating the socket");
exit(2);
}
Iterative Server
Example: “Echo Server” using stream socket
//Creation of the socket
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr= inet_addr("127.0.0.1");
servaddr.sin_port = htons(SERV_PORT); //convert to big-endian order
//Connection of the client to the socket
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
perror("Problem in connecting to the server");
exit(3);
}
printf("Please enter string from the client: ");
while (fgets(sendline, MAXLINE, stdin) != NULL) {
send(sockfd, sendline, strlen(sendline), 0);
if (recv(sockfd, recvline, MAXLINE,0) == 0){
//error: server terminated prematurely
perror("The server terminated prematurely");
exit(4);
}
Iterative Server
Example: “Echo Server” using stream socket
printf("%s", "String received from the server: ");
fputs(recvline, stdout);
printf("Please enter string from the client: ");
}
exit(0);
}
Multitasking – Per-Client Process
For each client connection request, a new process is
Client/sever model
created to handle the communication.
int fork();
A new process is created, identical to the calling
process, except for its process ID and the return value it
receives from fork().
Return 0 to child process, and the process ID of the
new child to parent.
When a child process Use waitpid() to
terminates, it does not parent in order to
automatically disappears “harvest” zombies.
Multitasking – Per-Client Process
fork()
int fork(void);
Client/sever model
The fork function creates a new process.
The new process called the child process will be an exact
copy of the calling process (parent process). The child
process inherits many attributes from the parent process.
Upon successful completion, fork() returns 0 to the child
process and the process ID of the child process to the parent
process.
Otherwise -1 is returned to the parent process, no child
process is created and errno is set to indicate the error.
Multitasking – Per-Client Process
Example: fork()
#include <stdio.h> void ChildProcess(void)
#include <sys/types.h> {
Client/sever model
int i;
#define MAX_COUNT 200
for (i = 1; i <= MAX_COUNT; i++)
void ChildProcess(void); printf(" This line is from
/* child process prototype */ child, value = %d\n", i);
void ParentProcess(void); printf(" *** Child process
/* parent process prototype */ is done ***\n");
}
void main(void)
{ void ParentProcess(void)
pid_t pid; {
int i;
pid = fork();
if (pid == 0) for (i = 1; i <= MAX_COUNT; i++)
ChildProcess(); printf("This line is from
else parent, value = %d\n", i);
ParentProcess(); printf("*** Parent is done
} ***\n");
}
Multitasking – Per-Client Process
Example
To allow the server to handle multiple simultaneously
Client/sever model
connection:
Put the accept statement
After a connection is established, call
and the following code in an fork() to create a new process
infinite loop
The child process will close sockfd and call
doprocessing function, passing the new The parent process close newsockfd.
socket file descriptor as an argument. When
the two processes have completed their
As all of this code is in an infinite loop,
conversation, as indicated by it will return to the accept statement
doprocessing() returning, this process to wait for the next connection
simply exits.
Multitasking – Per-Client Process
Example: using fork()
//Server /* Initialize socket structure */
#include <stdio.h> bzero((char *) &serv_addr,
Client/sever model
#include <stdlib.h> sizeof(serv_addr));
portno = 5001;
#include <netdb.h>
#include <netinet/in.h> serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
#include <string.h> serv_addr.sin_port = htons(portno);
void doprocessing (int sock); /* Now bind the host address using bind()
call.*/
int main( int argc, char *argv[] ) { if (bind(sockfd, (struct sockaddr *)
int sockfd, newsockfd, portno, clilen; &serv_addr, sizeof(serv_addr)) < 0) {
char buffer[256]; perror("ERROR on binding");
struct sockaddr_in serv_addr, cli_addr; exit(1);
int n, pid; }
/* First call to socket() function */ /* Now start listening for the clients,
sockfd = socket(AF_INET, SOCK_STREAM, 0); here process will go in sleep mode and
will wait for the incoming connection
if (sockfd < 0) { */
perror("ERROR opening socket");
exit(1);
}
Multitasking – Per-Client Process
Example: using fork()
listen(sockfd,5); else {
clilen = sizeof(cli_addr); close(newsockfd);
Client/sever model }
while (1) { } /* end of while */
newsockfd = accept(sockfd, (struct }
sockaddr *) &cli_addr, &clilen);
void doprocessing (int sock) {
if (newsockfd < 0) { int n;
perror("ERROR on accept"); char buffer[256];
exit(1); bzero(buffer,256);
} n = read(sock,buffer,255);
/* Create child process */ if (n < 0) {
pid = fork(); perror("ERROR reading from socket");
exit(1);
if (pid < 0) { }
perror("ERROR on fork"); printf("Here is the message: %s\n",buffer);
exit(1); n = write(sock,"I got your message",18);
}
if (pid == 0) { if (n < 0) {
/* This is the client process */ perror("ERROR writing to socket");
close(sockfd); exit(1);
doprocessing(newsockfd); }
exit(0); }
}
Multitasking – Per-Client Process
Example: using fork()
//Client /* Create a socket point */
#include <stdio.h> sockfd = socket(AF_INET, SOCK_STREAM, 0);
Client/sever model
#include <stdlib.h>
#include <netdb.h> if (sockfd < 0) {
#include <netinet/in.h> perror("ERROR opening socket");
#include <string.h> exit(1);
}
int main(int argc, char *argv[]) {
int sockfd, portno, n; server = gethostbyname(argv[1]);
struct sockaddr_in serv_addr;
struct hostent *server; if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
char buffer[256]; exit(0);
}
if (argc < 3) {
fprintf(stderr,"usage %s hostname bzero((char *) &serv_addr,
port\n", argv[0]); sizeof(serv_addr));
exit(0); serv_addr.sin_family = AF_INET;
} bcopy((char *)server->h_addr, (char *)
&serv_addr.sin_addr.s_addr,
portno = atoi(argv[2]); server->h_length);
serv_addr.sin_port = htons(portno);
Multitasking – Per-Client Process
Example: using fork()
/* Now connect to the server */ /* Now read server response */
if (connect(sockfd, (struct sockaddr*) bzero(buffer,256);
Client/sever model
&serv_addr, sizeof(serv_addr)) < 0) { n = read(sockfd, buffer, 255);
perror("ERROR connecting");
exit(1); if (n < 0) {
} perror("ERROR reading from socket");
exit(1);
/* Now ask for a message from the user, }
this message will be read by server
*/ printf("%s\n",buffer);
return 0;
printf("Please enter the message: "); }
bzero(buffer,256);
fgets(buffer,255,stdin);
/* Send message to the server */
n = write(sockfd, buffer, strlen(buffer));
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
Multitasking – Per-Client Thread
Client/sever
Forkingmodela new process is expensive.
Duplicate the entire state (memory, stack,
file/socket descriptors, ….)
Threads decrease this cost by allowing
multitasking within the same process.
Threads share the same address space (code
and data)
An example is provided using POSIX
Threads
Multitasking – Per-Client Thread
Example: echo using stream socket
Client/sever model
Multitasking – Per-Client Thread
Example: echo using stream socket
Client/sever model
Multitasking – Constrained
Both process and thread incurred overhead.
Client/sever
Creation, model
scheduling and context switching
As their numbers increases:
This overhead increases
After some point it would be better if a client was blocked
Solution: Constrained multitasking. The server:
Begins, creating, binding and listening to a socket
Creates a number of processes, each loop forever and
accept connections from the same socket.
When a connection is established:
The client socket descriptors is returned to only one process.
The other remain blocked.
Multitasking – Constrained
Example: echo using stream socket
Client/sever model
Multiplexing
So far, we have dealt with a single I/O channel.
Client/sever model
We may need to cope with multiple I/O channels.
E.g., supporting the echo service over multiple ports.
Problem: From which socket the server should accept
connections or receive messages?
It can be solved using non-blocking sockets.
But it requires polling
Solution: select()
Specifies a list of descriptors to check for pending I/O
operations.
Blocks until one of the descriptors is ready.
Returns which descriptors are ready.
Multiplexing
Example: echo using stream socket
Client/sever model
Multiplexing
Example: echo using stream socket
Client/sever model
Multiple Recipients
So far, all sockets have dealt with unicast communication.
Client/sever model
i.e., an one-to-one communication, where one copy (“uni”) of the
data is sent (“cast”)
What if we want to send data to multiple recipients?
1st Solution: unicast a copy of data to each recipient
Inefficient, e.g.,
Consider we are connected to the internet through a 3Mbps
line
A video server send 1-Mbps streams
Then, server can support only three clients simultaneously.
2nd Solution: using network support
Broadcast, all the host of the network receive the message.
Multicast, a message is sent to some subset of the host
For IP, only UDP sockets are allowed to broadcast and multicast.
Multiple Recipients
Broadcast
Only the IP address changes
Client/sever model
Local broadcast: to address 255.255.255.255
Send the message to every host on the same broadcast network
Not forwarded by routers
Directed broadcast:
For network identifier 169.125 (i.e., with subnet mask
255.255.0.0)
The directed broadcast address is 169.125.255.255
In order to use broadcast the options of socket must change:
int bradcastPermission = 1;
setsocopt (soc, SOL_SOCKET,SO_BROADCAST, (void*)
&broadcastPermission, sizeof(broadcastPermission));
Multiple Recipients
Multicast
Client/sever
Using class model
D addresses
Range from 224.0.0.0 to 239.255.255.255
Hosts send multicast request for specific
addresses
A multicast group formed
We need to set TTL (time-to-live), to limit the
number of hops
Using sockopt()
No need to change the options of socket
The End
Q&A