Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Socket Programming: Interface and Implementation, Study notes of Communication

An overview of socket programming, focusing on the socket interface and its implementation. It covers various socket types, network protocols, and system calls used in socket programming. The document also includes code examples for creating and using sockets in both the Internet and UNIX domains.

Typology: Study notes

2021/2022

Uploaded on 09/27/2022

xyzxyz
xyzxyz 🇮🇳

4.8

(24)

309 documents

1 / 48

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
11
Programming With Sockets 2
This chapter presents the socket interface and illustrates them with sample
programs. The programs demonstrate the Internet domain sockets.
Sockets are Multithread Safe
The interface described in this chapter is multithread safe. Applications that
contain socket function calls can be used freely in a multithreaded application.
SunOS Binary Compatibility
There are two major changes from SunOS 4.x that hold true for Solaris 2.x
releases. The binary compatibility package allows SunOS 4.x–based
dynamically linked socket applications to run in Solaris 2.x.
1. You must explicitly specify the socket library (-lsocket) on the
compilation line.
What Are Sockets page 12
Socket Tutorial page 14
Standard Routines page 31
Client-Server Programs page 34
Advanced Topics page 41
Moving Socket Applications to Solaris 2.x page 54
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30

Partial preview of the text

Download Socket Programming: Interface and Implementation and more Study notes Communication in PDF only on Docsity!

Programming With Sockets 2

This chapter presents the socket interface and illustrates them with sample

programs. The programs demonstrate the Internet domain sockets.

Sockets are Multithread Safe

The interface described in this chapter is multithread safe. Applications that

contain socket function calls can be used freely in a multithreaded application.

SunOS Binary Compatibility

There are two major changes from SunOS 4.x that hold true for Solaris 2.x

releases. The binary compatibility package allows SunOS 4.x–based

dynamically linked socket applications to run in Solaris 2.x.

1. You must explicitly specify the socket library (-lsocket) on the

compilation line.

What Are Sockets page 12 Socket Tutorial page 14 Standard Routines page 31 Client-Server Programs page 34 Advanced Topics page 41 Moving Socket Applications to Solaris 2.x page 54

12 Transport Interfaces Programming GuideNovember 1995

2. You must recompile all SunOS 4.x socket-based applications with the socket

library to run under Solaris 2.x. The differences in the two socket

implementations are outlined in “Moving Socket Applications to Solaris 2.x”

on page 54.

What Are Sockets

Sockets are the 4.2 Berkeley software distribution (BSD) UNIX interface to

network protocols. It has been an integral part of SunOS releases since 1981.

They are commonly referred to as Berkeley sockets or BSD sockets. Since the

days of early UNIX, applications have used the file system model of

input/output to access devices and files. The file system model is sometimes

called open-close-read-write after the basic system calls used in this model.

However, the interaction between user processes and network protocols are

more complex than the interaction between user processes and I/O devices.

A socket is an endpoint of communication to which a name can be bound. A

socket has a type and one associated process. Sockets were designed to

implement the client-server model for interprocess communication where:

- The interface to network protocols needs to accommodate multiple

communication protocols, such as TCP/IP, XNS, and UNIX domain.

- The interface to network protocols need to accommodate server code that

waits for connections and client code that initiates connections.

- They also need to operate differently, depending on whether communication

is connection-oriented or connectionless.

- Application programs may wish to specify the destination address of the

datagrams it delivers instead of binding the address with the open() call.

To address these issues and others, sockets are designed to accommodate

network protocols, while still behaving like UNIX files or devices whenever it

makes sense to. Applications create sockets when they need to. Sockets work

with the open(), close(), read(), and write() system calls, and the

operating system can differentiate between the file descriptors for files, and file

descriptors for sockets.

UNIX domain sockets are named with UNIX paths. For example, a socket may

be named /tmp/foo. UNIX domain sockets communicate only between

processes on a single host. Sockets in the UNIX domain are not considered part

14 Transport Interfaces Programming GuideNovember 1995

Socket Tutorial

This section covers the basic methodologies of using sockets.

Socket Creation

The socket() call creates a socket,

s = socket(domain, type, protocol);

in the specified domain and of the specified type. If the protocol is unspecified

(a value of 0 ), the system selects a protocol that supports the requested socket

type. The socket handle (a file descriptor) is returned.

The domain is specified by one of the constants defined in <sys/socket.h>.

For the UNIX domain the constant is AF_UNIX. For the Internet domain it is

AF_INET. Constants named AF_< suite > specify the address format to use in

interpreting names.

Socket types are defined in <sys/socket.h>. SOCK_STREAM, SOCK_DGRAM,

or SOCK_RAW is supported by AF_INET and AF_UNIX. The following creates a

