Está en la página 1de 64

Programacin Programacin

de sockets de sockets
Xavier Perramon Tornil Xavier Perramon Tornil
Enric Peig Oliv Enric Peig Oliv

P03/75064/00978 P03/75064/00978
FUOC P03/75064/00978 Programacin de sockets FUOC P03/75064/00978 Programacin de sockets

ndice ndice

Introduccin............................................................................................... 5 Introduccin............................................................................................... 5

Objetivos ...................................................................................................... 6 Objetivos ...................................................................................................... 6

1. Qu son los sockets ............................................................................... 7 1. Qu son los sockets ............................................................................... 7


1.1. Visin general .................................................................................... 7 1.1. Visin general .................................................................................... 7
1.2. Relacin entre los sockets y el sistema operativo UNIX .................... 7 1.2. Relacin entre los sockets y el sistema operativo UNIX .................... 7
1.3. Direcciones de los sockets y su clasificacin ...................................... 8 1.3. Direcciones de los sockets y su clasificacin ...................................... 8
1.3.1. El espacio de nombres de ficheros ......................................... 9 1.3.1. El espacio de nombres de ficheros ......................................... 9
1.3.2. El espacio de nombres Internet.............................................. 9 1.3.2. El espacio de nombres Internet.............................................. 9
1.4. Estilos de comunicacin .................................................................... 12 1.4. Estilos de comunicacin .................................................................... 12
1.4.1. Estilo secuencia de bytes ......................................................... 11 1.4.1. Estilo secuencia de bytes ......................................................... 11
1.4.2. Estilo datagrama..................................................................... 12 1.4.2. Estilo datagrama..................................................................... 12
1.5. La comunicacin entre sockets .......................................................... 13 1.5. La comunicacin entre sockets .......................................................... 13

2. Sockets con lenguaje C......................................................................... 15 2. Sockets con lenguaje C......................................................................... 15


2.1. Operaciones comunes a servidores y clientes ................................... 15 2.1. Operaciones comunes a servidores y clientes ................................... 15
2.1.1. Crear un socket........................................................................ 15 2.1.1. Crear un socket........................................................................ 15
2.1.2. Asignar direccin a un socket ................................................. 18 2.1.2. Asignar direccin a un socket ................................................. 18
2.1.3. Enviar datos............................................................................ 23 2.1.3. Enviar datos............................................................................ 23
2.1.4. Recibir datos ........................................................................... 26 2.1.4. Recibir datos ........................................................................... 26
2.1.5. Esperar disponibilidad de datos ............................................. 29 2.1.5. Esperar disponibilidad de datos ............................................. 29
2.1.6. Cerrar un socket ...................................................................... 33 2.1.6. Cerrar un socket ...................................................................... 33
2.2. Operaciones propias de los servidores............................................... 34 2.2. Operaciones propias de los servidores............................................... 34
2.2.1. Preparar un socket para recibir conexiones ............................ 34 2.2.1. Preparar un socket para recibir conexiones ............................ 34
2.2.2. Aceptar una peticin de conexin ......................................... 35 2.2.2. Aceptar una peticin de conexin ......................................... 35
2.2.3. Ejemplos de programacin de un servidor ............................ 36 2.2.3. Ejemplos de programacin de un servidor ............................ 36
2.2.4. El servidor inetd ................................................................... 39 2.2.4. El servidor inetd ................................................................... 39
2.3. Operaciones propias de los clientes................................................... 42 2.3. Operaciones propias de los clientes................................................... 42
2.3.1. Conectar un socket.................................................................. 42 2.3.1. Conectar un socket.................................................................. 42
2.3.2. Ejemplo de programacin de un cliente................................ 44 2.3.2. Ejemplo de programacin de un cliente................................ 44
2.4. Operaciones auxiliares....................................................................... 45 2.4. Operaciones auxiliares....................................................................... 45
2.4.1. Obtener direcciones de sockets ............................................... 45 2.4.1. Obtener direcciones de sockets ............................................... 45
2.4.2. Convertir direcciones Internet............................................... 46 2.4.2. Convertir direcciones Internet............................................... 46
2.4.3. Consultar bases de datos de nombres .................................... 46 2.4.3. Consultar bases de datos de nombres .................................... 46
2.4.4. Acceso secuencial a las bases de datos ................................... 50 2.4.4. Acceso secuencial a las bases de datos ................................... 50
2.4.5. Opciones de los sockets........................................................... 50 2.4.5. Opciones de los sockets........................................................... 50

3. Sockets con lenguaje Java ................................................................... 54 3. Sockets con lenguaje Java ................................................................... 54
3.1. Las clases Socket y ServerSocket ................................................. 54 3.1. Las clases Socket y ServerSocket ................................................. 54
3.2. Ejemplo de programacin de un servidor y un cliente..................... 56 3.2. Ejemplo de programacin de un servidor y un cliente..................... 56
3.3. Comunicacin con datagramas......................................................... 58 3.3. Comunicacin con datagramas......................................................... 58
FUOC P03/75064/00978 Programacin de sockets FUOC P03/75064/00978 Programacin de sockets

Resumen....................................................................................................... 60 Resumen....................................................................................................... 60

Actividades.................................................................................................. 63 Actividades.................................................................................................. 63

Ejercicios de autoevaluacin .................................................................. 63 Ejercicios de autoevaluacin .................................................................. 63

Solucionario................................................................................................ 64 Solucionario................................................................................................ 64

Glosario ........................................................................................................ 64 Glosario ........................................................................................................ 64

Bibliografa................................................................................................. 64 Bibliografa................................................................................................. 64
FUOC P03/75064/00978 5 Programacin de sockets FUOC P03/75064/00978 5 Programacin de sockets

Introduccin Introduccin

Este mdulo didctico contiene una descripcin detallada de la llamada inter- Consultad los protocolos TCP y UDP Este mdulo didctico contiene una descripcin detallada de la llamada inter- Consultad los protocolos TCP y UDP
en los apartados 7 y 8 del mdulo en los apartados 7 y 8 del mdulo
didctico TCP/IP: los protocolos didctico TCP/IP: los protocolos
faz de programacin de sockets. Dicha interfaz facilita el desarrollo de aplicacio- de la red Internet de esta asignatura. faz de programacin de sockets. Dicha interfaz facilita el desarrollo de aplicacio- de la red Internet de esta asignatura.

nes basadas en los protocolos de transporte TCP y UDP, que se han estudiado nes basadas en los protocolos de transporte TCP y UDP, que se han estudiado
en otros mdulos. Diseada en un inicio para el sistema operativo UNIX, en la en otros mdulos. Diseada en un inicio para el sistema operativo UNIX, en la
actualidad existen versiones de la librera de sockets para una gran variedad actualidad existen versiones de la librera de sockets para una gran variedad
de plataformas y sistemas operativos. de plataformas y sistemas operativos.

La interfaz de programacin de sockets est formada por una serie de llamadas La interfaz de programacin de sockets est formada por una serie de llamadas
al sistema, funciones auxiliares de soporte y definiciones de tipos de datos para al sistema, funciones auxiliares de soporte y definiciones de tipos de datos para
representar las variables con que trabaja, tales como direcciones IP y nmeros representar las variables con que trabaja, tales como direcciones IP y nmeros
de puerto. En este mdulo se describen todos estos elementos de la interfaz con de puerto. En este mdulo se describen todos estos elementos de la interfaz con
suficiente detalle para poderlo utilizar como manual de referencia. suficiente detalle para poderlo utilizar como manual de referencia.

Para poder seguir este mdulo, son necesarios ciertos conocimientos o bien del Para poder seguir este mdulo, son necesarios ciertos conocimientos o bien del
lenguaje de programacin C, o bien del lenguaje Java. Asimismo, es conve- lenguaje de programacin C, o bien del lenguaje Java. Asimismo, es conve-
niente, pero no imprescindible, tener algunos conocimientos de sistemas ope- niente, pero no imprescindible, tener algunos conocimientos de sistemas ope-
rativos en general y de UNIX en particular. rativos en general y de UNIX en particular.
FUOC P03/75064/00978 6 Programacin de sockets FUOC P03/75064/00978 6 Programacin de sockets

Objetivos Objetivos

Los objetivos principales que debis lograr con este mdulo didctico son los Los objetivos principales que debis lograr con este mdulo didctico son los
siguientes: siguientes:

1. Saber situar la interfaz de programacin de sockets en el contexto de los 1. Saber situar la interfaz de programacin de sockets en el contexto de los
protocolos TCP, UDP e IP, de las aplicaciones Internet y del sistema opera- protocolos TCP, UDP e IP, de las aplicaciones Internet y del sistema opera-
tivo UNIX. tivo UNIX.

2. Conocer con detalle las llamadas al sistema que forman la interfaz de los 2. Conocer con detalle las llamadas al sistema que forman la interfaz de los
sockets y los parmetros de los mismos, si se opta por trabajar con el len- sockets y los parmetros de los mismos, si se opta por trabajar con el len-
guaje C, o conocer detalladamente las clases de Java que proporcionan guaje C, o conocer detalladamente las clases de Java que proporcionan
toda la funcionalidad de los sockets. toda la funcionalidad de los sockets.

3. Ver cmo la interfaz de programacin de sockets puede utilizarse para dife- 3. Ver cmo la interfaz de programacin de sockets puede utilizarse para dife-
rentes tipos de aplicaciones: comunicacin de procesos en un mismo orde- rentes tipos de aplicaciones: comunicacin de procesos en un mismo orde-
nador, o en ordenadores conectados por medio de una red, y aplicaciones nador, o en ordenadores conectados por medio de una red, y aplicaciones
basadas en protocolos de transporte fiables o en datagramas no fiables. basadas en protocolos de transporte fiables o en datagramas no fiables.

4. Poder escribir aplicaciones basadas en sockets, tanto programas cliente como 4. Poder escribir aplicaciones basadas en sockets, tanto programas cliente como
programas servidor. programas servidor.

5. Conocer las principales funciones auxiliares que incorpora la interfaz de 5. Conocer las principales funciones auxiliares que incorpora la interfaz de
los sockets (o, si procede, los mtodos de las clases Java), tales como las que los sockets (o, si procede, los mtodos de las clases Java), tales como las que
permiten traducir nombres a direcciones o las que sirven para modificar el permiten traducir nombres a direcciones o las que sirven para modificar el
comportamiento de los sockets por medio de sus opciones. comportamiento de los sockets por medio de sus opciones.
FUOC P03/75064/00978 7 Programacin de sockets FUOC P03/75064/00978 7 Programacin de sockets

1. Qu son los sockets 1. Qu son los sockets

1.1. Visin general 1.1. Visin general

Al principio de la dcada de los ochenta, una parte importante de los ordena- Al principio de la dcada de los ochenta, una parte importante de los ordena-
dores conectados por la red ARPANET y a su sucesora, la red ARPA Internet, dores conectados por la red ARPANET y a su sucesora, la red ARPA Internet,
sobre las que se desarrollaron los protocolos IP, TCP y UDP, utilizaba el siste- sobre las que se desarrollaron los protocolos IP, TCP y UDP, utilizaba el siste-
ma operativo UNIX y, ms concretamente, la variante de la Universidad de ma operativo UNIX y, ms concretamente, la variante de la Universidad de
Berkeley (BSD UNIX). A partir de la versin BSD 4.2, se incorpor a este sistema Berkeley (BSD UNIX). A partir de la versin BSD 4.2, se incorpor a este sistema
operativo una serie de llamadas en el mbito del ncleo (o kernel) para facilitar operativo una serie de llamadas en el mbito del ncleo (o kernel) para facilitar
el diseo de aplicaciones que utilizaran los protocolos de ARPANET. Dichas el diseo de aplicaciones que utilizaran los protocolos de ARPANET. Dichas
llamadas, junto con algunas funciones auxiliares de la librera estndar de llamadas, junto con algunas funciones auxiliares de la librera estndar de
UNIX, forman la llamada interfaz de programacin de sockets. UNIX, forman la llamada interfaz de programacin de sockets.

Un socket o conector es un punto de acceso a los servicios de comunicacin Un socket o conector es un punto de acceso a los servicios de comunicacin
en el mbito de transporte. Cada socket tiene asociada una direccin que lo en el mbito de transporte. Cada socket tiene asociada una direccin que lo
identifica. Conociendo esta ltima, se puede establecer una comunicacin identifica. Conociendo esta ltima, se puede establecer una comunicacin
con un socket para que acte como extremo de un canal bidireccional. con un socket para que acte como extremo de un canal bidireccional.

Existen otras interfaces de programacin de los protocolos TCP y UDP, tales Existen otras interfaces de programacin de los protocolos TCP y UDP, tales
Interfaz TLI Interfaz TLI
como la TLI, pero la de los sockets es probablemente la que ms se utiliza en la como la TLI, pero la de los sockets es probablemente la que ms se utiliza en la
Para acceder a los protocolos Para acceder a los protocolos
actualidad. Adems de haberse incorporado a la especificacin System V Re- actualidad. Adems de haberse incorporado a la especificacin System V Re-
de transporte, la interfaz TLI de transporte, la interfaz TLI
lease 4 UNIX, la interfaz de programacin de los sockets se ha llevado a dife- utiliza el mecanismo de los flu- lease 4 UNIX, la interfaz de programacin de los sockets se ha llevado a dife- utiliza el mecanismo de los flu-
jos de datos(streams), propio jos de datos(streams), propio
rentes sistemas operativos distintos o se ha adaptado a los mismos. de la variante de UNIX llamada rentes sistemas operativos distintos o se ha adaptado a los mismos. de la variante de UNIX llamada
System V. System V.
TLI es la sigla de Transport TLI es la sigla de Transport
Layer Interface. Layer Interface.
1.2. Relacin entre los sockets y el sistema operativo UNIX 1.2. Relacin entre los sockets y el sistema operativo UNIX

Dado su origen, la interfaz de programacin de los sockets est ntimamente vin- Dado su origen, la interfaz de programacin de los sockets est ntimamente vin-
culada al sistema operativo UNIX. Algunas de las llamadas proporcionadas por la culada al sistema operativo UNIX. Algunas de las llamadas proporcionadas por la
interfaz son directas al ncleo del sistema, y otras constituyen funciones integra- interfaz son directas al ncleo del sistema, y otras constituyen funciones integra-
das en la librera estndar del lenguaje de programacin ms utilizado en UNIX, das en la librera estndar del lenguaje de programacin ms utilizado en UNIX,
el lenguaje C (desde el punto de vista del programador, las llamadas al ncleo el lenguaje C (desde el punto de vista del programador, las llamadas al ncleo
tambin se ven como si fueran funciones de la librera C). tambin se ven como si fueran funciones de la librera C).

En la actualidad, hay disponibles otros lenguajes de programacin que propor- En la actualidad, hay disponibles otros lenguajes de programacin que propor-
* De hecho, el intrprete de Perl * De hecho, el intrprete de Perl
cionan acceso a las llamadas del sistema para trabajar con sockets, como el len- est escrito en C. cionan acceso a las llamadas del sistema para trabajar con sockets, como el len- est escrito en C.
guaje interpretado Perl*, o el lenguaje Java. En este mdulo veremos cmo se guaje interpretado Perl*, o el lenguaje Java. En este mdulo veremos cmo se
trabaja con sockets en dos de estos lenguajes: C y Java. trabaja con sockets en dos de estos lenguajes: C y Java.

El motivo de utilizar C es evidente: como se ha comentado, la relacin entre sockets y C El motivo de utilizar C es evidente: como se ha comentado, la relacin entre sockets y C
es bastante ntima. Por lo que respecta a Java, su uso est cada vez ms extendido, prin- es bastante ntima. Por lo que respecta a Java, su uso est cada vez ms extendido, prin-
cipalmente en el desarrollo de interfaces de usuario. Y el motivo de explicar los dos es cipalmente en el desarrollo de interfaces de usuario. Y el motivo de explicar los dos es
ofrecer al alumno la opcin de elegir el lenguaje en que se sienta ms cmodo a la hora ofrecer al alumno la opcin de elegir el lenguaje en que se sienta ms cmodo a la hora
de realizar aplicaciones con sockets. de realizar aplicaciones con sockets.
FUOC P03/75064/00978 8 Programacin de sockets FUOC P03/75064/00978 8 Programacin de sockets

En el modelo de programacin de los sockets se sigue la filosofa general de En el modelo de programacin de los sockets se sigue la filosofa general de
UNIX de tratar los dispositivos y los mecanismos de entrada/salida como fi- UNIX de tratar los dispositivos y los mecanismos de entrada/salida como fi-
cheros. Excepto la operacin de abrir o crear un socket, que es especial, las otras cheros. Excepto la operacin de abrir o crear un socket, que es especial, las otras
funciones bsicas aplicables a ficheros (leer datos, escribirlos, cerrar) tambin funciones bsicas aplicables a ficheros (leer datos, escribirlos, cerrar) tambin
son directamente aplicables a los sockets. Sin embargo, como es natural, exis- son directamente aplicables a los sockets. Sin embargo, como es natural, exis-
ten otras funciones que son especficas de estos ltimos. ten otras funciones que son especficas de estos ltimos.

De hecho, la interfaz de los sockets proporciona un mtodo general de comuni- De hecho, la interfaz de los sockets proporciona un mtodo general de comuni-
cacin entre procesos. Una de las posibilidades que ofrece este mtodo es comu- cacin entre procesos. Una de las posibilidades que ofrece este mtodo es comu-
nicar procesos que se ejecutan en un mismo ordenador, de manera similar a las nicar procesos que se ejecutan en un mismo ordenador, de manera similar a las
pipes (que tambin se representan por medio de descriptores de ficheros). La pipes (que tambin se representan por medio de descriptores de ficheros). La
aplicacin ms habitual, sin embargo, es utilizar los sockets como canal de comu- aplicacin ms habitual, sin embargo, es utilizar los sockets como canal de comu-
Consultad las pipes en el Consultad las pipes en el
nicacin entre procesos que pueden correr en ordenadores diferentes, conecta- subapartado 5.1 del mdulo nicacin entre procesos que pueden correr en ordenadores diferentes, conecta- subapartado 5.1 del mdulo
didctico Los dispositivos de entrada/ didctico Los dispositivos de entrada/
salida de la asignatura Sistemas salida de la asignatura Sistemas
dos mediante una red. operativos I. dos mediante una red. operativos I.

1.3. Direcciones de los sockets y su clasificacin 1.3. Direcciones de los sockets y su clasificacin

Como hemos visto, cada socket tiene asociada una direccin que sirve para Como hemos visto, cada socket tiene asociada una direccin que sirve para
identificarlo y para que se le puedan enviar datos desde otro socket. identificarlo y para que se le puedan enviar datos desde otro socket.

En numerosas ocasiones, tambin se habla del nombre de un socket, que no En numerosas ocasiones, tambin se habla del nombre de un socket, que no
es ms que su direccin. es ms que su direccin.

Asimismo, hemos visto que puede haber diferentes clases de sockets, bsicamen- Asimismo, hemos visto que puede haber diferentes clases de sockets, bsicamen-
te los que comunican procesos de un mismo sistema y los que permiten la co- te los que comunican procesos de un mismo sistema y los que permiten la co-
municacin entre sistemas diferentes. La distincin se efecta por medio de los municacin entre sistemas diferentes. La distincin se efecta por medio de los
nombres o direcciones, puesto que a cada clase de sockets le corresponde un es- nombres o direcciones, puesto que a cada clase de sockets le corresponde un es-
pacio de nombres diferente. pacio de nombres diferente.

De este modo, existen dos espacios de nombres bsicos que se pueden especi- De este modo, existen dos espacios de nombres bsicos que se pueden especi-
ficar para un socket y que son los siguientes: ficar para un socket y que son los siguientes:

El espacio de nombres de ficheros: se utiliza en los sockets que deben co- El espacio de nombres de ficheros: se utiliza en los sockets que deben co-
municar un proceso con otro del mismo sistema. municar un proceso con otro del mismo sistema.

El espacio de nombres Internet: se utiliza en los sockets que deben comuni- El espacio de nombres Internet: se utiliza en los sockets que deben comuni-
car un proceso con otro de cualquier sistema. En casos particulares, puede car un proceso con otro de cualquier sistema. En casos particulares, puede
ser el mismo sistema, aunque, por norma general, ser otro sistema al que ser el mismo sistema, aunque, por norma general, ser otro sistema al que
est conectado por medio de una red. est conectado por medio de una red.

Por otro lado, la clase de un socket tambin determina los protocolos de comu- Por otro lado, la clase de un socket tambin determina los protocolos de comu-
nicacin que se pueden utilizar. Por consiguiente, cuando se especifica a qu nicacin que se pueden utilizar. Por consiguiente, cuando se especifica a qu
espacio de nombres pertenece un socket, se indica al mismo tiempo un con- espacio de nombres pertenece un socket, se indica al mismo tiempo un con-
junto de posibles protocolos, de los que deber seleccionarse uno para poder junto de posibles protocolos, de los que deber seleccionarse uno para poder
establecer la comunicacin con otro socket (obviamente, para que dos sockets se establecer la comunicacin con otro socket (obviamente, para que dos sockets se
puedan comunicar deben utilizar el mismo protocolo). puedan comunicar deben utilizar el mismo protocolo).
FUOC P03/75064/00978 9 Programacin de sockets FUOC P03/75064/00978 9 Programacin de sockets

Por ello, en ocasiones se utiliza la expresin familia de protocolos como sinni- Por ello, en ocasiones se utiliza la expresin familia de protocolos como sinni-
* El trmino dominio tiene * El trmino dominio tiene
mo de espacio de nombres. Y en algunas situaciones tambin se utiliza el trmi- acepciones diferentes en otros mo de espacio de nombres. Y en algunas situaciones tambin se utiliza el trmi- acepciones diferentes en otros
contextos y podra dar lugar contextos y podra dar lugar
no dominio para referirse a un espacio de nombres*. a confusiones. no dominio para referirse a un espacio de nombres*. a confusiones.

En definitiva, podemos decir que los conceptos clase de socket, espacio de En definitiva, podemos decir que los conceptos clase de socket, espacio de
nombres, dominio (referido a nombres de sockets) y familia de protocolos se nombres, dominio (referido a nombres de sockets) y familia de protocolos se
pueden considerar equivalentes. pueden considerar equivalentes.

Asimismo, a cada espacio de nombres le corresponde un formato de direcciones; Asimismo, a cada espacio de nombres le corresponde un formato de direcciones;
as pues, tambin existe una asociacin obvia entre ambos conceptos. as pues, tambin existe una asociacin obvia entre ambos conceptos.

1.3.1. El espacio de nombres de ficheros 1.3.1. El espacio de nombres de ficheros

En el espacio de nombres de ficheros (denominado tambin dominio UNIX) las En el espacio de nombres de ficheros (denominado tambin dominio UNIX) las
Entradas de directorio Entradas de directorio
direcciones de los sockets simplemente constituyen nombres de ficheros. Es decir, direcciones de los sockets simplemente constituyen nombres de ficheros. Es decir,
a cada socket de esta clase le corresponde un fichero y, ms concretamente, en el Las entradas de directorio a cada socket de esta clase le corresponde un fichero y, ms concretamente, en el Las entradas de directorio
en el sistema de ficheros UNIX, en el sistema de ficheros UNIX,
caso del sistema operativo UNIX, una entrada de directorio de tipo socket en el sis- adems del tipo socket, pueden caso del sistema operativo UNIX, una entrada de directorio de tipo socket en el sis- adems del tipo socket, pueden
ser de tipo fichero regular, di- ser de tipo fichero regular, di-
tema de ficheros. Ello hace que slo se puedan utilizar los sockets de este espacio rectorio, enlace simblico (link), tema de ficheros. Ello hace que slo se puedan utilizar los sockets de este espacio rectorio, enlace simblico (link),
de nombres para comunicar procesos que se ejecuten en el mismo ordenador. pipe o dispositivo de bloques o de nombres para comunicar procesos que se ejecuten en el mismo ordenador. pipe o dispositivo de bloques o
de carecteres. de carecteres.

El mecanismo de comunicacin por medio de esta clase de sockets es similar al El mecanismo de comunicacin por medio de esta clase de sockets es similar al
de las pipes en UNIX. La diferencia principal reside en que en un socket la co- de las pipes en UNIX. La diferencia principal reside en que en un socket la co-
municacin es bidireccional, mientras que en una pipe slo se puede escribir municacin es bidireccional, mientras que en una pipe slo se puede escribir
por uno de los extremos y leer por el otro. por uno de los extremos y leer por el otro.

Como en este espacio de nombres los sockets residen en el sistema de ficheros, Como en este espacio de nombres los sockets residen en el sistema de ficheros,
Un ejemplo... Un ejemplo...
para asignarles un nombre es preciso considerar los requisitos impuestos por el para asignarles un nombre es preciso considerar los requisitos impuestos por el
... de aplicacin UNIX que uti- ... de aplicacin UNIX que uti-
sistema: es necesario tener permiso de escritura en el directorio en que se quiere liza los sockets del dominio de
sistema: es necesario tener permiso de escritura en el directorio en que se quiere liza los sockets del dominio de
crear el socket, no puede haber otra entrada (de cualquier tipo: fichero, directo- ficheros es el sistema de venta- crear el socket, no puede haber otra entrada (de cualquier tipo: fichero, directo- ficheros es el sistema de venta-
nas X, que en muchas imple- nas X, que en muchas imple-
rio, socket) con el mismo nombre, etc. En UNIX es habitual crear los sockets de mentaciones los utiliza para rio, socket) con el mismo nombre, etc. En UNIX es habitual crear los sockets de mentaciones los utiliza para
comunicar a los clientes comunicar a los clientes
esta clase en el directorio /tmp. con el servidor cuando corren esta clase en el directorio /tmp. con el servidor cuando corren
en el mismo ordenador. en el mismo ordenador.

1.3.2. El espacio de nombres Internet 1.3.2. El espacio de nombres Internet

El espacio de nombres Internet se denomina de este modo por la familia de pro- El espacio de nombres Internet se denomina de este modo por la familia de pro-
tocolos que se utilizan en la comunicacin entre los sockets (bsicamente TCP y tocolos que se utilizan en la comunicacin entre los sockets (bsicamente TCP y
UDP). La direccin de un socket en este espacio de nombres consta, adems del UDP). La direccin de un socket en este espacio de nombres consta, adems del
protocolo concreto que debe utilizarse, de los dos componentes siguientes: protocolo concreto que debe utilizarse, de los dos componentes siguientes:

La direccin de red del nodo, es decir, la direccin Internet de la mquina La direccin de red del nodo, es decir, la direccin Internet de la mquina
correspondiente. correspondiente.

Las direcciones Internet de las mquinas se representan por medio de los Consultad las direcciones utilizadas Las direcciones Internet de las mquinas se representan por medio de los Consultad las direcciones utilizadas
en el protocolo IP en el subapartado en el protocolo IP en el subapartado
nmeros de 32 bits (4 bytes) utilizados en el protocolo IP. Como puede 3.1 del mdulo didctico TCP/IP: los
protocolos de la red Internet
nmeros de 32 bits (4 bytes) utilizados en el protocolo IP. Como puede 3.1 del mdulo didctico TCP/IP: los
protocolos de la red Internet
de esta asignatura. de esta asignatura.
haber mquinas conectadas a ms de una red IP, una mquina puede dis- haber mquinas conectadas a ms de una red IP, una mquina puede dis-
poner de mltiples direcciones Internet; sin embargo, a cada direccin debe poner de mltiples direcciones Internet; sin embargo, a cada direccin debe
corresponderle una sola mquina. corresponderle una sola mquina.
FUOC P03/75064/00978 10 Programacin de sockets FUOC P03/75064/00978 10 Programacin de sockets

Un nmero de puerto. Sirve para distinguir los sockets de una mquina de- Un nmero de puerto. Sirve para distinguir los sockets de una mquina de-
terminada (para un protocolo determinado). terminada (para un protocolo determinado).

Tanto en TCP como en UDP, los nmeros de puerto son cantidades de 16 bits, Tanto en TCP como en UDP, los nmeros de puerto son cantidades de 16 bits,
de manera que su valor puede estar comprendido entre 1 y 65.535 (en mu- de manera que su valor puede estar comprendido entre 1 y 65.535 (en mu-
chos sistemas, el nmero 0 no corresponde a un puerto vlido, sino que re- chos sistemas, el nmero 0 no corresponde a un puerto vlido, sino que re-
presenta un puerto indeterminado). presenta un puerto indeterminado).

La gran mayora de las aplicaciones que utilizan sockets siguen el modelo clien- La gran mayora de las aplicaciones que utilizan sockets siguen el modelo clien-
te/servidor. En este ltimo, una de las partes, la que solicita un determinado El modelo cliente/servidor se explica te/servidor. En este ltimo, una de las partes, la que solicita un determinado El modelo cliente/servidor se explica
detalladamente en el captulo detalladamente en el captulo
servicio (el cliente), inicia la comunicacin, mientras que la otra parte, la que El modelo cliente-servidor del mdulo
didctico Aplicaciones Internet servicio (el cliente), inicia la comunicacin, mientras que la otra parte, la que El modelo cliente-servidor del mdulo
didctico Aplicaciones Internet
de esta asignatura. de esta asignatura.
proporciona el servicio (el servidor), espera que le lleguen las peticiones de ser- proporciona el servicio (el servidor), espera que le lleguen las peticiones de ser-
vicio y las responde. vicio y las responde.

Socket servidor Socket servidor

Cuando se crea un socket que debe actuar como destino de una comunica- Cuando se crea un socket que debe actuar como destino de una comunica-
cin (socket servidor), es importante asignarle una direccin bien determina- cin (socket servidor), es importante asignarle una direccin bien determina-
da, puesto que los sockets de origen (clientes) la necesitarn para poder da, puesto que los sockets de origen (clientes) la necesitarn para poder
establecer la conexin. Por norma general, la parte correspondiente a la direc- establecer la conexin. Por norma general, la parte correspondiente a la direc-
cin del servidor ya estar fijada y, por tanto, ser preciso preocuparse simple- cin del servidor ya estar fijada y, por tanto, ser preciso preocuparse simple-
mente por el nmero de puerto. mente por el nmero de puerto.

A la hora de asignar un nmero de puerto a un socket, es conveniente consi- A la hora de asignar un nmero de puerto a un socket, es conveniente consi-
derar que en el sistema operativo UNIX se encuentran definidos dos rangos de derar que en el sistema operativo UNIX se encuentran definidos dos rangos de
puertos: el correspondiente a los puertos reservados, con nmeros entre el 1 puertos: el correspondiente a los puertos reservados, con nmeros entre el 1
y el 1.023, y el resto de los puertos, con nmeros entre el 1.024 y el 65.535. y el 1.023, y el resto de los puertos, con nmeros entre el 1.024 y el 65.535.
Un proceso cualquiera por lo general no puede asignar un nmero de puerto Un proceso cualquiera por lo general no puede asignar un nmero de puerto
reservado a un socket; el sistema slo permite hacer esto ltimo a los procesos reservado a un socket; el sistema slo permite hacer esto ltimo a los procesos
con privilegios de superusuario. El motivo de esta restriccin es que los puer- con privilegios de superusuario. El motivo de esta restriccin es que los puer-
tos reservados se utilizan habitualmente para los servicios estndar como, por tos reservados se utilizan habitualmente para los servicios estndar como, por
ejemplo, telnet, ftp, rlogin, rsh, finger, etc. ejemplo, telnet, ftp, rlogin, rsh, finger, etc.

Si un proceso asignara a un socket uno de estos puertos, podra recibir conexiones de otros Si un proceso asignara a un socket uno de estos puertos, podra recibir conexiones de otros
* Por ejemplo, contraseas * Por ejemplo, contraseas
procesos que creeran que se conectaban al proceso servidor oficial y enviarles infor- (passwords). procesos que creeran que se conectaban al proceso servidor oficial y enviarles infor- (passwords).
macin falsa o recibir informacin secreta*. macin falsa o recibir informacin secreta*.

La tabla siguiente muestra los nmeros de puerto TCP asignados a algunos de La tabla siguiente muestra los nmeros de puerto TCP asignados a algunos de
los servicios Internet oficiales: los servicios Internet oficiales:

Servicio Puerto Servicio Puerto

ftp 21 ftp 21

telnet 23 telnet 23

smtp (correo) 25 smtp (correo) 25

finger 79 finger 79

http (WWW) 80 http (WWW) 80

nntp (noticias) 119 nntp (noticias) 119

rlogin 513 rlogin 513

rsh 514 rsh 514


FUOC P03/75064/00978 11 Programacin de sockets FUOC P03/75064/00978 11 Programacin de sockets

