Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Introducción
Las seis características básicas de un lenguaje ideal, expuestas por Pratt, son:
1. claridad y sencillez
2. 2. claridad de la estructura del programa
3. sencillez de la aplicación
4. facilidad de ampliación
5. facilidad de corrección y mantenimiento.
6. eficacia.
1. movimiento,
2. definición de estado,
3. consulta de estado.
¿Qué es un socket?
Dominios de comunicación.
Algunos dominios:
Figura 1-1
Sockets Stream son los más utilizados, hacen uso del protocolo TCP
(figura 1-1), el cual nos provee un flujo de datos vi direccional, secuenciado, sin
duplicación de paquetes y libre de errores.
La especificación del protocolo TCP se puede leer en la RFC-793.
Sockets Datagram hacen uso del protocolo UDP, el cual nos provee un
flujo de datos bidireccional, pero los paquetes pueden llegar fuera de secuencia,
pueden no llegar o contener errores.
Por lo tanto el proceso que recibe los datos debe realizar resecuencimiento,
eliminar duplicados y asegurar la confiabilidad.
Se llaman también sockets sin conexión, porque no hay que mantener una
conexión activa, como en el caso de sockets stream.
Son utilizados para transferencia de información paquete por paquete. Ejemplo:
dns, tftp, bootp, etc.
Entones podríamos preguntar, ¿Cómo hacen estos programas para funcionar si
pueden perder datos?
Ellos implementan un protocolo encima de UDP que realiza control de errores.
La especificación del protocolo UDP se puede leer en la RFC-768.
Byte order.
Network byte order y Host byte order son dos formas en las que el sistema
puede almacenar los datos en memoria.
Está relacionado con el orden en que se almacenan los bytes en la memoria RAM.
Si al almacenar un short int (2 bytes) o un long int (4 bytes) en RAM, en la posición
más alta se almacena el byte menos significativo, entonces está en network byte
order, caso contrario es host byte order ( figura 2-1).
• Todos los bytes que se transmiten hacia la red, sean números IP o datos,
deben estar en network byte order.
• Todos los datos que se reciben de la red, deben convertirse a host byte
order.
Creación de un socket.
Analogía:
Para que una persona pueda recibir llamadas debe tener instalado un
teléfono, para poder realizar una conexión se debe crear un socket.
Los sockets se crean llamando a la función socket(), esta función retorna
un descriptor de socket, que es tipo int.
Si hubo algún error, socket() retorna -1 y la variable global errno se establece
con un valor que indica el error que se produjo
Errores en la creación:
Los errores más comunes son :
Función Bind()
Analogía:
Para poder recibir llamadas, se debe tener un número telefónico, para
poder recibir conexiones, se le debe asignar un nombre al socket.
El socket se crea sin nombre, debemos asignarle uno para poder recibir
conexiones.
• inet_ntoa()
Debemos asignarle valores a una variable tipo sockaddr_in antes de llamar a las
función bind().
Veamos un ejemplo:
...
..
struct sockaddr_in my_addr;
......
my_addr.sin_family = AF_INET;
my_addr.sin port = htons ( 3490 ); // Numero de puerto por donde escuchara el servidor.
my_addr.sin_addr.s_addr = inet_addr ("132.241.5.10"); // IP de la interface por donde
escuchara el servidor.
bzero ( &(my_addr.sin_zero), 8); // Relleno con ceros.
Notas :
my_addr.sin_port=0;
Ambos, cliente y servidor, deben crean un socket mediante la función socket(), para
poder comunicarse.
• El servidor llama a bind() para darle un nombre al socket, para
luego poder recibir conexiones, es decir establece por cual número de
puerto escuchará. Por ejemplo si este sería un servidor de telnet,
establecería el puerto 23. Para el cliente no es necesario establecer el
número de puerto, porque no recibirá intentos de conexión, sólo intentará
conectarse con el servidor .
• El servidor habilita su socket para poder recibir conexiones,
llamando a la función listen(). El cliente no necesita realizar este paso
porque no va a recibir conexiones, solo intentará conectarse con el servidor.
• El servidor ejecuta la función accept() y queda en estado de
espera, la función accept() no retorna hasta que intenten conectarse. El
cliente usa la función connect() para realizar el intento de conexión, en ese
momento la función accept() del servidor retorna con un parámetro que es
un nuevo descriptor de socket, el cual se utiliza para realizar la
transferencia de datos por la red con el cliente.
• Una vez establecida la conexión se utilizan las funciones send()
y recv() con el descriptor de socket del paso anterior para realizar la
transferencia de datos.
• Para finalizar la conexión se utilizan las funciones close() o
shutdown().
Ejemplo cliente-servidor TCP simple
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <time.h>
#define MAX 5
#define TAMBUFFER 512
#define PUERTO 4949
char opcion=‘0’;
char cadena[MAX];
int idsocket,tamMandado;
/*Creamos el socket*/
printf("____________________________Programa del
cliente______________________________\n");
if (argc !=2)
{
/* Nuestro programa cliente sólo necesita un
argumento, que es la IP*/
printf("Error, debe de escribrir: %s <Dirección IP>\n",argv[0]);
exit(-1);
}
idsocket=socket(AF_INET,SOCK_STREAM,0);
if (idsocket==-1)
{
printf("Error: El socket no se ha abierto\n");
}
else
{
printf("Socket creado\n");
//Se prepara el nombre de la maquina remota
infoservidor.sin_family=AF_INET;
infoservidor.sin_addr/*.s_addr*/=*((struct in_addr *)he->h_addr);
inet_addr("127.0.0.1");
/* es necesario comentar esta linea cuando queremos que el cliente
y el servidor no sean la misma maquina*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <stdlib.h>
#include <time.h>
#define MAXIMOCONEXIONES 1
//numero maximo de conexiones en espera
#define PUERTO 4949
#define TAMBUFFER 512
main ()
{
int idsocket,s_aux;
int asignaDir,tamdir,tamRecibido;
struct sockaddr_in datosSocket,infocliente;
char buf[TAMBUFFER];
/*Creamos el socket*/
printf("____________________________Programa del
servidor______________________________\n");
idsocket=socket(AF_INET,SOCK_STREAM,0);
if (idsocket==-1)
{
printf("Error: El socket no se ha abierto\n");
}
else
{
datosSocket.sin_family=AF_INET;
datosSocket.sin_addr.s_addr=INADDR_ANY;
//INADDR_ANY coloca la del cliente IP automaticamente.
datosSocket.sin_port=htons(PUERTO);
bzero(&(datosSocket.sin_zero),8);/*rellena a 0 este capo se la
estructura*/
printf("Socket creado\n");
//Asigar un nombre local al socket
if ((bind(idsocket,(struct
sockaddr*)&datosSocket,sizeof(datosSocket))<0) ||
(listen(idsocket,MAXIMOCONEXIONES)<0))
{
printf("Error al nombrar el socket o servidor no a la escucha\n");
}
else
{
}
else//TODO VA BIEN
{
//***************************************************************
//********************IMPLEMENTAR CODIGO AQUI*********************
}
}
}
printf("____________________________Programa del
servidor______________________________\n");
}//else
}//main
La elección del Linux junto con su extensión de tiempo real RT-Linux. Nos
proveen de herramientas de desarrollo muy potentes como el entorno gnu wpe
(Windows Programming Environment), o el compilador de c gnu, todo ello sin coste.
Bibliografía