You are on page 1of 24

C Socket Programming Tutorial SHARE Session 5959

Writing Client/Server Programs in C


Using Sockets (A Tutorial)
Part II

Session 5959

Greg Granger
grgran@sas.com

SAS/C & C++ Support


SAS Institute
Cary, NC
SAS Institute Inc Slide 1
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Remote Execution Sample Program


U Remote Execution Connection Diagram
U getservbyname() coding
U rexec() function declaration
U gethostbyname() and struct hostent
U rexec() caller source code examination
U System call return conventions
U Socket address structures and conventions
U recv() and send() conventions
U File descriptor sets and select()

SAS Institute Inc Slide 2


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Remote Execution Connection Diagram


Client issues:
rexec server.unx mark mypass ls -l

host.mvs server.unx
<child>
stdout
Primary
exec cmd
Socket
rexeccmd (ls -l)
stdin
rexec
stderr (pipe)

Secondary
Socket rexecd
<parent>

SAS Institute Inc Slide 3


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

REXEC Initial Connection


host.mvs server.unx

inetd
rexeccmd
Primary
rexec
Socket rexecd

client issues: rexecd issues:


rexeccmd.c
[53] getservbyname() socket()
[60] rexec() bind()
rexec.c listen()
[61] gethostbyname() select()
[70] socket() accept()
[79] connect()
SAS Institute Inc Slide 4
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

getservbyname() Coding
getservbyname() returns NULL for failure or a pointer to this structure for success:
struct servent {
char *s_name; /* official name */
char **s_aliases; /* array of aliases */
int s_port; /* well-known port */
char *s_proto; }; /* protocol to use (udp/tcp) */

On UNIX the data comes from the “/etc/services” file formatted like the following:

exec 512/tcp # remote execution


login 513/tcp # remote login
who 513/udp whod # remote who and uptime

SAS Institute Inc Slide 5


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

rexec() Function Declaration