Socket cliente Socket cliente

Cuando se crea un socket para utilizarlo como origen de una comunicacin (socket Cuando se crea un socket para utilizarlo como origen de una comunicacin (socket
cliente), su nmero de puerto suele ser irrelevante. Lo que es ms habitual es cliente), su nmero de puerto suele ser irrelevante. Lo que es ms habitual es
dejar que el sistema asigne uno de manera automtica, puesto que la direc- dejar que el sistema asigne uno de manera automtica, puesto que la direc-
cin del socket cliente slo la necesita el socket servidor para saber a dnde cin del socket cliente slo la necesita el socket servidor para saber a dnde
debe enviar los datos intercambiados. debe enviar los datos intercambiados.

Existen algunos casos en los que es necesario asignar un nmero de puerto es- Existen algunos casos en los que es necesario asignar un nmero de puerto es-
pecfico a un socket cliente. Salvo situaciones especiales, por norma general pecfico a un socket cliente. Salvo situaciones especiales, por norma general
slo ser preciso asignar un nmero de puerto a un socket cuando deba actuar slo ser preciso asignar un nmero de puerto a un socket cuando deba actuar
como servidor. como servidor.

Las aplicaciones rsh y rlogin constituyen dos ejemplos de estos casos especiales. Estas l- Las aplicaciones rsh y rlogin constituyen dos ejemplos de estos casos especiales. Estas l-
timas permiten que un usuario acceda a un sistema remoto sin necesidad de identificarse timas permiten que un usuario acceda a un sistema remoto sin necesidad de identificarse
explcitamente*. Los servidores correspondientes basan la autenticacin en la identidad del explcitamente*. Los servidores correspondientes basan la autenticacin en la identidad del
* Una manera de identificarse sera * Una manera de identificarse sera
usuario en el sistema cliente y simplemente comprueban que est en una lista de usuarios con un nombre y una contrasea. usuario en el sistema cliente y simplemente comprueban que est en una lista de usuarios con un nombre y una contrasea.
autorizados. Por consiguiente, es capital que la identidad que se enva al sistema remoto autorizados. Por consiguiente, es capital que la identidad que se enva al sistema remoto
no se pueda falsificar con facilidad. Por ello, estos servidores slo permiten el acceso sin no se pueda falsificar con facilidad. Por ello, estos servidores slo permiten el acceso sin
identificacin cuando la conexin proviene de un puerto reservado. De este modo, existe identificacin cuando la conexin proviene de un puerto reservado. De este modo, existe
cierta garanta de que el proceso que pide la conexin disponga de suficientes privilegios cierta garanta de que el proceso que pide la conexin disponga de suficientes privilegios
para que se pueda confiar en la informacin que proporciona, es decir, en la identidad del para que se pueda confiar en la informacin que proporciona, es decir, en la identidad del
usuario en cuyo nombre solicita el acceso. usuario en cuyo nombre solicita el acceso.

Se debe tener en cuenta que, si, al asignar un nmero de puerto a un servidor, Se debe tener en cuenta que, si, al asignar un nmero de puerto a un servidor,
se elige un nmero cualquiera, existe la posibilidad de que este ltimo ya est se elige un nmero cualquiera, existe la posibilidad de que este ltimo ya est
asignado a un socket cliente al que el sistema haya proporcionado, como he- asignado a un socket cliente al que el sistema haya proporcionado, como he-
mos visto con anterioridad, una direccin automtica. Para evitar esto, mu- mos visto con anterioridad, una direccin automtica. Para evitar esto, mu-
chos sistemas dividen el rango de los nmeros de puerto no reservados en dos chos sistemas dividen el rango de los nmeros de puerto no reservados en dos
subrangos y garantizan que las direcciones generadas automticamente siem- subrangos y garantizan que las direcciones generadas automticamente siem-
pre estn en el primer subrango. De este modo, para que no haya conflictos, pre estn en el primer subrango. De este modo, para que no haya conflictos,
slo es preciso elegir para los servidores no estndar nmeros de puerto que slo es preciso elegir para los servidores no estndar nmeros de puerto que
estn en el segundo subrango. estn en el segundo subrango.

De hecho, los protocolos de transporte no impiden que dos sockets de un mismo sistema De hecho, los protocolos de transporte no impiden que dos sockets de un mismo sistema
utilicen el mismo nmero de puerto, siempre que no se intenten comunicar con el mismo utilicen el mismo nmero de puerto, siempre que no se intenten comunicar con el mismo
socket remoto. Sin embargo, por norma general, los sistemas no permiten reutilizar n- socket remoto. Sin embargo, por norma general, los sistemas no permiten reutilizar n-
meros de puerto; es decir, asignar a un socket un nmero que ya est ocupado, salvo que meros de puerto; es decir, asignar a un socket un nmero que ya est ocupado, salvo que
se utilice una opcin especfica de los sockets con esta finalidad. se utilice una opcin especfica de los sockets con esta finalidad.

1.4. Estilos de comunicacin 1.4. Estilos de comunicacin

Al establecer un canal de comunicacin entre dos procesos por medio de un Al establecer un canal de comunicacin entre dos procesos por medio de un
socket, uno de los parmetros que se debe especificar es el estilo que se utilizar socket, uno de los parmetros que se debe especificar es el estilo que se utilizar
en esta comunicacin. Bsicamente, existen dos estilos de comunicacin po- en esta comunicacin. Bsicamente, existen dos estilos de comunicacin po-
sibles (llamados tambin tipos de sockets): sibles (llamados tambin tipos de sockets):

El estilo secuencia de bytes. El estilo secuencia de bytes.


El estilo datagrama. El estilo datagrama.
FUOC P03/75064/00978 12 Programacin de sockets FUOC P03/75064/00978 12 Programacin de sockets

1.4.1. Estilo secuencia de bytes 1.4.1. Estilo secuencia de bytes

En los sockets que utilizan el estilo secuencia de bytes, los datos se transmiten En los sockets que utilizan el estilo secuencia de bytes, los datos se transmiten
de extremo a extremo como una corriente o flujo ordenado de bytes. de extremo a extremo como una corriente o flujo ordenado de bytes.

Asimismo, este estilo se puede llamar orientado a conexin, puesto que la comu- Asimismo, este estilo se puede llamar orientado a conexin, puesto que la comu-
nicacin consiste en establecer previamente una conexin con el socket remoto nicacin consiste en establecer previamente una conexin con el socket remoto
y despus utilizarla para intercambiar los datos. Cuando se utiliza el espacio de y despus utilizarla para intercambiar los datos. Cuando se utiliza el espacio de
nombres Internet, este estilo se corresponde con el protocolo TCP. nombres Internet, este estilo se corresponde con el protocolo TCP.

El protocolo de transporte utilizado en el estilo secuencia de bytes debe garan- El protocolo de transporte utilizado en el estilo secuencia de bytes debe garan-
tizar que los datos lleguen al otro extremo en el mismo orden en que se han tizar que los datos lleguen al otro extremo en el mismo orden en que se han
enviado y sin prdidas ni repeticiones. enviado y sin prdidas ni repeticiones.

Es posible que el protocolo permita la transmisin de datos fuera de ban- Es posible que el protocolo permita la transmisin de datos fuera de ban-
da. Por norma general, estos ltimos se utilizan para enviar informacin urgen- da. Por norma general, estos ltimos se utilizan para enviar informacin urgen-
te, puesto que se supone que el destinatario, cuando los reciba, los procesar te, puesto que se supone que el destinatario, cuando los reciba, los procesar
antes que los datos normales que tenga pendientes de leer. antes que los datos normales que tenga pendientes de leer.

1.4.2. Estilo datagrama 1.4.2. Estilo datagrama

En los sockets que utilizan el estilo datagrama, cada vez que el emisor escribe En los sockets que utilizan el estilo datagrama, cada vez que el emisor escribe
datos en los mismos se transmite un paquete individual o datagrama con di- datos en los mismos se transmite un paquete individual o datagrama con di-
chos datos, y cada vez que el destinatario quiere leer estos ltimos recibe como chos datos, y cada vez que el destinatario quiere leer estos ltimos recibe como
mximo un datagrama. mximo un datagrama.

Todos los datagramas contienen la direccin del socket al que van dirigidos, de Todos los datagramas contienen la direccin del socket al que van dirigidos, de
manera que se pueden direccionar independientemente. Ello hace que algn da- manera que se pueden direccionar independientemente. Ello hace que algn da-
tagrama pueda llegar a su destino despus de otro que se ha enviado ms tarde y, tagrama pueda llegar a su destino despus de otro que se ha enviado ms tarde y,
por tanto, no hay garantas sobre el orden en que se recibirn los datos en el otro por tanto, no hay garantas sobre el orden en que se recibirn los datos en el otro
extremo. Asimismo, puede suceder que algn datagrama se pierda o llegue dupli- extremo. Asimismo, puede suceder que algn datagrama se pierda o llegue dupli-
cado, mientras que los que han seguido otro camino lleguen correctamente. cado, mientras que los que han seguido otro camino lleguen correctamente.

Este estilo tambin se denomina no orientado a conexin, puesto que, por el he- Este estilo tambin se denomina no orientado a conexin, puesto que, por el he-
cho de utilizar paquetes direccionados individualmente a su destino, no es cho de utilizar paquetes direccionados individualmente a su destino, no es
preciso establecer ninguna conexin previa con el socket remoto. Cuando se preciso establecer ninguna conexin previa con el socket remoto. Cuando se
utiliza el espacio de nombres Internet, dicho estilo se corresponde con el pro- utiliza el espacio de nombres Internet, dicho estilo se corresponde con el pro-
tocolo UDP. tocolo UDP.

Con el uso de datagramas no se garantiza la llegada de todos los paquetes, ni Con el uso de datagramas no se garantiza la llegada de todos los paquetes, ni
su orden, ni su unicidad. su orden, ni su unicidad.

La ventaja de este estilo de comunicacin radica en que requiere muchos me- La ventaja de este estilo de comunicacin radica en que requiere muchos me-
nos recursos que el estilo secuencia de bytes (no se necesitan nmeros de nos recursos que el estilo secuencia de bytes (no se necesitan nmeros de
secuencia en las cabeceras, buffers y ventanas de transmisin y recepcin, con- secuencia en las cabeceras, buffers y ventanas de transmisin y recepcin, con-
firmaciones acknowledgements, retransmisiones, etc.). firmaciones acknowledgements, retransmisiones, etc.).
FUOC P03/75064/00978 13 Programacin de sockets FUOC P03/75064/00978 13 Programacin de sockets

Los datagramas son apropiados cuando no es indispensable la fiabilidad total en Los datagramas son apropiados cuando no es indispensable la fiabilidad total en
la recepcin de los datos, por ejemplo cuando basta con un mecanismo sencillo la recepcin de los datos, por ejemplo cuando basta con un mecanismo sencillo
de recuperacin de los errores (como puede ser reenviar un paquete si no se ha de recuperacin de los errores (como puede ser reenviar un paquete si no se ha
recibido ninguna respuesta despus de cierto tiempo). En este caso, los mecanis- recibido ninguna respuesta despus de cierto tiempo). En este caso, los mecanis-
mos de correccin, si existen, se implementan en el nivel de aplicacin. mos de correccin, si existen, se implementan en el nivel de aplicacin.

En cambio, cuando se necesita asegurar la recepcin ordenada de los datos sin En cambio, cuando se necesita asegurar la recepcin ordenada de los datos sin
prdidas ni repeticiones, no es conveniente que la aplicacin utilice datagra- prdidas ni repeticiones, no es conveniente que la aplicacin utilice datagra-
mas y se intente recuperar de los errores por s misma, sino que es ms eficien- mas y se intente recuperar de los errores por s misma, sino que es ms eficien-
te encargar esta tarea a los niveles inferiores (es decir, utilizar un protocolo de te encargar esta tarea a los niveles inferiores (es decir, utilizar un protocolo de
transporte que garantice la fiabilidad). transporte que garantice la fiabilidad).

1.5. La comunicacin entre sockets 1.5. La comunicacin entre sockets

Para poder establecer una comunicacin entre dos sockets, las dos partes invo- Para poder establecer una comunicacin entre dos sockets, las dos partes invo-
lucradas, cliente y servidor, deben efectuar una serie de operaciones, antes y lucradas, cliente y servidor, deben efectuar una serie de operaciones, antes y
despus de llevar a cabo el intercambio de informacin. despus de llevar a cabo el intercambio de informacin.

Las operaciones que debe efectuar el servidor son las siguientes: Las operaciones que debe efectuar el servidor son las siguientes:

Crear un socket en el espacio de nombres y con el protocolo deseados. Crear un socket en el espacio de nombres y con el protocolo deseados.

Asignar una direccin al socket. Asignar una direccin al socket.

Dejar el socket preparado para recibir conexiones y crear una cola en la que Dejar el socket preparado para recibir conexiones y crear una cola en la que
se irn guardando las peticiones que le lleguen (slo en los protocolos se irn guardando las peticiones que le lleguen (slo en los protocolos
orientados a conexin). Esta operacin se conoce como establecer una co- orientados a conexin). Esta operacin se conoce como establecer una co-
nexin pasiva. nexin pasiva.

Aceptar una peticin de conexin de la cola o esperar hasta que llegue una Aceptar una peticin de conexin de la cola o esperar hasta que llegue una
si no hay ninguna (slo en los protocolos orientados a conexin). si no hay ninguna (slo en los protocolos orientados a conexin).

Intercambiar datos con el cliente que ha solicitado la comunicacin leyen- Intercambiar datos con el cliente que ha solicitado la comunicacin leyen-
do los datos y escribindolos en el socket. do los datos y escribindolos en el socket.

Cerrar el socket cuando haya finalizado el intercambio. Cerrar el socket cuando haya finalizado el intercambio.

Por otro lado, las operaciones que debe efectuar el cliente son las siguientes: Por otro lado, las operaciones que debe efectuar el cliente son las siguientes:

Crear un socket en el espacio de nombres y con el protocolo deseados. Crear un socket en el espacio de nombres y con el protocolo deseados.

Asignar una direccin al socket (si la familia de protocolos no lo requiere, Asignar una direccin al socket (si la familia de protocolos no lo requiere,
como en el caso de los protocolos Internet, este paso es opcional). como en el caso de los protocolos Internet, este paso es opcional).

Enviar una peticin de conexin al servidor (slo en los protocolos orienta- Enviar una peticin de conexin al servidor (slo en los protocolos orienta-
dos a conexin). Esta operacin se conoce como establecer una conexin activa. dos a conexin). Esta operacin se conoce como establecer una conexin activa.
FUOC P03/75064/00978 14 Programacin de sockets FUOC P03/75064/00978 14 Programacin de sockets

Intercambiar datos con el servidor leyndolos y escribindolos en el socket. Intercambiar datos con el servidor leyndolos y escribindolos en el socket.

Cerrar el socket cuando haya finalizado el intercambio. Cerrar el socket cuando haya finalizado el intercambio.

El captulo 2 de este mdulo El captulo 2 de este mdulo


La figura siguiente recoge las operaciones correspondientes a los clientes y a muestra cmo se realizan estas
operaciones en lenguaje C y el captulo
La figura siguiente recoge las operaciones correspondientes a los clientes y a muestra cmo se realizan estas
operaciones en lenguaje C y el captulo
3, en Java. 3, en Java.
los servidores (en el caso de los protocolos orientados a conexin): los servidores (en el caso de los protocolos orientados a conexin):
FUOC P03/75064/00978 15 Programacin de sockets FUOC P03/75064/00978 15 Programacin de sockets

2. Sockets con lenguaje C 2. Sockets con lenguaje C

A continuacin, veremos con detalle todas las operaciones que hemos descrito A continuacin, veremos con detalle todas las operaciones que hemos descrito
en el apartado anterior y las llamadas correspondientes proporcionadas por la en el apartado anterior y las llamadas correspondientes proporcionadas por la
interfaz de programacin de los sockets en UNIX, agrupadas en tres categoras: interfaz de programacin de los sockets en UNIX, agrupadas en tres categoras:
las comunes a servidores y clientes, las propias de los servidores y las propias las comunes a servidores y clientes, las propias de los servidores y las propias
de los clientes. de los clientes.

2.1. Operaciones comunes a servidores y clientes 2.1. Operaciones comunes a servidores y clientes

2.1.1. Crear un socket 2.1.1. Crear un socket

El prototipo de la llamadas bsica para crear un socket est declarado en el fi- El prototipo de la llamadas bsica para crear un socket est declarado en el fi-
El fichero <sys/socket.h> El fichero <sys/socket.h>
chero cabecera <sys/socket.h>: chero cabecera <sys/socket.h>:
En algunos sistemas, es necesa- En algunos sistemas, es necesa-
rio haber incluido el fichero ca- rio haber incluido el fichero ca-
becera <sys/types.h> antes becera <sys/types.h> antes
int socket (int espacio, int estilo, int protocolo); de incluir el <sys/socket.h>. int socket (int espacio, int estilo, int protocolo); de incluir el <sys/socket.h>.

Los parmetros que utiliza esta llamada son los siguientes: Los parmetros que utiliza esta llamada son los siguientes:

1) El parmetro espacio especifica el espacio de nombres o familia de proto- 1) El parmetro espacio especifica el espacio de nombres o familia de proto-
colos correspondiente al socket. El mismo fichero cabecera <sys/socket.h> colos correspondiente al socket. El mismo fichero cabecera <sys/socket.h>
define las constantes siguientes para utilizarlas como valor de este parmetro: define las constantes siguientes para utilizarlas como valor de este parmetro:

PF_FILE: representa la familia de protocolos del espacio de nombres de fi- PF_FILE: representa la familia de protocolos del espacio de nombres de fi-
cheros. cheros.

PF_UNIX: es un sinnimo de PF_FILE definido por compatibilidad con PF_UNIX: es un sinnimo de PF_FILE definido por compatibilidad con
versiones antiguas de la librera de sockets. versiones antiguas de la librera de sockets.

PF_INET: representa la familia de protocolos Internet. PF_INET: representa la familia de protocolos Internet.

PF_NS, PF_ISO, PF_CCITT, PF_IMPLINK, PF_ROUTE, etc., representan PF_NS, PF_ISO, PF_CCITT, PF_IMPLINK, PF_ROUTE, etc., representan
otras familias de protocolos, no tan utilizadas como las anteriores, al menos otras familias de protocolos, no tan utilizadas como las anteriores, al menos
por medio de sockets, y que, por tanto, no estudiaremos aqu: son los protoco- por medio de sockets, y que, por tanto, no estudiaremos aqu: son los protoco-
los Network Software de Xerox, protocolos OSI, etc. Muchos sistemas, aunque los Network Software de Xerox, protocolos OSI, etc. Muchos sistemas, aunque
proporcionan las definiciones de estos smbolos, no tienen implementado el proporcionan las definiciones de estos smbolos, no tienen implementado el
acceso a los protocolos respectivos por medio de la interfaz de los sockets (si se acceso a los protocolos respectivos por medio de la interfaz de los sockets (si se
intenta crear un socket de alguna de estas familias, la llamada retorna error). intenta crear un socket de alguna de estas familias, la llamada retorna error).

2) El parmetro estilo especifica el estilo de comunicacin que se quiere uti- 2) El parmetro estilo especifica el estilo de comunicacin que se quiere uti-
lizar en el socket. El fichero cabecera <sys/socket.h> proporciona las cons- lizar en el socket. El fichero cabecera <sys/socket.h> proporciona las cons-
tantes siguientes para el valor de dicho parmetro: tantes siguientes para el valor de dicho parmetro:

SOCK_STREAM: representa el estilo de comunicacin secuencia de bytes. SOCK_STREAM: representa el estilo de comunicacin secuencia de bytes.
FUOC P03/75064/00978 16 Programacin de sockets FUOC P03/75064/00978 16 Programacin de sockets

SOCK_DGRAM: representa el estilo de comunicacin datagrama. SOCK_DGRAM: representa el estilo de comunicacin datagrama.
SOCK_RAW SOCK_RAW

SOCK_RAW: representa un estilo con acceso directo al nivel de red que per- En UNIX se permite la creacin SOCK_RAW: representa un estilo con acceso directo al nivel de red que per- En UNIX se permite la creacin
mite enviar datagramas arbitrarios (una aplicacin que utilice este estilo de sockets de este tipo slo en mite enviar datagramas arbitrarios (una aplicacin que utilice este estilo de sockets de este tipo slo en
los procesos con privilegios de los procesos con privilegios de
puede definir, por ejemplo, su formato de cabeceras de los paquetes). superusuario. puede definir, por ejemplo, su formato de cabeceras de los paquetes). superusuario.

SOCK_SEQPACKET (datagramas transferidos de manera fiable), SOCK_RDM SOCK_SEQPACKET (datagramas transferidos de manera fiable), SOCK_RDM
(reliably delivered message, tambin basado en datagramas), etc., represen- (reliably delivered message, tambin basado en datagramas), etc., represen-
tan estilos de comunicacin que tampoco estudiaremos aqu. tan estilos de comunicacin que tampoco estudiaremos aqu.

3) El parmetro protocolo especifica el protocolo concreto que se quiere uti- 3) El parmetro protocolo especifica el protocolo concreto que se quiere uti-
lizar en el socket por medio del nmero asociado a dicho protocolo. lizar en el socket por medio del nmero asociado a dicho protocolo.

Dada una familia de protocolos (primer parmetro), el estilo de comunicacin (segundo Dada una familia de protocolos (primer parmetro), el estilo de comunicacin (segundo
parmetro) determina qu subconjunto de los mismos se puede utilizar en un socket. parmetro) determina qu subconjunto de los mismos se puede utilizar en un socket.
Dentro de este subconjunto, a cada protocolo le corresponde un nmero preestablecido Dentro de este subconjunto, a cada protocolo le corresponde un nmero preestablecido
que se especifica por medio del parmetro protocolo. que se especifica por medio del parmetro protocolo.

Cuando, para una familia y un estilo dados, slo hay un protocolo definido, Cuando, para una familia y un estilo dados, slo hay un protocolo definido,
simplemente es necesario proporcionar el nmero 0 como valor del tercer par- simplemente es necesario proporcionar el nmero 0 como valor del tercer par-
Protocolo 0 Protocolo 0
metro. Cuando hay ms de uno, el nmero 0 representa el protocolo por de- metro. Cuando hay ms de uno, el nmero 0 representa el protocolo por de-
fecto o el ms utilizado. El espacio de nombres de fi- fecto o el ms utilizado. El espacio de nombres de fi-
cheros slo soporta un nico cheros slo soporta un nico
protocolo para cada estilo de protocolo para cada estilo de
Ejemplo de funcin para crear un socket TCP comunicacin y se selecciona Ejemplo de funcin para crear un socket TCP comunicacin y se selecciona
con el nmero 0. Y, en el espa- con el nmero 0. Y, en el espa-
cio de nombres Internet, el n- cio de nombres Internet, el n-
mero 0 selecciona mero 0 selecciona
int crear_socket_TCP(void) el protocolo TCP para el estilo int crear_socket_TCP(void) el protocolo TCP para el estilo
secuencia de bytes y el proto- secuencia de bytes y el proto-
{ {
colo UDP para el estilo da- colo UDP para el estilo da-
return socket(PF_INET, SOCK_STREAM, 0); tagrama. return socket(PF_INET, SOCK_STREAM, 0); tagrama.
} }

Ejemplo de funcin para crear un socket UDP Ejemplo de funcin para crear un socket UDP

int crear_socket_UDP(void) int crear_socket_UDP(void)


{ {
return socket(PF_INET, SOCK_DGRAM, 0); return socket(PF_INET, SOCK_DGRAM, 0);
} }

El valor retornado por la llamada socket es un entero que, si no es negativo, El valor retornado por la llamada socket es un entero que, si no es negativo,
representa el descriptor de fichero asociado al socket creado. Si vale 1, indica representa el descriptor de fichero asociado al socket creado. Si vale 1, indica
que se ha producido un error y no se ha podido crear el socket. que se ha producido un error y no se ha podido crear el socket.

Cuando el nmero retornado represente un descriptor de fichero, ser preciso Cuando el nmero retornado represente un descriptor de fichero, ser preciso
guardarlo para poder especificar sobre qu socket se quieren efectuar las opera- guardarlo para poder especificar sobre qu socket se quieren efectuar las opera-
ciones posteriores. Este nmero pertenece al mismo espacio de descriptores ciones posteriores. Este nmero pertenece al mismo espacio de descriptores
que los correspondientes a ficheros o dispositivos que un proceso haya abier- que los correspondientes a ficheros o dispositivos que un proceso haya abier-
to, por ejemplo, con la llamada open. Es decir, el descriptor asociado a un to, por ejemplo, con la llamada open. Es decir, el descriptor asociado a un
socket creado por un proceso nunca coincidir con el de un fichero abierto por socket creado por un proceso nunca coincidir con el de un fichero abierto por
el mismo proceso. Asimismo, muchas de las llamadas al sistema que admiten el mismo proceso. Asimismo, muchas de las llamadas al sistema que admiten
un descriptor de fichero tambin funcionan cuando el descriptor representa un un descriptor de fichero tambin funcionan cuando el descriptor representa un
socket: read, write, close, etc. socket: read, write, close, etc.
FUOC P03/75064/00978 17 Programacin de sockets FUOC P03/75064/00978 17 Programacin de sockets

Los sockets creados con la llamada socket en un inicio no tienen ninguna direc- Los sockets creados con la llamada socket en un inicio no tienen ninguna direc-
cin asignada, ni estn conectados a ningn otro socket. Hay otra llamada que cin asignada, ni estn conectados a ningn otro socket. Hay otra llamada que
permite la creacin de una pareja de sockets ya conectados entre s. Su prototipo, permite la creacin de una pareja de sockets ya conectados entre s. Su prototipo,
tambin declarado en el fichero cabecera <sys/socket.h>, es el siguiente: tambin declarado en el fichero cabecera <sys/socket.h>, es el siguiente:

int socketpair(int espacio, int estilo, int socketpair(int espacio, int estilo,
int protocolo, int vs[2]); int protocolo, int vs[2]);

Los tres primeros parmetros, espacio, estilo y protocolo, son anlogos a Los tres primeros parmetros, espacio, estilo y protocolo, son anlogos a
los de la llamada socket. Es preciso considerar, sin embargo, que muchos siste- los de la llamada socket. Es preciso considerar, sin embargo, que muchos siste-
mas slo soportan el espacio de nombres de ficheros en la llamada socketpair. mas slo soportan el espacio de nombres de ficheros en la llamada socketpair.

El parmetro vs debe ser la direccin de un vector de enteros que disponga de El parmetro vs debe ser la direccin de un vector de enteros que disponga de
al menos dos elementos. Si la llamada tiene xito, retorna 0 y llena los dos pri- al menos dos elementos. Si la llamada tiene xito, retorna 0 y llena los dos pri-
meros elementos del vector vs (vs[0] y vs[1]) con los descriptores de los meros elementos del vector vs (vs[0] y vs[1]) con los descriptores de los
sockets creados. Estos dos sockets no tendrn direccin o nombre; sin embargo, sockets creados. Estos dos sockets no tendrn direccin o nombre; sin embargo,
ya estarn conectados el uno con el otro y, por tanto, preparados para empezar ya estarn conectados el uno con el otro y, por tanto, preparados para empezar
a intercambiar datos (si conviene, siempre se le puede asignar una direccin, a intercambiar datos (si conviene, siempre se le puede asignar una direccin,
aunque, por norma general, no es necesario). Si la llamada no tiene xito, in- aunque, por norma general, no es necesario). Si la llamada no tiene xito, in-
dica que se ha producido un error retornando el valor -1. dica que se ha producido un error retornando el valor -1.

As pues, se puede crear una pareja de sockets con una sola llamada; sin embargo, As pues, se puede crear una pareja de sockets con una sola llamada; sin embargo,
ambos estarn necesariamente en el mismo sistema y, asimismo, corresponde- ambos estarn necesariamente en el mismo sistema y, asimismo, corresponde-
rn al mismo proceso. Por tanto, puede parecer que esta llamada no es dema- rn al mismo proceso. Por tanto, puede parecer que esta llamada no es dema-
siado til, sobre todo si se tiene en cuenta que el objetivo principal de los siado til, sobre todo si se tiene en cuenta que el objetivo principal de los
sockets es la comunicacin entre procesos. Sin embargo, existe un tipo de apli- sockets es la comunicacin entre procesos. Sin embargo, existe un tipo de apli-
cacin en el que es conveniente el uso de estas parejas de sockets: la comunica- cacin en el que es conveniente el uso de estas parejas de sockets: la comunica-
cin entre un proceso padre y un proceso hijo. cin entre un proceso padre y un proceso hijo.

Aprovechando que, en UNIX, cuando un proceso crea un hijo, este ltimo he- Aprovechando que, en UNIX, cuando un proceso crea un hijo, este ltimo he-
reda sus descriptores abiertos, el proceso padre suele crear en primer lugar los reda sus descriptores abiertos, el proceso padre suele crear en primer lugar los
sockets con la llamada socketpair y, despus, genera el proceso hijo con la sockets con la llamada socketpair y, despus, genera el proceso hijo con la
llamada fork. Entonces, para comunicarse entre s, el padre utiliza uno de los llamada fork. Entonces, para comunicarse entre s, el padre utiliza uno de los
dos descriptores y el hijo, el otro,y as se ahorran la asignacin de direcciones dos descriptores y el hijo, el otro,y as se ahorran la asignacin de direcciones
y el establecimiento de la conexin. y el establecimiento de la conexin.

Cuando retornan con error, tanto socket como socketpair utilizan el m- Cuando retornan con error, tanto socket como socketpair utilizan el m-
todo habitual en la interfaz de llamadas al sistema desde C para indicar su cau- todo habitual en la interfaz de llamadas al sistema desde C para indicar su cau-
sa: asignar a una variable global denominada errno un entero que representa sa: asignar a una variable global denominada errno un entero que representa
un cdigo de error. La declaracin de dicha variable y las definiciones de las un cdigo de error. La declaracin de dicha variable y las definiciones de las
constantes que representan sus valores posibles estn contenidas en el fichero constantes que representan sus valores posibles estn contenidas en el fichero
cabecera <errno.h>. cabecera <errno.h>.

Los cdigos de error concretos pueden variar de un sistema a otro; sin embar- Los cdigos de error concretos pueden variar de un sistema a otro; sin embar-
go, existe una serie de causas tpicas por las que pueden fallar las llamadas go, existe una serie de causas tpicas por las que pueden fallar las llamadas
socket y socketpair. Los valores que, por norma general, encontraremos socket y socketpair. Los valores que, por norma general, encontraremos
FUOC P03/75064/00978 18 Programacin de sockets FUOC P03/75064/00978 18 Programacin de sockets

en la variable errno (segn las constantes definidas en el fichero <errno.h>), en la variable errno (segn las constantes definidas en el fichero <errno.h>),
aparte de los que representan errores por memoria insuficiente o exceso de aparte de los que representan errores por memoria insuficiente o exceso de
descriptores abiertos, son los siguientes: descriptores abiertos, son los siguientes:

EAFNOSUPPORT: la librera de sockets no soporta el espacio de nombres espe- EAFNOSUPPORT: la librera de sockets no soporta el espacio de nombres espe-
cificado. cificado.

EPROTONOSUPPORT: la librera de sockets, para el espacio de nombres espe- EPROTONOSUPPORT: la librera de sockets, para el espacio de nombres espe-
cificado, no soporta la combinacin de estilo de comunicacin y nmero cificado, no soporta la combinacin de estilo de comunicacin y nmero
de protocolo. de protocolo.

EACCESS: el proceso no tiene privilegios para crear un socket con el estilo EACCESS: el proceso no tiene privilegios para crear un socket con el estilo
y/o el protocolo especificados. y/o el protocolo especificados.

EOPNOTSUPP (slo para la llamada socketpair): el protocolo especificado EOPNOTSUPP (slo para la llamada socketpair): el protocolo especificado
no soporta la creacin de parejas de sockets. no soporta la creacin de parejas de sockets.

2.1.2. Asignar direccin a un socket 2.1.2. Asignar direccin a un socket

Antes de estudiar la llamada que permite asignar direcciones a los sockets, vere- Antes de estudiar la llamada que permite asignar direcciones a los sockets, vere-
mos cmo se representan estas direcciones en la interfaz de programacin. mos cmo se representan estas direcciones en la interfaz de programacin.

Formatos de las direcciones Formatos de las direcciones

