Title: Sockets de Unix
1Sockets de Unix
- Sistemas Informáticos Distribuidos
2Sockets
- Parte 1 Manejo de sockets desde C
- Parte 2 Manejo de sockets desde JAVA
3Sockets en C
4Modelo OSI de ISO
MÁQUINA A
MÁQUINA B
APLICACIÓN
APLICACIÓN
PRESENTACIÓN
PRESENTACIÓN
SESIÓN
SESIÓN
TRANSPORTE
TRANSPORTE
RED
RED
ENLACE
ENLACE
FÍSICA
FÍSICA
5Familias
- Familia AF_UNIX Usa protocolos internos de Unix.
- Familia AF_INET Usa protocolos de Internet, como
el TCP (Transmisión Control Protocol). - Familia AF_CCITT Norma X.25 de CCITT.
- Familia AF_NS Protocolos NS de XEROX.
- Familia AF_SNA Protocolos IBM SNA.
- Familia AF_DECnet.
- Familia AF_APPLETALK.
6Tipos de conexión
- Circuito virtual Mediante la búsqueda de enlaces
libres, se establece un circuito virtual.
Conexión permanente hasta el final de la
comunicación. SOCK_STREAM - Datagramas no trabajan con circuitos
permanentes. La transmisión se realiza a nivel de
paquetes. SOCK_DGRAM
7Direcciones de red
struct sockaddr u_short sa_family / familia
de sockets AF_xxxx / char sa_data14 / 14
bytes con la dirección./ / Su codificación
depende de la familia /
struct sockaddr_un short sun_family /
AF_UNIX / char sun_path108 / Path name
/
8Direcciones de red (II)
struct in_addr u_long s_addr / 32 bits con la
identificación de la red y el host (en
binario) / struct sockaddr_in short
sin_family /en este caso, AF_INET / u_short
sin_port / 16 bits con el número de puerto
/ in_addr sin_addr / id. red y host / char
sin_zero8 / 8 bytes sin usar /
9Direcciones de red (III)
Número de puerto se usa para asociar el socket
al proceso que se está ejecutando. Si en una
misma máquina hay distintos sockets abiertos cada
uno de ellos deberá llevar un número de puerto
distinto, puesto que todos llevarán la misma
dirección de red. Número de puerto puede
tomar valores entre 1024 y 65535. El sistema
proporciona automáticamente números de puerto que
estén libres entre 1024 y 5000 mediante ciertas
funciones. Del número 1 al 1024 están reservados
al sistema y no pueden ser usados por
aplicaciones de usuario. La función int
rresvport (int port) reserva un puerto entre
1024 y 5000. Si el número de puerto contiene un
0 antes de efectuar la operación BIND, el sistema
también le gestionará un número de forma
automática.
10Funciones para convertir direcciones
- unsigned long inet_addr (const char cp)
- Convierte al formato decimal estándar del
usuario apuntado por cp al formato binario
definido en la estructura struct in_addr. - struct in_addr direccion
- .................................
- direccion.s_addr inet_addr(128.12.10.00)
-
- Las direcciones en internet se dan al usuario en
formato decimal formado por números del 0 al 255
separados por puntos, que identifican la red o
subred y el número de host. -
- char inet_ntoa ( struct in_addr in ) Hace la
operación contraria.
11Funciones para convertir formatos numéricos
a) big-endian dirección N byte más
significativo dirección N1 byte menos
significativo (IBM RS6000, SUN, ...,
TCP,UDP) b) little-endian dirección N byte
menos significativo dirección N1 byte más
significativo DEC Alpha, Intel x86,...)
12Funciones para convertir formatos numéricos (II)
-
- unsigned long htonl ( unsigned long hostlong )
- Convierte un long del formato de la máquina al de
la red. - unsigned short htons ( unsigned short hostshort
) - Convierte un short del formato de la máquina al
de la red. - unsigned long ntohl ( unsigned long netlong )
- Convierte un long del formato de la red al de la
máquina. - unsigned short ntohs ( unsigned short netshort )
- Convierte un short del formato de la red al de la
máquina. -
- struct sockaddr_in servidor_addr
- ........................................
- servidor_addr.sin_port htons(7000)
13Apertura de un punto terminal en un canal.
- int socket (int af, int type, int protocol)
- Socket crea un punto terminal para conectarse a
un canal bidireccional, devuelve un descriptor
del canal. - af - Es la familia AF_UNIX, AF_INET, AF_CCITT,
AF_NS, ... - type - El tipo de conexión SOCK_STREAM,
SOCK_DGRAM - protocol - Protocolo particular que se desea
usar. Normalmente cada tipo de socket sólo tiene
un protocolo, pero si hay más de uno se puede
especificar. Si no, se pone un 0. - Si todo funciona bien, socket devuelve un
descriptor de fichero. En caso contrario devuelve
-1, quedando codificado el error en la variable
global errno.
14Nombre de un socket
- int bind(int sfd, const void addr,int addrlen)
- Bind une un socket a una dirección de red
determinada. - Bind hace que el socket con descriptor sfd se una
a la dirección de socket que especifica la
estructura apuntada por addr y de longitud
addrlen. - La estructura a la que apunta addr deberá ser
struct sockaddr_un en el caso de la familia
AF_UNIX, y será struct sockaddr_in en el caso de
la familia AF_INET. - Si la llamada funciona correctamente, bind
devuelve 0, en caso contrario -1.
15Disponibilidad para recibir peticiones de
servicio.
- int listen (int sfd, int backlog)
- Listen habilita una cola asociada al socket
descrito por sfd para alojar las peticiones de
conexión que le realicen otros programas. La
longitud de esa cola se especifica en backlog. - Listen sólo tiene sentido en sockets del tipo
SOCK_STREAM. - Si listen funciona correctamente devuelve 0, y en
caso de error -1.
16Petición de conexión
- int connect (int sfd,const void addr,int
addrlen) - Llamada del proceso cliente para empezar a
comunicar. - sfd descriptor del socket.
- addr puntero a estructura de dirección del
socket remoto con el que se quiere conectar.
(struct sockaddr_in). - addrlen tamaño de la estructura.
- En SOCK_DGRAM, connect especifica la dirección
del socket remoto, pero no se conecta con él. - En SOCK_STREAM, connect intenta conexión
devolviendo error si no se consigue (cuando está
activo el modo de acceso no bloqueante O_NDELAY). - El modo de acceso al socket se puede modificar
usando la función fcntl(). - fcntl ( sfd, F_SETFL, O_NDELAY )
- La conexión correcta devuelve un 0. Se devuelve
-1 en caso de error.
17Aceptación de conexión
- int accept(int sfd, void addr, int addrlen)
- Acepta demanda de servicio en sockets orientados
a conexión. - sfd descriptor del socket.
- accept extrae la primera llamada de la cola que
ha creado listen sobre el socket, y después crea
un nuevo socket con las mismas propiedades que
sfd, reservándole un nuevo descriptor de fichero. - Si no hay peticiones para extraer de la cola,
accept permanecerá bloqueada a menos que esté
activo el control de acceso no bloqueante
(O_NDELAY) en cuyo caso devolverá un error. - addr debe apuntar a una estructura local de
dirección de socket. La propia llamada accept
rellenará esa estructura con la dirección del
socket remoto que ha pedido la conexión. - addrlen debe ser un puntero para permitir que la
llamada sobrescriba sobre él el tamaño real de la
dirección leída. - Si no error, devolverá descriptor del nuevo
socket. En error devuelve -1.
18Lectura o recepción de mensajes de un socket
- int read (int sfd, char buf, unsigned nbyte)
- Read lee nbyte bytes del socket sfd y los
almacena en el buffer apuntado por buf. Si no hay
error, devuelve el número de bytes leídos. - ssize_t readv (int sfd, const struct iovec iov,
size_t iovcnt) - struct iovec
- caddr_t iov_base / Dirección inicial del
buffer / - int iov_len / Tamaño en bytes del buffer /
-
- Readv lee los datos del socket sfd y los
distribuye entre los distintos buffers
especificados por el array iov. El total de
elementos de iov viene especificado por iovcnt
iov0, .., ioviovcnt-1
19Lectura o recepción de mensajes de un socket (II)
- int recv (int sfd, void buf, int len, int flags)
- int recvfrom (int sfd,void buf,int len,int
flags,void from, int fromlen) - int recvmsg (int sfd, struct msghdr msg, int
flags) - sfd descriptor del socket del que se lee.
- buf puntero al buffer donde se escriben los
datos leídos. - len número máximo de bytes que cabe en el
buffer. - flags es una combinación de 2 bits
- MSG_PEEK1 el dato leído del socket no se vacía,
se volverá a leer. - MSG_OOB1 lee sólo los datos "urgentes" (mensajes
fuera de banda). - Por lo tanto, flags puede valer 0 (00), 1 (01), 2
(10) o 3 (11). - En AF_UNIX no puede tener activos ninguno de los
dos anteriores. - Las 3 funciones devuelven el total de bytes
leídos del socket.
20Lectura o recepción de mensajes de un socket (III)
- int recv (int sfd, void buf, int len, int flags)
- int recvfrom (int sfd,void buf,int len,int
flags,void from, int fromlen) - int recvmsg (int sfd, struct msghdr msg, int
flags) - En SOCK_STREAM, las llamadas sólo pueden usarse
después de haber establecido una conexión con
CONNECT. - En los SOCK_DGRAM no es necesario, si se hace,
entonces se recibe siempre del mismo, si no, se
recibe de cualquiera. - Recvfrom puede devolver la dirección del socket
desde el que se enviaron los datos. Si
fromltgtNULL, al volver, la dirección del socket
origen se recibirá en la estructura apuntada, y
fromlen debe contener el tamaño de la dirección
apuntada por from (al llamar a la función, la que
tenga from, y al salir la que ha leído realmente) - En SOCK_STREAM, recvfrom recv.
21Lectura o recepción de mensajes de un socket (IV)
- int recv (int sfd, void buf, int len, int flags)
- int recvfrom (int sfd,void buf,int len,int
flags,void from, int fromlen) - int recvmsg (int sfd, struct msghdr msg, int
flags) - recvmsg permite que los datos leídos puedan
distribuirse entre varios buffers. Así msg es un
array de cabeceras de mensaje con la siguiente
estructura - struct msghdr
- caddr_t msg_name / dirección de socket
(opcional) / - int msg_namelen / tamaño de la dirección de
socket / - struct iovec msg_iov / array de buffers
sobre los que distribuir los datos leídos / - int msg_iovlen / num. de elementos del array
msg_iov / - caddr_t msg_accrights / derechos de acceso /
- int msg_accrightslen / tamaño de msg_accrights
/
22Escritura o envío de mensajes a un socket
- int write (int sfd, char buf, unsigned nbyte)
- Write escribe nbyte bytes del buffer apuntado por
buf en el socket sfd. Si no hay error, devuelve
el número de bytes escritos realmente. - ssize_t writev (int sfd, const struct iovec iov,
size_t iovcnt) - Writev escribe los datos en el socket sfd
tomándolos de los distintos buffers especificados
por el array iov. El total de elementos de iov
viene especificado por iovcnt. - Writev devuelve el número total de bytes
escritos.
23Escritura o envío de mensajes a un socket (II)
- int send (int sfd, void buf, int len, int flags)
- int sendto (int sfd, void buf, int len, int
flags, void to, int tolen) - int sendmsg (int sfd, struct msghdr msg, int
flags) - sfd descriptor del socket donde se escribe.
- buf puntero al buffer de donde se leen los
datos a escribir. - len número de bytes en el buffer.
- flags puede valer 0 o MSG_OOB. (MSG_PEEK no
tiene sentido aquí) - Las 3 funciones devuelven el total de bytes
escritos en el socket. - En SOCK_STREAM, las llamadas sólo pueden usarse
después de haber establecido una conexión con
CONNECT. - En los SOCK_DGRAM no es necesario.
24Obtención de nombres de socket
- int getsockname(int sfd, void addr, int addrlen)
- int getpeername(int sfd, void addr, int addrlen)
- En la familia SOCK_STREAM.
- Getsockname devuelve sobre la estructura apuntada
por addr, la dirección del socket de descriptor
sfd. - Getpeername devuelve sobre la estructura apuntada
por addr, la dirección del socket que se
encuentra conectado al socket de descriptor sfd. - addrlen indica el tamaño en bytes de la
estructura apuntada por addr.
25Nombre del nodo actual
- int gethostname (char hostname, size_t size)
- Se usa para determinar el nombre oficial que
tiene un nodo en la red. - gethostname devuelve en el array apuntado por
hostname el nombre oficial de host del ordenador
que hace la llamada. Size contiene la longitud de
ese array.
26Pipes con sockets
- int socketpair(int family, int type, int
protocol, int sockvec2) - Crea un par de sockets que permiten la
comunicación bidireccional. - family, type y protocol tiene el mismo
significado que en la definición de socket
aunque, por ahora, sólo admite la familia
AF_UNIX. - sockvec es un vector que contendrá los 2
descriptores de los sockets generados.
27Cierre del socket
- int close (int sfd)
- cierra el socket en los dos sentidos de recepción
y envío. - int shutdown(int sfd, int how)
- Si how0 cierra recepción de datos, 1 cierra
envío de datos y 2 cierra ambos.
28Lectura del fichero etc/hosts
- struct hostent gethostent()
- struct hostent gethostbyname(char name)
- struct hostent gethostbyaddr(const char addr,
int len, int type) - int sethostent(int stayopen)
- int endhostname()
- etc/hosts contiene la información sobre todas las
direcciones internet y los nombres de host de
todos los nodos conectados a la red. - Si nuestra red tiene un servidor de nombres
(DNS), es éste el que resuelve la correspondencia
entre direcciones IP y nombres de máquinas.
29Lectura del fichero etc/hosts (II)
- struct hostent
- char h_name
- char h_aliases
- int h_addrtype
- int h_lenght
- char h_addr_list
- define h_addr h_addrlist0 / Para
compatibilizar / - h_name nombre oficial del host.
- h_aliases array con nombres alternativos del
host - h_addrtype Siempre AF_INET.
- h_lenght longitud en bytes de la estructura.
- h_addr_list array de direcciones de red a las
que responde el host. La lista se devuelve en
formato de trabajo interno de la máquina
(unsigned long), no como cadena de caracteres.
30Lectura del fichero etc/hosts (III)
- struct hostent gethostent()
- struct hostent gethostbyname(char name)
- struct hostent gethostbyaddr(const char addr,
int len, int type) - int sethostent(int stayopen)
- int endhostname()
- Gethostent lee la siguiente línea del fichero
devolviendo la estructura anterior. Si es la
primera, además abre el fichero para lectura. Si
es la última, devuelve NULL. - Sethostent abre el fichero para lectura y lo deja
preparado para leer en la primera línea. Si
además stayopen es distinto de 0, después de cada
llamada de gethostent no se cierra el fichero. - Endhostent cierra el fichero.
- Gethostbyname lee secuencialmente el fichero
hasta encontrar el nombre de host, o su alias,
que coincide con name. - Gethostbyaddr hace lo propio con la dirección
addr con longitud len.
31Esquema general C/S
Proceso Servidor
Proceso Cliente
Abrir canal
Abrir canal
Publicar dirección
Contactar servidor
Esperar petición servicio
proceso hijo
Pedir servicio
fork
Atender cliente
Esperar respuesta
proceso padre
Fin hijo
Fin cliente
32Esquema Cliente-Servidor con sockets orientados
a conexión
Proceso Servidor
Proceso Cliente
socket( )
socket( )
bind( )
listen( )
accept( )
connect( )
read( )
write( )
write( )
read( )
close( )
33Esquema Cliente-Servidorcon sockets orientados a
datagrama
Proceso Servidor
Proceso Cliente
socket( )
socket( )
bind( )
bind( )
recvfrom()
sendto( )
sendto( )
recvfrom()
close( )
34Bibliografía
- Márquez García, Francisco Manuel. UNIX,
programación avanzada. RA-MA, 1993 - Rifflet, J.M. Comunicaciones en UNIX
McGraw-Hill, 1992
35Sockets en JAVA
36Sockets en JAVA
- Modelo general
- SERVIDOR CLIENTE
- ServerSocket(port,timeout) Socket(host,port)
- accept()
- ............ ............
- OutputStream OutputStream
- InputStream InputStream
- ............ ............
- close() close()
37Conexión cliente
- Socket miCliente
- miCliente new Socket(maquina, numeroPuerto)
- --------------------------------------------------
------------------- - Socket miCliente
- try
- miCliente new Socket(maquina,numeroPuerto)
- catch ( IOException e )
- System.out.println ( e )
38Conexión servidor
- Socket miServicio
- try
- miServicio new ServerSocket(numeroPuerto)
- catch ( IOException e )
- System.out.println ( e )
-
- .......
- Socket socketServicio null
- try
- socketServicio miServicio.accept()
- catch ( IOException e )
- System.out.println ( e )
-
39Creación Streams entrada
- DataInputStream entrada (--- CLIENTE ---)
- try
- entrada new DataInputStream(
miCliente.getInputStream() ) - catch ( IOException e )
- System.out.println ( e )
-
-
- DataInputStream entrada (--- SERVIDOR ---)
- try
- entrada new DataInputStream(
socketServicio.getInputStream() ) - catch ( IOException e )
- System.out.println ( e )
-
40DataInputStream
- Lectura del socket
- read()
- readChar()
- readInt()
- readDouble()
- readLine()
41Creación Streams salida
- PrintStream salida (--- CLIENTE y SERVIDOR ---)
- try
- salida new PrintStream( miCliente.getOutputStre
am() ) - catch ( IOException e )
- System.out.println ( e )
-
-
- DataOutputStream salida (--- CLIENTE y SERVIDOR
---) - try
- entrada new DataOutputStream(miCliente.getOutpu
tStream() ) - catch ( IOException e )
- System.out.println ( e )
-
42PrintStream//DataOutputStream
- PrintStream
- write()
- println()
- DataOutputStream
- writeBytes()
43Cierre Sockets
- CLIENTE
- PrintStream salida
- try
- salida.close()
- entrada.close()
- miCliente.close()
- catch ( IOException e )
- System.out.println ( e )
-
-
SERVIDOR PrintStream salida try
salida.close() entrada.close() socketServic
io.close() miServicio.close() catch (
IOException e ) System.out.println ( e
)
44Clases útiles
- Socket objeto básico
- ServerSocket socket de servidor
- DatagramSocket socket datagrama
- DatagramPacket paquete datagrama
- MulticastSocket comunicación en grupo
- SocketImpl interfaz para crear un modelo de
comunicación