int rexec( /* Returns primary socket */

char **host, /* Pointer to hostname by */


/* reference */

int port, /* Port for rexecd server */

char *username, /* Username on remote host */

char *passwd, /* Password on remote host */

char *cmd, /* Command to execute */

int *ptr_secondary /* Place to store secondary */

SAS Institute Inc Slide 6


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

gethostbyname() Coding
Gethostbyname() returns NULL for failure or a pointer to this structure for success:
Struct hostent {
char *h_name; /* Official name */
char **h_aliases; /* array of aliases */
int h_addrtype; /* AF_INET for TCP/IP */
int h_length; /* sizeof(struct in_addr) for TCP/IP */
char **h_addr_list; /* points to array of struct in_addr */
#define h_addr h_addr_list[0]}; /* Primary IP address */

Here is an example of printing the IP address:


struct hostent *he;
char * host = ”ahost.unx.sas.com";
struct in_addr *ia;

he = gethostbyname(host);
ia = (struct in_addr *)(he->h_addr);
printf("IP address: %s\n",inet_ntoa(*ia));

SAS Institute Inc Slide 7


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

“struct hostent” diagram


char[]
tools.sas.com
Struct hostent
array of char[]
char *
char *h_name server1.sas.com

char **h_aliases char[]


bigserver.sas.com
int h_addrtype AF_INET 0

int h_length 4 array of


char *
struct in_addr
char **h_addr_list
149.179.3.3

0 struct in_addr
154.166.17.231

SAS Institute Inc Slide 8


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

System Call Return Conventions


U Most system calls have the same return
conventions
U An int value >= 0 indicates success; -1 indicates
failure.
U Failed calls set “errno” to indicate the cause of
failure; perror() will print a message based on the
“errno” value.
U Here is the typical coding logic:
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror(“socket() failed”);
exit(EXIT_FAILURE); }
SAS Institute Inc Slide 9
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Socket Address Structures


Socket address formats vary. Each format is called an “addressing family”.
The generic format is:
struct sockaddr {
u_short sa_family; /* Addressing family */
char sa_data[14]; }; /* varies */

AF_INET is the addressing family for TCP/IP. It’s format is:


struct in_addr {
u_long s_addr; }; /* net byte order */

struct sockaddr_in {
short sin_family; /* AF_INET */
u_short sin_port; /* TCP or UDP port */
struct in_addr sin_addr; /* IP address */
char sin_zero[8]; }; /* varies */

SAS Institute Inc Slide 10


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Socket Address Conventions


U For connect(), the port and IP address must be
specified.
U For bind(), either may be set to zero.
U Specifying “sin_port” as zero requests that the
system assign a transient port. Use getsockname()
to find out what port number was chosen.
U Specifying “sin_addr” as zero binds to all IP
addresses on the host (some hosts have more than
one).

SAS Institute Inc Slide 11


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

inetd Create Server Program


host.mvs server.unx

inetd
rexeccmd fork()
Primary
rexec
Socket

exec()

rexec.c lines [79 - 82] rexecd

Server creation program (inetd) issues a fork() and exec() call to start
rexecd. The socket descriptor is attached to stdin, stdout and stderr
of rexecd.

SAS Institute Inc Slide 12


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Server Creation Socket Close


host.mvs server.unx

inetd
rexeccmd close()
Primary
rexec
Socket

rexec.c lines [79 - 82] rexecd

Server creation program (inetd) issues a


close() to close it’s connection to the socket,
then waits for a new client connection.

SAS Institute Inc Slide 13


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Client Establishes stderr port


host.mvs server.unx

rexeccmd
Primary stdin/stdout/stderr
rexec rexecd
Socket

rexec.c lines [83 - 140]

Rexecd reads stdin until a null character is found, if any


characters are read before the null they are interpreted as
an optional secondary port address to be used for stderr.

SAS Institute Inc Slide 14


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

recv() and send() conventions


U recv() returns 0 for EOF; >0 for number of bytes
read
U recv() often returns fewer bytes than requested;
call recv() in a loop until you have gotten them all
U For TCP, send() does not create record boundaries;
recv() may get the result of more or less than one
send()
U recv()/send() behavior is a common programming
error with TCP/IP and socket programming.

SAS Institute Inc Slide 15


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

rexecd connect() stderr Port


host.mvs server.unx

rexeccmd Primary
Socket
stdin/stdout
rexec rexecd

stderr

Secondary
rexec.c lines [83 - 140] Socket

Rexecd connects stderr to port created and specified by rexec.


Stderr is used to return error information to rexec and to send
signal requests (kill calls) to rexecd.
SAS Institute Inc Slide 16
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Send user, password and command


host.mvs server.unx

rexeccmd Primary
Socket
stdin/stdout
rexec rexecd

stderr

Secondary
rexec.c lines [141 - 150] Socket

Client rexec writes the userid, password and command to


execute to the primary socket, where rexecd receives them via
reads of the primary socket (which is stdin).

SAS Institute Inc Slide 17


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Server confirms
host.mvs server.unx

rexeccmd Primary
Socket
stdin/stdout
rexec rexecd

stderr

rexec.c lines [152 - 171] Secondary


Socket
rexec exits line [176]
Server rexecd writes a one byte value of binary zero to the
primary socket (stdout) if authorization is successful, otherwise
it writes a one byte value of binary one. Client rexec receives
this via a read of the primary socket
SAS Institute Inc Slide 18
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Server creates command executor


host.mvs server.unx

stdin rexecd
Primary
child
rexeccmd Socket
stdout
stderr
(pipe)

stderr
rexecd
parent
rexeccmd lines [61-118] Secondary
Socket

rexecd creates a pipe (for stderr) then forks creating a child


process in which to run the command. Note that rexecd
closes it’s connection to the primary socket and that the
child process closes it’s connection to the secondary socket.
SAS Institute Inc Slide 19
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Child Process Executes Command


host.mvs server.unx

stdin command
Primary
child
rexeccmd Socket
stdout
stderr
(pipe)

stderr
rexecd
parent
rexeccmd lines [61-118] Secondary
Socket

The child process then configures it’s environment to match


the userid and runs the command using the execl call.
Output from the command is sent to rexeccmd through the
primary socket.
SAS Institute Inc Slide 20
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

File Descriptor Sets


U A file descriptor is an integer [returned by open() or
socket()] which identifies a file or socket.
U Descriptors are numbered 0 through FD_SETSIZE-1
U “fd_set” is a type which contains a bit for each descriptor
U The following macros manipulate file descriptor sets:
#include <sys/types.h>
int desc;
fd_set fds;
FD_ZERO(&fds); /* zero entire set */
FD_CLR(desc, &fds); /* clear desc bit */
FD_SET(desc, &fds); /* set desc bit */
FD_ISSET(desc, &fds); /* test desc bit */

SAS Institute Inc Slide 21


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

The select() call


U The select() system call awaits activity on
descriptor sets
int select( /* returns number active */
int nfds, /* highest desc used + 1 */
fd_set *read, /* Await read on these */
fd_set *write, /* await write on these */
fd_set *except, /* seldom used */
struct timeval *timeout /* inactivity timeout */

U A “timeout” parameter of NULL specifies indefinite


waiting
U A zero time value sets select() non-blocking
U A non-zero time value, sets a maximum wait time
SAS Institute Inc Slide 22
SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Summary
U Reviewed various socket API function calls
U REXEC / REXECD dialog
U Useable TCP/IP Socket Application
U Questions ?

SAS Institute Inc Slide 23


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998
C Socket Programming Tutorial SHARE Session 5959

Bibliography
U Internetworking with TCP/IP: Volumes I, II & III, Douglas
Comer, Prentice Hall, 1991 (ISBN Vol I: 0134685059, Vol
III: 0138487146)
U The Whole Internet User’s Guide & Catalog by Ed Kroll;
O’Reilly & Associates
U UNIX Network Programming by W. Richard Stevens;
Prentice Hall, 1990 (ISBN 0139498761)
U Socket API Programmer’s Reference
U UNIX “man” pages
U TCP/IP Illustrated: Volumes 1 & 2, W. Richard Stevens (v2
with Gary R. Wright); Addison-Wesley Publishing Company,
1994

SAS Institute Inc Slide 24


SAS/C & C++ Compiler R&D
Cary, NC Feb 1998

You might also like