El fichero cabecera <sys/socket.h> proporciona la definicin del tipo El fichero cabecera <sys/socket.h> proporciona la definicin del tipo
struct sockaddr: struct sockaddr:

struct sockaddr struct sockaddr


{ {
short int sa_family; short int sa_family;
char sa_data[...]; char sa_data[...];
}; };

Este tipo representa las direcciones de los sockets en general; sin embargo, por nor- Este tipo representa las direcciones de los sockets en general; sin embargo, por nor-
ma general, no se utiliza, puesto que los que se utilizan son los tipos especficos ma general, no se utiliza, puesto que los que se utilizan son los tipos especficos
de cada espacio de nombres. de cada espacio de nombres.

El tipo struct sockaddr contiene dos campos: El tipo struct sockaddr contiene dos campos:

El campo sa_family indica el espacio de nombres o familia de protocolos El campo sa_family indica el espacio de nombres o familia de protocolos
y, por tanto, el formato de la direccin representada. El fichero cabecera y, por tanto, el formato de la direccin representada. El fichero cabecera
<sys/socket.h> define las constantes que es preciso adoptar como valor <sys/socket.h> define las constantes que es preciso adoptar como valor
de este campo, que se corresponden una a una con las constantes definidas de este campo, que se corresponden una a una con las constantes definidas
para las familias de protocolos: para las familias de protocolos:

F_FILE: representa el formato de direcciones del espacio de nombres de fi- F_FILE: representa el formato de direcciones del espacio de nombres de fi-
cheros PF_FILE. cheros PF_FILE.
FUOC P03/75064/00978 19 Programacin de sockets FUOC P03/75064/00978 19 Programacin de sockets

AF_UNIX: es un sinnimo de AF_FILE (de la misma manera que PF_UNIX AF_UNIX: es un sinnimo de AF_FILE (de la misma manera que PF_UNIX
lo es de PF_FILE). lo es de PF_FILE).

AF_INET: representa el formato de direcciones del espacio de nombres AF_INET: representa el formato de direcciones del espacio de nombres
Internet PF_INET. Internet PF_INET.

AF_UNSPEC: es un valor especial que no representa ningn formato de direc- AF_UNSPEC: es un valor especial que no representa ningn formato de direc-
cin y que se utiliza en ciertos casos muy concretos (por analoga, en algunos cin y que se utiliza en ciertos casos muy concretos (por analoga, en algunos
sistemas se define el smbolo PF_UNSPEC, pero no tiene ningn uso). sistemas se define el smbolo PF_UNSPEC, pero no tiene ningn uso).

AF_ y PF_ AF_ y PF_

Para todos los otros smbolos que empiezan por PF_ se encuentra definido el smbolo co- Para todos los otros smbolos que empiezan por PF_ se encuentra definido el smbolo co-
rrespondiente, que empieza por AF_. Lo que es ms habitual es que los valores de las rrespondiente, que empieza por AF_. Lo que es ms habitual es que los valores de las
constantes que empiezan por AF_ sean idnticos a los de las respectivas constantes que constantes que empiezan por AF_ sean idnticos a los de las respectivas constantes que
empiezan por PF_. empiezan por PF_.

El campo sa_data es un contenedor genrico de la direccin que se quiere El campo sa_data es un contenedor genrico de la direccin que se quiere
representar. La longitud de este ltimo es irrelevante porque los programas representar. La longitud de este ltimo es irrelevante porque los programas
nunca trabajan directamente con variables del tipo struct sockaddr, nunca trabajan directamente con variables del tipo struct sockaddr,
sino con punteros que apuntan a este tipo; es decir, con el tipo propio del sino con punteros que apuntan a este tipo; es decir, con el tipo propio del
espacio de nombres correspondiente, que determina cmo est estructura- espacio de nombres correspondiente, que determina cmo est estructura-
da la informacin de la direccin (qu campos contiene, etc.). da la informacin de la direccin (qu campos contiene, etc.).

Los tipos correspondientes a cada espacio de nombres son los siguientes: Los tipos correspondientes a cada espacio de nombres son los siguientes:

a) En el espacio de nombres de ficheros, o dominio UNIX, se utiliza el tipo a) En el espacio de nombres de ficheros, o dominio UNIX, se utiliza el tipo
struct sockaddr_un, definido en el fichero cabecera <sys/un.h> de la ma- struct sockaddr_un, definido en el fichero cabecera <sys/un.h> de la ma-
nera siguiente: nera siguiente:

struct sockaddr_un UNIX_PATH_MAX struct sockaddr_un UNIX_PATH_MAX


{ {
La constante UNIX_PATH_MAX La constante UNIX_PATH_MAX
short int sun_family; determina la longitud mxima short int sun_family; determina la longitud mxima
char sun_path[UNIX_PATH_MAX]; del campo sun_path en la di- char sun_path[UNIX_PATH_MAX]; del campo sun_path en la di-
reccin de un socket UNIX, y su reccin de un socket UNIX, y su
}; valor en muchos sistemas, por }; valor en muchos sistemas, por
motivos histricos, es 108. motivos histricos, es 108.

El campo sun_family sirve para identificar el formato de la direccin, y su valor debe El campo sun_family sirve para identificar el formato de la direccin, y su valor debe
ser AF_FILE. ser AF_FILE.

El campo sun_path es una cadena de caracteres cuyo valor es el nombre del socket. El campo sun_path es una cadena de caracteres cuyo valor es el nombre del socket.

b) En el espacio de nombres Internet, se utiliza el tipo struct sockaddr_in, b) En el espacio de nombres Internet, se utiliza el tipo struct sockaddr_in,
definido en el fichero cabecera <netinet/in.h> de la manera siguiente: definido en el fichero cabecera <netinet/in.h> de la manera siguiente:

struct sockaddr_in El fichero <netinet/in.h> struct sockaddr_in El fichero <netinet/in.h>


{ {
Como en el caso del fichero Como en el caso del fichero
short int sin_family; <sys/socket>, en algunos short int sin_family; <sys/socket>, en algunos
struct in_addr sin_addr; sistemas es necesario struct in_addr sin_addr; sistemas es necesario
haber incluido el fichero haber incluido el fichero
unsigned short int sin_port; unsigned short int sin_port;
<sys/types.h> antes de <sys/types.h> antes de
}; incluir el <netinet/in.h>. }; incluir el <netinet/in.h>.
FUOC P03/75064/00978 20 Programacin de sockets FUOC P03/75064/00978 20 Programacin de sockets

El campo sin_family sirve para identificar el formato de la direccin, y su valor debe El campo sin_family sirve para identificar el formato de la direccin, y su valor debe
ser AF_INET. sin_addr ser AF_INET. sin_addr

El campo sin_addr se utiliza para especificar la direccin Internet del servidor El motivo por el cual el campo El campo sin_addr se utiliza para especificar la direccin Internet del servidor El motivo por el cual el campo
representada con el tipo struct in_addr, que se define en el mismo fichero sin_addr es una estructura representada con el tipo struct in_addr, que se define en el mismo fichero sin_addr es una estructura
de un solo miembro, en lugar de un solo miembro, en lugar
<netinet/in.h> de la manera siguiente: <netinet/in.h> de la manera siguiente:
de ser directamente un entero de ser directamente un entero
de 4 bytes es histrico: en ver- de 4 bytes es histrico: en ver-
siones anteriores, este campo siones anteriores, este campo
era una unin de otros campos era una unin de otros campos
struct in_addr que permitan acceder a los struct in_addr que permitan acceder a los
{ bytes de diferentes maneras. { bytes de diferentes maneras.
unsigned long int s_addr; unsigned long int s_addr;
}; };

Es decir, este tipo contiene un campo, s_addr, que tiene por valor los 4 bytes de la Es decir, este tipo contiene un campo, s_addr, que tiene por valor los 4 bytes de la
direccin IP almacenados en el orden de la red. direccin IP almacenados en el orden de la red.

El campo sin_port representa el nmero de puerto y tiene 2 bytes almacenados tam- El campo sin_port representa el nmero de puerto y tiene 2 bytes almacenados tam-
bin en el orden de la red. bin en el orden de la red.

En las cabeceras de los datagramas IP y de los paquetes TCP y UDP, algunos En las cabeceras de los datagramas IP y de los paquetes TCP y UDP, algunos
campos representan nmeros de ms de un byte. Estos protocolos establecen campos representan nmeros de ms de un byte. Estos protocolos establecen
un orden cannico para la transmisin de los bytes, el orden de la red: el pri- un orden cannico para la transmisin de los bytes, el orden de la red: el pri-
mer byte es el de ms peso, y el ltimo, el de menos peso. La interfaz de pro- mer byte es el de ms peso, y el ltimo, el de menos peso. La interfaz de pro-
gramacin de los sockets requiere que los valores correspondientes a estos gramacin de los sockets requiere que los valores correspondientes a estos
campos estn almacenados en la memoria en el orden de la red. campos estn almacenados en la memoria en el orden de la red.

En algunos ordenadores la representacin interna en la memoria de los nme- En algunos ordenadores la representacin interna en la memoria de los nme-
Big/little endian Big/little endian
ros enteros puede coincidir con el orden de la red; sin embargo, en otros puede ros enteros puede coincidir con el orden de la red; sin embargo, en otros puede
ser a la inversa (de menor a mayor peso). Para realizar la conversin entre el or- En ocasiones, de los ordenado- ser a la inversa (de menor a mayor peso). Para realizar la conversin entre el or- En ocasiones, de los ordenado-
res que almacenan los bytes res que almacenan los bytes
den interno y el de la red, la interfaz de los sockets proporciona cuatro funciones, de mayor peso a menor, se den interno y el de la red, la interfaz de los sockets proporciona cuatro funciones, de mayor peso a menor, se
dice que son big endian y, de dice que son big endian y, de
cuyos prototipos se declaran en el fichero cabecera <netinet/in.h> de la ma- los que los almacenan de me- cuyos prototipos se declaran en el fichero cabecera <netinet/in.h> de la ma- los que los almacenan de me-
nor peso a mayor, little endian. nor peso a mayor, little endian.
nera siguiente: nera siguiente:

unsigned short int htons(unsigned short int n2_intern); unsigned short int htons(unsigned short int n2_intern);
unsigned long int htonl(unsigned long int n4_intern); unsigned long int htonl(unsigned long int n4_intern);
unsigned short int ntohs(unsigned short int n2_red); unsigned short int ntohs(unsigned short int n2_red);
unsigned long int ntohl(unsigned long int n4_red); unsigned long int ntohl(unsigned long int n4_red);

Las dos primeras reciben como argumento un nmero, de 2 y 4 bytes respecti- Las dos primeras reciben como argumento un nmero, de 2 y 4 bytes respecti-
vamente, en la representacin interna de la mquina (es decir, del ordenador lo- vamente, en la representacin interna de la mquina (es decir, del ordenador lo-
cal), y retornan la representacin del mismo nmero en el orden de la red. Las cal), y retornan la representacin del mismo nmero en el orden de la red. Las
otras dos funciones llevan a cabo la conversin inversa: pasan del orden de la otras dos funciones llevan a cabo la conversin inversa: pasan del orden de la
red a la representacin interna. red a la representacin interna.

En los ordenadores en que el orden interno de los bytes coincida con el de En los ordenadores en que el orden interno de los bytes coincida con el de
la red, estas funciones retornarn sus argumentos sin modificar; sin embar- la red, estas funciones retornarn sus argumentos sin modificar; sin embar-
go, conviene utilizarlas siempre para garantizar la portabilidad de los pro- go, conviene utilizarlas siempre para garantizar la portabilidad de los pro-
gramas. gramas.
FUOC P03/75064/00978 21 Programacin de sockets FUOC P03/75064/00978 21 Programacin de sockets

Relleno de una direccin Internet con unos valores concretos Relleno de una direccin Internet con unos valores concretos

La funcin siguiente llena una direccin Internet (primer parmetro) con los valores que La funcin siguiente llena una direccin Internet (primer parmetro) con los valores que
se le pasan (direccin IP en el segundo parmetro y nmero de puerto en el tercero): se le pasan (direccin IP en el segundo parmetro y nmero de puerto en el tercero):

void llenar_dir_internet(struct sockaddr_in *adr, void llenar_dir_internet(struct sockaddr_in *adr,


unsigned long int adr_host, unsigned short int n_port) unsigned long int adr_host, unsigned short int n_port)
{ {
adr->sin_family = AF_INET; adr->sin_family = AF_INET;
adr->sin_addr.s_addr = htonl(adr_host); adr->sin_addr.s_addr = htonl(adr_host);
adr->sin_port = htons(n_port); adr->sin_port = htons(n_port);
} }

El fichero cabecera <netinet/in.h> proporciona, adems de las funciones El fichero cabecera <netinet/in.h> proporciona, adems de las funciones
ya mencionadas, las definiciones de constantes siguientes, que se pueden usar ya mencionadas, las definiciones de constantes siguientes, que se pueden usar
como valores especiales del campo s_addr de una struct in_addr: como valores especiales del campo s_addr de una struct in_addr:

INADDR_LOOPBACK: equivale a la direccin IP 127.0.0.1, que corresponde al INADDR_LOOPBACK: equivale a la direccin IP 127.0.0.1, que corresponde al
nombre del ordenador local (localhost). Las comunicaciones con esta direc- nombre del ordenador local (localhost). Las comunicaciones con esta direc-
cin por norma general no utilizan el dispositivo lgico de la red, que es in- cin por norma general no utilizan el dispositivo lgico de la red, que es in-
necesario cuando un ordenador se enva datos a s mismo, sino el llamado necesario cuando un ordenador se enva datos a s mismo, sino el llamado
loopback. loopback.

INADDR_BROADCAST: equivale a la direccin IP que es preciso utilizar INADDR_BROADCAST: equivale a la direccin IP que es preciso utilizar
para enviar mensajes de difusin. para enviar mensajes de difusin.

INADDR_ANY: representa una direccin IP indeterminada. Se utiliza en los INADDR_ANY: representa una direccin IP indeterminada. Se utiliza en los
sockets pasivos para indicar que pueden recibir peticiones de conexin des- sockets pasivos para indicar que pueden recibir peticiones de conexin des-
tinadas a cualquier direccin IP si el ordenador tiene ms de una. Si el or- tinadas a cualquier direccin IP si el ordenador tiene ms de una. Si el or-
denador que debe recibir las peticiones tiene una sola direccin IP, denador que debe recibir las peticiones tiene una sola direccin IP,
tambin se puede utilizar para representar esta ltima sin necesidad de es- tambin se puede utilizar para representar esta ltima sin necesidad de es-
pecificar su valor. pecificar su valor.

El mismo fichero <netinet/in.h> tambin define las constantes siguientes El mismo fichero <netinet/in.h> tambin define las constantes siguientes
para representar valores especiales de los nmeros de puerto: para representar valores especiales de los nmeros de puerto:

IPPORT_RESERVED: los nmeros ms pequeos de esta constante (1.024) IPPORT_RESERVED: los nmeros ms pequeos de esta constante (1.024)
corresponden a puertos reservados. corresponden a puertos reservados.

IPPORT_USERRESERVED: en los sistemas que dividen el rango de los puer- IPPORT_USERRESERVED: en los sistemas que dividen el rango de los puer-
tos no reservados en dos subrangos, los nmeros inferiores a esta constante* tos no reservados en dos subrangos, los nmeros inferiores a esta constante*
pertenecen al primer subrango, y los mayores o iguales, al segundo. Ello * El valor de pertenecen al primer subrango, y los mayores o iguales, al segundo. Ello * El valor de
IPPORT_USERRESERVED IPPORT_USERRESERVED
significa que los puertos asignados automticamente estarn comprendi- puede variar de un sistema a otro; significa que los puertos asignados automticamente estarn comprendi- puede variar de un sistema a otro;
sin embargo, por norma general sin embargo, por norma general
dos entre los valores IPPORT_RESERVED e IPPORT_USERRESERVED - 1, suele ser 5.000. dos entre los valores IPPORT_RESERVED e IPPORT_USERRESERVED - 1, suele ser 5.000.

mientras que los servidores de usuario (no estndar) pueden utilizar los mientras que los servidores de usuario (no estndar) pueden utilizar los
puertos a partir de IPPORT_USERRESERVED. puertos a partir de IPPORT_USERRESERVED.
FUOC P03/75064/00978 22 Programacin de sockets FUOC P03/75064/00978 22 Programacin de sockets

Vale la pena remarcar que, en todos los tipos que se utilizan para representar Vale la pena remarcar que, en todos los tipos que se utilizan para representar
direcciones de sockets, el primer campo siempre es un short int que identi- direcciones de sockets, el primer campo siempre es un short int que identi-
fica el formato de la direccin. As, a partir de su valor se puede saber cmo fica el formato de la direccin. As, a partir de su valor se puede saber cmo
debe interpretarse el resto de la informacin. debe interpretarse el resto de la informacin.

Asignacin de direccin Asignacin de direccin

La llamada para asignar una direccin a un socket posee el prototipo siguiente, La llamada para asignar una direccin a un socket posee el prototipo siguiente,
declarado en el fichero cabecera <sys/socket.h>: declarado en el fichero cabecera <sys/socket.h>:

int bind(int descr, const struct sockaddr *adr, int bind(int descr, const struct sockaddr *adr,
size_t long_adr); size_t long_adr);

El tipo size_t El tipo size_t

El parmetro descr es el descriptor del socket. El tipo size_t, utilizado en El parmetro descr es el descriptor del socket. El tipo size_t, utilizado en
la librera C para representar la librera C para representar
El parmetro adr es un puntero a la estructura que representa la direccin que debe asig- nmeros de bytes, est defini- El parmetro adr es un puntero a la estructura que representa la direccin que debe asig- nmeros de bytes, est defini-
narse. do en el fichero cabecera narse. do en el fichero cabecera
<sys/types.h> y, por lo ge- <sys/types.h> y, por lo ge-
neral, equivale a unsigned neral, equivale a unsigned
El parmetro long_adr indica cuntos bytes ocupa esta estructura, por si su longitud es int. El parmetro long_adr indica cuntos bytes ocupa esta estructura, por si su longitud es int.
variable (como el caso del espacio de nombres de ficheros). variable (como el caso del espacio de nombres de ficheros).

Como ya hemos comentado con anterioridad, para representar la direccin no Como ya hemos comentado con anterioridad, para representar la direccin no
se suele utilizar una variable del tipo struct sockaddr. En su lugar, se utiliza se suele utilizar una variable del tipo struct sockaddr. En su lugar, se utiliza
una variable del tipo propio del espacio de nombres correspondiente y, habitual- una variable del tipo propio del espacio de nombres correspondiente y, habitual-
mente, se pasa como segundo parmetro de la llamada bind, a la que se aplica mente, se pasa como segundo parmetro de la llamada bind, a la que se aplica
una conversin explcita de tipo (cast). una conversin explcita de tipo (cast).

Asignacin de un nombre a un socket del espacio de nombres de fichero Asignacin de un nombre a un socket del espacio de nombres de fichero

int asignar_dir_fichero(int sock, const char *nombre) int asignar_dir_fichero(int sock, const char *nombre)
{ {
struct sockaddr_un adr; struct sockaddr_un adr;

adr.sun_family = AF_FILE; adr.sun_family = AF_FILE;


strcpy(adr.sun_path, nom); strcpy(adr.sun_path, nom);
return bind(sock, (struct sockaddr *)&adr, return bind(sock, (struct sockaddr *)&adr,
sizeof adr.sun_family + strlen(nom) + 1); sizeof adr.sun_family + strlen(nom) + 1);
} }

En este caso, el tercer parmetro de la llamada bind se calcula como la suma de la longi- En este caso, el tercer parmetro de la llamada bind se calcula como la suma de la longi-
tud del campo sun_family ms la longitud efectiva del campo sun_path (es decir, el n- tud del campo sun_family ms la longitud efectiva del campo sun_path (es decir, el n-
mero de caracteres de la cadena nombre incluyendo el '\0' que marca su final). mero de caracteres de la cadena nombre incluyendo el '\0' que marca su final).

Asignacin de un nombre a un socket del espacio Internet Asignacin de un nombre a un socket del espacio Internet

Esta funcin asigna una direccin a un socket del espacio Internet utilizando la fun- Esta funcin asigna una direccin a un socket del espacio Internet utilizando la fun-
Recordad Recordad
cin asignar_dir_internet: cin asignar_dir_internet:
En el espacio de nombres Inter- En el espacio de nombres Inter-
net, por lo general no es preciso net, por lo general no es preciso
int asignar_dir_internet(int sock, asignar ninguna direccin a un int asignar_dir_internet(int sock, asignar ninguna direccin a un
unsigned long int adr_host, unsigned short int n_port) socket si debe actuar como unsigned long int adr_host, unsigned short int n_port) socket si debe actuar como
{ cliente, puesto que el sistema le { cliente, puesto que el sistema le
struct sockaddr_in adr; asignar una automticamente struct sockaddr_in adr; asignar una automticamente
cuando la necesite. cuando la necesite.
FUOC P03/75064/00978 23 Programacin de sockets FUOC P03/75064/00978 23 Programacin de sockets

llenar_dir_internet(&adr, adr_host, n_port); llenar_dir_internet(&adr, adr_host, n_port);


return bind(sock, (struct sockaddr *)&adr, sizeof adr); return bind(sock, (struct sockaddr *)&adr, sizeof adr);
} }

El valor retornado por la llamada bind es 0 si la direccin se ha podido asignar El valor retornado por la llamada bind es 0 si la direccin se ha podido asignar
correctamente. Si se produce algn error, la llamada retorna -1 y asigna a la correctamente. Si se produce algn error, la llamada retorna -1 y asigna a la
variable global errno un valor que, por norma general, ser uno de los si- variable global errno un valor que, por norma general, ser uno de los si-
guientes: guientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK: el primer parmetro es un descriptor; sin embargo, no co- ENOTSOCK: el primer parmetro es un descriptor; sin embargo, no co-
rresponde a un socket. rresponde a un socket.

EADDRNOTAVAIL: no se puede asignar la direccin especificada desde este EADDRNOTAVAIL: no se puede asignar la direccin especificada desde este
sistema (por ejemplo, la direccin IP del segundo parmetro no correspon- sistema (por ejemplo, la direccin IP del segundo parmetro no correspon-
de a ninguna de las del ordenador local). de a ninguna de las del ordenador local).

EADDRINUSE: la direccin especificada ya est asignada a otro socket. EADDRINUSE: la direccin especificada ya est asignada a otro socket.

EACCESS: el proceso no posee suficientes privilegios para asignar la direc- EACCESS: el proceso no posee suficientes privilegios para asignar la direc-
cin especificada (en el espacio de ficheros, porque los permisos de los di- cin especificada (en el espacio de ficheros, porque los permisos de los di-
rectorios lo prohben o, en el espacio Internet, porque el nmero de puerto rectorios lo prohben o, en el espacio Internet, porque el nmero de puerto
del segundo parmetro corresponde a un puerto reservado). del segundo parmetro corresponde a un puerto reservado).

EINVAL: el primer parmetro es incorrecto porque corresponde a un socket EINVAL: el primer parmetro es incorrecto porque corresponde a un socket
que ya tiene direccin asignada, o bien el tercer parmetro es incorrecto que ya tiene direccin asignada, o bien el tercer parmetro es incorrecto
porque no corresponde a una longitud de direccin vlida en el espacio de porque no corresponde a una longitud de direccin vlida en el espacio de
nombres del socket. nombres del socket.

Adems de estos posibles errores, en el espacio de nmeros de ficheros tambin se pue- Adems de estos posibles errores, en el espacio de nmeros de ficheros tambin se pue-
den dar los errores propios de la creacin de ficheros, puesto que el hecho de asignar den dar los errores propios de la creacin de ficheros, puesto que el hecho de asignar
direccin a un socket de este espacio implica crear una entrada de directorio. Entre estos direccin a un socket de este espacio implica crear una entrada de directorio. Entre estos
errores, podemos citar, por ejemplo, ENOENT (alguno de los componentes del camino errores, podemos citar, por ejemplo, ENOENT (alguno de los componentes del camino
de subdirectorios especificado en el nombre no existe) y ENOTDIR (alguno de los com- de subdirectorios especificado en el nombre no existe) y ENOTDIR (alguno de los com-
ponentes del camino existe, pero no es un subdirectorio). ponentes del camino existe, pero no es un subdirectorio).

2.1.3. Enviar datos 2.1.3. Enviar datos

Para enviar datos, podemos utilizar tres llamadas diferentes: Para enviar datos, podemos utilizar tres llamadas diferentes:

1) La llamada write. A un socket que ya tenga establecida una conexin 1) La llamada write. A un socket que ya tenga establecida una conexin
con otro se le puede aplicar esta llamada para escribir datos; es decir, para con otro se le puede aplicar esta llamada para escribir datos; es decir, para
enviarlos al socket remoto. Si este limo es no orientado a conexin, pero enviarlos al socket remoto. Si este limo es no orientado a conexin, pero
tiene definida una direccin de destino por defecto, tambin se le puede tiene definida una direccin de destino por defecto, tambin se le puede
aplicar esta llamada. aplicar esta llamada.
FUOC P03/75064/00978 24 Programacin de sockets FUOC P03/75064/00978 24 Programacin de sockets

En los sistemas UNIX, el prototipo de la llamada write est declarado en el En los sistemas UNIX, el prototipo de la llamada write est declarado en el
fichero cabecera <unistd.h> de la manera siguiente: fichero cabecera <unistd.h> de la manera siguiente:

ssize_t write(int descr, const void *datos, El tipo ssize_t ssize_t write(int descr, const void *datos, El tipo ssize_t
size_t longitud); size_t longitud);
El tipo ssize_t, definido El tipo ssize_t, definido
tambin en el fichero cabecera tambin en el fichero cabecera
<sys/types.h>, es como <sys/types.h>, es como
size_t, pero con signo (por size_t, pero con signo (por
El primer parmetro, descr, es un descriptor que, por norma general, puede corres- El primer parmetro, descr, es un descriptor que, por norma general, puede corres-
norma general, equivale a norma general, equivale a
ponder a un fichero, un dispositivo, una pipe, un socket, etc. int), y se utiliza en la librera C ponder a un fichero, un dispositivo, una pipe, un socket, etc. int), y se utiliza en la librera C
para valores que pueden repre- para valores que pueden repre-
El segundo parmetro, datos, es la direccin de memoria donde se encuentran los da- sentar un nmero de bytes si El segundo parmetro, datos, es la direccin de memoria donde se encuentran los da- sentar un nmero de bytes si
tos que queremos escribir. son positivos, o un cdigo de tos que queremos escribir. son positivos, o un cdigo de
error si son negativos. error si son negativos.
El tercer parmetro, longitud, indica cuntos bytes queremos escribir. El tercer parmetro, longitud, indica cuntos bytes queremos escribir.

El valor retornado constituye el nmero de bytes que se han escrito en realidad (que, por El valor retornado constituye el nmero de bytes que se han escrito en realidad (que, por
norma general, ser igual al tercer parmetro, pero podra ser menor), salvo que valga 1, norma general, ser igual al tercer parmetro, pero podra ser menor), salvo que valga 1,
lo que significa que se ha producido un error. lo que significa que se ha producido un error.

2) La llamada send. Es especfica de los sockets. Su prototipo est declarado en 2) La llamada send. Es especfica de los sockets. Su prototipo est declarado en
el fichero cabecera <sys/socket.h> de la manera siguiente: el fichero cabecera <sys/socket.h> de la manera siguiente:

int send(int descr, const void *datos, size_t longitud, int send(int descr, const void *datos, size_t longitud,
int flags); int flags);

Los tres primeros parmetros y el valor retornado tienen el mismo significado Los tres primeros parmetros y el valor retornado tienen el mismo significado
que en la llamada write. que en la llamada write.

Los sockets a los que se les puede aplicar la llamada send tambin son los mis- Los sockets a los que se les puede aplicar la llamada send tambin son los mis-
mos que los de la llamada write; es decir, los que estn conectados o tengan mos que los de la llamada write; es decir, los que estn conectados o tengan
definido un destino por defecto. La nica diferencia entre ambas llamadas es definido un destino por defecto. La nica diferencia entre ambas llamadas es
que send admite un parmetro adicional, flags, que permite especificar ciertas que send admite un parmetro adicional, flags, que permite especificar ciertas
opciones de transmisin. Cuando no se utiliza ninguna de estas opciones, el va- opciones de transmisin. Cuando no se utiliza ninguna de estas opciones, el va-
lor del parmetro flags es 0 y entonces la llamada send acta exactamente lor del parmetro flags es 0 y entonces la llamada send acta exactamente
igual que la llamada write. igual que la llamada write.

La lista de opciones se representa con una combinacin de bits en la que cada La lista de opciones se representa con una combinacin de bits en la que cada
bit igual a 1 indica que se quiere aplicar una opcin determinada. El fichero bit igual a 1 indica que se quiere aplicar una opcin determinada. El fichero
cabecera <sys/socket.h> define una serie de smbolos que pueden combi- cabecera <sys/socket.h> define una serie de smbolos que pueden combi-
narse directamente con la operacin OR binaria (o bien con una suma) para narse directamente con la operacin OR binaria (o bien con una suma) para
obtener el conjunto de bits deseados. Los smbolos correspondientes a las op- obtener el conjunto de bits deseados. Los smbolos correspondientes a las op-
ciones aplicables a la llamada send son los dos siguientes: ciones aplicables a la llamada send son los dos siguientes:

MSG_OOB: indica que los datos deben enviarse como datos urgentes; es de- MSG_OOB: indica que los datos deben enviarse como datos urgentes; es de-
* El protocolo TCP es uno de los que * El protocolo TCP es uno de los que
cir, fuera de banda. Slo tiene efecto si el protocolo asociado al socket so- pueden soportar la transmisin cir, fuera de banda. Slo tiene efecto si el protocolo asociado al socket so- pueden soportar la transmisin
urgente de datos. urgente de datos.
porta la transmisin de datos urgentes*. porta la transmisin de datos urgentes*.

MSG_DONTROUTE: indica que no se incluya informacin de direccionamiento MSG_DONTROUTE: indica que no se incluya informacin de direccionamiento
en el mensaje transmitido (esta opcin slo es interesante cuando se trabaja en el mensaje transmitido (esta opcin slo es interesante cuando se trabaja
en el nivel de red o se quieren realizar pruebas para obtener diagnsticos). en el nivel de red o se quieren realizar pruebas para obtener diagnsticos).
FUOC P03/75064/00978 25 Programacin de sockets FUOC P03/75064/00978 25 Programacin de sockets

3) La llamada sendto. Su prototipo* tambin est declarado en el fichero 3) La llamada sendto. Su prototipo* tambin est declarado en el fichero
* Esta llamada tambin permite * Esta llamada tambin permite
cabecera <sys/socket.h>: enviar datos por medio de cabecera <sys/socket.h>: enviar datos por medio de
un socket. un socket.

int sendto(int descr, const void *datos, size_t longitud, int sendto(int descr, const void *datos, size_t longitud,
int flags, const struct sockaddr *adr, size_t long_adr); int flags, const struct sockaddr *adr, size_t long_adr);

La llamada sendto se diferencia de la send en dos parmetros adicionales, La llamada sendto se diferencia de la send en dos parmetros adicionales,
que permiten especificar a qu socket deben enviarse los datos por medio de que permiten especificar a qu socket deben enviarse los datos por medio de
un puntero a su direccin (adr) y el nmero de bytes que esta ltima ocupa un puntero a su direccin (adr) y el nmero de bytes que esta ltima ocupa
(long_adr). (long_adr).

Si el socket correspondiente a descr es no orientado a conexin, esta llamada Si el socket correspondiente a descr es no orientado a conexin, esta llamada
enva al socket indicado por los parmetros adr y long_adr un datagrama con enva al socket indicado por los parmetros adr y long_adr un datagrama con
los datos especificados. Si el socket est conectado, estos parmetros se ignoran. los datos especificados. Si el socket est conectado, estos parmetros se ignoran.

