Linux Sockets with TCP/IP communications

gazecummingΔίκτυα και Επικοινωνίες

26 Οκτ 2013 (πριν από 3 χρόνια και 11 μήνες)

65 εμφανίσεις

Linux Sockets with TCP/IP communications

1.

SOCKET
--

create and open a socket

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netdb.h>

#include <netinet/in.h>

#include <arpa/inet.h>


int socket (int domain, int type, int protoc
ol);

// domain is P
F_INET
(or in some cases AF_INIT)
for a network socket

// type is SOCK_STREAM for TCP/IP

// protocol default (0) is TCP for SOCK_STREAM

//

returns a file descriptor for a newly created and opened socket

This function creates a stream so
cket and opens a file descriptor. Socket does not block.

2.

BIND
--

associate a socket with an address and port

int bind (int sd, const struct sockaddr_in *p, int addr_len);

// sd is a file descriptor for an open socket

// p points to a sockaddr_in structu
re containing the port and address

// addr_len is the byte size of the sockaddr_in structure

//

returns success (0) or failure (non
-
zero)

Bind associates a socket with a network address and a port to allow future connec
tions requests. Bind does
not bloc
k. An attempt to connect to a port prior to the destination binding a socket to the port will result in the
connect() call failing.

3.

CONNECT

int connect (int sd, const struct sockaddr_in *p, int addr_len);

// (see bind() for parameter descriptions)

/
/

returns success or failure

Connect() attempts to establish a connection with another socket and blocks until an associated accept() is
executed on the destination. If the listen() queue has been exceeded, a connect request will fail.

4.

LISTEN

int liste
n (int sd, int backlog_size);

// sd is an open socket file descriptor

// backlog_size is the number of connection requests that can be pending or queued without failing.

//

return success or failure

Listen does not block.

5.

ACCEPT

int accept (int sd, str
uct sockaddr_in *p, int *addr_lenp);

// sd is a file descriptor for an open socket

// p points to a sockaddr_in structure
--

on return will contain info about the source making a connection.

// addr_lenp
--

on return will contain the length of the source s
ockaddr_in structure

//

returns an open file descriptor for a connected socket corresponding to an incoming connection request.

Accept recognizes the oldest pending connection request on a given socket file descriptor and returns a
new

socket file descript
or that is connected to the requestor. As such, the requestor is actually handed off to a new
socket and the original socket is still available to listen and accept fur
ther connection requests from other
sources. Accept blocks if no connection request is
queued.

6.

READ, WRITE, CLOSE

Once established, a socket file descriptor can be used with the standard POSIX interface


read(), write(),
and close(). Read() blocks until an incoming message is received. Messages are received in FIFO order. Unread
message
bytes are left in the incoming buffer.

7.

STRUCT SOCKADDR_IN (or the generic form STRUCT SOCKADDR)

struct sockaddr_in

// network domain socket address structure

{

short sin_family;

// PF_INET is the family for Linux TCP network sockets


u_short sin_port
;

// associated port number


struct in_addr sin_addr;

// associated network address (containing s_addr)


...

};

The field
sin_addr.s_addr

may be set to INADDR_ANY by a listening process to accept connection
requests from any source network address. To spe
cify an outgoing network address, use memcpy() to transfer
an address from a hostent structure (see below).

11.

GETHOSTBYNAME

struct hostent *gethostbyname (const char *name);

// name is a string containing a text network address

//

returns a pointer to a
hostent structure containing corresponding numeric or canonical address

The function gethostbyname() uses a local name service to fill the
hostent

structure with address
information for a host with a textual network address specified by the char
acter
-
stri
ng parameter
name
.

12.

STRUCT HOSTENT

struct hostent

{

char *h_name;


// official name of host


char **h_aliases;


// alias list


int h_addrtype;


// host address type


int h_length;


// length of address


char **
h_addr_list;


// list of addresses from name server

};

Socket communications use canonical network addresses, which are somewhat different from the text/dot
notation that is more human readable. The canonical network address filled into a
hostent

