+ All Categories
Home > Documents > Socket Programming - NTU

Socket Programming - NTU

Date post: 18-Mar-2022
Category:
Upload: others
View: 7 times
Download: 0 times
Share this document with a friend
42
Socket Programming 1
Transcript

Socket Programming

1

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

Server & Client

App.

• 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

Typical timeline

• 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);

}

What is File Descriptor?

Internet

#x

sock

http://en.wikipedia.org/wiki/File_descriptor

Internet

What is File Descriptor?

#x

http://en.wikipedia.org/wiki/File_descriptor

Internet

#x

sock

• 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

• man

– man 2 (socket | bind | listen | read | write |

connect)

– man XXXXX

Reference / Q&A

– man XXXXX

• Book

– W. Richard Stevens, “Unix Network

Programming 2/e Volume 1”,1998


Recommended