En muchos sistemas, estas tres llamadas (write, send y sendto) por norma ge- En muchos sistemas, estas tres llamadas (write, send y sendto) por norma ge-
Modo no bloqueante Modo no bloqueante
neral retornan cuando los datos que deben enviarse se han copiado en el buffer neral retornan cuando los datos que deben enviarse se han copiado en el buffer
de transmisin del socket. Si el buffer est lleno, las llamadas esperan hasta que Como en cualquier descriptor de transmisin del socket. Si el buffer est lleno, las llamadas esperan hasta que Como en cualquier descriptor
de fichero en general, el modo de fichero en general, el modo
haya suficiente espacio disponible, salvo que el socket trabaje en el llamado de trabajo de los sockets por haya suficiente espacio disponible, salvo que el socket trabaje en el llamado de trabajo de los sockets por
defecto es bloqueante; sin em- defecto es bloqueante; sin em-
modo no bloqueante. Por consiguiente, un retorno sin error de cualquiera de estas bargo, se puede cambiar a no modo no bloqueante. Por consiguiente, un retorno sin error de cualquiera de estas bargo, se puede cambiar a no
bloqueante por medio de la bloqueante por medio de la
llamadas no implica necesariamente una recepcin correcta en el socket remoto. llamada fcntl, con la operacin llamadas no implica necesariamente una recepcin correcta en el socket remoto. llamada fcntl, con la operacin
F_SETFL y el indicador F_SETFL y el indicador
O_NONBLOCK. O_NONBLOCK.
En los sockets no orientados a conexin es posible, incluso, que la direccin de En los sockets no orientados a conexin es posible, incluso, que la direccin de
destino no exista. En este caso, la red no sabr qu hacer con los datagramas destino no exista. En este caso, la red no sabr qu hacer con los datagramas
una vez han salido de la mquina origen. una vez han salido de la mquina origen.

Cuando estas llamadas retornan con error, los valores que solemos encontrar Cuando estas llamadas retornan con error, los valores que solemos encontrar
en la variable global errno son los siguientes: en la variable global errno son los siguientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK (slo para las llamadas send y sendto): el primer parmetro es ENOTSOCK (slo para las llamadas send y sendto): el primer parmetro es
un descriptor, pero no corresponde a un socket. un descriptor, pero no corresponde a un socket.

EINVAL (slo para la llamada sendto): el sexto parmetro es incorrecto EINVAL (slo para la llamada sendto): el sexto parmetro es incorrecto
porque no corresponde a una longitud de direccin vlida en el espacio porque no corresponde a una longitud de direccin vlida en el espacio
de nmeros del socket. de nmeros del socket.

ENOTCONN: el socket es orientado a conexin, pero no est conectado. ENOTCONN: el socket es orientado a conexin, pero no est conectado.

EDESTADDRREQ (slo para las llamadas write y send): el socket no tiene EDESTADDRREQ (slo para las llamadas write y send): el socket no tiene
destino por defecto. destino por defecto.

EMSGSIZE: la longitud de los datos que se precisa enviar es demasiado EMSGSIZE: la longitud de los datos que se precisa enviar es demasiado
grande para el protocolo asociado al socket. grande para el protocolo asociado al socket.

EWOULDBLOCK*: el socket es no bloqueante y los datos no se pueden enviar * En muchos sistemas, EAGAIN EWOULDBLOCK*: el socket es no bloqueante y los datos no se pueden enviar * En muchos sistemas, EAGAIN
es un sinnimo de EWOULDBLOCK. es un sinnimo de EWOULDBLOCK.
inmediatamente (la memoria intermedia est llena). inmediatamente (la memoria intermedia est llena).
FUOC P03/75064/00978 26 Programacin de sockets FUOC P03/75064/00978 26 Programacin de sockets

EPIPE: el socket estaba conectado; sin embargo, ya no hay conexin esta- EPIPE: el socket estaba conectado; sin embargo, ya no hay conexin esta-
blecida (por ejemplo, porque se ha cerrado desde el otro extremo). En este blecida (por ejemplo, porque se ha cerrado desde el otro extremo). En este
caso, el proceso recibe primero una seal SIGPIPE. La accin que provoca caso, el proceso recibe primero una seal SIGPIPE. La accin que provoca
por defecto la recepcin de esta seal por defecto es la culminacin del pro- por defecto la recepcin de esta seal por defecto es la culminacin del pro-
ceso y, por tanto, la llamada no retorna. Si la seal SIGPIPE est inhabilitada ceso y, por tanto, la llamada no retorna. Si la seal SIGPIPE est inhabilitada
o la accin se ha reprogramado, y la llamada finalmente retorna, entonces o la accin se ha reprogramado, y la llamada finalmente retorna, entonces
el cdigo de error es EPIPE. el cdigo de error es EPIPE.

EINTR: no se ha completado la operacin porque ha llegado una seal no La accin con que un proceso EINTR: no se ha completado la operacin porque ha llegado una seal no La accin con que un proceso
responde a una determinada seal responde a una determinada seal
puede cambiarse, por ejemplo, con puede cambiarse, por ejemplo, con
ignorada. la funcin signal. ignorada. la funcin signal.

Esta causa de error es propia de las llamadas al sistema bloqueadoras; es decir, Esta causa de error es propia de las llamadas al sistema bloqueadoras; es decir,
las que pueden necesitar cierto tiempo para completarse (puesto que deben es- las que pueden necesitar cierto tiempo para completarse (puesto que deben es-
perar hasta que se produzca cierta condicin, como que se vace el buffer de perar hasta que se produzca cierta condicin, como que se vace el buffer de
transmisin). Si, mientras una llamada est bloqueada, el proceso recibe una se- transmisin). Si, mientras una llamada est bloqueada, el proceso recibe una se-
al no ignorada, la llamada se interrumpe para ejecutar el gestor (handler) aso- al no ignorada, la llamada se interrumpe para ejecutar el gestor (handler) aso-
ciado a esta seal. ciado a esta seal.

Segn el sistema, puede ser que, al acabar la ejecucin del gestor, la llamada Segn el sistema, puede ser que, al acabar la ejecucin del gestor, la llamada
La funcin siginterrupt La funcin siginterrupt
pendiente no contine, sino que retorne de inmediato con la variable errno pendiente no contine, sino que retorne de inmediato con la variable errno
Muchos sistemas proporcio- Muchos sistemas proporcio-
igual a EINTR. Por tanto, conviene que tengamos en cuenta esta situacin si nan una funcin llamada igual a EINTR. Por tanto, conviene que tengamos en cuenta esta situacin si nan una funcin llamada
en un programa queremos efectuar llamadas que se puedan bloquear y nos in- siginterrupt, que permite en un programa queremos efectuar llamadas que se puedan bloquear y nos in- siginterrupt, que permite
controlar el comportamiento controlar el comportamiento
teresa tener capturada alguna seal. de las llamadas interrumpidas. teresa tener capturada alguna seal. de las llamadas interrumpidas.

Escritura de datos en presencia de seales no ignoradas Escritura de datos en presencia de seales no ignoradas

Esta funcin escribe los datos que se le pasan aunque lleguen seales no ignoradas: Esta funcin escribe los datos que se le pasan aunque lleguen seales no ignoradas:

int escribe_datos(int sock, void *datos, size_t n) int escribe_datos(int sock, void *datos, size_t n)
{ {
int ret; int ret;

while ((ret = send(sock, datos, n, 0)) < 0 && errno == EINTR); while ((ret = send(sock, datos, n, 0)) < 0 && errno == EINTR);
return ret; return ret;
} }

2.1.4. Recibir datos 2.1.4. Recibir datos

Para recibir datos, podemos utilizar tres llamadas diferentes: Para recibir datos, podemos utilizar tres llamadas diferentes:

1) La llamada read. Como cualquier descriptor de fichero en general, los soc- 1) La llamada read. Como cualquier descriptor de fichero en general, los soc-
kets no slo admiten la llamada write para enviar datos, sino tambin la lla- kets no slo admiten la llamada write para enviar datos, sino tambin la lla-
mada read para recibirlos. En UNIX, el prototipo de esta llamada est mada read para recibirlos. En UNIX, el prototipo de esta llamada est
declarado en el fichero cabecera <unistd.h> de la manera siguiente: declarado en el fichero cabecera <unistd.h> de la manera siguiente:

ssize_t read(int descr, void *datos, size_t longitud); ssize_t read(int descr, void *datos, size_t longitud);
FUOC P03/75064/00978 27 Programacin de sockets FUOC P03/75064/00978 27 Programacin de sockets

El parmetro descr es el descriptor del socket. El parmetro descr es el descriptor del socket.

El parmetro datos es un puntero a la zona de memoria en que deben dejarse los da- El parmetro datos es un puntero a la zona de memoria en que deben dejarse los da-
tos ledos. tos ledos.

El parmetro longitud es el nmero mximo de bytes que queremos leer*. * En la zona apuntada por datos, El parmetro longitud es el nmero mximo de bytes que queremos leer*. * En la zona apuntada por datos,
deben caber como mnimo deben caber como mnimo
longitud bytes. longitud bytes.
El valor retornado informa del nmero de bytes ledos, que puede ser menor que El valor retornado informa del nmero de bytes ledos, que puede ser menor que
el tercer parmetro si, de momento, no hay ms disponibles. Si el valor re- el tercer parmetro si, de momento, no hay ms disponibles. Si el valor re-
tornado es igual a 0, indica que ya no quedan ms bytes para leer; es decir, si tornado es igual a 0, indica que ya no quedan ms bytes para leer; es decir, si
se trata de un fichero, indica que se ha llegado al final de su contenido y, si se se trata de un fichero, indica que se ha llegado al final de su contenido y, si se
trata de un socket, que el otro extremo ha cerrado la conexin. Si el valor de- trata de un socket, que el otro extremo ha cerrado la conexin. Si el valor de-
vuelto es 1, se ha producido algn error en la lectura. vuelto es 1, se ha producido algn error en la lectura.

Bucle de lecturas Bucle de lecturas

Si esperamos que el socket remoto nos enve n bytes, puede ser que una sola llamadas Si esperamos que el socket remoto nos enve n bytes, puede ser que una sola llamadas
read con el valor n como tercer parmetro no sea suficiente para recibirlos todos, puesto read con el valor n como tercer parmetro no sea suficiente para recibirlos todos, puesto
que la llamada slo espera que haya bytes disponibles, pero no necesariamente que haya que la llamada slo espera que haya bytes disponibles, pero no necesariamente que haya
tantos como se le piden. Ello significa que, para leer exactamente n bytes, en general es tantos como se le piden. Ello significa que, para leer exactamente n bytes, en general es
preciso llevar a cabo un bucle de lecturas, como el presentado en la funcin siguiente: preciso llevar a cabo un bucle de lecturas, como el presentado en la funcin siguiente:

int leer_n_bytes(int sock, char *buffer, int n) int leer_n_bytes(int sock, char *buffer, int n)
{ {
int leidos, posicion = 0; int leidos, posicion = 0;

while (posicion < n) while (posicion < n)


{ {
if ((leidos = read(sock, buffer + posicion, if ((leidos = read(sock, buffer + posicion,
n - posicion)) < 0) return -1; n - posicion)) < 0) return -1;
if (leidos == 0) break; if (leidos == 0) break;
posicion += leidos; posicion += leidos;
} }
return posicion; return posicion;
} }

El nmero de llamadas read necesarias para leer n bytes no tiene por qu guardar relacin El nmero de llamadas read necesarias para leer n bytes no tiene por qu guardar relacin
con el nmero de llamadas write que se han efectuado en el socket remoto para enviarlas. con el nmero de llamadas write que se han efectuado en el socket remoto para enviarlas.

2) La llamada recv. Es la llamada especfica de los sockets para leer datos, an- 2) La llamada recv. Es la llamada especfica de los sockets para leer datos, an-
loga a la llamada send del caso de la escritura. Su prototipo est declarado en loga a la llamada send del caso de la escritura. Su prototipo est declarado en
el fichero cabecera <sys/socket.h> de la manera siguiente: el fichero cabecera <sys/socket.h> de la manera siguiente:

int recv(int descr, void *datos, size_t longitud, int recv(int descr, void *datos, size_t longitud,
int flags); int flags);

De una manera igual a la de las llamadas write y send, la diferencia entre De una manera igual a la de las llamadas write y send, la diferencia entre
read y recv es simplemente el parmetro adicional flags*. Este ltimo se co- read y recv es simplemente el parmetro adicional flags*. Este ltimo se co-
* Si el parmetro flags vale 0, * Si el parmetro flags vale 0,
difica, de la misma manera que en la llamada send, como una cadena de bits, las llamadass read y recv son difica, de la misma manera que en la llamada send, como una cadena de bits, las llamadass read y recv son
iguales. iguales.
y las opciones que se pueden especificar en el caso de la lectura estn determi- y las opciones que se pueden especificar en el caso de la lectura estn determi-
nadas por las constantes siguientes: nadas por las constantes siguientes:

MSG_PEEK: hace que la llamada lea los datos sin borrarlos del buffer de re- MSG_PEEK: hace que la llamada lea los datos sin borrarlos del buffer de re-
cepcin del socket (por tanto, la llamadas siguiente volver a leer los mis- cepcin del socket (por tanto, la llamadas siguiente volver a leer los mis-
mos datos). mos datos).
FUOC P03/75064/00978 28 Programacin de sockets FUOC P03/75064/00978 28 Programacin de sockets

MSG_OOB: hace que la llamada lea datos urgentes enviados fuera de banda, MSG_OOB: hace que la llamada lea datos urgentes enviados fuera de banda,
MSG_OOB MSG_OOB
aunque haya datos normales (no urgentes) en el buffer de recepcin pendien- aunque haya datos normales (no urgentes) en el buffer de recepcin pendien-
tes de lectura. Sin la opcin MSG_OOB, la llamada slo lee datos normales. Esta opcin slo es aplicable tes de lectura. Sin la opcin MSG_OOB, la llamada slo lee datos normales. Esta opcin slo es aplicable
al estilo de comunicacin se- al estilo de comunicacin se-
cuencia de bytes. cuencia de bytes.
En UNIX, cuando llegan datos urgentes a un socket, el proceso correspondien- En UNIX, cuando llegan datos urgentes a un socket, el proceso correspondien-
te recibe de inmediato una seal SIGURG. Por defecto, los procesos la ignoran; te recibe de inmediato una seal SIGURG. Por defecto, los procesos la ignoran;
sin embargo, se puede capturar para que se ejecute automticamente una fun- sin embargo, se puede capturar para que se ejecute automticamente una fun-
cin definida por el usuario que lea los datos urgentes. De este modo, se puede cin definida por el usuario que lea los datos urgentes. De este modo, se puede
conferir prioridad a los datos urgentes por encima de los datos normales. conferir prioridad a los datos urgentes por encima de los datos normales.

Los datos urgentes, pues, se pueden leer fuera de secuencia, pero tambin es Los datos urgentes, pues, se pueden leer fuera de secuencia, pero tambin es
posible saber en qu punto de la secuencia de datos normales se transmitieron, posible saber en qu punto de la secuencia de datos normales se transmitieron,
puesto que en este punto se inserta automticamente una marca. puesto que en este punto se inserta automticamente una marca.

Ello es til cuando los dastos urgentes contienen, por ejemplo, un mensaje de Ello es til cuando los dastos urgentes contienen, por ejemplo, un mensaje de
control que significa interrumpir el proceso actual y descartar los datos recibidos control que significa interrumpir el proceso actual y descartar los datos recibidos
hasta aquel momento. hasta aquel momento.

Si una llamada de lectura de datos normales encuentra una marca de datos ur- Si una llamada de lectura de datos normales encuentra una marca de datos ur-
gentes, deja de leer y retorna con los datos que hay antes de la marca. Es decir, gentes, deja de leer y retorna con los datos que hay antes de la marca. Es decir,
los datos enviados antes y despus de un mensaje urgente no se leern nunca los datos enviados antes y despus de un mensaje urgente no se leern nunca
en una misma llamada. en una misma llamada.

Deteccin de la marca Deteccin de la marca

En UNIX, existe una operacin de control llamada SIOCATMARK, que permite comprobar En UNIX, existe una operacin de control llamada SIOCATMARK, que permite comprobar
si la ltima llamada de lectura ha retornado porque ha llegado a una marca. A continua- si la ltima llamada de lectura ha retornado porque ha llegado a una marca. A continua-
cin, presentamos un ejemplo de uso de esta operacin. El prototipo de la llamada ioctl cin, presentamos un ejemplo de uso de esta operacin. El prototipo de la llamada ioctl
est declarado en <unistd.h> y el smbolo SIOCATMARK se define en <sys/ioctl.h>: est declarado en <unistd.h> y el smbolo SIOCATMARK se define en <sys/ioctl.h>:

int marca_encontrada(int sock) int marca_encontrada(int sock)


{ {
int resultado; int resultado;

if (ioctl(sock, SIOCATMARK, &resultado) < 0) if (ioctl(sock, SIOCATMARK, &resultado) < 0)


{ {
perror("ioctl(SIOCATMARK)"); perror("ioctl(SIOCATMARK)");
return -1; return -1;
} }
return resultado; return resultado;
} }

El resultado retornado ser 1 si la ltima lectura ha encontrado una marca y 0 en caso El resultado retornado ser 1 si la ltima lectura ha encontrado una marca y 0 en caso
contrario. contrario.

3) La llamada recvfrom. Lee datos e indica de dnde han venido (opera de 3) La llamada recvfrom. Lee datos e indica de dnde han venido (opera de
la misma manera que la llamada sendto). Su prototipo est declarado en el la misma manera que la llamada sendto). Su prototipo est declarado en el
fichero cabecera <sys/socket.h> de la manera siguiente: fichero cabecera <sys/socket.h> de la manera siguiente:

int recvfrom(int descr, void *datos, size_t longitud, int recvfrom(int descr, void *datos, size_t longitud,
int flags, struct sockaddr *adr, size_t *long_adr); int flags, struct sockaddr *adr, size_t *long_adr);
FUOC P03/75064/00978 29 Programacin de sockets FUOC P03/75064/00978 29 Programacin de sockets

La diferencia entre recv y recvfrom es que la segunda llena la estructura La diferencia entre recv y recvfrom es que la segunda llena la estructura
apuntada por el parmetro adr con la direccin del socket del que se han reci- apuntada por el parmetro adr con la direccin del socket del que se han reci-
bido los datos (salvo que este parmetro constituya un puntero nulo). bido los datos (salvo que este parmetro constituya un puntero nulo).

El parmetro long_adr en un inicio debe apuntar a un valor que indica cun- El parmetro long_adr en un inicio debe apuntar a un valor que indica cun-
tos bytes puede ocupar como mximo la estructura y, cuando retorna, la lla- tos bytes puede ocupar como mximo la estructura y, cuando retorna, la lla-
mada cambia este valor al nmero de bytes que ha llenado. En muchos mada cambia este valor al nmero de bytes que ha llenado. En muchos
sistemas, sin embargo, la llamada recvfrom no proporciona informacin so- sistemas, sin embargo, la llamada recvfrom no proporciona informacin so-
bre la direccin remota en el espacio de nombres de ficheros. bre la direccin remota en el espacio de nombres de ficheros.

En los sockets orientados a conexin (estilo de comunicacin secuencia de En los sockets orientados a conexin (estilo de comunicacin secuencia de
bytes), las llamadas read, recv y recvfrom leen los datos a partir del ltimo bytes), las llamadas read, recv y recvfrom leen los datos a partir del ltimo
byte ledo por la llamada anterior. En los no orientados a conexin, en cambio, byte ledo por la llamada anterior. En los no orientados a conexin, en cambio,
leen slo un datagrama cada vez y, si la longitud del datagrama recibido es ma- leen slo un datagrama cada vez y, si la longitud del datagrama recibido es ma-
yor que el parmetro longitud, los bytes que sobran se descartan y no hay yor que el parmetro longitud, los bytes que sobran se descartan y no hay
manera de recuperarlos. manera de recuperarlos.

Cada uno de estas tres llamadas puede retornar un nmero de bytes ledos me- Cada uno de estas tres llamadas puede retornar un nmero de bytes ledos me-
nor que el solicitado en el parmetro longitud si no hay ms disponibles en nor que el solicitado en el parmetro longitud si no hay ms disponibles en
el buffer de recepcin. Sin embargo, si este ltimo est vaco, las llamadas es- el buffer de recepcin. Sin embargo, si este ltimo est vaco, las llamadas es-
peran hasta que haya datos para leer, salvo que el socket trabaje en modo no peran hasta que haya datos para leer, salvo que el socket trabaje en modo no
bloqueante. bloqueante.

Cuando estas llamadas retornan con error, los valores habituales de la variable Cuando estas llamadas retornan con error, los valores habituales de la variable
errno son los siguientes: errno son los siguientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK (slo para las llamadas recv y recvfrom): el primer parmetro ENOTSOCK (slo para las llamadas recv y recvfrom): el primer parmetro
es un descriptor, pero no corresponde a un socket. es un descriptor, pero no corresponde a un socket.

ENOTCONN: el socket es orientado a conexin, pero no est conectado. ENOTCONN: el socket es orientado a conexin, pero no est conectado.

EWOULDBLOCK: el socket es no bloqueante y no existen datos disponibles EWOULDBLOCK: el socket es no bloqueante y no existen datos disponibles
para leerlos (la memoria intermedia est vaca). para leerlos (la memoria intermedia est vaca).

EINTR: no se ha completado la operacin porque ha llegado una seal no EINTR: no se ha completado la operacin porque ha llegado una seal no
ignorada. ignorada.

2.1.5. Esperar disponibilidad de datos 2.1.5. Esperar disponibilidad de datos

La llamada select en UNIX permite esperar hasta que se puedan leer o escri- La llamada select en UNIX permite esperar hasta que se puedan leer o escri-
bir datos en algn descriptor de una lista determinada. Esta llamada tambin bir datos en algn descriptor de una lista determinada. Esta llamada tambin
es aplicable a los sockets y es muy til cuando, por ejemplo, un proceso debe es aplicable a los sockets y es muy til cuando, por ejemplo, un proceso debe
FUOC P03/75064/00978 30 Programacin de sockets FUOC P03/75064/00978 30 Programacin de sockets

recibir datos por diferentes canales, que pueden ser dos o ms sockets, o un socket recibir datos por diferentes canales, que pueden ser dos o ms sockets, o un socket
y la entrada estndar, etc. Con la llamada select se puede saber por cul de y la entrada estndar, etc. Con la llamada select se puede saber por cul de
estos canales se han recibido datos, y de este modo se evita que el proceso que- estos canales se han recibido datos, y de este modo se evita que el proceso que-
de bloqueado esperando datos en un descriptor mientras por otro, quiz, van de bloqueado esperando datos en un descriptor mientras por otro, quiz, van
llegando otros sin que se puedan leer. llegando otros sin que se puedan leer.

El prototipo de la llamada select, que se detalla a continuacin, tradicional- El prototipo de la llamada select, que se detalla a continuacin, tradicional-
mente estaba declarado, como se indica a continuacin, en el fichero cabecera mente estaba declarado, como se indica a continuacin, en el fichero cabecera
<sys/types.h>; sin embargo, el estndar POSIX requiere que aparezca en el <sys/types.h>; sin embargo, el estndar POSIX requiere que aparezca en el
fichero <sys/time.h>: fichero <sys/time.h>:

int select(int n_descr, fd_set *d_lect, fd_set *d_escr, int select(int n_descr, fd_set *d_lect, fd_set *d_escr,
fd_set *d_excep, struct timeval *tiempo); fd_set *d_excep, struct timeval *tiempo);

Para representar los parmetros, se utilizan los tipos fd_set y struct timeval. Para representar los parmetros, se utilizan los tipos fd_set y struct timeval.
El primero se define en el fichero cabecera <sys/types.h> y/o <sys/time.h>, El primero se define en el fichero cabecera <sys/types.h> y/o <sys/time.h>,
segn el sistema, y el segundo, en el fichero <sys/time.h>. segn el sistema, y el segundo, en el fichero <sys/time.h>.

Veamos estos tipos con detalle: Veamos estos tipos con detalle:

a) El tipo fd_set sirve para representar conjuntos de descriptores. Por norma a) El tipo fd_set sirve para representar conjuntos de descriptores. Por norma
general, se codifica como una mscara de bits en la que los bits puestos a 1 in- general, se codifica como una mscara de bits en la que los bits puestos a 1 in-
dican qu descriptores pertenecen al conjunto. Sin embargo, el programador dican qu descriptores pertenecen al conjunto. Sin embargo, el programador
no debe preocuparse de la representacin interna de estos conjuntos, puesto no debe preocuparse de la representacin interna de estos conjuntos, puesto
que los mismos ficheros <sys/types.h> y/o <sys/time.h> definen las ope- que los mismos ficheros <sys/types.h> y/o <sys/time.h> definen las ope-
raciones siguientes para trabajar con variables del tipo fd_set: raciones siguientes para trabajar con variables del tipo fd_set:

void FD_ZERO(fd_set *conj_d);. La operacin FD_ZERO pone a 0 to- void FD_ZERO(fd_set *conj_d);. La operacin FD_ZERO pone a 0 to-
dos los descriptores del conjunto conj_d. dos los descriptores del conjunto conj_d.

void FD_SET(int descr, fd_set *conj_d);. La operacin FD_SET void FD_SET(int descr, fd_set *conj_d);. La operacin FD_SET
pone a 1 el descriptor correspondiente al argumento descr del conjunto pone a 1 el descriptor correspondiente al argumento descr del conjunto
conj_d. conj_d.

void FD_CLR(int descr, fd_set *conj_d);. La operacin FD_CLR Por norma general, los smbolos void FD_CLR(int descr, fd_set *conj_d);. La operacin FD_CLR Por norma general, los smbolos
FD_ZERO, FD_SET, FD_CLR FD_ZERO, FD_SET, FD_CLR
pone a 0 el descriptor correspondiente al argumento descr del conjunto y FD_ISSET se definen pone a 0 el descriptor correspondiente al argumento descr del conjunto y FD_ISSET se definen
como macros. como macros.
conj_d. conj_d.

int FD_ISSET(int descr, fd_set *conj_d);. La operacin FD_ISSET int FD_ISSET(int descr, fd_set *conj_d);. La operacin FD_ISSET
retorna un valor diferente de 0 si el descriptor correspondiente al argumento retorna un valor diferente de 0 si el descriptor correspondiente al argumento
descr del conjunto conj_d est puesto a 1, o retorna 0 si est puesto a 0. descr del conjunto conj_d est puesto a 1, o retorna 0 si est puesto a 0.

El fichero <sys/types.h> y/o <sys/time.h> tambin define la constante El fichero <sys/types.h> y/o <sys/time.h> tambin define la constante
FD_SETSIZE, que equivale al nmero mximo de descriptores que caben en FD_SETSIZE, que equivale al nmero mximo de descriptores que caben en
una variable del tipo fd_set. una variable del tipo fd_set.
FUOC P03/75064/00978 31 Programacin de sockets FUOC P03/75064/00978 31 Programacin de sockets

b) El tipo struct timeval sirve para representar un intervalo de tiempo y b) El tipo struct timeval sirve para representar un intervalo de tiempo y
se define de la manera siguiente: se define de la manera siguiente:

struct timeval struct timeval


{ {
long int tv_sec; long int tv_sec;
long int tv_usec; long int tv_usec;
}; };

El campo tv_sec expresa el nmero de segundos del intervalo y el campo tv_usec, el Una vez explicados los tipos El campo tv_sec expresa el nmero de segundos del intervalo y el campo tv_usec, el Una vez explicados los tipos
de los parmetros, volvemos al de los parmetros, volvemos al
nmero de microsegundos. funcionamiento de la llamada select. nmero de microsegundos. funcionamiento de la llamada select.

La llamadas select retorna cuando se da alguna de las cuatro condiciones si- La llamadas select retorna cuando se da alguna de las cuatro condiciones si-
guientes: guientes:

Se puede llevar a cabo una lectura sin bloqueo. Por ejemplo, cuando exis- Se puede llevar a cabo una lectura sin bloqueo. Por ejemplo, cuando exis-
ten datos disponibles para leer en alguno de los descriptores de la lista es- ten datos disponibles para leer en alguno de los descriptores de la lista es-
pecificada en el segundo parmetro, d_lect. Asimismo, en el caso de que pecificada en el segundo parmetro, d_lect. Asimismo, en el caso de que
se haya llegado al final de los datos (en un socket conectado, cuando se se haya llegado al final de los datos (en un socket conectado, cuando se
haya cerrado la conexin). haya cerrado la conexin).

Se pueden escribir datos inmediatamente (sin bloqueo) en alguno de los Se pueden escribir datos inmediatamente (sin bloqueo) en alguno de los
descriptores de la lista especificada en el tercer parmetro, d_escr. descriptores de la lista especificada en el tercer parmetro, d_escr.

Hay una situacin especial (una condicin excepcional) pendiente de proce- Hay una situacin especial (una condicin excepcional) pendiente de proce-
sar en alguno de los descriptores de la lista especificada en el cuarto parme- sar en alguno de los descriptores de la lista especificada en el cuarto parme-
tro, d_excep. En el caso de los sockets, se considera como una condicin tro, d_excep. En el caso de los sockets, se considera como una condicin
excepcional la llegada de datos urgentes. excepcional la llegada de datos urgentes.

Ha transcurrido el tiempo especificado en el quinto parmetro, tiempo. Ha transcurrido el tiempo especificado en el quinto parmetro, tiempo.

La constante FD_SETSIZE La constante FD_SETSIZE


El primer parmetro, n_descr, indica el nmero mximo de descriptores exis- El primer parmetro, n_descr, indica el nmero mximo de descriptores exis-
Cuando hay ms de un socket Cuando hay ms de un socket
tentes en cada una de las tres listas. Es decir, slo se consideran significativos en las listas, y cualquiera puede tentes en cada una de las tres listas. Es decir, slo se consideran significativos en las listas, y cualquiera puede
ser el mayor, es habitual utilizar ser el mayor, es habitual utilizar
los n_descr primeros bits de cada lista (los correspondientes a los descriptores la constante FD_SETSIZE
los n_descr primeros bits de cada lista (los correspondientes a los descriptores la constante FD_SETSIZE
entre 0 y n_descr - 1). como valor del primer entre 0 y n_descr - 1). como valor del primer
parmetro. parmetro.

Cuando retorna, la llamada modifica las listas de descriptores y deja puestos a 1 Cuando retorna, la llamada modifica las listas de descriptores y deja puestos a 1
Fuera de tiempo Fuera de tiempo
slo los bits de los descriptores en que se cumplen las condiciones respectivas slo los bits de los descriptores en que se cumplen las condiciones respectivas
(posibilidad de lectura o escritura, o presencia de excepciones). En algunos sistemas, la llamada (posibilidad de lectura o escritura, o presencia de excepciones). En algunos sistemas, la llamada
select tambin modifica el select tambin modifica el
contenido del quinto parme- contenido del quinto parme-
tro para indicar cunto tiempo tro para indicar cunto tiempo
El valor retornado es el nmero total de bits que han quedado puestos a 1 en falta para llegar al fuera de
El valor retornado es el nmero total de bits que han quedado puestos a 1 en falta para llegar al fuera de
todas las listas, si no se ha producido ningn error, caso en el que el valor tiempo. Por tanto, un progra- todas las listas, si no se ha producido ningn error, caso en el que el valor tiempo. Por tanto, un progra-
ma que deba ser portable no ma que deba ser portable no
retornado es 1. Si es 0, significa que la llamada ha retornado por tiempo puede presuponer que el con- retornado es 1. Si es 0, significa que la llamada ha retornado por tiempo puede presuponer que el con-
tenido del quinto parmetro tenido del quinto parmetro
agotado (time out); es decir que ha transcurrido el tiempo indicado por el ltimo continuar siendo el mismo agotado (time out); es decir que ha transcurrido el tiempo indicado por el ltimo continuar siendo el mismo
despus de devolver la llamada. despus de devolver la llamada.
parmetro sin que se diera ninguna de las otras condiciones. parmetro sin que se diera ninguna de las otras condiciones.
FUOC P03/75064/00978 32 Programacin de sockets FUOC P03/75064/00978 32 Programacin de sockets

Si alguno de los parmetros d_lect, d_escr, d_excep o tiempo es un pun- Si alguno de los parmetros d_lect, d_escr, d_excep o tiempo es un pun-
tero nulo, la llamada select no comprueba la condicin correspondiente. tero nulo, la llamada select no comprueba la condicin correspondiente.
Por ejemplo, si tiempo es nulo, significa que no hay tiempo mximo y, por Por ejemplo, si tiempo es nulo, significa que no hay tiempo mximo y, por
consiguiente, la llamada espera indefinidamente hasta que se d alguna de las consiguiente, la llamada espera indefinidamente hasta que se d alguna de las
otras condiciones. otras condiciones.