stream socket in the Internet domain:

s = socket(AF_INET, SOCK_STREAM, 0);

This call results in a stream socket with the TCP protocol providing the

underlying communication. A datagram socket for intramachine use is created

by:

s = socket(AF_UNIX, SOCK_DGRAM, 0);

Use the default protocol (the protocol argument is 0 ) in most situations. You can

specify a protocol other than the default, as described in “Advanced Topics” on

page 41.

Binding Local Names

A socket is created with no name. A remote process has no way to refer to a

socket until an address is bound to it. Communicating processes are connected

through addresses. In the Internet domain, a connection is composed of local

and remote addresses, and local and remote ports. In the UNIX domain, a

connection is composed of (usually) one or two path names. In most domains,

connections must be unique.

Programming With Sockets 15

In the Internet domain, there may never be duplicate ordered sets, such as:

<protocol, local address, local port, foreign address, foreign

port>. UNIX domain sockets need not always be bound to a name, but when

bound there may never be duplicate ordered sets such as: <local pathname,

foreign pathname>. The path names may not refer to existing files.

The bind() call allows a process to specify the local address of the socket. This

forms the set <local address, local port> (or )

while connect() and accept() complete a socket’s association. The bind()

system call is used as follows:

bind ( s, name, namelen );

s is the socket handle. The bound name is a byte string that is interpreted by

the supporting protocol(s). Internet domain names contain an Internet address

and port number. UNIX domain names contain a path name and a family.

Code Example 2-1 binds the name /tmp/foo to a UNIX domain socket.

Code Example 2-1 Bind Name to Socket

#include <sys/un.h> ... struct sockaddr_un addr; ... strcpy(addr.sun_path, "/tmp/foo"); addr.sun_family = AF_UNIX; bind (s, (struct sockaddr *) &addr, strlen(addr.sun_path) + sizeof (addr.sun_family));

Note that in determining the size of an AF_UNIX socket address, null bytes are

not counted, which is why strlen() use is fine.

The file name referred to in addr.sun_path is created as a socket in the

system file name space. The caller must have write permission in the directory

where addr.sun_path is created. The file should be deleted by the caller

when it is no longer needed. AF_UNIX sockets can be deleted with unlink().

Binding an Internet address is more complicated. The call is similar:

#include <sys/types.h> #include <netinet/in.h> ... struct sockaddr_in sin; ... bind (s, (struct sockaddr *) &sin, sizeof sin);

Programming With Sockets 17

with the address of the client. A NULL pointer may be passed. fromlen is the

length of the structure. (In the UNIX domain, from is declared a struct

sockaddr_un.)

accept() normally blocks. accept() returns a new socket descriptor that is

connected to the requesting client. The value of fromlen is changed to the actual

size of the address.

There is no way for a server to indicate that it will accept connections only

from specific addresses. The server can check the from-address returned by

accept() and close a connection with an unacceptable client. A server can

accept connections on more than one socket, or avoid blocking on the accept

call. These techniques are presented in “Advanced Topics” on page 41.

Connection Errors

An error is returned if the connection is unsuccessful (however, an address

bound by the system remains). Otherwise, the socket is associated with the

server and data transfer may begin.

Table 2-2 lists some of the more common errors returned when a connection

attempt fails.

Table 2-2 Socket Connection Errors

Socket Errors Error Description

ENOBUFS Lack of memory available to support the call.

EPROTONOSUPPORT Request for an unknown protocol.

EPROTOTYPE Request for an unsupported type of socket.

ETIMEDOUT No connection established in specified time. This happens when the destination host is down or when problems in the network result in lost transmissions.

ECONNREFUSED The host refused service. This happens when a server process is not present at the requested address.

ENETDOWN or EHOSTDOWN

These errors are caused by status information delivered by the underlying communication interface.

18 Transport Interfaces Programming GuideNovember 1995

Data Transfer

This section describes the functions to send and receive data. You can send or

receive a message with the normal read() and write() system calls:

write(s, buf, sizeof buf); read(s, buf, sizeof buf);

Or the calls send() and recv() can be used:

send(s, buf, sizeof buf, flags); recv(s, buf, sizeof buf, flags);

send() and recv() are very similar to read() and write(), but the flags

argument is important. The flags, defined in <sys/socket.h>, can be

specified as a nonzero value if one or more of the following is required:

MSG_OOB send and receive out-of-band data

MSG_PEEK look at data without reading

MSG_DONTROUTE send data without routing packets

Out-of-band data is specific to stream sockets. When MSG_PEEK is specified

with a recv() call, any data present is returned to the user but treated as still

unread. The next read() or recv() call on the socket returns the same data.

