Diapositivas Sockets

Anuncio
Sockets
Unidad 4
Socket
Es un canal de comunicación bidireccional que permite que los
procesos (que están en la misma computadora o en diferentes
computadoras) se comuniquen entre si.
Tipos
de
sockets
sockets de Internet: Comunican procesos en
AF_INET
diferentes máquinas.
sockets unix:
AF_UNIX
Comunican procesos en la
misma máquina.
Sockets
1.- Sockets orientados a la conexión: SOCK_STREAM
(sockets de flujo)
Ambos procesos deben conectarse entre ellos con un socket y
hasta que no esté establecida correctamente la conexión,
ninguno de los dos puede transmitir datos.
Usa protocolo TCP.
2.- Sockets orientados a la no conexión: SOCK_DGRAM
(sockets de datagramas)
No es necesario que los programas se conecten. Cualquiera de
ellos puede transmitir datos en cualquier momento,
independientemente de que el otro programa esté
"escuchando" o no.
Usa protocolo UDP.
Modelo cliente-servidor
Proceso Servidor: Provee un servicio a otro(s) proceso(s)
Generalmente para proveer datos.
Para establecer la conexión inicialmente, el servidor permanece
arrancado y pasivo en espera de que otro proceso quiera
conectarse a él.
Proceso Cliente: Es el que solicita conexión con el servidor,
normalmente para solicitarle datos.
Conexión entre cliente y servidor
Para poder realizar la conexión entre ambos procesos se
requiere:
Dirección IP: El cliente debe conocer a qué ordenador desea
conectarse.
Servicio (puerto) que queremos crear / utilizar: En una
misma computadora pueden estar corriendo varios
programas servidores.
Cuando un cliente desea conectarse, debe indicar qué
servicio quiere.
Cada servicio dentro de la computadora debe tener un
número único que lo identifique: Mayor a 1024, hasta 65535.
Los números menores a 1024 están reservados para
servicios habituales del sistemas operativo.
Pasos que debe seguir un programa Servidor:
1.- Apertura de un socket, mediante la llamada socket().
2.- Avisar al sistema operativo de que hemos abierto un socket y
queremos que asocie nuestro programa a dicho socket: Con
la llamada bind(). En esta llamada se indica el número de
servicio al que se quiere atender.
3.- Avisar al sistema de que comience a atender dicha conexión
de red. Con la llamada listen(). El S.O puede hacer una cola
de clientes.
4.- Aceptar las conexiones de clientes al sistema operativo.
Con la llamada accept(). El S.O obtiene siguiente cliente de
la cola. Si no hay clientes se quedará bloqueado hasta que
algún cliente se conecte.
5.- Escribir y recibir datos del cliente, por medio de las
llamadas write() y read(), o bien con send() y recv().
Pasos que debe seguir un programa Cliente:
1.- Apertura de un socket, como el servidor, por medio de la
llamada socket().
2.- Solicitar conexión con el servidor por medio de la llamada
connect(). Dicha llamada bloquerá al cliente hasta que el
servidor acepte la conexión o bien si no hay servidor
regresará un error.
En esta llamada se da la dirección IP del servidor y el
número de servicio que se desea.
3.- Escribir y recibir datos del servidor por medio de las
funciones write() y read() o bien con send() y recv().
4.- Cerrar la comunicación por medio de close().
Llamadas al sistema
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
Crea un socket y regresa su descriptor de archivo.
domain Familia de direcciones: AF_INET o AF_UNIX
type
Indica si el socket es orientado a conexión
SOCK_STREAM o no lo es SOCK_DGRAM.
protocol Indica el protocolo a emplear. Habitualmente se
pone 0 (el socket elige el protocolo)
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
Notifica al S.O de que se ha abierto un socket y se le solicita
que lo asocie con nuestro proceso.
sockfd
Descriptor de socket obtenido con socket()
My addr La estructura sockaddr lleva varios campos, entre
los que es obligatorio rellenar:
sin_family Es el tipo de conexión (igual que el primer
parámetro de socket(). )
sin_port
número correspondiente al servicio.
sin_addr.s_addr Es la dirección del cliente al que el servidor
atenderá. Colocando en ese campo el valor INADDR_ANY,
atenderá a cualquier cliente.
addrlen Longitud de la estructura struct sockaddr
Ejemplo:
struct sockaddr_in my_addr;
…
my_addr.sin_family = AF_INET; // Ordenación de bytes de la máquina
my_addr.sin_port = htons(3490); // short, Ordenación de bytes de la red
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', 8); // Poner a cero el resto de la estru
int addrlen=sizeof(struct sockaddr);
if (bind(sockfd, (struct sockaddr *)&my_addr, addrlen) == -1) {
perror("bind");
exit(1);
}
int listen(int sockfd, int backlog);
Notiica al S.O que comience a atender una conexión
entrante.
El servidor debe estar atento a conexiones entrante de un
cliente.
sockfd
Descriptor de socket (obtenido con socket() )
backlog
Número de conexiones permitidas en la cola de
entrada (máximo de clientes en la cola).
int accept(int sockfd, void *addr, int *addrlen);
- Acepta conexiones de otras máquinas.
- Extrae la primera conexión de la cola de conexiones entrantes.
- Devuelve un nuevo descriptor de socket con el que se
atenderá la conexión, recibiendo ( recv() ) o enviando ( send() )
sockfd
Descriptor de socket obtenido con socket()
struct sockaddr_in Será llenado por el S.O contendrá el ip y
puerto de la conexión entrante.
addrlen
Será llenado por el S.O y tendrá
sizeof(struct sockaddr_in)
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
Solicita conexión con el servidor.
El cliente se bloqueará hasta que el servidor acepte la
conexión de lo contrario regresará error.
sockfd
Descriptor de socket obtenido con socket()
serv_addr
Dirección IP del servidor y el número de servicio
que se desea.
Longitud de la estructura struct sockaddr.
addrelen
int send(int sockfd, void *msg, int len, int flags);
int recv(int sockfd, void *msg, int len, int flags);
Archivos de linux implicados
Para la programación de socket no es estrictamente necesario
ningún archivo. Sabiendo la dirección IP y el número de servicio,
se ponen directamente en código y todo resuelto
/etc/hosts Contiene una lista de nombres de computadoras
conectados en red y dirección IP de cada uno. Habitualmente en
el /etc/hosts del cliente se suele colocar el nombre del servidor y
su dirección IP.
La llamada gethostbyname(), a la que pasándole el nombre de la
máquina como una cadena de caracteres, devuelve una
estructura de datos entre los que está la dirección IP.
Ejemplo: En el programa cliente:
struct hostent *he;
struct sockaddr_in their_addr;
……
if ((he=gethostbyname(argv[1])) == NULL) { // obtener información de máquina
perror("gethostbyname");exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket"); exit(1);
}
their_addr.sin_family = AF_INET; // Ordenación de bytes de la máquina
their_addr.sin_port = htons(PORT); // short, Ordenación de bytes de la red
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8); // poner a cero el resto de la estructura
if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))
== -1) { perror("connect"); exit(1); }
Descargar