Asimismo, es posible hacer que la llamada select retorne de inmediato, si se le Asimismo, es posible hacer que la llamada select retorne de inmediato, si se le
pasa en el parmetro tiempo, un puntero a una estructura que tenga sus campos pasa en el parmetro tiempo, un puntero a una estructura que tenga sus campos
a 0. Ello es til para efectuar una operacin de encuesta sobre los descriptores, a 0. Ello es til para efectuar una operacin de encuesta sobre los descriptores,
puesto que, en este caso, la llamada simplemente retorna indicando en cules se puesto que, en este caso, la llamada simplemente retorna indicando en cules se
dan en aquel momento las condiciones especificadas, sin esperar nada. dan en aquel momento las condiciones especificadas, sin esperar nada.

Cuando la llamada select retorna con error, la variable errno puede tener Cuando la llamada select retorna con error, la variable errno puede tener
alguno de los valores siguientes: alguno de los valores siguientes:

EBADF: algn bit de las listas del segundo parmetro, el tercero y/o el cuarto EBADF: algn bit de las listas del segundo parmetro, el tercero y/o el cuarto
no corresponde a un descriptor vlido. no corresponde a un descriptor vlido.

EINVAL: el contenido del quinto parmetro es incorrecto (es negativo o de- EINVAL: el contenido del quinto parmetro es incorrecto (es negativo o de-
masiado grande). masiado grande).

EINTR: no se ha esperado el tiempo indicado por el quinto parmetro EINTR: no se ha esperado el tiempo indicado por el quinto parmetro
porque ha llegado una seal no ignorada. porque ha llegado una seal no ignorada.

Reemisin de datos Reemisin de datos

La funcin siguiente tiene como parmetros tres descriptores: todos los datos recibidos La funcin siguiente tiene como parmetros tres descriptores: todos los datos recibidos
por el primero, los reenva al segundo y, simultneamente, los recibidos por el segundo, por el primero, los reenva al segundo y, simultneamente, los recibidos por el segundo,
los reenva al tercero. La funcin retorna cuando se detecta el final de los datos en el pri- los reenva al tercero. La funcin retorna cuando se detecta el final de los datos en el pri-
mer descriptor o en el segundo. mer descriptor o en el segundo.

int recibir_enviar(int d1, int d2, int d3) int recibir_enviar(int d1, int d2, int d3)
{ {
char buffer[DIM_BUFFER]; char buffer[DIM_BUFFER];
fd_set lista, preparados; fd_set lista, preparados;
int n; int n;

FD_ZERO(&lista); FD_ZERO(&lista);
FD_SET(d1, &lista); FD_SET(d1, &lista);
FD_SET(d2, &lista); FD_SET(d2, &lista);
while (1) while (1)
{ {
preparados = lista; preparados = lista;
if (select(FD_SETSIZE, &preparados, NULL, NULL, NULL) < if (select(FD_SETSIZE, &preparados, NULL, NULL, NULL) <
0) 0)
return -1; return -1;
if (FD_ISSET(d1, &preparados)) if (FD_ISSET(d1, &preparados))
{ {
if ((n = read(d1, buffer, sizeof buffer)) < 0) if ((n = read(d1, buffer, sizeof buffer)) < 0)
return -1; return -1;
if (n == 0) break; if (n == 0) break;
if (write(d2, buffer, n) < 0) return -1; if (write(d2, buffer, n) < 0) return -1;
} }
if (FD_ISSET(d2, &preparados)) if (FD_ISSET(d2, &preparados))
{ {
if ((n = read(d2, buffer, sizeof buffer)) < 0) if ((n = read(d2, buffer, sizeof buffer)) < 0)
return -1; return -1;
FUOC P03/75064/00978 33 Programacin de sockets FUOC P03/75064/00978 33 Programacin de sockets

if (n == 0) break; if (n == 0) break;
if (write(d3, buffer, n) < 0) return -1; if (write(d3, buffer, n) < 0) return -1;
} }
} }
return 0; return 0;
} }

El uso de la llamada select permite saber dnde se encuentran datos disponibles. As, El uso de la llamada select permite saber dnde se encuentran datos disponibles. As,
se evita tener que leer en un descriptor que no tiene datos y, por tanto, que el proceso se se evita tener que leer en un descriptor que no tiene datos y, por tanto, que el proceso se
bloquee si mientras tanto llegan datos por el otro (hemos supuesto, por simplicidad, que bloquee si mientras tanto llegan datos por el otro (hemos supuesto, por simplicidad, que
las operaciones de escritura siempre se pueden llevar a cabo inmediatamente). las operaciones de escritura siempre se pueden llevar a cabo inmediatamente).

Como caso particular, se puede llamar esta funcin y pasarle como primer parmetro el Como caso particular, se puede llamar esta funcin y pasarle como primer parmetro el
valor 0 (el descriptor que por norma general corresponde a la entrada estndar), como valor 0 (el descriptor que por norma general corresponde a la entrada estndar), como
segundo el descriptor de un socket y, como tercero, el valor 1 (la salida estndar). Con segundo el descriptor de un socket y, como tercero, el valor 1 (la salida estndar). Con
ello, se obtiene un procedimiento que enva por el socket los datos que lee del dispositivo ello, se obtiene un procedimiento que enva por el socket los datos que lee del dispositivo
de entrada (si no est redireccionado, ser el teclado) y que, simultneamente, escribe por Consultad un ejemplo del uso de entrada (si no est redireccionado, ser el teclado) y que, simultneamente, escribe por Consultad un ejemplo del uso
de la funcin recibir_enviar de la funcin recibir_enviar
el dispositivo de salida (si no est redireccionado, ser la pantalla) los datos que recibe en el subapartado 2.3.2. de este mdulo el dispositivo de salida (si no est redireccionado, ser la pantalla) los datos que recibe en el subapartado 2.3.2. de este mdulo
didctico. didctico.
por este mismo socket, hasta que encuentra el final de la entrada o de la conexin. por este mismo socket, hasta que encuentra el final de la entrada o de la conexin.

2.1.6. Cerrar un socket 2.1.6. Cerrar un socket

La llamada close proporciona el mecanismo general para cerrar un descriptor La llamada close proporciona el mecanismo general para cerrar un descriptor
cuando ya no se necesita trabajar ms en el mismo y liberar los recursos que cuando ya no se necesita trabajar ms en el mismo y liberar los recursos que
el sistema tiene destinados (buffers de lectura y escritura, etc.). Una vez cerra- el sistema tiene destinados (buffers de lectura y escritura, etc.). Una vez cerra-
do, el argumento de esta llamada deja de ser un descriptor vlido. do, el argumento de esta llamada deja de ser un descriptor vlido.

El prototipo de la llamada close, que est declarado en el fichero cabecera El prototipo de la llamada close, que est declarado en el fichero cabecera
<unistd.h>, es el siguiente: <unistd.h>, es el siguiente:

int close(int descr); int close(int descr);

El parmetro descr indica el descriptor que se quiere cerrar, y el valor retor- El parmetro descr indica el descriptor que se quiere cerrar, y el valor retor-
nado ser 0 para informar de que la operacin se ha llevado a cabo correcta- nado ser 0 para informar de que la operacin se ha llevado a cabo correcta-
mente, o 1 para indicar que se ha producido algn error. mente, o 1 para indicar que se ha producido algn error.

Cuando se aplica la llamada close a un socket, se dan por acabadas las comu- Cuando se aplica la llamada close a un socket, se dan por acabadas las comu-
nicaciones para este ltimo. Si el socket estaba conectado, se siguen los pasos nicaciones para este ltimo. Si el socket estaba conectado, se siguen los pasos
establecidos en el protocolo correspondiente para cerrar la conexin. En par- establecidos en el protocolo correspondiente para cerrar la conexin. En par-
ticular, si se cierra un socket que utiliza un protocolo de transmisin fiable, y ticular, si se cierra un socket que utiliza un protocolo de transmisin fiable, y
todava quedan datos pendientes de enviar, por norma general la llamada no todava quedan datos pendientes de enviar, por norma general la llamada no
Cierre de un socket TCP Cierre de un socket TCP
retorna hasta que no se han acabado de enviar todos los datos. retorna hasta que no se han acabado de enviar todos los datos.
Cuando se cierra un socket que Cuando se cierra un socket que
utiliza el protocolo TCP, puede utiliza el protocolo TCP, puede
Si se cierra un socket del espacio de nombres de ficheros, la entrada de directo- suceder que la llamada retor- Si se cierra un socket del espacio de nombres de ficheros, la entrada de directo- suceder que la llamada retor-
ne, pero que el nmero de ne, pero que el nmero de
rio correspondiente a este socket permanece en el sistema de ficheros. Para eli- puerto que tena asignado el rio correspondiente a este socket permanece en el sistema de ficheros. Para eli- puerto que tena asignado el
socket contine estando ocu- socket contine estando ocu-
minarla, es preciso borrarla, por ejemplo, con la llamada unlink. pado durante cierto tiempo.
minarla, es preciso borrarla, por ejemplo, con la llamada unlink. pado durante cierto tiempo.
Ello significa que la conexin Ello significa que la conexin
que corresponda a este socket que corresponda a este socket
Por otro lado, hay una llamada especfica de los sockets denominada shutdown, todava est en el estado Por otro lado, hay una llamada especfica de los sockets denominada shutdown, todava est en el estado
time_wait del protocolo. time_wait del protocolo.
que permite dar por finalizada la comunicacin en cualquiera de los dos cana- que permite dar por finalizada la comunicacin en cualquiera de los dos cana-
FUOC P03/75064/00978 34 Programacin de sockets FUOC P03/75064/00978 34 Programacin de sockets

les del intercambio de datos bidireccional. Su prototipo est declarado en el les del intercambio de datos bidireccional. Su prototipo est declarado en el
fichero cabecera <sys/socket.h> de la manera siguiente: fichero cabecera <sys/socket.h> de la manera siguiente:

int shutdown(int descr, int modo); int shutdown(int descr, int modo);

El parmetro descr corresponde al descriptor del socket. El parmetro descr corresponde al descriptor del socket.
El parmetro modo indica cmo debe aplicarse la operacin al socket: El parmetro modo indica cmo debe aplicarse la operacin al socket:

Si vale 0, se da por finalizada la recepcin de datos por el socket (si llegan ms datos, Si vale 0, se da por finalizada la recepcin de datos por el socket (si llegan ms datos,
no se leern). no se leern).
Si vale 1, se da por culminado el envo de datos por el socket (si hay datos pendientes Si vale 1, se da por culminado el envo de datos por el socket (si hay datos pendientes
de enviar, se descartan). de enviar, se descartan).
Si vale 2, se dan por acabados tanto la recepcin, como el envo de datos. Si vale 2, se dan por acabados tanto la recepcin, como el envo de datos.

Los valores de la variable errno siguientes indican errores que se pueden pro- Los valores de la variable errno siguientes indican errores que se pueden pro-
ducir en las llamadas close y shutdown: ducir en las llamadas close y shutdown:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK (slo para la llamada shutdown): el primer parmetro es un des- ENOTSOCK (slo para la llamada shutdown): el primer parmetro es un des-
criptor, pero no corresponde a un socket. criptor, pero no corresponde a un socket.

ENOTCONN (slo para la llamada shutdown): el socket es orientado a co- ENOTCONN (slo para la llamada shutdown): el socket es orientado a co-
nexin, pero no est conectado. nexin, pero no est conectado.

EINTR (slo para la llamada close): no se ha completado la operacin (no EINTR (slo para la llamada close): no se ha completado la operacin (no
se han acabado de transmitir los datos que quedaban pendientes) puesto se han acabado de transmitir los datos que quedaban pendientes) puesto
que ha llegado una seal no ignorada. que ha llegado una seal no ignorada.

2.2. Operaciones propias de los servidores 2.2. Operaciones propias de los servidores

2.2.1. Preparar un socket para recibir conexiones 2.2.1. Preparar un socket para recibir conexiones

En los protocolos orientados a conexin, el socket servidor debe estar prepara- En los protocolos orientados a conexin, el socket servidor debe estar prepara-
do para recibir conexiones de manera pasiva. La manera de conseguirlo es por do para recibir conexiones de manera pasiva. La manera de conseguirlo es por
medio de la llamada listen, cuyo prototipo est declarado en el fichero ca- medio de la llamada listen, cuyo prototipo est declarado en el fichero ca-
becera <sys/socket.h> de la manera siguiente: becera <sys/socket.h> de la manera siguiente:

int listen(int descr, unsigned int n_petic); int listen(int descr, unsigned int n_petic);

La llamada listen crea una cola en la que se irn guardando las peticiones de En el espacio de nombres La llamada listen crea una cola en la que se irn guardando las peticiones de En el espacio de nombres
Internet,... Internet,...
conexin que lleguen destinadas a la direccin del socket indicado por el primer conexin que lleguen destinadas a la direccin del socket indicado por el primer
parmetro, descr. El parmetro n_petic determina la longitud de la cola. ... si el socket pasado a la llama- parmetro, descr. El parmetro n_petic determina la longitud de la cola. ... si el socket pasado a la llama-
da listen no tuviera direc- da listen no tuviera direc-
cin, el sistema le asignara una cin, el sistema le asignara una
Como es natural, los clientes deben saber la direccin del socket servidor para (aleatoria) de manera autom- Como es natural, los clientes deben saber la direccin del socket servidor para (aleatoria) de manera autom-
tica y, por tanto, los clientes no tica y, por tanto, los clientes no
poderse conectar al mismo. Por tanto, es necesario haberle asignado una con podran saber a priori a dnde poderse conectar al mismo. Por tanto, es necesario haberle asignado una con podran saber a priori a dnde
deberan conectarse. deberan conectarse.
la llamada bind antes de aplicarle la llamada listen. la llamada bind antes de aplicarle la llamada listen.
FUOC P03/75064/00978 35 Programacin de sockets FUOC P03/75064/00978 35 Programacin de sockets

El valor retornado por esta llamada es 0 si no se produce error, o 1 en caso El valor retornado por esta llamada es 0 si no se produce error, o 1 en caso
contrario. Los posibles valores de la variable errno son los que mencionamos contrario. Los posibles valores de la variable errno son los que mencionamos
a continuacin: a continuacin:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a un ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a un
socket. socket.

EOPNOTSUPP: el socket especificado no soporta la operacin (no es un socket EOPNOTSUPP: el socket especificado no soporta la operacin (no es un socket
orientado a conexin). orientado a conexin).

EINVAL: el primer parmetro es incorrecto porque corresponde a un socket EINVAL: el primer parmetro es incorrecto porque corresponde a un socket
al que no se le puede aplicar la operacin (por ejemplo, porque ya est co- al que no se le puede aplicar la operacin (por ejemplo, porque ya est co-
nectado a otro socket). nectado a otro socket).

2.2.2. Aceptar una peticin de conexin 2.2.2. Aceptar una peticin de conexin

Un socket servidor al que se le haya aplicado la llamada listen debe utilizar Un socket servidor al que se le haya aplicado la llamada listen debe utilizar
la llamada accept para establecer las conexiones con los clientes que las soli- la llamada accept para establecer las conexiones con los clientes que las soli-
citen. El prototipo de dicha llamada est declarado en el fichero cabecera citen. El prototipo de dicha llamada est declarado en el fichero cabecera
<sys/socket.h> de la manera siguiente: <sys/socket.h> de la manera siguiente:

int accept(int descr, struct sockaddr *adr, int accept(int descr, struct sockaddr *adr,
size_t *long_adr); size_t *long_adr);

La llamada accept extrae la primera peticin de conexin de la cola asociada La llamada accept extrae la primera peticin de conexin de la cola asociada
al socket indicado por el primer parmetro, descr, y crea un nuevo socket, que al socket indicado por el primer parmetro, descr, y crea un nuevo socket, que
tendr la misma direccin que el original y estar conectado al originador de tendr la misma direccin que el original y estar conectado al originador de
la peticin. El socket original continuar preparado para recibir nuevas peticio- la peticin. El socket original continuar preparado para recibir nuevas peticio-
nes de conexin. nes de conexin.

El valor retornado es el descriptor del nuevo socket creado, que deber utilizar- El valor retornado es el descriptor del nuevo socket creado, que deber utilizar-
se en el intercambio de datos con el cliente. Asimismo, la llamada llena la es- se en el intercambio de datos con el cliente. Asimismo, la llamada llena la es-
tructura apuntada por el segundo parmetro, adr, con la direccin del socket tructura apuntada por el segundo parmetro, adr, con la direccin del socket
cliente con que se ha establecido la conexin y el tercer parmetro, long_adr cliente con que se ha establecido la conexin y el tercer parmetro, long_adr
(que en un inicio debe contener la longitud mxima admisible), con la longi- (que en un inicio debe contener la longitud mxima admisible), con la longi-
tud total de esta direccin. Si se produce algn error, el valor retornado es 1. tud total de esta direccin. Si se produce algn error, el valor retornado es 1.

Si en el momento de invocar la llamada accept no hay ninguna peticin de Si en el momento de invocar la llamada accept no hay ninguna peticin de
conexin a la cola, dicha llamada acta de la misma manera que read: se blo- conexin a la cola, dicha llamada acta de la misma manera que read: se blo-
quea y se queda esperando hasta que llegue una, salvo que el socket trabaje en quea y se queda esperando hasta que llegue una, salvo que el socket trabaje en
modo no bloqueante. modo no bloqueante.

Asimismo, es posible esperar o comprobar si hay peticiones por medio de la Consultad las llamadas read y Asimismo, es posible esperar o comprobar si hay peticiones por medio de la Consultad las llamadas read y
select en los subapartados 2.4.1 select en los subapartados 2.4.1
y 2.1.5 de este mdulo didctico. y 2.1.5 de este mdulo didctico.
llamada select. Para ello, simplemente es preciso incluir el descriptor del socket llamada select. Para ello, simplemente es preciso incluir el descriptor del socket
FUOC P03/75064/00978 36 Programacin de sockets FUOC P03/75064/00978 36 Programacin de sockets

en la lista de descriptores del segundo parmetro, d_lect, puesto que, en el en la lista de descriptores del segundo parmetro, d_lect, puesto que, en el
caso de un socket servidor al que se le ha aplicado la llamada listen, la con- caso de un socket servidor al que se le ha aplicado la llamada listen, la con-
dicin de disponibilidad de datos de lectura se interpreta como una presen- dicin de disponibilidad de datos de lectura se interpreta como una presen-
cia de peticiones de conexin en la cola. cia de peticiones de conexin en la cola.

Cuando la llamada accept retorna con error, la variable errno puede tener Cuando la llamada accept retorna con error, la variable errno puede tener
uno de los valores siguientes: uno de los valores siguientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a
un socket. un socket.

EOPNOTSUPP: el socket especificado no soporta la operacin (no es un socket EOPNOTSUPP: el socket especificado no soporta la operacin (no es un socket
orientado a conexin). orientado a conexin).

EINVAL: el primer parmetro es incorrecto porque corresponde a un socket al EINVAL: el primer parmetro es incorrecto porque corresponde a un socket al
que no se le puede aplicar la operacin (no se ha invocado la llamada listen que no se le puede aplicar la operacin (no se ha invocado la llamada listen
y, por consiguiente, no est preparado para recibir peticiones de conexin). y, por consiguiente, no est preparado para recibir peticiones de conexin).

EWOULDBLOCK: el socket es no bloqueante y no hay conexiones pendientes EWOULDBLOCK: el socket es no bloqueante y no hay conexiones pendientes
de aceptar en la cola. de aceptar en la cola.

EINTR: no se ha completado la operacin porque ha llegado una seal no EINTR: no se ha completado la operacin porque ha llegado una seal no
ignorada. ignorada.

2.2.3. Ejemplos de programacin de un servidor 2.2.3. Ejemplos de programacin de un servidor

Los ejemplos que vienen a continuacin ilustran el uso de las llamadas de sockets Los ejemplos que vienen a continuacin ilustran el uso de las llamadas de sockets
para programar un servidor basado en el protocolo TCP. Utilizando dos tc- para programar un servidor basado en el protocolo TCP. Utilizando dos tc-
nicas de programacin diferentes, los fragmentos de cdigo siguientes mues- nicas de programacin diferentes, los fragmentos de cdigo siguientes mues-
tran cmo se puede implementar un servidor que acepte conexiones de un tran cmo se puede implementar un servidor que acepte conexiones de un
nmero cualquiera de clientes. Para cada conexin, el servidor lee los datos que nmero cualquiera de clientes. Para cada conexin, el servidor lee los datos que
le enva el cliente, genera una respuesta procesando los datos recibidos y se la en- le enva el cliente, genera una respuesta procesando los datos recibidos y se la en-
va al cliente. va al cliente.

Ejemplo de gestin de conexiones con un solo proceso Ejemplo de gestin de conexiones con un solo proceso

En este ejemplo, el programa deja el socket servidor preparado para recibir pe- En este ejemplo, el programa deja el socket servidor preparado para recibir pe-
ticiones de conexin y, a continuacin, entra en un bucle en el que comprue- ticiones de conexin y, a continuacin, entra en un bucle en el que comprue-
ba, por medio de la llamada select, si llegan nuevas peticiones y/o datos de ba, por medio de la llamada select, si llegan nuevas peticiones y/o datos de
las conexiones ya establecidas. las conexiones ya establecidas.

Cuando hay algn socket preparado, lo atiende: si es una peticin de conexin, Cuando hay algn socket preparado, lo atiende: si es una peticin de conexin,
la acepta y la aade a la lista de sockets activos para las prximas llamadas la acepta y la aade a la lista de sockets activos para las prximas llamadas
select y, si son datos que han llegado por un socket ya conectado, los procesa select y, si son datos que han llegado por un socket ya conectado, los procesa
y les enva la respuesta. y les enva la respuesta.
FUOC P03/75064/00978 37 Programacin de sockets FUOC P03/75064/00978 37 Programacin de sockets

Cuando detecta el final de una conexin, cierra el socket correspondiente y lo Cuando detecta el final de una conexin, cierra el socket correspondiente y lo
borra de la lista. borra de la lista.

El parmetro de la funcin servidor de este ejemplo es el nmero de puerto en que El parmetro de la funcin servidor de este ejemplo es el nmero de puerto en que
Consultad el ejemplo de creacin Consultad el ejemplo de creacin
de un socket TCP en el subapartado de un socket TCP en el subapartado
deben recibirse las peticiones de conexin. Para asignar la direccin al socket 2.1.1 y la asignacin de un nombre deben recibirse las peticiones de conexin. Para asignar la direccin al socket 2.1.1 y la asignacin de un nombre
a un socket del espacio Internet en el a un socket del espacio Internet en el
subapartado 2.1.2 de este mdulo. subapartado 2.1.2 de este mdulo.
servidor, utiliza la funcin asignar_dir_internet y pone en la parte de di- servidor, utiliza la funcin asignar_dir_internet y pone en la parte de di-
reccin del servidor la constante INADDR_ANY. Asimismo, utiliza la funcin reccin del servidor la constante INADDR_ANY. Asimismo, utiliza la funcin
crear_socket_TCP. crear_socket_TCP.

Para generar las respuestas, supondremos que hay una funcin procesa_datos Para generar las respuestas, supondremos que hay una funcin procesa_datos
que recibe dos parmetros que indican dnde se encuentran los datos de entra- que recibe dos parmetros que indican dnde se encuentran los datos de entra-
da y cuntos bytes ocupan. Esta funcin retorna un puntero a los datos proce- da y cuntos bytes ocupan. Esta funcin retorna un puntero a los datos proce-
sados (salvo que todava no haya suficientes datos de entrada para generar la sados (salvo que todava no haya suficientes datos de entrada para generar la
respuesta) y, en un parmetro por referencia (el tercero), retorna su longitud. respuesta) y, en un parmetro por referencia (el tercero), retorna su longitud.

char *procesa_datos(char *, int, int *); char *procesa_datos(char *, int, int *);

int servidor(unsigned short int port) int servidor(unsigned short int port)
{ {

char buffer[DIM_BUFFER], *buf_proc; char buffer[DIM_BUFFER], *buf_proc;


struct sockaddr_in adr; struct sockaddr_in adr;
fd_set activos, preparados; fd_set activos, preparados;
int sock, conn, i, n, n_proc; int sock, conn, i, n, n_proc;
unsigned int long_adr; unsigned int long_adr;
if ((sock = crear_socket_TCP())< 0) return -1; if ((sock = crear_socket_TCP())< 0) return -1;
if (asignar_dir_internet(sock, INADDR_ANY, if (asignar_dir_internet(sock, INADDR_ANY,
port) < 0) return -1; port) < 0) return -1;
if (listen(sock, 1) < 0) return -1; if (listen(sock, 1) < 0) return -1;
FD_ZERO(&activos); FD_ZERO(&activos);
FD_SET(sock, &activos); FD_SET(sock, &activos);
while (1) while (1)
{ {
preparados = activos; preparados = activos;
if (select(FD_SETSIZE, &preparados, NULL, NULL, if (select(FD_SETSIZE, &preparados, NULL, NULL,
NULL) < 0) return -1; NULL) < 0) return -1;
for (i = 0; i < FD_SETSIZE; i++) for (i = 0; i < FD_SETSIZE; i++)
if (FD_ISSET(i, &preparados)) if (FD_ISSET(i, &preparados))
{ {
if (i == sock) if (i == sock)
{ {
long_adr = sizeof adr; long_adr = sizeof adr;
if ((conn = accept(sock, (struct sockaddr *) if ((conn = accept(sock, (struct sockaddr *)
&adr, &long_adr))< 0) return -1; &adr, &long_adr))< 0) return -1;
FD_SET(conn, &activos); FD_SET(conn, &activos);
continue; continue;
FUOC P03/75064/00978 38 Programacin de sockets FUOC P03/75064/00978 38 Programacin de sockets

} }
if ((n = read(i, buffer, sizeof buffer)) < 0) if ((n = read(i, buffer, sizeof buffer)) < 0)
return -1; return -1;
if (n == 0) if (n == 0)
{ {
close(i); close(i);
FD_CLR(i, &activos); FD_CLR(i, &activos);
continue; continue;
} }
if ((buf_proc = procesa_datos(buffer, n, if ((buf_proc = procesa_datos(buffer, n,
&n_proc)) ! = NULL) &n_proc)) ! = NULL)
if (write(i, buf_proc, n_proc) < 0) if (write(i, buf_proc, n_proc) < 0)
return -1; return -1;
} }
} }
} }

La funcin de este ejemplo retorna cuando se produce cualquier error en las llamadas al La funcin de este ejemplo retorna cuando se produce cualquier error en las llamadas al
sistema (quien haya llamado esta funcin siempre puede consultar el valor de la variable sistema (quien haya llamado esta funcin siempre puede consultar el valor de la variable
errno). errno).

Ejemplo de bucle de creacin de procesos Ejemplo de bucle de creacin de procesos

El ejemplo anterior gestiona todas las conexiones con un solo proceso; sin em- El ejemplo anterior gestiona todas las conexiones con un solo proceso; sin em-
bargo, en UNIX, en numerosas ocasiones es ms conveniente crear un nuevo bargo, en UNIX, en numerosas ocasiones es ms conveniente crear un nuevo
proceso cada vez que llega una peticin de servicio y dejar que cada uno de proceso cada vez que llega una peticin de servicio y dejar que cada uno de
dichos procesos se encargue de atender a su cliente. dichos procesos se encargue de atender a su cliente.

En el ejemplo siguiente, el bucle del servidor espera conexiones y, cuando lle- En el ejemplo siguiente, el bucle del servidor espera conexiones y, cuando lle-
ga una, crea un proceso hijo con la llamada fork. El proceso padre vuelve a ga una, crea un proceso hijo con la llamada fork. El proceso padre vuelve a
esperar nuevas conexiones, mientras que el hijo se encarga de intercambiar los esperar nuevas conexiones, mientras que el hijo se encarga de intercambiar los
datos con el cliente por medio de la funcin auxiliar bucle_conexion (sus datos con el cliente por medio de la funcin auxiliar bucle_conexion (sus
parmetros son el descriptor de entrada y el de salida). parmetros son el descriptor de entrada y el de salida).

char *procesa_datos(char *, int, int *); char *procesa_datos(char *, int, int *);

int bucle_conexion(int entrada, int salida) int bucle_conexion(int entrada, int salida)
{ {
char buffer[DIM_BUFFER], *buf_proc; char buffer[DIM_BUFFER], *buf_proc;
int n, n_proc; int n, n_proc;

while ((n = read(entrada, buffer, while ((n = read(entrada, buffer,


sizeof buffer)) ! = 0) sizeof buffer)) ! = 0)
{ {
if (n < 0) return -1; if (n < 0) return -1;
FUOC P03/75064/00978 39 Programacin de sockets FUOC P03/75064/00978 39 Programacin de sockets

if ((buf_proc = procesa_datos(buffer, n, if ((buf_proc = procesa_datos(buffer, n,


&n_proc)) ! = NULL) &n_proc)) ! = NULL)
if (write(salida, buf_proc, n_proc) < 0) if (write(salida, buf_proc, n_proc) < 0)
return -1; return -1;

} }
return 0; return 0;
} }

int servidor(unsigned short int port) int servidor(unsigned short int port)
{ {

struct sockaddr_in adr; struct sockaddr_in adr;


int sock, conn, proceso; int sock, conn, proceso;
unsigned int long_adr; unsigned int long_adr;

if ((sock = crear_socket_TCP()) < 0) return -1; if ((sock = crear_socket_TCP()) < 0) return -1;

if (asignar_dir_internet(sock, INADDR_ANY, if (asignar_dir_internet(sock, INADDR_ANY,


port) < 0) return -1; port) < 0) return -1;
if (listen(sock, 1) < 0) return -1; if (listen(sock, 1) < 0) return -1;
while (1) while (1)
{ {
long_adr = sizeof adr; long_adr = sizeof adr;
if ((conn = accept(sock, (struct sockaddr *)&adr, if ((conn = accept(sock, (struct sockaddr *)&adr,
&long_adr)) < 0) return -1; &long_adr)) < 0) return -1;
if ((proceso = fork()) < 0) return -1; if ((proceso = fork()) < 0) return -1;
if (proceso == 0) if (proceso == 0)
{ {
if (bucle_conexion(conn, conn) < 0) exit(1); if (bucle_conexion(conn, conn) < 0) exit(1);
close(conn); close(conn);
exit(0); exit(0);
} }
} }
} }

En este ejemplo, para simplificar, el proceso padre no invoca la llamada wait para con- En este ejemplo, para simplificar, el proceso padre no invoca la llamada wait para con-
sultar el estatus de salida de los hijos cuando acaban, puesto que dicha llamada, como su sultar el estatus de salida de los hijos cuando acaban, puesto que dicha llamada, como su
nombre indica, es bloqueante. Por tanto, aunque ya no se ejecutan, los hijos se quedan nombre indica, es bloqueante. Por tanto, aunque ya no se ejecutan, los hijos se quedan
ocupando una entrada en la tabla de procesos; es decir, pasan a ser lo que se conoce como Consultad el ejemplo Escritura ocupando una entrada en la tabla de procesos; es decir, pasan a ser lo que se conoce como Consultad el ejemplo Escritura
de datos en presencia de seales de datos en presencia de seales
procesos zombis. Lo que se puede evitar si se captura la seal SIGCHLD (que se ignora no ignoradas en el subapartado 2.1.3. procesos zombis. Lo que se puede evitar si se captura la seal SIGCHLD (que se ignora no ignoradas en el subapartado 2.1.3.
por defecto) y se lleva a cabo la llamada wait en el gestor de esta seal. Si se opta por esta por defecto) y se lleva a cabo la llamada wait en el gestor de esta seal. Si se opta por esta
solucin, conviene considerar que la llamada accept puede retornar prematuramente solucin, conviene considerar que la llamada accept puede retornar prematuramente
con EINTR si un hijo acaba mientras se esperan conexiones y, por tanto, es preciso reali- con EINTR si un hijo acaba mientras se esperan conexiones y, por tanto, es preciso reali-
zar una comprobacin como la que deba hacerse cuando llegaban seales no ignoradas zar una comprobacin como la que deba hacerse cuando llegaban seales no ignoradas
mientras se escriban datos, o bien utilizar la funcin siginterrupt. mientras se escriban datos, o bien utilizar la funcin siginterrupt.

2.2.4. El servidor inetd 2.2.4. El servidor inetd

Con frecuencia, los sistemas UNIX ofrecen una serie de servicios Internet, como Con frecuencia, los sistemas UNIX ofrecen una serie de servicios Internet, como
por ejemplo, Telnet, FTP, correo electrnico, posiblemente WWW, etc. Una ma- por ejemplo, Telnet, FTP, correo electrnico, posiblemente WWW, etc. Una ma-
FUOC P03/75064/00978 40 Programacin de sockets FUOC P03/75064/00978 40 Programacin de sockets