structu
re by
gethostbyname() may be copied into a s.addr field of a sockaddr_in struc
ture with the following;

struct sockaddr mysocket;

struct hostent *p;

...

memcpy (&mysocket.sin_addr.s.addr, p
-
>h_name, p
-
>h_length);

13.

DATA CONVERSIONS and other USEFUL FUNCT
IONS

int ntohi (int x);

// convert a network
-
format integer to local format

long ntohl (long x);

// convert a network
-
format long to local format

int htoni (int x);

// convert a local
-
format int to network format

long htonl (long x);

// convert a local
-
for
mat long to network format

char *inet_ntoa (struct in_addr sin_addr); // convert a canonical network address to text/dot notation.

int getpeername (int sd, struct sockaddr_in *addr, int *addrlen); // fill the sockaddr_in structure with the
network

information of the host connected to the other side of this port.


Client operation

1. open a socket with socket()





2. connect the socket to an server’s internet port

2.

read and write using the POSIX interface

3.

close the socket


Example client

/*
r
client.c


test of remote client calls (no error detection for brevity) */

/*


call with remote server host name and port number as arguments */

/*


example: % rclient lab1.usu.edu 4321


*/


#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#inc
lude <sys/socket.h>

#include <netdb.h>

#include <netinet/in.h>

#include <arpa/inet.h>


void main(int argc, char *argv[])


{

static struct hostent *hostp;


/* internet host information */


struct sockaddr_in name;


/* internet socket address */


int sd;


c
har buf[64];



/* create an internet socket */


sd = socket (PF_INET, SOCK_STREAM, 0);


/* internet domain stream */


/* now connect the socket to the right port and server host */


name.sin_family = PF_INET;


/* internet domain */


name.sin_port = atoi (a
rgv[2]);


/* advertised port */


hostp = gethostbyname (argv[1]);


/* advertised host name */


memcpy (&name.sin_addr.s_addr, hostp
-
>h_addr, hostp
-
>h_length);


connect (sd, &name, sizeof(name));


/* now talk to the server... */


write (sd, “help!”, 6);


re
ad (sd, buf, 64);


printf (“reply: %s
\
n”, buf);


close (sd);


}



Server operation

1. open a listening socket with socket()

2.

bind the socket to a port for incoming requests

3.

set the size of the listening queue for incoming connection requests with liste
n()

4.

wait for then accept a connection request on a temporary port with accept()

5.

read and write using the POSIX interface with the temporary port

6. close the sockets


Example server

/*
server.c

test of remote server (no error detection for brevity) */


#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netdb.h>

#include <netinet/in.h>

#include <arpa/inet.h>


#define PORTNUM 4321

/* publicly advertised port number */


void main(int argc, char *argv[])


{

str
uct sockaddr_in name, *p;

/* internet socket address */


struct sockaddr addr;

/* generic socket address */


int sd, ld, addrlen;


char buf[64];



ld = socket (PF_INET, SOCK_STREAM, 0);

// listening socket for incoming connections


name.sin_family = PF_INE
T;


name.sin_port = PORTNUM;


name.sin_addr.s_addr = INADDR_ANY;

/* accept any incoming addr */


bind (ld, &name, sizeof(name));

/* bind socket to port */


printf (“Server listening on port %d
\
n”, PORTNUM);

/* (just for demonstration) */



listen (ld, 5);


addrlen = sizeof(addr);


p = (struct sockaddr_in *) &addr;


while (1)



/* input service loop */


{

sd = accept (ld, 0, 0);

// sd is a temporary port for this connection only.



getpeername (sd, &addr, &addrlen);

/* who’s calling? */



printf (“ call from
: %s
\
n”, inet_ntoa(p
-
>sin_addr));



read (sd, buf, sizeof(buf));



write (sd, “on the way”, 11);



close (sd);


}


}


Compilation:


% g++
-
o client client.c

lsocket

lnsl


% g++
-
o server server.c

lsocket

lnsl


Execution:

on machine labA.cs.usu.edu:




% server





on machine labB.cs.usu.edu:




% client labA.cs.usu.edu 4321