The option to send data without routing applied to the outgoing packets is

currently used only by the routing table management process and is unlikely

to be interesting to most users.

Closing Sockets

A SOCK_STREAM socket can be discarded by a close() system call. If data is

queued to a socket that promises reliable delivery after a close(), the

protocol continues to try to transfer the data. If the data is still undelivered

after an arbitrary period, it is discarded.

ENETUNREACH or EHOSTUNREACH

These operational errors can occur either because there is no route to the network or host, or because of status information returned by intermediate gateways or switching nodes. The status returned is not always sufficient to distinguish between a network that is down and a host that is down.

Table 2-2 Socket Connection Errors (Continued)

Socket Errors Error Description

20 Transport Interfaces Programming GuideNovember 1995

Figure 2-1 Connection-Oriented Communication Using Stream Sockets

Code Example 2-2 Internet Domain Stream Connection (Client) #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h>

#define DATA "Half a league, half a league.. ."

socket()

bind()

listen()

Connection establishment

Server

Client

Data transfer

accept()

read()/ write()

shutdown() and/or close()

read()/ write()

shutdown() and/or close()

socket()

connect()

Programming With Sockets 21

  • This program creates a socket and initiates a connection with the
  • socket given in the command line. Some data are sent over the
  • connection and then the socket is closed, ending the connection.
  • The form of the command line is: streamwrite hostname portnumber
  • Usage: pgm host port */ main(argc, argv) int argc; char *argv[]; { int sock; struct sockaddr_in server; struct hostent *hp, *gethostbyname(); char buf[1024];

/* Create socket. / sock = socket( AF_INET, SOCK_STREAM, 0 ); if (sock == -1) { perror("opening stream socket"); exit(1); } / Connect socket using name specified by command line. / server.sin_family = AF_INET; hp = gethostbyname(argv[1] ); /

  • gethostbyname returns a structure including the network address
  • of the specified host. */ if (hp == (struct hostent *) 0) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(2); } memcpy((char *) &server.sin_addr, (char *) hp->h_addr, hp->h_length); server.sin_port = htons(atoi( argv[2])); if (connect(sock, (struct sockaddr *) &server, sizeof server) == -1) { perror("connecting stream socket"); exit(1); } if (write( sock, DATA, sizeof DATA ) == -1) perror("writing on stream socket");

Programming With Sockets 23

perror("getting socket name"); exit(1); } printf("Socket port #%d\n", ntohs(server.sin_port)); /* Start accepting connections. */ listen(sock, 5); do { msgsock = accept(sock,(struct sockaddr *) 0,(int ) 0); if (msgsock == - perror("accept"); else do { memset(buf, 0, sizeof buf); if ((rval = read(msgsock,buf, 1024)) == -1) perror("reading stream message"); if (rval == 0) printf("Ending connection\n"); else printf("-->%s\n", buf); } while (rval != 0); close(msgsock); } while(TRUE); /

  • Since this program has an infinite loop, the socket "sock" is
  • never explicitly closed. However, all sockets will be closed
  • automatically when a process is killed or terminates normally. */ exit(0); }

Datagram Sockets

A datagram socket provides a symmetric data exchange interface. There is no

requirement for connection establishment. Each message carries the destination

address. Figure 2-2 shows the flow of communication between server and

client.

Datagram sockets are created as described in “Socket Creation” on page 14. If a

particular local address is needed, the bind() operation must precede the first

data transmission. Otherwise, the system sets the local address and/or port

when data is first sent. To send data, the sendto() call is used:

sendto(s, buf, buflen, flags, (struct sockaddr *) &to, tolen);

24 Transport Interfaces Programming GuideNovember 1995

The s , buf , buflen , and flags parameters are the same as in connection-oriented

sockets. The to and tolen values indicate the address of the intended recipient

of the message. A locally detected error condition (such as an unreachable

network) causes a return of –1 and errno to be set to the error number.

To receive messages on a datagram socket, the recvfrom() call is used:

recvfrom(s, buf, buflen, flags, (struct sockaddr *) &from, &fromlen);

Before the call, fromlen is set to the size of the from buffer. On return it is set to

the size of the address from which the datagram was received.

Datagram sockets can also use the connect() call to associate a socket with a

specific destination address. It can then use the send() call. Any data sent on

the socket without explicitly specifying a destination address is addressed to

the connected peer, and only data received from that peer is delivered. Only

one connected address is permitted for one socket at a time. A second

connect() call changes the destination address. Connect requests on

datagram sockets return immediately. The system simply records the peer’s

address. accept(), and listen() are not used with datagram sockets.

While a datagram socket is connected, errors from previous send() calls may