nera de poder atender a las peticiones correspondientes es tener corriendo tan- nera de poder atender a las peticiones correspondientes es tener corriendo tan-
tos procesos como servicios y que cada uno se encargue de esperar las peticiones tos procesos como servicios y que cada uno se encargue de esperar las peticiones
que lleguen al puerto asociado a su servicio. Sin embargo, para aprovechar me- que lleguen al puerto asociado a su servicio. Sin embargo, para aprovechar me-
jor los recursos, lo que es ms habitual es tener un nico proceso, llamado jor los recursos, lo que es ms habitual es tener un nico proceso, llamado
inetd o Internet daemon, que se encarga de escuchar simultneamente todos inetd o Internet daemon, que se encarga de escuchar simultneamente todos
los puertos por los que pueden llegar peticiones y que, cada vez que llega una, los puertos por los que pueden llegar peticiones y que, cada vez que llega una,
arranca un proceso hijo que proporciona el servicio correspondiente. arranca un proceso hijo que proporciona el servicio correspondiente.

No todos los servicios son atendidos por inetd No todos los servicios son atendidos por inetd

El proceso inetd no necesariamente debe atender a todas las posibles peticiones de ser- El proceso inetd no necesariamente debe atender a todas las posibles peticiones de ser-
vicio que lleguen a un sistema UNIX. Aparte de los servicios no estndar que puedan ser vicio que lleguen a un sistema UNIX. Aparte de los servicios no estndar que puedan ser
proporcionados por procesos de usuario, inetd por norma general no atiende al servicio proporcionados por procesos de usuario, inetd por norma general no atiende al servicio
de correo electrnico. El motivo es que el proceso encargado de este servicio (sendmail) de correo electrnico. El motivo es que el proceso encargado de este servicio (sendmail)
no slo atiende a peticiones de clientes, sino que tambin lleva a cabo otras acciones no slo atiende a peticiones de clientes, sino que tambin lleva a cabo otras acciones
(procesar peridicamente la cola de mensajes, etc.). Asimismo, su fichero de configura- (procesar peridicamente la cola de mensajes, etc.). Asimismo, su fichero de configura-
cin (/etc/sendmail.cf) puede tener cierta complejidad, y es ms conveniente leerlo cin (/etc/sendmail.cf) puede tener cierta complejidad, y es ms conveniente leerlo
una vez al inicio que tenerlo que leer y analizar a cada peticin de servicio. La compleji- una vez al inicio que tenerlo que leer y analizar a cada peticin de servicio. La compleji-
dad del fichero de configuracin tambin es el motivo por el cual algunas implementa- dad del fichero de configuracin tambin es el motivo por el cual algunas implementa-
ciones de servidores WWW tampoco utilizan el proceso inetd. ciones de servidores WWW tampoco utilizan el proceso inetd.

Al proceso inetd se le indican los puertos que debe escuchar por medio de un Al proceso inetd se le indican los puertos que debe escuchar por medio de un
fichero de configuracin denominado inetd.conf, que suele estar en el di- fichero de configuracin denominado inetd.conf, que suele estar en el di-
rectorio /etc. Cada lnea del fichero consta de una serie de campos separados rectorio /etc. Cada lnea del fichero consta de una serie de campos separados
por espacios, de acuerdo con el esquema siguiente: por espacios, de acuerdo con el esquema siguiente:

servicio estilo protocolo espera usuario programa argumentos servicio estilo protocolo espera usuario programa argumentos

Ejemplo Ejemplo

Dos lneas que podramos encontrar en el fichero /etc/inetd.conf: Dos lneas que podramos encontrar en el fichero /etc/inetd.conf:

ftp stream tcp nowait root /usr/etc/ftpd ftpd -l ftp stream tcp nowait root /usr/etc/ftpd ftpd -l
talk dgram udp wait root /usr/etc/talkd talkd talk dgram udp wait root /usr/etc/talkd talkd

El significado de los campos que forman cada lnea de fichero es el siguiente: El significado de los campos que forman cada lnea de fichero es el siguiente:

El primer campo de la lnea es el nombre del servicio. El primer campo de la lnea es el nombre del servicio.

El segundo campo indica el estilo de comunicacin. Se expresa con los El segundo campo indica el estilo de comunicacin. Se expresa con los
smbolos definidos en el fichero <sys/socket.h>, pero sin el prefijo smbolos definidos en el fichero <sys/socket.h>, pero sin el prefijo
SOCK_ y en minsculas. SOCK_ y en minsculas.

El tercer campo es el protocolo que debe utilizarse. Por norma general, ser El tercer campo es el protocolo que debe utilizarse. Por norma general, ser
tcp si el estilo es stream y udp si el estilo es dgram. tcp si el estilo es stream y udp si el estilo es dgram.
wait y nowait wait y nowait

El cuarto campo indica si el servidor inetd debe esperar (wait) que el pro- wait slo es aplicable a los ser- El cuarto campo indica si el servidor inetd debe esperar (wait) que el pro- wait slo es aplicable a los ser-
vicios que utilizan el estilo vicios que utilizan el estilo
ceso hijo acabe, o no (nowait), antes de continuar atendiendo a nuevas pe- datagrama; en todos los otros ceso hijo acabe, o no (nowait), antes de continuar atendiendo a nuevas pe- datagrama; en todos los otros
debe utilizarse nowait. debe utilizarse nowait.
ticiones del servicio correspondiente. ticiones del servicio correspondiente.
FUOC P03/75064/00978 41 Programacin de sockets FUOC P03/75064/00978 41 Programacin de sockets

En el quinto campo encontramos el usuario en cuyo nombre se ejecutar el En el quinto campo encontramos el usuario en cuyo nombre se ejecutar el
proceso hijo. proceso hijo.

El sexto campo es el nombre del programa que debe ejecutar el proceso hi- El sexto campo es el nombre del programa que debe ejecutar el proceso hi-
jo. Alternativamente, este campo puede ser la palabra internal para indi- jo. Alternativamente, este campo puede ser la palabra internal para indi-
car que el servicio es atendido directamente por el mismo servidor inetd, car que el servicio es atendido directamente por el mismo servidor inetd,
sin necesidad de llamar a ningn otro proceso. Es el caso de algunos servi- sin necesidad de llamar a ningn otro proceso. Es el caso de algunos servi-
cios llamados triviales. cios llamados triviales.

Ejemplos de servicios internos del proceso inetd Ejemplos de servicios internos del proceso inetd

echo: retorna los datos que recibe. echo: retorna los datos que recibe.
discard: no retorna nada. discard: no retorna nada.
chargen: genera una secuencia de caracteres. chargen: genera una secuencia de caracteres.
daytime: enva una cadena de caracteres con el da y la hora. daytime: enva una cadena de caracteres con el da y la hora.
time: enva 4 bytes que representan la hora actual en binario. time: enva 4 bytes que representan la hora actual en binario.

El sptimo campo y los siguientes forman la lista de argumentos que se El sptimo campo y los siguientes forman la lista de argumentos que se
pasarn al proceso hijo. Por norma general, los procesos interpretan el pasarn al proceso hijo. Por norma general, los procesos interpretan el
primer argumento de la lista como el nombre con que se han invocado. primer argumento de la lista como el nombre con que se han invocado.

Privilegios de inetd Privilegios de inetd


En primer lugar, el servidor inetd crea un socket para cada servicio que en- En primer lugar, el servidor inetd crea un socket para cada servicio que en-
inetd debe tener privilegios inetd debe tener privilegios
cuentra en el fichero de configuracin por medio del estilo indicado (segundo de superusuario para escuchar cuentra en el fichero de configuracin por medio del estilo indicado (segundo de superusuario para escuchar
en puertos reservados y cam- en puertos reservados y cam-
campo). A cada socket le asigna, con la llamada bind, un nmero de puerto biar el propietario de los proce-
campo). A cada socket le asigna, con la llamada bind, un nmero de puerto biar el propietario de los proce-
obtenido a partir del nombre del servicio (primer campo) y del protocolo aso- sos hijos. obtenido a partir del nombre del servicio (primer campo) y del protocolo aso- sos hijos.

ciado (tercer campo) utilizando, por ejemplo, la funcin getservbyname, ciado (tercer campo) utilizando, por ejemplo, la funcin getservbyname,
como veremos ms adelante. A los sockets que sean orientados a conexin, se como veremos ms adelante. A los sockets que sean orientados a conexin, se
les aplica la llamada listen. Despus se queda en un bucle esperando, por les aplica la llamada listen. Despus se queda en un bucle esperando, por
medio de la llamada select, a que lleguen peticiones de conexin a los sockets medio de la llamada select, a que lleguen peticiones de conexin a los sockets
con estilo stream, o datagramas a los sockets con estilo dgram. con estilo stream, o datagramas a los sockets con estilo dgram.

Modificacin del fichero inetd.conf Modificacin del fichero inetd.conf

El servidor inetd slo consulta el fichero de configuracin cuando se empieza a ejecutar El servidor inetd slo consulta el fichero de configuracin cuando se empieza a ejecutar
(por norma general, cuando arranca el sistema operativo) y cuando recibe una seal SIGHUP. (por norma general, cuando arranca el sistema operativo) y cuando recibe una seal SIGHUP.
Por tanto, si se modifica el fichero inetd.conf, es preciso enviar esta seal al proceso Por tanto, si se modifica el fichero inetd.conf, es preciso enviar esta seal al proceso
inetd para que los cambios tengan efecto. inetd para que los cambios tengan efecto.

Cuando la llamada select notifique que se ha recibido una peticin de un Cuando la llamada select notifique que se ha recibido una peticin de un
cliente, el servidor inetd aplicar la llamada accept al socket si es orientado cliente, el servidor inetd aplicar la llamada accept al socket si es orientado
a conexin. A continuacin, crear un proceso hijo, har que su propietario a conexin. A continuacin, crear un proceso hijo, har que su propietario
sea el usuario indicado (quinto campo), ejecutar el programa correspondien- sea el usuario indicado (quinto campo), ejecutar el programa correspondien-
te (sexto campo) y le pasar los argumentos especificados (sptimo campo). te (sexto campo) y le pasar los argumentos especificados (sptimo campo).
Entonces ocurrir lo siguiente: Entonces ocurrir lo siguiente:

Si el cuarto campo es nowait, el servidor inetd continuar atendiendo a Si el cuarto campo es nowait, el servidor inetd continuar atendiendo a
peticiones de servicio y poniendo en marcha nuevos procesos para cada peticiones de servicio y poniendo en marcha nuevos procesos para cada
una que llegue, con independencia de si los otros han acabado o no. Es una que llegue, con independencia de si los otros han acabado o no. Es
decir, a cada cliente que solicite el servicio, le corresponder un proceso decir, a cada cliente que solicite el servicio, le corresponder un proceso
hijo. hijo.
FUOC P03/75064/00978 42 Programacin de sockets FUOC P03/75064/00978 42 Programacin de sockets

Si el cuarto campo es wait (lo que implica que el servicio es no orientado a Si el cuarto campo es wait (lo que implica que el servicio es no orientado a
conexin), el servidor inetd se quedar esperando hasta que el proceso hijo conexin), el servidor inetd se quedar esperando hasta que el proceso hijo
acabe. De los nuevos datagramas que lleguen mientras tanto, tanto si son del acabe. De los nuevos datagramas que lleguen mientras tanto, tanto si son del
mismo cliente, como si son de otro, deber encargarse el proceso hijo. mismo cliente, como si son de otro, deber encargarse el proceso hijo.

As pues, no es necesario que los procesos que deban ser ejecutados por el ser- As pues, no es necesario que los procesos que deban ser ejecutados por el ser-
vidor inetd se preocupen por establecer la comunicacin con el cliente (crear vidor inetd se preocupen por establecer la comunicacin con el cliente (crear
el socket, asignarle direccin, esperar a que llegue la peticin y, en el caso de el socket, asignarle direccin, esperar a que llegue la peticin y, en el caso de
los servicios nowait, distinguir los diferentes clientes que solicitan la co- los servicios nowait, distinguir los diferentes clientes que solicitan la co-
nexin), puesto que se encarga de los mismos el proceso inetd. Y no slo eso, nexin), puesto que se encarga de los mismos el proceso inetd. Y no slo eso,
sino que, adems, el proceso hijo recibe los descriptores correspondientes en sino que, adems, el proceso hijo recibe los descriptores correspondientes en
la entrada y la salida estndar redireccionados al socket con que el cliente ha la entrada y la salida estndar redireccionados al socket con que el cliente ha
establecido la comunicacin. establecido la comunicacin.

Ello significa que, cuando el proceso hijo escriba datos por la salida estndar, Ello significa que, cuando el proceso hijo escriba datos por la salida estndar,
se los enviar al cliente por medio del socket y, cuando quiera leer datos de la se los enviar al cliente por medio del socket y, cuando quiera leer datos de la
entrada estndar, encontrar los que haya enviado el cliente. Por tanto, los pro- entrada estndar, encontrar los que haya enviado el cliente. Por tanto, los pro-
gramas servidores arrancados por el proceso inetd ni siquiera tienen por gramas servidores arrancados por el proceso inetd ni siquiera tienen por
qu saber que se comunicarn mediante sockets y, por lo general, pueden utili- qu saber que se comunicarn mediante sockets y, por lo general, pueden utili-
zar directamente las llamadas read, write, etc. e, incluso, funciones de nivel zar directamente las llamadas read, write, etc. e, incluso, funciones de nivel
ms alto como fgets, scanf, printf, etc. para leer y escribir los datos. ms alto como fgets, scanf, printf, etc. para leer y escribir los datos.

Programacin de un servidor invocado por el proceso inetd Programacin de un servidor invocado por el proceso inetd
Consultad el ejemplo de bucle Consultad el ejemplo de bucle
Si el servidor encargado de crear un proceso para cada conexin debiera ser arrancado por el de creacin de procesos Si el servidor encargado de crear un proceso para cada conexin debiera ser arrancado por el de creacin de procesos
en el subapartado 2.2.3 de este mdulo en el subapartado 2.2.3 de este mdulo
servidor inetd, como el descriptor 0 corresponde a la entrada estndar y el descriptor 1 a la didctico. servidor inetd, como el descriptor 0 corresponde a la entrada estndar y el descriptor 1 a la didctico.
salida estndar, la funcin servidor se podra escribir sencillamente de la manera siguiente: salida estndar, la funcin servidor se podra escribir sencillamente de la manera siguiente:

int servidor(void) int servidor(void)


{ {
return bucle_conexion(0, 1); return bucle_conexion(0, 1);
} }

En este caso, la funcin no necesitara como parmetro el nmero de puerto en que de- En este caso, la funcin no necesitara como parmetro el nmero de puerto en que de-
bera escuchar las peticiones de conexin, puesto que esta informacin ya se habra pro- bera escuchar las peticiones de conexin, puesto que esta informacin ya se habra pro-
porcionado al servidor inetd. porcionado al servidor inetd.

2.3. Operaciones propias de los clientes 2.3. Operaciones propias de los clientes

2.3.1. Conectar un socket 2.3.1. Conectar un socket

La llamada connect sirve para que un cliente inicie de manera activa una co- La llamada connect sirve para que un cliente inicie de manera activa una co-
nexin y su prototipo est declarado en el fichero cabecera <sys/socket.h> nexin y su prototipo est declarado en el fichero cabecera <sys/socket.h>
de la manera siguiente: de la manera siguiente:

int connect(int descr, const struct sockaddr *adr, int connect(int descr, const struct sockaddr *adr,
size_t long_adr); size_t long_adr);
FUOC P03/75064/00978 43 Programacin de sockets FUOC P03/75064/00978 43 Programacin de sockets

Si el socket indicado por el primer parmetro, descr, es orientado a conexin, la llamada Si el socket indicado por el primer parmetro, descr, es orientado a conexin, la llamada
sigue los pasos necesarios, segn el protocolo correspondiente, para establecer una co- sigue los pasos necesarios, segn el protocolo correspondiente, para establecer una co-
nexin con el socket servidor que tiene por direccin la que se especifica en el segundo nexin con el socket servidor que tiene por direccin la que se especifica en el segundo
parmetro, adr. El tercer parmetro, long_adr, indica el nmero de bytes que ocupa di- parmetro, adr. El tercer parmetro, long_adr, indica el nmero de bytes que ocupa di-
cha direccin. La llamada no retorna hasta que el servidor no responde a la peticin de cha direccin. La llamada no retorna hasta que el servidor no responde a la peticin de
conexin, excepto en los sockets no bloqueadores. conexin, excepto en los sockets no bloqueadores.

La llamada connect tambin puede aplicarse a sockets no orientados a co- La llamada connect tambin puede aplicarse a sockets no orientados a co-
nexin: simplemente les asocia una direccin de destino por defecto de ma- nexin: simplemente les asocia una direccin de destino por defecto de ma-
nera que se les pueda enviar datos con la llamadas sendto, as como con send nera que se les pueda enviar datos con la llamadas sendto, as como con send
y write. Otro efecto de la llamada connect en este caso es que por el socket y write. Otro efecto de la llamada connect en este caso es que por el socket
slo se recibirn los datagramas que procedan de la direccin especificada. slo se recibirn los datagramas que procedan de la direccin especificada.

La direccin remota asociada a un socket no orientado a conexin se puede La direccin remota asociada a un socket no orientado a conexin se puede
* En los sockets conectados no * En los sockets conectados no
cambiar en cualquier momento* volviendo a invocar la llamada connect. Asi- se puede llevar a cabo el cambio cambiar en cualquier momento* volviendo a invocar la llamada connect. Asi- se puede llevar a cabo el cambio
de direccin remota. de direccin remota.
mismo, se puede cancelar esta asociacin utilizando como parmetro una di- mismo, se puede cancelar esta asociacin utilizando como parmetro una di-
reccin que tenga en el campo sa_family el valor AF_UNSPEC. reccin que tenga en el campo sa_family el valor AF_UNSPEC.

No es necesario que el socket que se pasa a la llamada connect tenga asignada No es necesario que el socket que se pasa a la llamada connect tenga asignada
una direccin. En el espacio de nombres Internet, si el socket no tiene direc- una direccin. En el espacio de nombres Internet, si el socket no tiene direc-
cin, es decir, nmero de puerto, el sistema elige uno que no est ocupado en cin, es decir, nmero de puerto, el sistema elige uno que no est ocupado en
el rango comprendido entre IPPORT_RESERVED e IPPORT_USERRESERVED - 1 el rango comprendido entre IPPORT_RESERVED e IPPORT_USERRESERVED - 1
antes de intentar establecer la conexin. antes de intentar establecer la conexin.

Como es habitual, el valor retornado por la llamada ser 0 o 1, dependiendo Como es habitual, el valor retornado por la llamada ser 0 o 1, dependiendo
de si la operacin se ha completado con xito o no. Cuando hay error, los va- de si la operacin se ha completado con xito o no. Cuando hay error, los va-
lores posibles de la variable errno son los siguientes: lores posibles de la variable errno son los siguientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a ENOTSOCK: el primer parmetro es un descriptor, pero no corresponde a
un socket. un socket.

EINVAL: el tercer parmetro es incorrecto porque no corresponde a una EINVAL: el tercer parmetro es incorrecto porque no corresponde a una
longitud de direccin vlida en el espacio de nombres del socket. longitud de direccin vlida en el espacio de nombres del socket.

EAFNOSUPPORT: la direccin especificada no pertenece al espacio de nom- EAFNOSUPPORT: la direccin especificada no pertenece al espacio de nom-
bres del socket. bres del socket.

EISCONN: el socket es orientado a conexin y ya est conectado. EISCONN: el socket es orientado a conexin y ya est conectado.

ENETUNREACH: el socket es orientado a conexin y la direccin especificada es ENETUNREACH: el socket es orientado a conexin y la direccin especificada es
del espacio de nombres Internet; sin embargo, el sistema local no puede en- del espacio de nombres Internet; sin embargo, el sistema local no puede en-
contrar un camino para llegar a la red correspondiente al sistema remoto. contrar un camino para llegar a la red correspondiente al sistema remoto.

ETIMEDOUT: el socket es orientado a conexin y ha transcurrido cierto tiem- ETIMEDOUT: el socket es orientado a conexin y ha transcurrido cierto tiem-
po mximo sin que se haya podido completar la operacin de conexin (por po mximo sin que se haya podido completar la operacin de conexin (por
ejemplo, porque el servidor no responda). ejemplo, porque el servidor no responda).

ECONNREFUSED: el servidor ha rechazado la peticin de conexin. ECONNREFUSED: el servidor ha rechazado la peticin de conexin.

Esta situacin se da cuando en el servidor no hay ningn socket con la direccin especifi- Esta situacin se da cuando en el servidor no hay ningn socket con la direccin especifi-
cada que est esperando peticiones de conexin (es decir, al que se haya aplicado la llama- cada que est esperando peticiones de conexin (es decir, al que se haya aplicado la llama-
FUOC P03/75064/00978 44 Programacin de sockets FUOC P03/75064/00978 44 Programacin de sockets

da listen). Segn el protocolo utilizado, tambin se puede dar cuando la cola de da listen). Segn el protocolo utilizado, tambin se puede dar cuando la cola de
peticiones del socket servidor est llena, como sucede en el espacio de nombres de ficheros. peticiones del socket servidor est llena, como sucede en el espacio de nombres de ficheros.

En el espacio Internet, algunos servidores rechazan las peticiones que llegan cuando la En el espacio Internet, algunos servidores rechazan las peticiones que llegan cuando la
cola est llena y otros las ignoran. Con los primeros, la llamada connect en el cliente cola est llena y otros las ignoran. Con los primeros, la llamada connect en el cliente
retorna con ECONNREFUSED y, con los segundos, continuar retransmitiendo las peticio- retorna con ECONNREFUSED y, con los segundos, continuar retransmitiendo las peticio-
nes hasta que consiga conectarse o hasta que retorne con ETIMEDOUT. nes hasta que consiga conectarse o hasta que retorne con ETIMEDOUT.

EINPROGRESS: el socket es no bloqueante y la conexin no se ha podido EINPROGRESS: el socket es no bloqueante y la conexin no se ha podido
efectuar de manera inmediata. efectuar de manera inmediata.

En este caso, la llamada retorna; sin embargo, el sistema contina intentando la co- En este caso, la llamada retorna; sin embargo, el sistema contina intentando la co-
nexin. Para saber cundo ha conseguido establecerla, se puede comprobar con la llama- nexin. Para saber cundo ha conseguido establecerla, se puede comprobar con la llama-
da select si el socket est preparado para escribir datos en la misma. da select si el socket est preparado para escribir datos en la misma.

EALREADY: el socket es no bloqueante e intenta establecer una conexin. EALREADY: el socket es no bloqueante e intenta establecer una conexin.

EINTR: no se ha completado la operacin porque ha llegado una seal no EINTR: no se ha completado la operacin porque ha llegado una seal no
ignorada. ignorada.

Adems de estos posibles errores, en el espacio de nombres de ficheros tambin Adems de estos posibles errores, en el espacio de nombres de ficheros tambin
se pueden producir los errores propios del acceso a ficheros, como en la llamada se pueden producir los errores propios del acceso a ficheros, como en la llamada
bind: ENOENT, ENOTDIR, EACCESS, etc. Asimismo, hay un error especfico de la bind: ENOENT, ENOTDIR, EACCESS, etc. Asimismo, hay un error especfico de la
llamada connect, EPROTOTYPE, que indica que el socket servidor existe en el sis- llamada connect, EPROTOTYPE, que indica que el socket servidor existe en el sis-
tema de ficheros; sin embargo, su tipo de protocolo (secuencial o datagramas) tema de ficheros; sin embargo, su tipo de protocolo (secuencial o datagramas)
no coincide con el del socket cliente. no coincide con el del socket cliente.

2.3.2. Ejemplo de programacin de un cliente 2.3.2. Ejemplo de programacin de un cliente

El ejemplo siguiente ilustra cmo se pueden utilizar las llamadas de sockets Consultad el ejemplo Remisin
El ejemplo siguiente ilustra cmo se pueden utilizar las llamadas de sockets Consultad el ejemplo Remisin
de datos en el subapartado 2.1.5 de datos en el subapartado 2.1.5
para escribir un programa cliente. de este mdulo didctico. para escribir un programa cliente. de este mdulo didctico.

La funcin cliente definida a continuacin recibe dos parmetros: la direccin La funcin cliente definida a continuacin recibe dos parmetros: la direccin
Internet y el nmero de puerto correspondientes al socket al que debe conec- Internet y el nmero de puerto correspondientes al socket al que debe conec-
tarse, en que se supone que hay un proceso servidor esperando. Si consigue tarse, en que se supone que hay un proceso servidor esperando. Si consigue
establecer la conexin en el mismo, utiliza la funcin recibir_enviar para establecer la conexin en el mismo, utiliza la funcin recibir_enviar para
enviar al servidor todo lo que lea de la entrada estndar y para escribir por la enviar al servidor todo lo que lea de la entrada estndar y para escribir por la
salida estndar todo lo que reciba del servidor. salida estndar todo lo que reciba del servidor.

Tambin aqu se utilizan las funciones auxiliares que se utilizan para crear Consultad el ejemplo de creacin
Tambin aqu se utilizan las funciones auxiliares que se utilizan para crear Consultad el ejemplo de creacin
de un socket en el subapartado 2.1.1 de un socket en el subapartado 2.1.1
un socket y llenar una direccin en Internet. En este caso, no es necesario asignar y el ejemplo de relleno de una direccin un socket y llenar una direccin en Internet. En este caso, no es necesario asignar y el ejemplo de relleno de una direccin
en el subapartado 2.1.2 de este mdulo en el subapartado 2.1.2 de este mdulo
didctico. didctico.
direccin al socket, puesto que, en el momento de intentar la conexin, el sis- direccin al socket, puesto que, en el momento de intentar la conexin, el sis-
tema le asignar una automticamente. tema le asignar una automticamente.

int cliente(unsigned long int adr_host, int cliente(unsigned long int adr_host,
unsigned short int port) unsigned short int port)
{ {
struct sockaddr_in adr; struct sockaddr_in adr;
int sock; int sock;
FUOC P03/75064/00978 45 Programacin de sockets FUOC P03/75064/00978 45 Programacin de sockets

if ((sock = crear_socket_TCP()) < 0) return -1; if ((sock = crear_socket_TCP()) < 0) return -1;
llenar_dir_internet(&adr, adr_host, port); llenar_dir_internet(&adr, adr_host, port);
if (connect(sock, (struct sockaddr *)&adr, if (connect(sock, (struct sockaddr *)&adr,
sizeof adr) < 0) return -1; sizeof adr) < 0) return -1;
if (recibir_enviar(0, sock, 1) < 0) return -1; if (recibir_enviar(0, sock, 1) < 0) return -1;
close(sock); close(sock);
return 0; return 0;
} }

2.4. Operaciones auxiliares 2.4. Operaciones auxiliares

Adems de las llamadas al sistema que hemos visto hasta ahora, los programas Adems de las llamadas al sistema que hemos visto hasta ahora, los programas
que trabajan con sockets pueden utilizar otras llamadas o funciones auxiliares que trabajan con sockets pueden utilizar otras llamadas o funciones auxiliares
proporcionadas por la librera correspondiente. proporcionadas por la librera correspondiente.

2.4.1. Obtener direcciones de sockets 2.4.1. Obtener direcciones de sockets

Hay dos llamadas al sistema que permiten saber la direccin de un socket local Hay dos llamadas al sistema que permiten saber la direccin de un socket local
y la del socket remoto al que est conectado. Los prototipos de estas llamadas se y la del socket remoto al que est conectado. Los prototipos de estas llamadas se
declaran en el fichero cabecera <sys/socket.h> de la manera siguiente: declaran en el fichero cabecera <sys/socket.h> de la manera siguiente:

1) La llamada getsockname permite conocer la direccin del socket local: 1) La llamada getsockname permite conocer la direccin del socket local:

int getsockname(int descr, struct sockaddr *adr, int getsockname(int descr, struct sockaddr *adr,
size_t *long_adr); size_t *long_adr);

El parmetro adr contiene la direccin del socket correspondiente al parmetro descr. El parmetro adr contiene la direccin del socket correspondiente al parmetro descr.

El parmetro long_adr en un inicio debe contener el nmero mximo de bytes de la El parmetro long_adr en un inicio debe contener el nmero mximo de bytes de la
estructura que deben llenarse y, cuando la funcin retorne, contendr el nmero real estructura que deben llenarse y, cuando la funcin retorne, contendr el nmero real
de bytes que se han llenado (como en las llamadas recvfrom y accept). de bytes que se han llenado (como en las llamadas recvfrom y accept).

El valor retornado es 0 o 1 para indicar si se ha podido llevar a cabo la opera- El valor retornado es 0 o 1 para indicar si se ha podido llevar a cabo la opera-
cin o no. En este ltimo caso, la causa de error se notifica con la variable errno, cin o no. En este ltimo caso, la causa de error se notifica con la variable errno,
que puede tener valores como EBADF o ENOTSOCK. que puede tener valores como EBADF o ENOTSOCK.

Algunos sistemas no soportan la obtencin de direcciones en el espacio de nom- Algunos sistemas no soportan la obtencin de direcciones en el espacio de nom-
bres de ficheros. En este caso, la llamada retorna un nombre de longitud 0. bres de ficheros. En este caso, la llamada retorna un nombre de longitud 0.

2) La llamada getpeername permite obtener la direccin del socket remoto: 2) La llamada getpeername permite obtener la direccin del socket remoto:

int getpeername(int descr, struct sockaddr *adr, int getpeername(int descr, struct sockaddr *adr,
size_t *long_adr); size_t *long_adr);
FUOC P03/75064/00978 46 Programacin de sockets FUOC P03/75064/00978 46 Programacin de sockets

Esta llamada opera como la anterior; sin embargo, en lugar de retornar la direccin del Esta llamada opera como la anterior; sin embargo, en lugar de retornar la direccin del
socket indicado por el parmetro descr, retorna la del socket al que est conectado. En socket indicado por el parmetro descr, retorna la del socket al que est conectado. En
esta llamada hay una causa de error adicional: ENOTCONN. esta llamada hay una causa de error adicional: ENOTCONN.

2.4.2. Convertir direcciones Internet 2.4.2. Convertir direcciones Internet

Estas funciones permiten trabajar con la representacin de las direcciones IP Estas funciones permiten trabajar con la representacin de las direcciones IP
El fichero <arpa/inet.h> El fichero <arpa/inet.h>
en la notacin textual de los bytes en decimal separados por puntos (por ejem- en la notacin textual de los bytes en decimal separados por puntos (por ejem-
plo, 193.146.196.5). Existen dos prototipos encargados de realizar este cambio En algunos sistemas, es necesa- plo, 193.146.196.5). Existen dos prototipos encargados de realizar este cambio En algunos sistemas, es necesa-
rio haber incluido el fichero rio haber incluido el fichero
y se declaran en el fichero cabecera <arpa/inet.h>: <netinet/in.h> antes de y se declaran en el fichero cabecera <arpa/inet.h>: <netinet/in.h> antes de
incluir el fichero incluir el fichero
<arpa/inet.h>. <arpa/inet.h>.
1) La llamada inet_aton est definida de la manera siguiente: 1) La llamada inet_aton est definida de la manera siguiente:

int inet_aton(const char *text, struct in_addr *adr); int inet_aton(const char *text, struct in_addr *adr);

Esta llamada convierte la direccin textual contenida en el primer parmetro en una Esta llamada convierte la direccin textual contenida en el primer parmetro en una
struct in_addr, con los bytes en el orden de la red, y se la asigna al segundo parmetro. La funcin inet_addr struct in_addr, con los bytes en el orden de la red, y se la asigna al segundo parmetro. La funcin inet_addr
Si el primer parmetro no contiene una direccin vlida, retorna 0; de otro modo, retorna Si el primer parmetro no contiene una direccin vlida, retorna 0; de otro modo, retorna
un valor diferente de 0. Esta funcin (obsoleta) un valor diferente de 0. Esta funcin (obsoleta)
recibe como nico parmetro recibe como nico parmetro
la representacin textual de la representacin textual de
2) La llamada inet_ntoa est definida de la manera siguiente: una direccin y retorna direc- 2) La llamada inet_ntoa est definida de la manera siguiente: una direccin y retorna direc-
tamente un unsigned_long tamente un unsigned_long
int correspondiente a esta di- int correspondiente a esta di-
reccin, o bien la constante reccin, o bien la constante
char *inet_ntoa(struct in_addr adr); INADDR_NONE (definida en char *inet_ntoa(struct in_addr adr); INADDR_NONE (definida en
<netinet/in.h> con el va- <netinet/in.h> con el va-
lor 1) si no es vlida. lor 1) si no es vlida.

