What is Socket?From the point of view of the networking
• Service access
point of TCP/IP
protocol stack
• Socket is an • Socket is an
interface
between
Application layer
and Transport
layer
2
What is Socket?From the point of view of the program
• A socket is a file descriptor that lets an application read/write data from/to the networkfrom/to the network
• Once configured the application can
– Send data to the socket
– Receive data from the socket
3
Concept of Port Numbers
Telnetserver
Web server
port 23 port 80
�Port numbers are used to identify
“entities” on a host
�Port numbers can be
� Well-known (port 0-1023)
TCP/UDP
IP
Ethernet Adapter
� Well-known (port 0-1023)
� Dynamic or private (port 1024-65535)
�Servers/daemons usually use well-
known ports
� Any client can identify the server/service
� HTTP = 80, FTP = 21, Telnet = 23, ...
�Clients usually use dynamic ports
� Assigned by the kernel at run time
– Receive data from the socket
• Socket API
– Application Programming Interface (API) comprises a library for developing applications for inter-process communication
Socket API
– Provides a series of functions:
• socket()
• bind()
• connect()
• …
• For UNIX: Berkeley Socket API
• For Windows: Windows Socket API
• Sample code (4 files)– ./sample/Makefile // Makefile
– ./sample/echo_server.c// server sample code
– ./sample/echo_client.c // client sample code
Sample code -echoserver/echoclient
– ./sample/fdtest.c // file descriptor sample code
• Compile source code– make all
• Run echoserver– make s
• Run echoclient– make c
<sys/socket.h>
struct sockaddr {
u_short sa_family; // address family
char sa_data[14]; // up to 14 bytes of direct address
};
Some data struct
<netinet/in.h>
struct sockaddr_in { // Socket address, internet style
short sin_family; // Should be AF_INET
u_short sin_port; // Port number
struct in_addr sin_addr; // IP address
char sin_zero[8]; // unused
};
struct in_addr {
unsigned long s_addr; // fill this with inet_aton()
};
• socket(): Create a socket
• bind(): Bind a socket to a port
• listen(): Make a socket listen for
incoming connection
Server side : Socket API
incoming connection
• accept(): Make a socket accept incoming
connection
• read(): Read data from a socket (if any)
• write(): Write data to a socket
• int socket (int domain, int type,
int protocol)
– Return a file descriptor for the new socket, or -1 if fail
– domain: integer, communication domain
socket
– domain: integer, communication domain
• e.g. AF_INET (IPv4 protocol) – typically used
– type: communication type
• SOCK_STREAM: reliable, 2-way, connection-based service (e.g. TCP)
• SOCK_DGRAM: unreliable, connectionless (e.g. UDP)
– protocol: specifies protocol (see file /etc/protocols for a
list of options)
• usually set to 0
socket( ) : an example
#define ERROR -1
...
int sock;int sock;
// create a socket
if((sock = socket(AF_INET, SOCK_STREAM, 0))
== ERROR)
{
perror("server socket: ");
exit(-1);
}
...
• int bind (int sockfd, const
struct sockaddr *addr,
socklen_t addrlen)
bind
socklen_t addrlen)
– Return 0 if success , -1 if failed
– sockfd: file descriptor of a socket
– addr: struct sockaddr, the (IP) address and
port of the machine (address usually set to
INADDR_ANY – chooses a local address)
– addrlen: the size of the addr structure
bind( ) : an example...
struct sockaddr_in server;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(1234);
server.sin_addr.s_addr = INADDR_ANY;server.sin_addr.s_addr = INADDR_ANY;
// bind a socket
if(bind(sock, (struct sockaddr *)&server,
sizeof(server))
== ERROR)
{
perror("bind : ");
exit(-1);
}
Concept of Byte Ordering
union {
u_int32_t addr; /* 4 bytes address */char c[4];
} un;/* 140.112.90.72 */
un.addr = 0x8C705a48;
� Big Endian - higher bytes first
� Sun Solaris, PowerPC, ...
� Little Endian - lower bytes first
� i386, alpha, ...
� Network byte order = Big Endian
0x8c 0x70 0x5a 0x48
un.addr = 0x8C705a48;/* c[0] = ? */
c[0] c[1] c[2] c[3]
0x48 0x5a 0x70 0x8c
• htons(): “Host to Network Short”
• htonl(): “Host to Network Long”
• ntohs(): “Network to Host Short”
Byte Ordering Solution
• ntohs(): “Network to Host Short”
• ntohl(): “Network to Host Long”
• int listen (int sockfd,
int backlog)
– Return 0 if success , -1 if fail
listen
– Return 0 if success , -1 if fail
– sockfd: file descriptor of socket
– backlog: integer, # of active
participants that can “wait” for a
connection
– listen is non-blocking: returns
immediately
listen( ) : an example
#define MAX_CLIENTS 10
...
// listen a socket
if(listen(sock, MAX_CLIENTS) == ERROR)
{
perror("listen");
exit(-1);
}
...
• int accept (int sockfd, struct
sockaddr *addr, socklen_t
*addrlen)
– cli: the file descriptor of new socket (used
accept
– cli: the file descriptor of new socket (used
for data-transfer) , cli>0 if success, -1 if fail
– sockfd: integer, the orig. socket (being listened
on)
– addr: struct sockaddr, address of the active
participant
– addrlen: size of addr
• must be set appropriately before call
• adjusted by OS upon return
– accept is blocking: waits for connection
accept( ) : an example#define MAX_DATA 1024
...
int cli;
struct sockaddr_in client;
int sockaddr_len = sizeof(client);
int data_len;
char data[MAX_DATA];
while(1)while(1)
{
if((cli = accept(sock, (struct sockaddr *)&client,
&sockaddr_len)) == ERROR)
{
perror("accept");
exit(-1);
}
printf("New Client from port %d and IP %s\n",
ntohs(client.sin_port),
inet_ntoa(client.sin_addr));
...
}
• The htons() function converts the unsigned short integer host short from host byte order to network byte order.
• The inet_ntoa() function converts the
ntohs/ inet_ntoa
• The inet_ntoa() function converts the Internet host address in given in network byte order to a string in standard numbers-and-dots notation. The string is returned in a statically allocated buffer, which subsequent calls will overwrite.
• int read (int fd, void *buf, size_t
count)
– Return the number of bytes that are successfully read
read
read
– fd: file descriptor of socket
– buf & count: attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
– read is blocking: waits for “kernel space
buffer” to “user space buffer” before
returning
• int write (int fd, void *buf, size_t
count)
– Return the number of bytes that are successfully wrote
write
wrote
– fd: file descriptor of socket
– buf & count: write() writes up to count bytes from the buffer pointed buf to the file referred to by the file descriptor fd.
– write is blocking: waits for “user space buffer”
to “kernel space buffer” before returning
read( ) & write(): an example
...
do
{
printf("wait data from client..\n");
data_len = read(cli, data, MAX_DATA);
if(data_len > 0)if(data_len > 0)
{
data[data_len] = '\0';
printf("%d bytes is sent: %s", data_len, data);
write(cli, data, data_len);
} else {
perror("read");
}
}while(data_len > 0);
printf("Client disconnected\n");
close(cli);
...
Client Side : Socket API
• socket(): Create a socket
• bind(): Bind a socket to a port (optional)
• connect(): Connect a socket to a specific
IP/portIP/port
• read(): Read data from a socket (if any)
• write(): Write data to a socket
• int connect (int sockfd,
struct sockaddr *addr,
socklen_t *addrlen)
connect
socklen_t *addrlen)
– Return 0 if success, -1 if fail
– sockfd: file descriptor of the socket
– addr: address of the server
– addrlen: the size of the addr
structure
connect( ) / inet_addr() : an example
struct sockaddr_in server;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(“140.112.30.41”);
server.sin_port = htons(1234);server.sin_port = htons(1234);
// connect
if(connect(ser, (struct sockaddr*)&server, sizeof(server))
== ERROR)
{
perror("connect");
exit(-1);
}
• in_addr_t inet_addr
(const char *cp)
– Converts the Internet host address
inet_addr
– Converts the Internet host address
cp from numbers-and-dots notation
into binary data in network byte
order. If the input is invalid,
INADDR_NONE (usually -1) is
returned.
int rbyte;
char rbuf[MAX_DATA];
int rrbyte;
char rrbuf[MAX_DATA];
do
{
// read stdin
rbyte = read(0, rbuf, MAX_DATA);
if(rbyte > 0)
{
// write socket
write(ser, rbuf, rbyte);write(ser, rbuf, rbyte);
// read socket
rrbyte = read(ser, rrbuf, MAX_DATA);
// write stdout
write(1, rrbuf, rrbyte);
} else {
perror("read");
}
}while(rbyte > 0);
close(ser);
Concept of Names and AddressesConcept of Names and Addresses
Each attachment point on Internet is given unique address
� Based on location within network – like phone � Based on location within network – like phone numbers
Humans prefer to deal with names not addresses
� DNS provides mapping of name to address
� linux10.csie.ntu.edu.tw � 140.112.30.41
Translate name to Translate name to addressaddress
• We can’t use name in inet_addr(…)
– struct hostent – struct hostent
*gethostbyname(const char
*name)
– Translate name to address
Translate name to Translate name to addressaddress
struct hostent *phost;
struct sockaddr_in sa;
bzero(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(1234);sa.sin_port = htons(1234);
if((phost = gethostbyname(addr)) != NULL)
{
sa.sin_addr.s_addr = *((in_addr_t*)(phost->h_addr_list[0]));
printf("Translate %s => %s\n", addr, inet_ntoa(sa.sin_addr));
} else {
printf("gethostbyname failed\n");
exit(-1);
}
• void bzero(void *dest, size_tnbytes);
• in_addr_t inet_addr(const char *cp)
• char * inet_ntoa(const struct in_addr in)
Other Useful Function Summary
• char * inet_ntoa(const struct in_addr in)
• int gethostname(char *name, int len)
• struct hostent * gethostbyaddr(char *addr, int len, nt type):
• Make sure to #include the header files!
Concurrent Server using select()
int select(int maxfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
FD_CLR(int fd, fd_set *fds); /* clear the bit for fd in
fds */
FD_ISSET(int fd, fd_set *fds); /* is the bit for fd in fds?
*/
FD_SET(int fd, fd_set *fds); /* turn on the bit for fd in
fds */
FD_ZERO(fd_set *fds); /* clear all bits in fds */
Concurrent Server using select()
� maxfds: max value of the socket descriptors to be tested
� descriptors (0, 1, ... maxfds-1) will be tested
� only for compatibility with Berkeley sockets
� readfds: a set of fds we want to check if data is available
� returns a set of fds ready to read
� if input argument is NULL, not interested in that condition
� writefds: returns a set of fds ready to write
� exceptfds: returns a set of fds with exception conditions
Concurrent Server using select()
int select(int maxfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
struct timeval {struct timeval {
long tv_sec; /* seconds /
long tv_usec; /* microseconds */
}
� timeout
� if NULL, wait forever and return only when one of the descriptors is ready for I/O
� otherwise, wait up to a fixed amount of time specified by timeout
� if we don’t want to wait at all, create a timeout structure with timer value equal to
� Refer to the man page for more information
int s1, s2; /* socket descriptors */
fd_set readfds; /* used by select() */
/* create and bind s1 and s2 */
while(1) {
Concurrent Server using select()
� select allows synchronous I/O multiplexing
while(1) {
FD_ZERO(&readfds); /* initialize the fd set */
FD_SET(s1, &readfds); /* add s1 to the fd set */
FD_SET(s2, &readfds); /* add s2 to the fd set */
if(select(s2+1, &readfds, 0, 0, 0) < 0) {
perror(“select”);
exit(1);
}
if(FD_ISSET(s1, &readfds)) {
recvfrom(s1, buf, sizeof(buf), ...);
/* process buf */
}
/* do the same for s2 */
}
pid_t pid;
int listenfd, connfd;
listenfd = socket(...);
/* fill in sockaddr_in{} with server’s well known port */
Concurrent Server using fork()
� fork creates a child process.
/* fill in sockaddr_in{} with server’s well known port */
bind(listenfd, ...);
listen(listenfd, LISTENQ);
for( ; ; ){
connfd = accept(listenfd, ...); /* probably blocks*/
if( (pid = fork()) == 0){
close(listenfd); /* child closes listening socket*/
doit(connfd); /* process the request */
close(connfd); /* done with this client */
exit(0); /* child terminates */
}
close(connfd); /* parent closes connected socket */
}
connect()
listenfd
Client Server
connfdConnection
(Parent)
Concurrent Server using fork()
listenfd
Server (Child)
connfd
fork
Connection