be returned asynchronously. These errors can be reported on subsequent

operations on the socket, or an option of getsockopt, SO_ERROR, can be used

to interrogate the error status.

26 Transport Interfaces Programming GuideNovember 1995

#include <stdio.h>

/*

  • The include file <netinet/in.h> defines sockaddr_in as:
  • struct sockaddr_in {
  • short sin_family;
  • u_short sin_port;
  • struct in_addr sin_addr;
  • char sin_zero[8];
  • };
  • This program creates a datagram socket, binds a name to it, then
  • reads from the socket. */

main() { int sock, length; struct sockaddr_in name; char buf[1024];

/* Create socket from which to read. / sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { perror("opening datagram socket"); exit(1); } / Create name with wildcards. */ name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; name.sin_port = 0; if (bind(sock,(struct sockaddr )&name, sizeof name) == -1) { perror("binding datagram socket"); exit(1); } / Find assigned port value and print it out. */ length = sizeof(name); if (getsockname(sock,(struct sockaddr ) &name, &length) == -1) { perror("getting socket name"); exit(1); } printf("Socket port #%d\n", ntohs( name.sin_port)); / Read from the socket. */ if ( read(sock, buf, 1024) == -1 ) perror("receiving datagram packet"); printf("-->%s\n", buf);

Programming With Sockets 27

close(sock); exit(0); }

Code Example 2-5 Sending an Internet Domain Datagram

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h>

#define DATA "The sea is calm, the tide is full.. ."

/*

  • Here I send a datagram to a receiver whose name I get from the
  • command line arguments. The form of the command line is:

* dgramsend hostname portnumber

main(argc, argv) int argc; char *argv[]; { int sock; struct sockaddr_in name; struct hostent *hp, *gethostbyname();

/* Create socket on which to send. / sock = socket(AF_INET,SOCK_DGRAM, 0); if (sock == -1) { perror("opening datagram socket"); exit(1); } /

  • Construct name, with no wildcards, of the socket to ‘‘send’’
  • to. gethostbyname returns a structure including the network
  • address of the specified host. The port number is taken from
  • the command line. */ hp = gethostbyname(argv[1]); if (hp == (struct hostent *) 0) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(2); } memcpy((char *) &name.sin_addr, (char *) hp->h_addr, hp->h_length); name.sin_family = AF_INET;

Programming With Sockets 29

select() normally returns the number of file descriptors selected. select()

returns a 0 if the time-out has expired. select() returns -1 for an error or

interrupt with the error number in errno and the file descriptor masks

unchanged.

For a successful return, the three sets indicate which file descriptors are ready

to be read from, written to, or have exceptional conditions pending.

Test the status of a file descriptor in a select mask with the FD_ISSET( fd ,

& mask ) macro. It returns a nonzero value if fd is in the set mask, and 0 if it is

not. Use select() followed by a FD_ISSET( fd , & mask ) macro on the read set

to check for queued connect requests on a socket.

Code Example 2-6 shows how to select on a “listening” socket for readability

to determine when a new connection can be picked up with a call to

accept(). The program accepts connection requests, reads data, and

disconnects on a single socket.

Code Example 2-6 Check for Pending Connections With select()

#include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h>

#define TRUE 1

/*

  • This program uses select to check that someone is
  • trying to connect before calling accept. */

main() { int sock, length; struct sockaddr_in server; int msgsock; char buf[1024]; int rval; fd_set ready; struct timeval to;

/* Open a socket and bind it as in previous examples. */

30 Transport Interfaces Programming GuideNovember 1995

/* Start accepting connections. */ listen(sock, 5); do { FD_ZERO(&ready); FD_SET(sock, &ready); to.tv_sec = 5; to.tv_usec = 0; if (select(1, &ready, (fd_set *)0, (fd_set *)0, &to) == -1) { perror("select"); continue; } if (FD_ISSET(sock, &ready)) { msgsock = accept(sock, (struct sockaddr *)0, (int *)0); if (msgsock == -1) perror("accept"); else do { memset(buf, 0, sizeof buf); if ((rval = read(msgsock, buf, 1024)) == -1) perror("reading stream message"); else if (rval == 0) printf("Ending connection\n"); else printf("-->%s\n", buf); } while (rval > 0); close(msgsock); } else printf("Do something else\n"); } while (TRUE); exit(0); }

In previous versions of the select() routine, its arguments were pointers to

integers instead of pointers to fd_sets. This style of call still works if the

number of file descriptors is smaller than the number of bits in an integer.

select() provides a synchronous multiplexing scheme. The SIGIO and

SIGURG signals described in “Advanced Topics” on page 41 provide

asynchronous notification of output completion, input availability, and

exceptional conditions.