Esta llamada genera una cadena de caracteres, que representa en notacin textual la di- Esta llamada genera una cadena de caracteres, que representa en notacin textual la di-
reccin correspondiente al parmetro, y la retorna (las llamadas posteriores utilizarn el reccin correspondiente al parmetro, y la retorna (las llamadas posteriores utilizarn el
mismo espacio de memoria para dejar el resultado). Se supone que los bytes del parme- mismo espacio de memoria para dejar el resultado). Se supone que los bytes del parme-
tro estn ordenados en el orden de la red. tro estn ordenados en el orden de la red.

2.4.3. Consultar bases de datos de nombres 2.4.3. Consultar bases de datos de nombres

La familia de protocolos Internet trabaja con diferentes tipos de nombres que, La familia de protocolos Internet trabaja con diferentes tipos de nombres que,
a la hora de intercambiar paquetes por medio de la red, se representan mediante a la hora de intercambiar paquetes por medio de la red, se representan mediante
nombres. Los dos casos ms habituales son los nombres de los servidores, que * Por ejemplo, de www.uoc.edu nombres. Los dos casos ms habituales son los nombres de los servidores, que * Por ejemplo, de www.uoc.edu
se pasa a 213.73.40.217. se pasa a 213.73.40.217.
se traducen en direcciones IP*, y los nombres de los servicios, que se traducen ** Por ejemplo, de www se traducen en direcciones IP*, y los nombres de los servicios, que se traducen ** Por ejemplo, de www
se pasa a 80. se pasa a 80.
en nmeros de puerto**. en nmeros de puerto**.

La traduccin de una representacin a la otra se lleva a cabo consultando una La traduccin de una representacin a la otra se lleva a cabo consultando una
base de datos que contiene una lista de los nombres y los nmeros asociados. base de datos que contiene una lista de los nombres y los nmeros asociados.

Segn el sistema, los datos se pueden obtener de un fichero de texto en el El DNS se explica en el mdulo Segn el sistema, los datos se pueden obtener de un fichero de texto en el El DNS se explica en el mdulo
Aplicaciones Internet. Aplicaciones Internet.
que cada lnea corresponde a una entrada (como, por ejemplo, los ficheros que cada lnea corresponde a una entrada (como, por ejemplo, los ficheros
/etc/hosts o /etc/services en UNIX) y/o por medio de un servicio de /etc/hosts o /etc/services en UNIX) y/o por medio de un servicio de
informacin distribuida local (como NIS) o global (como DNS, el servicio informacin distribuida local (como NIS) o global (como DNS, el servicio
de nombres Internet). de nombres Internet).
FUOC P03/75064/00978 47 Programacin de sockets FUOC P03/75064/00978 47 Programacin de sockets

El servicio NIS El servicio NIS

El servicio NIS (Network Information Service, antes conocido como Yellow Pages) permite al El servicio NIS (Network Information Service, antes conocido como Yellow Pages) permite al
administrador de un conjunto de ordenadores mantener ciertas bases de datos, como la de administrador de un conjunto de ordenadores mantener ciertas bases de datos, como la de
usuarios o la de direcciones IP, de una manera centralizada. Cada vez que deba modificarse usuarios o la de direcciones IP, de una manera centralizada. Cada vez que deba modificarse
algn registro, en lugar de llevar a cabo las actualizaciones en cada uno de los ordenadores, algn registro, en lugar de llevar a cabo las actualizaciones en cada uno de los ordenadores,
slo es preciso realizarlas en el servidor NIS y, automticamente, se propagarn a los otros slo es preciso realizarlas en el servidor NIS y, automticamente, se propagarn a los otros
ordenadores. ordenadores.

El grupo de funciones que veremos a continuacin permite consultar las bases El grupo de funciones que veremos a continuacin permite consultar las bases
de datos de nombres con una interfaz homognea que esconda los detalles de de datos de nombres con una interfaz homognea que esconda los detalles de
acceso. Sus prototipos se declaran en el fichero cabecera <netdb.h> de la ma- acceso. Sus prototipos se declaran en el fichero cabecera <netdb.h> de la ma-
nera siguiente: nera siguiente:

1) La funcin gethostbyname 1) La funcin gethostbyname

struct hostent *gethostbyname(const char *nombre); struct hostent *gethostbyname(const char *nombre);

Esta funcin, que recibe como parmetro un nombre de servidor, lo busca en Esta funcin, que recibe como parmetro un nombre de servidor, lo busca en
la base de datos correspondiente y, si lo encuentra, llena una variable de tipo la base de datos correspondiente y, si lo encuentra, llena una variable de tipo
struct hostent con informacin sobre el servidor. El valor retornado iden- struct hostent con informacin sobre el servidor. El valor retornado iden-
tifica esta variable (las llamadas posteriores utilizarn la misma variable para tifica esta variable (las llamadas posteriores utilizarn la misma variable para
dejar el resultado en la misma). Si no se puede encontrar el nombre, el valor dejar el resultado en la misma). Si no se puede encontrar el nombre, el valor
retornado es NULL. retornado es NULL.

El tipo struct hostent, que sirve para representar las entradas de la base de El tipo struct hostent, que sirve para representar las entradas de la base de
datos de nombres de servidores, se define en el fichero <netdb.h> de la ma- datos de nombres de servidores, se define en el fichero <netdb.h> de la ma-
nera siguiente: nera siguiente:

struct hostent struct hostent


{ {
char *h_name; char *h_name;
char **h_aliases; char **h_aliases;
int h_addrtype; int h_addrtype;
int h_length; int h_length;
char **h_addr_list; char **h_addr_list;
}; };

El campo h_name es el nombre oficial del servidor. El campo h_name es el nombre oficial del servidor.

El campo h_aliases es una lista de punteros que apuntan a diferentes alias o nom- El campo h_aliases es una lista de punteros que apuntan a diferentes alias o nom-
bres alternativos de que puede disponer el servidor. Para saber dnde acaba la lista, bres alternativos de que puede disponer el servidor. Para saber dnde acaba la lista,
despus del puntero en el ltimo alias, hay un puntero igual a NULL (si el primer pun- despus del puntero en el ltimo alias, hay un puntero igual a NULL (si el primer pun-
tero es NULL, significa que la lista est vaca). tero es NULL, significa que la lista est vaca).

El campo h_addrtype indica el formato de la direccin o direcciones del servidor* y, * Recordad que un host puede tener El campo h_addrtype indica el formato de la direccin o direcciones del servidor* y, * Recordad que un host puede tener
por norma general, ser igual a AF_INET. ms de una direccin IP. por norma general, ser igual a AF_INET. ms de una direccin IP.

El campo h_length seala la longitud en bytes de cada una de las direcciones del ser- El campo h_length seala la longitud en bytes de cada una de las direcciones del ser-
vidor. Si el tipo de direccin es AF_INET, este campo ser igual a 4. vidor. Si el tipo de direccin es AF_INET, este campo ser igual a 4.

El campo h_addr_list es una lista de punteros que apuntan a las direcciones del ser- El campo h_addr_list es una lista de punteros que apuntan a las direcciones del ser-
vidor. La lista acaba con un puntero igual a NULL. Si las direcciones son del tipo vidor. La lista acaba con un puntero igual a NULL. Si las direcciones son del tipo
FUOC P03/75064/00978 48 Programacin de sockets FUOC P03/75064/00978 48 Programacin de sockets

AF_INET, cada una se representa con 4 bytes que ya estarn ordenados de acuerdo con AF_INET, cada una se representa con 4 bytes que ya estarn ordenados de acuerdo con
el orden de la red. el orden de la red.

Para hacerlo compatible con versiones anteriores de la librera, as como para Para hacerlo compatible con versiones anteriores de la librera, as como para
facilitar el acceso a la primera direccin de la lista, el fichero <netdb.h> suele facilitar el acceso a la primera direccin de la lista, el fichero <netdb.h> suele
incluir esta definicin: incluir esta definicin:

#define h_addr h_addr_list[0] #define h_addr h_addr_list[0]

2) La funcin gethostbyaddr 2) La funcin gethostbyaddr

struct hostent *gethostbyaddr(const char *adr, struct hostent *gethostbyaddr(const char *adr,
int long_adr, int formato); int long_adr, int formato);

Esta funcin realiza una bsqueda inversa en la base de datos: dada la direc- Esta funcin realiza una bsqueda inversa en la base de datos: dada la direc-
cin especificada por los parmetros, retorna la informacin del servidor que cin especificada por los parmetros, retorna la informacin del servidor que
tiene esta direccin o retorna NULL si no la puede encontrar. Si el tercer par- tiene esta direccin o retorna NULL si no la puede encontrar. Si el tercer par-
metro es AF_INET (el caso ms habitual), el primero debe ser una secuencia de metro es AF_INET (el caso ms habitual), el primero debe ser una secuencia de
4 bytes en el orden de la red y el segundo debe ser igual a 4. 4 bytes en el orden de la red y el segundo debe ser igual a 4.

Errores en la bsqueda Errores en la bsqueda

En muchos sistemas, cuando el valor retornado por las funciones gethostbyname y ge- En muchos sistemas, cuando el valor retornado por las funciones gethostbyname y ge-
thostbyaddr es NULL, se indica la causa del error en la bsqueda en una variable global thostbyaddr es NULL, se indica la causa del error en la bsqueda en una variable global
denominada h_errno, la cual se declara en el fichero <netdb.h>. Este mismo fichero denominada h_errno, la cual se declara en el fichero <netdb.h>. Este mismo fichero
contiene las definiciones de constantes que sirven para representar las causas de error si- contiene las definiciones de constantes que sirven para representar las causas de error si-
guientes: guientes:

HOST_NOT_FOUND: no hay ningn servidor con este nombre en la base de datos. HOST_NOT_FOUND: no hay ningn servidor con este nombre en la base de datos.
Respuesta con autoridad Respuesta con autoridad
TRY_AGAIN: el servidor DNS no responde, o bien ha enviado una respuesta sin auto- TRY_AGAIN: el servidor DNS no responde, o bien ha enviado una respuesta sin auto-
ridad diciendo que el servidor no existe (en este caso, puede ser que el nombre s que Las respuestas de un servidor ridad diciendo que el servidor no existe (en este caso, puede ser que el nombre s que Las respuestas de un servidor
figure en la base de datos, pero que se haya aadido recientemente). DNS pueden ser con autori- figure en la base de datos, pero que se haya aadido recientemente). DNS pueden ser con autori-
dad o sin la misma, depen- dad o sin la misma, depen-
NO_RECOVERY: error en la consulta DNS (formato incorrecto, peticin rechazada, etc.). diendo de si la informacin NO_RECOVERY: error en la consulta DNS (formato incorrecto, peticin rechazada, etc.). diendo de si la informacin
que proporcionan proviene que proporcionan proviene
NO_ADDRESS: el nombre existe, sin embargo no corresponde a un servidor (puede ser, del mismo servidor o de una NO_ADDRESS: el nombre existe, sin embargo no corresponde a un servidor (puede ser, del mismo servidor o de una
por ejemplo, un nombre de dominio). respuesta enviada con ante- por ejemplo, un nombre de dominio). respuesta enviada con ante-
rioridad por otro servidor. rioridad por otro servidor.

3) La funcin getservbyname 3) La funcin getservbyname

struct servent *getservbyname(const char *nombre, struct servent *getservbyname(const char *nombre,
const char *protocol); const char *protocol);

Esta funcin busca en la base de datos de servicios uno que tenga el nombre Esta funcin busca en la base de datos de servicios uno que tenga el nombre
conferido por el primero parmetro y que utilice el protocolo indicado por el conferido por el primero parmetro y que utilice el protocolo indicado por el
segundo parmetro, que por lo general ser TCP o UDP. Si lo encuentra, retorna segundo parmetro, que por lo general ser TCP o UDP. Si lo encuentra, retorna
la direccin de una variable de tipo struct servent que contiene informa- la direccin de una variable de tipo struct servent que contiene informa-
cin sobre el servicio (las llamadas posteriores utilizarn la misma variable cin sobre el servicio (las llamadas posteriores utilizarn la misma variable
para dejar el resultado en la misma) y, si no lo encuentra, retorna NULL. para dejar el resultado en la misma) y, si no lo encuentra, retorna NULL.
FUOC P03/75064/00978 49 Programacin de sockets FUOC P03/75064/00978 49 Programacin de sockets

El tipo que representa las entradas de la base de datos de servicios se define en El tipo que representa las entradas de la base de datos de servicios se define en
Protocolos utilizados Protocolos utilizados
el fichero <netdb.h> de la manera siguiente: en los servicios el fichero <netdb.h> de la manera siguiente: en los servicios

Existen servicios que slo se Existen servicios que slo se


utilizan con TCP, los hay que utilizan con TCP, los hay que
struct servent slo con UDP, as como otros struct servent slo con UDP, as como otros
{ que se pueden utilizar tanto { que se pueden utilizar tanto
con TCP como con UDP. En con TCP como con UDP. En
char *s_name; este ltimo caso, sin embargo, char *s_name; este ltimo caso, sin embargo,
los nmeros de puerto utiliza- los nmeros de puerto utiliza-
char **s_aliases; dos con los dos protocolos por char **s_aliases; dos con los dos protocolos por
int s_port; lo general coinciden. int s_port; lo general coinciden.

char *s_proto; char *s_proto;


}; };

El campo s_name contiene el nombre oficial del servicio. El campo s_name contiene el nombre oficial del servicio.

El campo s_aliases contiene una lista de alias del servicio acabada en NULL. El campo s_aliases contiene una lista de alias del servicio acabada en NULL.

Los dos bytes de menos peso del campo s_port representan el nmero de puerto aso- Los dos bytes de menos peso del campo s_port representan el nmero de puerto aso-
ciado al servicio (en el orden de la red). ciado al servicio (en el orden de la red).

El campo s_proto indica el protocolo que es preciso utilizar con dicho servicio. El campo s_proto indica el protocolo que es preciso utilizar con dicho servicio.

4) La funcin getservbyport 4) La funcin getservbyport

struct servent *getservbyport(int puerto, struct servent *getservbyport(int puerto,


const char *protocolo); const char *protocolo);

Es la funcin inversa a la anterior: encuentra un servicio a partir de su nmero Es la funcin inversa a la anterior: encuentra un servicio a partir de su nmero
de puerto (representado de la misma manera que en el campo s_port del tipo de puerto (representado de la misma manera que en el campo s_port del tipo
struct servent) y el protocolo que utiliza. struct servent) y el protocolo que utiliza.

Relleno de una direccin Internet con los nombres deseados Relleno de una direccin Internet con los nombres deseados

Podramos reescribir la funcin llenar_dir_internet para que recibiera como par- Consultad el ejemplo de relleno Podramos reescribir la funcin llenar_dir_internet para que recibiera como par- Consultad el ejemplo de relleno
metros el nombre del servidor, el nombre del servicio y el protocolo: de una direccin Internet en el metros el nombre del servidor, el nombre del servicio y el protocolo: de una direccin Internet en el
subapartado 2.1.2 de este mdulo subapartado 2.1.2 de este mdulo
didctico. didctico.

int llenar_dir_internet(struct sockaddr_in *adr, int llenar_dir_internet(struct sockaddr_in *adr,


char *host, char *servicio, char *protocolo) char *host, char *servicio, char *protocolo)
{ {
struct hostent *h; struct hostent *h;
struct servent *s; struct servent *s;
if ((h = gethostbyname(host)) == NULL) return 1; if ((h = gethostbyname(host)) == NULL) return 1;
if ((s = getservbyname(servicio, protocolo)) == NULL) if ((s = getservbyname(servicio, protocolo)) == NULL)
return 2; return 2;
adr->sin_family = AF_INET; adr->sin_family = AF_INET;
adr->sin_addr = *(struct in_addr *)h->h_addr; adr->sin_addr = *(struct in_addr *)h->h_addr;
No es preciso utilizar No es preciso utilizar
adr->sin_port = s->s_port; las funciones hton... adr->sin_port = s->s_port; las funciones hton...
return 0; return 0;
} ... puesto que ya obtenemos } ... puesto que ya obtenemos
los nombres directamente los nombres directamente
en el orden de la red. en el orden de la red.

Ejemplo de uso de la funcin anterior (el nombre http es un alias tpico de www): Ejemplo de uso de la funcin anterior (el nombre http es un alias tpico de www):

error = llenar_dir_internet(&adr, "www.uoc.es", "http", "tcp"); error = llenar_dir_internet(&adr, "www.uoc.es", "http", "tcp");
FUOC P03/75064/00978 50 Programacin de sockets FUOC P03/75064/00978 50 Programacin de sockets

2.4.4. Acceso secuencial a las bases de datos 2.4.4. Acceso secuencial a las bases de datos

Adems del acceso aleatorio a las bases de datos de nombres por medio de las Adems del acceso aleatorio a las bases de datos de nombres por medio de las
funciones que acabamos de ver, tambin es posible realizar un acceso secuen- funciones que acabamos de ver, tambin es posible realizar un acceso secuen-
cial a las mismas. Ello permite, por ejemplo, recorrer toda la base de datos de cial a las mismas. Ello permite, por ejemplo, recorrer toda la base de datos de
servidores o servicios conocidos, o listar los nombres que satisfacen una deter- servidores o servicios conocidos, o listar los nombres que satisfacen una deter-
minada condicin. minada condicin.

Las funciones siguientes, declaradas en el fichero <netdb.h>, proporcionan Las funciones siguientes, declaradas en el fichero <netdb.h>, proporcionan
el acceso secuencial a las bases de datos, y lo hacen de manera homognea y el acceso secuencial a las bases de datos, y lo hacen de manera homognea y
con independencia de si los nombres estn almacenados en un fichero o si de- con independencia de si los nombres estn almacenados en un fichero o si de-
ben obtenerse por medio del servicio NIS: ben obtenerse por medio del servicio NIS:

void sethostent(int no_cerrar) void sethostent(int no_cerrar)


void setservent(int no_cerrar) void setservent(int no_cerrar)
struct hostent *gethostent(void) struct hostent *gethostent(void)
struct servent *getservent(void) struct servent *getservent(void)
void endhostent(void) void endhostent(void)
void endservent(void) void endservent(void)

Las dos primeras dejan las bases de datos respectivas preparadas para empezar Las dos primeras dejan las bases de datos respectivas preparadas para empezar
La funcin gethostent... La funcin gethostent...
el acceso secuencial a partir del primer elemento. Si el parmetro es diferente el acceso secuencial a partir del primer elemento. Si el parmetro es diferente
... no utiliza el servicio DNS ... no utiliza el servicio DNS
de 0, la base de datos quedar abierta para las operaciones siguientes y, si es 0, para acceder secuencialmente
de 0, la base de datos quedar abierta para las operaciones siguientes y, si es 0, para acceder secuencialmente
se abrir y se cerrar a cada acceso que se haga a la misma. Las funciones ge- a la base de datos de nombres se abrir y se cerrar a cada acceso que se haga a la misma. Las funciones ge- a la base de datos de nombres
de servidores, sino slo la base de servidores, sino slo la base
thostent y getservent retornan el elemento siguiente de la base de datos, de datos local o el servicio NIS. thostent y getservent retornan el elemento siguiente de la base de datos, de datos local o el servicio NIS.

o NULL si ya no quedn ms. El orden en que se obtienen los diferentes ele- o NULL si ya no quedn ms. El orden en que se obtienen los diferentes ele-
mentos no es significativo; lo nico que es conveniente saber es que estas fun- mentos no es significativo; lo nico que es conveniente saber es que estas fun-
ciones las leen todos antes de retornar NULL. Las dos ltimas cierran la base ciones las leen todos antes de retornar NULL. Las dos ltimas cierran la base
de datos correspondiente. de datos correspondiente.

2.4.5. Opciones de los sockets 2.4.5. Opciones de los sockets

Es posible variar algunos aspectos del modo de funcionamiento de los sockets Es posible variar algunos aspectos del modo de funcionamiento de los sockets
modificando una serie de opciones. La interfaz de programacin proporciona modificando una serie de opciones. La interfaz de programacin proporciona
una llamada para cambiar el valor de una opcin en un socket y otra para con- una llamada para cambiar el valor de una opcin en un socket y otra para con-
sultar su valor actual. Los prototipos de estas llamadas se declaran en el fichero sultar su valor actual. Los prototipos de estas llamadas se declaran en el fichero
cabecera <sys/socket.h> de la manera siguiente: cabecera <sys/socket.h> de la manera siguiente:

1) La llamada setsockopt: cambia el valor de una opcin en un socket. 1) La llamada setsockopt: cambia el valor de una opcin en un socket.

int setsockopt(int descr, int nivel, int nombre_opc, int setsockopt(int descr, int nivel, int nombre_opc,
const void *val_opc, size_t long_opt); const void *val_opc, size_t long_opt);

El parmetro descr es el descriptor del socket. El parmetro descr es el descriptor del socket.

El parmetro nivel y el nombre_opc identifican la opcin, como veremos a conti- El parmetro nivel y el nombre_opc identifican la opcin, como veremos a conti-
nuacin. nuacin.
FUOC P03/75064/00978 51 Programacin de sockets FUOC P03/75064/00978 51 Programacin de sockets

El parmetro val_opc apunta a una variable que contiene el valor que debe asignarse El parmetro val_opc apunta a una variable que contiene el valor que debe asignarse
a la opcin. a la opcin.

El parmetro long_opt indica cuntos bytes ocupa este valor. El parmetro long_opt indica cuntos bytes ocupa este valor.

La mayora de los valores de las opciones se representan con enteros (int o La mayora de los valores de las opciones se representan con enteros (int o
size_t); sin embargo, los hay que se representan con otros tipos. Por este mo- size_t); sin embargo, los hay que se representan con otros tipos. Por este mo-
tivo, el valor se pasa a la llamada por medio de un puntero genrico (void *) tivo, el valor se pasa a la llamada por medio de un puntero genrico (void *)
y de su longitud en bytes. y de su longitud en bytes.

Si la llamada tiene xito, retorna 0 y, si no lo tiene, retorna -1 y asigna a la va- Si la llamada tiene xito, retorna 0 y, si no lo tiene, retorna -1 y asigna a la va-
riable global errno un cdigo correspondiente a la causa del error. riable global errno un cdigo correspondiente a la causa del error.

2) La llamada getsockopt: retorna el valor actual de una opcin en un socket. 2) La llamada getsockopt: retorna el valor actual de una opcin en un socket.

int getsockopt(int descr, int nivel, int nombre_opc, int getsockopt(int descr, int nivel, int nombre_opc,
void *val_opc, size_t *long_opt); void *val_opc, size_t *long_opt);

Los tres primeros parmetros son como los de la llamada setsockopt. Los tres primeros parmetros son como los de la llamada setsockopt.

El cuarto parmetro, val_opc, es un puntero que indica dnde debe dejarse el valor ledo. El cuarto parmetro, val_opc, es un puntero que indica dnde debe dejarse el valor ledo.

El quinto parmetro, long_opt, debe contener al principio el nmero mximo de bytes que El quinto parmetro, long_opt, debe contener al principio el nmero mximo de bytes que
debe ocupar este valor; la llamada le asignar el nmero de bytes que ocupa en realidad. debe ocupar este valor; la llamada le asignar el nmero de bytes que ocupa en realidad.

El valor retornado y los cdigos de error son los mismos que en la llamada El valor retornado y los cdigos de error son los mismos que en la llamada
setsockopt. setsockopt.

Cuando el valor retornado por setsockopt o getsockopt indica que ha ha- Cuando el valor retornado por setsockopt o getsockopt indica que ha ha-
bido error, la variable errno puede tener uno de los valores siguientes: bido error, la variable errno puede tener uno de los valores siguientes:

EBADF: el primer parmetro no es un descriptor vlido. EBADF: el primer parmetro no es un descriptor vlido.

ENOTSOCK: el primer parmetro es un descriptor; sin embargo, no corres- ENOTSOCK: el primer parmetro es un descriptor; sin embargo, no corres-
ponde a un socket. ponde a un socket.

ENOPROTOOPT: el valor del tercer parmetro no corresponde a ninguna ENOPROTOOPT: el valor del tercer parmetro no corresponde a ninguna
opcin del nivel indicado por el segundo. Las opciones que se pueden opcin del nivel indicado por el segundo. Las opciones que se pueden
especificar para un socket se agrupan en diferentes niveles identificados especificar para un socket se agrupan en diferentes niveles identificados
por el segundo parmetro de estas llamadas y se representan con alguna por el segundo parmetro de estas llamadas y se representan con alguna
de las constantes siguientes, que estn definidas en el fichero <sys/ de las constantes siguientes, que estn definidas en el fichero <sys/
socket.h>: socket.h>:

SOL_SOCKET: para las opciones en el mbito de la interfaz de sockets. SOL_SOCKET: para las opciones en el mbito de la interfaz de sockets.

SOL_TCP, SOL_UDP, SOL_IP, etc.: para las opciones relativas al protoco- SOL_TCP, SOL_UDP, SOL_IP, etc.: para las opciones relativas al protoco-
lo de comunicaciones correspondiente. lo de comunicaciones correspondiente.
FUOC P03/75064/00978 52 Programacin de sockets FUOC P03/75064/00978 52 Programacin de sockets

Segn el valor del segundo parmetro de las llamadas anteriores, tendremos Segn el valor del segundo parmetro de las llamadas anteriores, tendremos
diferentes tipos de opciones: diferentes tipos de opciones:

a) Opciones de socket: algunas de las opciones de socket (segundo parmetro a) Opciones de socket: algunas de las opciones de socket (segundo parmetro
igual a SOL_SOCKET), en que se indica el nombre definido en el fichero igual a SOL_SOCKET), en que se indica el nombre definido en el fichero
<sys/socket.h> que es preciso utilizar como tercer parmetro de las llama- <sys/socket.h> que es preciso utilizar como tercer parmetro de las llama-
das y el tipo del valor correspondiente al cuarto parmetro, son las siguientes: das y el tipo del valor correspondiente al cuarto parmetro, son las siguientes:

SO_REUSEADDR (tipo int): si el valor de la opcin es diferente de 0, significa SO_REUSEADDR (tipo int): si el valor de la opcin es diferente de 0, significa
Un ejemplo... Un ejemplo...
que la llamada bind permitir asignar al socket un nmero de puerto que que la llamada bind permitir asignar al socket un nmero de puerto que
ya sea utilizado por otro. ... de aplicacin que puede ya sea utilizado por otro. ... de aplicacin que puede
requerir el uso de diferentes requerir el uso de diferentes
sockets con el mismo puerto sockets con el mismo puerto
es la transferencia de ficheros es la transferencia de ficheros
SO_KEEPALIVE (tipo int): si el valor es diferente de 0 y el protocolo aso- SO_KEEPALIVE (tipo int): si el valor es diferente de 0 y el protocolo aso-
por medio del FTP. por medio del FTP.
ciado al socket es orientado a conexin, se enviarn de manera automtica ciado al socket es orientado a conexin, se enviarn de manera automtica
mensajes peridicos al socket remoto para comprobar si la comunicacin mensajes peridicos al socket remoto para comprobar si la comunicacin
contina establecida y, si no se recibe ninguna respuesta, se dar la co- contina establecida y, si no se recibe ninguna respuesta, se dar la co-
nexin por cerrada. Esta opcin permite detectar cortes en la comunica- nexin por cerrada. Esta opcin permite detectar cortes en la comunica-
cin aunque no se intercambien datos. cin aunque no se intercambien datos.

SO_DONTROUTE (tipo int): si el valor es diferente de 0, se aplica automtica- Consultad el significado SO_DONTROUTE (tipo int): si el valor es diferente de 0, se aplica automtica- Consultad el significado
del parmetro indicador del parmetro indicador
mente el parmetro indicador MSG_DONTROUTE a todos los datos enviados. MSG_DONTROUTE en el subapartado mente el parmetro indicador MSG_DONTROUTE a todos los datos enviados. MSG_DONTROUTE en el subapartado
2.1.3 de este mdulo didctico. 2.1.3 de este mdulo didctico.

SO_LINGER (tipo struct linger): esta opcin indica cmo debe actuar SO_LINGER (tipo struct linger): esta opcin indica cmo debe actuar
el socket si utiliza un protocolo de transmisin fiable y se le aplica la llama- el socket si utiliza un protocolo de transmisin fiable y se le aplica la llama-
da close cuando todava tiene datos pendientes de enviar. El tipo struct da close cuando todava tiene datos pendientes de enviar. El tipo struct
linger se define en el fichero <sys/socket.h> de la manera siguiente: linger se define en el fichero <sys/socket.h> de la manera siguiente:

struct linger struct linger


{ {
int l_onoff; int l_onoff;
int l_linger; int l_linger;
}; };

Si el campo l_onoff es diferente de 0, significa que la llamada close retornar cuan- Si el campo l_onoff es diferente de 0, significa que la llamada close retornar cuan-
do se hayan enviado los datos pendientes o haya transcurrido el nmero de segundos do se hayan enviado los datos pendientes o haya transcurrido el nmero de segundos
indicado por el campo l_linger. indicado por el campo l_linger.

Si el campo l_onoff es 0, la llamada retornar inmediatamente. Si el campo l_onoff es 0, la llamada retornar inmediatamente.

SO_BROADCAST (tipo int): si el valor es diferente de 0, se pueden enviar SO_BROADCAST (tipo int): si el valor es diferente de 0, se pueden enviar
mensajes de difusin (broadcast) por el socket. mensajes de difusin (broadcast) por el socket.

SO_OOBINLINE (tipo int): si el valor es diferente de 0, los datos urgentes SO_OOBINLINE (tipo int): si el valor es diferente de 0, los datos urgentes
o fuera de banda que se reciban se tratarn de la misma manera que los da- o fuera de banda que se reciban se tratarn de la misma manera que los da-
tos normales. tos normales.

SO_SNDBUF y SO_RCVBUF (tipo size_t): el valor de estas opciones es la SO_SNDBUF y SO_RCVBUF (tipo size_t): el valor de estas opciones es la
longitud en bytes del buffer de salida y la del de entrada, respectivamen- longitud en bytes del buffer de salida y la del de entrada, respectivamen-
te, asociadas al socket. te, asociadas al socket.
FUOC P03/75064/00978 53 Programacin de sockets FUOC P03/75064/00978 53 Programacin de sockets

SO_STYLE (tipo int): esta opcin es aplicable slo a la llamada getsockopt. SO_STYLE (tipo int): esta opcin es aplicable slo a la llamada getsockopt.
* En versiones anteriores de la * En versiones anteriores de la
Su valor es el estilo de comunicacin que utiliza el socket (SOCK_STREAM, interfaz de los sockets, la opcin Su valor es el estilo de comunicacin que utiliza el socket (SOCK_STREAM, interfaz de los sockets, la opcin
SO_STYLE se denomina SO_TYPE. SO_STYLE se denomina SO_TYPE.
SOCK_DGRAM, etc.)*. SOCK_DGRAM, etc.)*.

SO_ERROR (tipo int): esta opcin tambin es aplicable slo a la llamada SO_ERROR (tipo int): esta opcin tambin es aplicable slo a la llamada
getsockopt. Su valor es la ltima condicin de error que se ha produ- getsockopt. Su valor es la ltima condicin de error que se ha produ-
cido en el socket (este valor se reinicializa una vez se ha consultado con cido en el socket (este valor se reinicializa una vez se ha consultado con
getsockopt). getsockopt).

Ejemplo de tiempo de cierre de conexin de un socket Ejemplo de tiempo de cierre de conexin de un socket

La funcin tiempo_espera_cierre sirve para ajustar el tiempo que debe esperar un La funcin tiempo_espera_cierre sirve para ajustar el tiempo que debe esperar un
socket antes de dar por cerrada una conexin cuando no puede enviar los ltimos datos socket antes de dar por cerrada una conexin cuando no puede enviar los ltimos datos
que le han pasado: que le han pasado:

int tiempo_espera_cierre(int sock, int tiempo) int tiempo_espera_cierre(int sock, int tiempo)
{ {
struct linger l; struct linger l;

l.l_onoff = 1; l.l_onoff = 1;
l.l_linger = tiempo; l.l_linger = tiempo;
return setsockopt(sock, SOL_SOCKET, SO_LINGER, &l, sizeof l); return setsockopt(sock, SOL_SOCKET, SO_LINGER, &l, sizeof l);
} }

b) Opciones de TCP. Algunos ejemplos de opciones de TCP (segundo parme- b) Opciones de TCP. Algunos ejemplos de opciones de TCP (segundo parme-
tro igual a SOL_TCP) son los siguientes: tro igual a SOL_TCP) son los siguientes:

TCP_MAXSEG: indica la longitud mxima de los segmentos TCP. TCP_MAXSEG: indica la longitud mxima de los segmentos TCP.

TCP_NODELAY: indica si debe aplicarse el algoritmo de Nagle a la hora de TCP_NODELAY: indica si debe aplicarse el algoritmo de Nagle a la hora de
decidir cundo era preciso enviar un paquete o si no debe hacerse. decidir cundo era preciso enviar un paquete o si no debe hacerse.

c) Opciones de IP. Algunos ejemplos de opciones de IP (segundo parmetro c) Opciones de IP. Algunos ejemplos de opciones de IP (segundo parmetro
igual a SOL_IP) son los siguientes: igual a SOL_IP) son los siguientes:

IP_TOS: representa el tipo de servicio. IP_TOS: representa el tipo de servicio.


IP_TTL: representa el tiempo de vida de los datagramas. IP_TTL: representa el tiempo de vida de los datagramas.
FUOC P03/75064/00978 54 Programacin de sockets FUOC P03/75064/00978 54 Programacin de sockets

3. Sockets con lenguaje Java 3. Sockets con lenguaje Java

En el apartado anterior, hemos visto cmo en C hay una funcin para cada En el apartado anterior, hemos visto cmo en C hay una funcin para cada
una de las operaciones que deben llevarse a cabo en los dos extremos de la co- una de las operaciones que deben llevarse a cabo en los dos extremos de la co-
municacin y cmo podemos ajustar su comportamiento por medio de un in- municacin y cmo podemos ajustar su comportamiento por medio de un in-
gente nmero de parmetros. Ello es as por la filosofa de diseo del mismo gente nmero de parmetros. Ello es as por la filosofa de diseo del mismo
lenguaje C: acercarse al mximo al funcionamiento de la mquina. lenguaje C: acercarse al mximo al funcionamiento de la mquina.

En cambio, el lenguaje Java, y los lenguajes orientados a objetos en general, En cambio, el lenguaje Java, y los lenguajes orientados a objetos en general,
persigue unos objetivos bien diferentes: esconder detalles de implementacin persigue unos objetivos bien diferentes: esconder detalles de implementacin
y proporcionar al programador esencialmente lo que necesita. y proporcionar al programador esencialmente lo que necesita.

3.1. Las clases Socket y ServerSocket 3.1. Las clases Socket y ServerSocket

El mecanismo principal para conseguir este nivel de abstraccin y encapsula- El mecanismo principal para conseguir este nivel de abstraccin y encapsula-
miento en un lenguaje orientado a objetos es la clase. La clase Socket, que miento en un lenguaje orientado a objetos es la clase. La clase Socket, que
puede encontrarse en el paquete java.net, es la que implementa toda la funcio- puede encontrarse en el paquete java.net, es la que implementa toda la funcio-
nalidad de los sockets, con el espacio de nombres Internet. nalidad de los sockets, con el espacio de nombres Internet.

El constructor de la clase es el equivalente a la funcin socket de la librera El constructor de la clase es el equivalente a la funcin socket de la librera
de C, la que realiza la operacin de creacin del socket, mientras que el resto de de C, la que realiza la operacin de creacin del socket, mientras que el resto de
las operaciones que hemos descrito con anterioridad (asignar direccin, escu- las operaciones que hemos descrito con anterioridad (asignar direccin, escu-
char peticiones, aceptar conexiones, etc.) constituyen mtodos de la clase. char peticiones, aceptar conexiones, etc.) constituyen mtodos de la clase.

Para simplificar la gestin en ambos extremos de la comunicacin, existe otra Para simplificar la gestin en ambos extremos de la comunicacin, existe otra
clase, la ServerSocket, pensada para ser utilizada en el extremo del servidor. clase, la ServerSocket, pensada para ser utilizada en el extremo del servidor.
Su constructor se encarga de crear el socket, vincularlo a una direccin y crear la Su constructor se encarga de crear el socket, vincularlo a una direccin y crear la
cola en que se almacenarn las peticiones de conexin todava no atendidas. De cola en que se almacenarn las peticiones de conexin todava no atendidas. De
este modo, la clase Socket se utiliza en el extremo del cliente, en que el cons- este modo, la clase Socket se utiliza en el extremo del cliente, en que el cons-
tructor realiza la creacin del socket y la peticin de conexin con el servidor. tructor realiza la creacin del socket y la peticin de conexin con el servidor.

Clase: Socket Clase: Socket

Existen ocho versiones del Existen ocho versiones del


constructor de la clase Socket constructor de la clase Socket
Constructor: que se pueden consultar en la
web de Sun, los creadores del lenguaje:
Constructor: que se pueden consultar en la
web de Sun, los creadores del lenguaje:
http://java.sun.com/j2se/1.4.1/docs/ http://java.sun.com/j2se/1.4.1/docs/
api/java/net/Socket.html. api/java/net/Socket.html.
Socket(InetAddress adr, int port) Socket(InetAddress adr, int port)
Socket(InetAddress adr, int port, InetAddress adr_local, Socket(InetAddress adr, int port, InetAddress adr_local,
int port_local) int port_local)
Socket(string maquina, int port) Socket(string maquina, int port)
FUOC P03/75064/00978 55 Programacin de sockets FUOC P03/75064/00978 55 Programacin de sockets

La manera de especificar el servidor al que se quiere conectar condiciona cul La manera de especificar el servidor al que se quiere conectar condiciona cul
de los constructores se ejecuta: de los constructores se ejecuta:

Una manera consiste en pasar por parmetro la direccin IP y el puerto en Una manera consiste en pasar por parmetro la direccin IP y el puerto en
Formato Formato
que se quiere realizar la conexin. que se quiere realizar la conexin.
Las direcciones IP se especifi- Las direcciones IP se especifi-
can con objetos de la clase can con objetos de la clase
Una segunda manera de hacerlo consiste en suministrarle, adems de lo InetAddress, mientras que Una segunda manera de hacerlo consiste en suministrarle, adems de lo InetAddress, mientras que
los nombres de las mquinas los nombres de las mquinas
anterior, la direccin y el puerto locales que deben utilizarse. se especifican con simples anterior, la direccin y el puerto locales que deben utilizarse. se especifican con simples
cadenas de texto. cadenas de texto.

Una tercera manera consiste en especificar la mquina remota con el nom- Una tercera manera consiste en especificar la mquina remota con el nom-
bre, y no con la direccin IP. bre, y no con la direccin IP.

Clase: ServerSocket Clase: ServerSocket

Constructor: Constructor:

ServerSocket(int port) ServerSocket(int port)


ServerSocket(int port, int n_petic) ServerSocket(int port, int n_petic)
ServerSocket(int port, int n_petic, InetAddress adr) ServerSocket(int port, int n_petic, InetAddress adr)

De nuevo, la sobrecarga proporciona diferentes versiones del constructor, se- De nuevo, la sobrecarga proporciona diferentes versiones del constructor, se-
gn los parmetros que interese suministrar: gn los parmetros que interese suministrar:

En el primer caso, slo el puerto en que debe vincularse el socket. En el primer caso, slo el puerto en que debe vincularse el socket.

En el segundo, el puerto y el tamao de la cola. En el segundo, el puerto y el tamao de la cola.

En el tercero, adems de estos dos, la direccin IP de la interfaz a la que se En el tercero, adems de estos dos, la direccin IP de la interfaz a la que se
quiere vincular el socket. quiere vincular el socket.

Una vez creado el objeto de la clase ServerSocket, el mtodo accept (an- Una vez creado el objeto de la clase ServerSocket, el mtodo accept (an-
logo a la funcin accept de la librera de C) se encarga de esperar conexio- logo a la funcin accept de la librera de C) se encarga de esperar conexio-
nes de clientes por medio del socket. Cuando se haya efectuado la conexin, nes de clientes por medio del socket. Cuando se haya efectuado la conexin,
ya podr empezar el intercambio de informacin. ya podr empezar el intercambio de informacin.

Clase: ServerSocket Clase: ServerSocket

Hay ms de treinta mtodos Hay ms de treinta mtodos


definidos en la clase Socket, definidos en la clase Socket,
Mtodo: que sirven para realizar Mtodo: que sirven para realizar
operaciones auxiliares o cambiar operaciones auxiliares o cambiar
opciones de trabajo. opciones de trabajo.
La diferencia con el lenguaje C es que ni La diferencia con el lenguaje C es que ni
Public Socket accept() siquiera es necesario conocerlos para un Public Socket accept() siquiera es necesario conocerlos para un
funcionamiento bsico de los sockets. funcionamiento bsico de los sockets.
Se pueden consultar todos en la web de Se pueden consultar todos en la web de
Sun: http://java.sun.com/j2se/1.4.1/ Sun: http://java.sun.com/j2se/1.4.1/

Este mtodo se bloquea esperando una peticin de conexin desde un cliente Este mtodo se bloquea esperando una peticin de conexin desde un cliente
y, cuando llega, contina la ejecucin del programa servidor. El resultado que y, cuando llega, contina la ejecucin del programa servidor. El resultado que
FUOC P03/75064/00978 56 Programacin de sockets FUOC P03/75064/00978 56 Programacin de sockets

retorna es un nuevo socket, que es donde deben leerse/escribirse los datos que retorna es un nuevo socket, que es donde deben leerse/escribirse los datos que
se quieren intercambiar con el socket remoto. se quieren intercambiar con el socket remoto.

En el extremo del cliente, la creacin de un objeto de la clase Socket incluye, En el extremo del cliente, la creacin de un objeto de la clase Socket incluye,
asimismo, la solicitud de conexin. Por tanto, una vez aceptada esta conexin asimismo, la solicitud de conexin. Por tanto, una vez aceptada esta conexin
por parte del servidor, ya se puede proceder igualmente al intercambio de in- por parte del servidor, ya se puede proceder igualmente al intercambio de in-
formacin. formacin.

Para leer desde el socket, y para escribir en el mismo, se utilizan objetos de las Para leer desde el socket, y para escribir en el mismo, se utilizan objetos de las
clases inputStream y outputStream, que se conectan al socket mediante los clases inputStream y outputStream, que se conectan al socket mediante los
mtodos getOutputStream y getInputStream. mtodos getOutputStream y getInputStream.

3.2. Ejemplo de programacin de un servidor y un cliente 3.2. Ejemplo de programacin de un servidor y un cliente

Servidor: Servidor:

import java.io.*; import java.io.*;


import java.net.*; import java.net.*;

public class ejemplo_servidor { public class ejemplo_servidor {

public static void main(String args[]) { public static void main(String args[]) {

ServerSocket mi_servicio = null; ServerSocket mi_servicio = null;


String linea_recibida; String linea_recibida;
DataInputStream entrada; DataInputStream entrada;
PrintStream salida; PrintStream salida;
Socket socket_conectado = null; Socket socket_conectado = null;

try { try {
mi_servicio = new ServerSocket(2000); mi_servicio = new ServerSocket(2000);
} }
catch (IOException excepcion) { catch (IOException excepcion) {
System.out.println(excepcion); System.out.println(excepcion);
} }

try { try {
socket_conectado = mi_servicio.accept(); socket_conectado = mi_servicio.accept();
entrada = new DataInputStream(socket_conectado.getInputStream()); entrada = new DataInputStream(socket_conectado.getInputStream());
salida = new PrintStream(socket_conectado.getOutputStream()); salida = new PrintStream(socket_conectado.getOutputStream());
linea_recibida = entrada.readLine(); linea_recibida = entrada.readLine();
salida.println(linea_recibida); salida.println(linea_recibida);
salida.close(); salida.close();
entrada.close(); entrada.close();
socket_conectado.close(); socket_conectado.close();
FUOC P03/75064/00978 57 Programacin de sockets FUOC P03/75064/00978 57 Programacin de sockets

} }
catch (IOException excepcion) { catch (IOException excepcion) {
System.out.println(excepcion); System.out.println(excepcion);
} }
} }
} }

Cliente: Cliente:

import java.io.*; import java.io.*;


import java.net.*; import java.net.*;

public class ejemplo_cliente { public class ejemplo_cliente {

public static void main(String args[]) { public static void main(String args[]) {

Socket cliente = null; Socket cliente = null;


DataInputStream entrada = null; DataInputStream entrada = null;
DataOutputStream salida = null; DataOutputStream salida = null;

try { try {
cliente = new Socket("servidor.uoc.edu", 2000); cliente = new Socket("servidor.uoc.edu", 2000);
salida = new DataOutputStream(cliente.getOutputStream()); salida = new DataOutputStream(cliente.getOutputStream());
entrada = new DataInputStream(cliente.getInputStream()); entrada = new DataInputStream(cliente.getInputStream());
} }
catch (UnknownHostException excepcion) { catch (UnknownHostException excepcion) {
System.err.println("No encuentro servidor.uoc.edu"); System.err.println("No encuentro servidor.uoc.edu");
} }
catch (IOException excepcion) { catch (IOException excepcion) {
System.err.println("Error de entrada/salida"); System.err.println("Error de entrada/salida");
} }

if (cliente != null && salida != null && entrada!= null) { if (cliente != null && salida != null && entrada!= null) {
try { try {
String linea_recibida; String linea_recibida;
salida.writeBytes("Hola, servidor!\n"); salida.writeBytes("Hola, servidor!\n");
linia_recibida = entrada.readLine(); linia_recibida = entrada.readLine();
System.out.println("Servidor: " + linea_recibida); System.out.println("Servidor: " + linea_recibida);
salida.close(); salida.close();
entrada.close(); entrada.close();
FUOC P03/75064/00978 58 Programacin de sockets FUOC P03/75064/00978 58 Programacin de sockets

cliente.close(); cliente.close();
} }
catch (UnknownHostException excepcion) { catch (UnknownHostException excepcion) {
System.err.println("No encuentro 'servidor.uoc.edu'"); System.err.println("No encuentro 'servidor.uoc.edu'");
} }
catch (IOException excepcion) { catch (IOException excepcion) {
System.err.println("Error de entrada/salida"); System.err.println("Error de entrada/salida");
} }
} }
} }
} }

3.3. Comunicacin con datagramas 3.3. Comunicacin con datagramas

Todo lo que hemos expuesto hasta ahora sirve para crear sockets con el estilo Todo lo que hemos expuesto hasta ahora sirve para crear sockets con el estilo
de secuencia de bytes, es decir, con el protocolo TCP. de secuencia de bytes, es decir, con el protocolo TCP.

Para crear sockets en el estilo datagrama, es decir, con el protocolo UDP, dispo- Para crear sockets en el estilo datagrama, es decir, con el protocolo UDP, dispo-
nemos de las clases DatagramSocket y DatagramPacket: la primera para los nemos de las clases DatagramSocket y DatagramPacket: la primera para los
objetos sockets UDP y la segunda para los paquetes que deben enviarse. objetos sockets UDP y la segunda para los paquetes que deben enviarse.

La mecnica es muy sencilla y la ilustramos con un ejemplo: La mecnica es muy sencilla y la ilustramos con un ejemplo:

Servidor: Servidor:

import java.io.*; import java.io.*;


import java.net.*; import java.net.*;

public class ejemplo_servidor_datagrama { public class ejemplo_servidor_datagrama {

public static void main(String args[]) throws IOException { public static void main(String args[]) throws IOException {

byte[] buf = new byte [1024]; byte[] buf = new byte [1024];
DatagramSocket s = new DatagramSocket(2000); DatagramSocket s = new DatagramSocket(2000);
DatagramPacket p = new DatagramPacket(buf, 1024); DatagramPacket p = new DatagramPacket(buf, 1024);
s.receive(p); s.receive(p);
s.send(p); s.send(p);
s.close(); s.close();
} }
} }
FUOC P03/75064/00978 59 Programacin de sockets FUOC P03/75064/00978 59 Programacin de sockets

Cliente: Cliente:

import java.io.*; import java.io.*;


import java.net.*; import java.net.*;

public class ejemplo_data_c { public class ejemplo_data_c {

public static void main(String args[]) throws IOException { public static void main(String args[]) throws IOException {
InetAddress adr = InetAddress.getByName("servidor.uoc.edu"); InetAddress adr = InetAddress.getByName("servidor.uoc.edu");
DatagramSocket s = new DatagramSocket(); DatagramSocket s = new DatagramSocket();
DatagramPacket p = new DatagramPacket ("hola\n".getBytes(), 5, adr, 2000); DatagramPacket p = new DatagramPacket ("hola\n".getBytes(), 5, adr, 2000);
s.send(p); s.send(p);
s.receive(p); s.receive(p);
System.out.println (p.getAddress().getHostAddress()); System.out.println (p.getAddress().getHostAddress());
s.close(); s.close();
} }
} }
FUOC P03/75064/00978 60 Programacin de sockets FUOC P03/75064/00978 60 Programacin de sockets

Resumen Resumen

A continuacin, presentamos las principales funciones de C relacionadas con A continuacin, presentamos las principales funciones de C relacionadas con
la interfaz de programacin de sockets y sus formatos. la interfaz de programacin de sockets y sus formatos.

1) Crear un socket: 1) Crear un socket:

int socket(int espacio, int estilo, int protocolo); int socket(int espacio, int estilo, int protocolo);

2) Asignar direccin a un socket: 2) Asignar direccin a un socket:

int bind(int descr, const struct sockaddr *adr, int bind(int descr, const struct sockaddr *adr,
size_t long_adr); size_t long_adr);

3) Dejar un socket preparado para recibir peticiones de conexin: 3) Dejar un socket preparado para recibir peticiones de conexin:

int listen(int descr, unsigned int n_petic); int listen(int descr, unsigned int n_petic);

4) Esperar que haya disponibilidad de datos en un socket: 4) Esperar que haya disponibilidad de datos en un socket:

int select(int n_descr, fd_set *d_lect, fd_set *d_escr, int select(int n_descr, fd_set *d_lect, fd_set *d_escr,
fd_set *d_excep, struct timeval *tiempo); fd_set *d_excep, struct timeval *tiempo);

5) Enviar una peticin de conexin: 5) Enviar una peticin de conexin:

int connect(int descr, const struct sockaddr *adr, int connect(int descr, const struct sockaddr *adr,
size_t long_adr); size_t long_adr);

6) Aceptar una peticin de conexin: 6) Aceptar una peticin de conexin:

int accept(int descr, struct sockaddr *adr, int accept(int descr, struct sockaddr *adr,
size_t *long_adr); size_t *long_adr);
FUOC P03/75064/00978 61 Programacin de sockets FUOC P03/75064/00978 61 Programacin de sockets

7) Leer datos de un socket: 7) Leer datos de un socket:

int recvfrom(int descr, void *datos, size_t longitud, int recvfrom(int descr, void *datos, size_t longitud,
int flags, struct sockaddr *adr, size_t *long_adr); int flags, struct sockaddr *adr, size_t *long_adr);

int recv(int descr, void *datos, size_t longitud, int recv(int descr, void *datos, size_t longitud,
int flags); int flags);

ssize_t read(int descr, void *datos, size_t longitud); ssize_t read(int descr, void *datos, size_t longitud);

8) Escribir datos en un socket: 8) Escribir datos en un socket:

int sendto(int descr, const void *datos, size_t longitud, int sendto(int descr, const void *datos, size_t longitud,
int flags, const struct sockaddr *adr, size_t long_adr); int flags, const struct sockaddr *adr, size_t long_adr);

int send (int descr, const void *datos, int send (int descr, const void *datos,
size_t longi tud, int flags); size_t longi tud, int flags);

ssize_t write(int descr, const void *datos, ssize_t write(int descr, const void *datos,
size_t longitud); size_t longitud);

9) Cambiar opciones de un socket y consultarlas: 9) Cambiar opciones de un socket y consultarlas:

int setsockopt(int descr, int nivel, int nombre_opc, int setsockopt(int descr, int nivel, int nombre_opc,
const void *val_opc, size_t long_opt); const void *val_opc, size_t long_opt);

int getsockopt(int descr, int nivel, int nombre_opc, int getsockopt(int descr, int nivel, int nombre_opc,
void *val_opc, size_t *long_opt); void *val_opc, size_t *long_opt);

10) Cerrar un socket: 10) Cerrar un socket:

int shutdown(int descr, int modo); int shutdown(int descr, int modo);

int close(int descr); int close(int descr);


FUOC P03/75064/00978 62 Programacin de sockets FUOC P03/75064/00978 62 Programacin de sockets

Por lo que respecta al lenguaje Java, las clases ServerSocket (para los servi- Por lo que respecta al lenguaje Java, las clases ServerSocket (para los servi-
dores) y Socket (para los clientes) son las que incluyen toda la funcionalidad dores) y Socket (para los clientes) son las que incluyen toda la funcionalidad
de los sockets con el espacio de nombres Internet y orientados a conexin. de los sockets con el espacio de nombres Internet y orientados a conexin.

Constructores: Constructores:

ServerSocket(int port) ServerSocket(int port)


ServerSocket(int port, int n_petic) ServerSocket(int port, int n_petic)
ServerSocket(int port, int n_petic, InetAddress adr) ServerSocket(int port, int n_petic, InetAddress adr)

Socket(InetAddress adr, int port) Socket(InetAddress adr, int port)


Socket(InetAddress adr, int port, InetAddress Socket(InetAddress adr, int port, InetAddress
adr_local, int port_local) adr_local, int port_local)
Socket(string maquina, int port) Socket(string maquina, int port)

Adems de los constructores, slo es necesario ejecutar el mtodo accept en Adems de los constructores, slo es necesario ejecutar el mtodo accept en
el extremo del servidor para tener dos sockets conectados, a punto de intercam- el extremo del servidor para tener dos sockets conectados, a punto de intercam-
biarse informacin. biarse informacin.

Las clases DatagramSocket y DatagramPacket permiten la comunicacin Las clases DatagramSocket y DatagramPacket permiten la comunicacin
de sockets en modo no orientado a conexin (con protocolo UDP). de sockets en modo no orientado a conexin (con protocolo UDP).
FUOC P03/75064/00978 63 Programacin de sockets FUOC P03/75064/00978 63 Programacin de sockets

Actividades Actividades

1. En un sistema UNIX, inspeccionad el contenido del fichero /etc/inetd.conf. Qu ser- 1. En un sistema UNIX, inspeccionad el contenido del fichero /etc/inetd.conf. Qu ser-
vicios internos ofrece el proceso inetd? Hay algn servidor que no se ejecute como root? vicios internos ofrece el proceso inetd? Hay algn servidor que no se ejecute como root?

Si encontris que hay una serie de servicios (no internos) para los cuales el valor del sexto cam- Si encontris que hay una serie de servicios (no internos) para los cuales el valor del sexto cam-
po es igual, probablemente en el sistema hay instalado un programa llamado wrapper, que ac- po es igual, probablemente en el sistema hay instalado un programa llamado wrapper, que ac-
ta de intermediario entre el servidor inetd y los procesos hijos. Averiguad para qu sirve un ta de intermediario entre el servidor inetd y los procesos hijos. Averiguad para qu sirve un
wrapper. wrapper.

2. Intentad establecer una conexin a alguno de los servicios internos que ofrece el servidor 2. Intentad establecer una conexin a alguno de los servicios internos que ofrece el servidor
inetd. Desde el mismo sistema ello puede llevarse a cabo, por ejemplo, con lo siguiente: inetd. Desde el mismo sistema ello puede llevarse a cabo, por ejemplo, con lo siguiente:

telnet localhost daytime telnet localhost daytime

El segundo argumento (opcional) del comando telnet es un nombre de servicio o un n- El segundo argumento (opcional) del comando telnet es un nombre de servicio o un n-
mero de puerto en el que se puede establecer la conexin. El comando acaba cuando el ser- mero de puerto en el que se puede establecer la conexin. El comando acaba cuando el ser-
vidor cierra la conexin, o bien cuando la cierra el usuario (tecleando el carcter de escapada, vidor cierra la conexin, o bien cuando la cierra el usuario (tecleando el carcter de escapada,
que por norma general s ^] y entrando el comando quit). que por norma general s ^] y entrando el comando quit).

3. En el sistema UNIX al que habis accedido, se encuentra disponible el comando netstat? 3. En el sistema UNIX al que habis accedido, se encuentra disponible el comando netstat?
Si lo est, intentad hacer netstat -a. Podis interpretar la informacin que proporciona? Si lo est, intentad hacer netstat -a. Podis interpretar la informacin que proporciona?
Probablemente, os ser til haber hecho antes man netstat. Probablemente, os ser til haber hecho antes man netstat.

4. Inspeccionad el contenido de los ficheros /etc/hosts y /etc/services, y observad su 4. Inspeccionad el contenido de los ficheros /etc/hosts y /etc/services, y observad su
formato. Si el sistema utiliza el servicio NIS, podis listar las bases de datos haciendo ypcat formato. Si el sistema utiliza el servicio NIS, podis listar las bases de datos haciendo ypcat
hosts e ypcat services. hosts e ypcat services.

Ejercicios de autoevaluacin Ejercicios de autoevaluacin

1. Por qu creis que no se permite a los procesos de usuario (no privilegiados) crear sockets 1. Por qu creis que no se permite a los procesos de usuario (no privilegiados) crear sockets
con el estilo SOCK_RAW? con el estilo SOCK_RAW?

2. Explicad qu diferencia existe entre trabajar con el estilo de comunicacin secuencia de 2. Explicad qu diferencia existe entre trabajar con el estilo de comunicacin secuencia de
bytes y con el estilo datagrama en los sockets del espacio de nombres de ficheros. bytes y con el estilo datagrama en los sockets del espacio de nombres de ficheros.

3. De las condiciones de error con que puede retornar la llamada connect, indicad cules se 3. De las condiciones de error con que puede retornar la llamada connect, indicad cules se
pueden dar en sockets del espacio de nombres de ficheros o del espacio Internet, en sockets pueden dar en sockets del espacio de nombres de ficheros o del espacio Internet, en sockets
orientados a conexin o no orientados a conexin y en sockets bloqueadores o no bloquea- orientados a conexin o no orientados a conexin y en sockets bloqueadores o no bloquea-
dores. dores.
FUOC P03/75064/00978 64 Programacin de sockets FUOC P03/75064/00978 64 Programacin de sockets

Solucionario Solucionario

Ejercicios de autoevaluacin Ejercicios de autoevaluacin

1. Uno de los motivos es porque, de este modo, un usuario podra ejecutar un programa que 1. Uno de los motivos es porque, de este modo, un usuario podra ejecutar un programa que
generara paquetes TCP o UDP con puertos de origen reservados. Aparte de ello, un usuario generara paquetes TCP o UDP con puertos de origen reservados. Aparte de ello, un usuario
inexperto, o malintencionado, podra generar paquetes con cabeceras incorrectas que provo- inexperto, o malintencionado, podra generar paquetes con cabeceras incorrectas que provo-
caran errores en los equips de la red. caran errores en los equips de la red.

2. Suponiendo que, en el espacio de nombres de ficheros, los datagramas no se perdieran ni se 2. Suponiendo que, en el espacio de nombres de ficheros, los datagramas no se perdieran ni se
duplicaran o se desordenaran, la diferencia es que puede suceder que las operaciones de lectura duplicaran o se desordenaran, la diferencia es que puede suceder que las operaciones de lectura
en el estilo datagrama no lean todos los datos. ste sera el caso si el nmero de bytes que se qui- en el estilo datagrama no lean todos los datos. ste sera el caso si el nmero de bytes que se qui-
siera leer fuera menor que la longitud del datagrama. En cambio, en el estilo secuencia de bytes, siera leer fuera menor que la longitud del datagrama. En cambio, en el estilo secuencia de bytes,
no se perder ningn dato, sea cual sea la longitud de la memoria intermedia de lectura. no se perder ningn dato, sea cual sea la longitud de la memoria intermedia de lectura.

3. La relacin entre los diferentes tipos de sockets y los posibles errores se expone en el 3. La relacin entre los diferentes tipos de sockets y los posibles errores se expone en el
cuadro siguiente: cuadro siguiente:

Tipos de socket Tipos de error posible Tipos de socket Tipos de error posible

Todos los sockets EBADF, ENOTSOCK, EINVAL y EAFNOSUPPORT Todos los sockets EBADF, ENOTSOCK, EINVAL y EAFNOSUPPORT

Del espacio de nombres de ficheros ENOENT,ENOTDIR, EACCESS y EPROTOTYPE Del espacio de nombres de ficheros ENOENT,ENOTDIR, EACCESS y EPROTOTYPE

Del espacio de nombres Internet ENETUNREACH y ETIMEDOUT Del espacio de nombres Internet ENETUNREACH y ETIMEDOUT

EISCONN, ENETUNREACH, ETIMEDOUT, EISCONN, ENETUNREACH, ETIMEDOUT,


Orientados a conexin Orientados a conexin
ECONNREFUSED y EINPROGRESS ECONNREFUSED y EINPROGRESS

No orientados a conexin No hay ninguno especfico. No orientados a conexin No hay ninguno especfico.

Bloqueadores ETIMEDOUT y EINTR Bloqueadores ETIMEDOUT y EINTR

No bloqueadores EINPROGRESS y EALREADY No bloqueadores EINPROGRESS y EALREADY

Glosario Glosario

algoritmo de Nagle m Algoritmo para minimizar el nmero de paquetes TCP que deben algoritmo de Nagle m Algoritmo para minimizar el nmero de paquetes TCP que deben
transmitirse cuando la red est cargada. transmitirse cuando la red est cargada.

dato fuera de banda m Dato urgente que se transmite al destinatario con una prioridad dato fuera de banda m Dato urgente que se transmite al destinatario con una prioridad
ms alta que el dato normal. ms alta que el dato normal.

espacio de nombres m Dominio de comunicaciones al que pertenece un socket y que de- espacio de nombres m Dominio de comunicaciones al que pertenece un socket y que de-
termina el formato de su nombre o direccin. Hay dos bsicos: el de ficheros y el de Internet. termina el formato de su nombre o direccin. Hay dos bsicos: el de ficheros y el de Internet.

estilo de comunicacin m Semntica asociada a la emisin y recepcin de datos por me- estilo de comunicacin m Semntica asociada a la emisin y recepcin de datos por me-
dio de un socket. El estilo de comunicacin determina, por ejemplo, cul es la unidad de datos dio de un socket. El estilo de comunicacin determina, por ejemplo, cul es la unidad de datos
transmitida (bytes o datagramas), si se prev la posibilidad de perder datos, o si la comunica- transmitida (bytes o datagramas), si se prev la posibilidad de perder datos, o si la comunica-
cin requiere el establecimiento de una conexin, o bien cada paquete especifica su direccin cin requiere el establecimiento de una conexin, o bien cada paquete especifica su direccin
de destino. de destino.

familia de protocolos f Conjunto de protocolos de comunicacin que se pueden utilizar familia de protocolos f Conjunto de protocolos de comunicacin que se pueden utilizar
con los sockets que pertenecen a un determinado espacio de nombres. con los sockets que pertenecen a un determinado espacio de nombres.

orden de bytes de la red m Orden en el que se transmiten los bytes que representan un orden de bytes de la red m Orden en el que se transmiten los bytes que representan un
nmero binario; el byte de mayor peso se transmite el primero y el de menor peso, el ltimo. nmero binario; el byte de mayor peso se transmite el primero y el de menor peso, el ltimo.

tipos de socket m pl Conjunto de propiedades de los sockets que utilizan un mismo estilo tipos de socket m pl Conjunto de propiedades de los sockets que utilizan un mismo estilo
de comunicacin. de comunicacin.

Bibliografa Bibliografa

Loosemore, S.; Stallman, R.M.; McGrath, R.; Oram, A.; Drepper, U. (1992). The GNU Loosemore, S.; Stallman, R.M.; McGrath, R.; Oram, A.; Drepper, U. (1992). The GNU
C Library Reference Manual. Boston: Free Software Foundation. C Library Reference Manual. Boston: Free Software Foundation.

Mrquez Garca, F.M. (1996). UNIX. Programacin avanzada. Madrid: Ra-ma. Mrquez Garca, F.M. (1996). UNIX. Programacin avanzada. Madrid: Ra-ma.

Orfali, R. (1998). Client/server programming with Java and CORBA. Nueva York: Wiley & sons. Orfali, R. (1998). Client/server programming with Java and CORBA. Nueva York: Wiley & sons.

Rifflet, J.M. (1992). Comunicaciones en UNIX. Madrid: McGraw-Hill. Rifflet, J.M. (1992). Comunicaciones en UNIX. Madrid: McGraw-Hill.

También podría gustarte