Sockets en C

Anuncio
UNIVERSIDAD NACIONAL AUTÓNOMA
DE MÉXICO
Facultad de Ingeniería
Arquitecturas Cliente/Servidor
“Sockets en C”
Alumnos:
Arellano Santiago Víctor Manuel
Girón Capistrán Aldo Iván
Guerrero Ramirez Eduardo Daniel
Rosas Peña Ramiro
Fecha:
Entrega
08/septiembre/2009
 Objetivos.
Implementar Sockets en el lenguaje de programación “C”.
 Introducción.
A la hora de comunicar dos programas, existen varias posibilidades para establecer la
conexión inicialmente. Una de ellas es la que utiliza el modelo cliente y un servidor,un
modelo estándar de ejecución de aplicaciones en una red.
Un servidor es un proceso que se está ejecutando en un nodo de la red y que
gestiona el acceso a un determinado recurso.
Un cliente es un proceso que se ejecuta en el mismo o en diferente nodo y que
realiza peticiones de servicio al servidor. Su nombre se debe a que es el que solicita
información al servidor, es decir, las peticiones están originadas por la necesidad de
acceder al recurso que gestiona el servidor.
El servidor está continuamente esperando peticiones de servicio. Cuando se produce una
petición el servidor despierta y atiende al cliente. Cuando el servicio concluye, el
servidor vuelve al estado de espera.
Resumiendo, servidor es el programa que permanece pasivo a la espera de que alguien
solicite conexión con él, normalmente, para pedirle algún dato. Cliente es el programa
que solicita la conexión para, normalmente, pedir datos al servidor.

Desarrollo.
Un socket es una interfaz de entrada-salida de datos que permite la intercomunicación
entre procesos. Los procesos pueden estar ejecutándose en el mismo o en distintos
sistemas, unidos mediante una red.
Los procesos pueden estar ejecutándose en el mismo o en distintos sistemas, unidos
mediante una red.
Los sockets permiten la comunicación entre procesos, como los teléfonos permiten la
comunicación entre las personas. Los sockets se crean dentro de un dominio de
comunicación, igual que un archivo se crea de un filesystem.
El dominio de
comunicación nos dice dónde se encuentran los procesos que se van a intercomunicar. Si
los procesos están en el mismo sistema, el dominio de comunicación será AF_UNIX, si los
procesos están en distintos sistemas y estos se hallan unidos mediante una red TCP/IP, el
dominio de comunicación será AF_INET.
Una forma de conseguir que dos programas se transmitan datos, basada en el protocolo
TCP/IP, es la programación de sockets. Un socket no es más que un "canal de
comunicación" entre dos programas que corren sobre ordenadores distintos o incluso en
el mismo ordenador.
Desde el punto de vista de programación, un socket no es más que un "fichero" que se
abre de una manera especial. Una vez abierto se pueden escribir y leer datos de él con
las habituales funciones de read() y write() del lenguaje C.
 Tipos de sockets.
Tenemos dos categorías de sockets:

Sockets Stream son los más utilizados, hacen uso del protocolo
TCP ( figura 4-1), el cual nos provee un flujo de datos bidireccional, secuenciado,
sin duplicación de paquetes y libre de errores. Son llamados sockets orientados a
conexión. 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. Se llaman también sockets no orientados a 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. La especificacion del protocolo UDP se puede leer
en la RFC-768.

Sockets raw no son para el usuario más común, son provistos principalmente
para aquellos interesados en desarrollar nuevos protocolos de comunicación o para
hacer
uso
de
facilidades
ocultas
de un protocolo existente.
Implementación de Sockets en C.
Existen diversos lenguajes de programación para implementar sockets como PHP, Java,
Visual Basic, Python, C, C++ y otros. En esta ocasión emplearemos al lenguaje C para
lograr nuestro objetivo.
Para lograr el objetivo del trabajo primero conoceremos cómo es el almacenamiento de
datos en la memoria y qué funciones de conversión se requieren cuando se crean
sockets, también daremos un vistazo a la creación y conexión de sockets y las funciones
implicadas en el proceso para los dos tipos de sockets estudiados.
 Almacenamiento de datos en la memoria y funciones de conversión.
Network byte order y Host byte order son dos formas en las que el sistema puede
almacenar los datos en memoria. Dependiendo del microprocesador que se esté
utilizando,
podríamos
estar programando en un sistema host byte order o network byte order, pero cuando
enviamos los datos por la red deben ir en un orden especificado, sino enviaríamos todos
los datos al revés. Lo mismo sucede cuando recibimos datos de la red, debemos
ordenarlos al orden que utiliza nuestro sistema. Debemos cumplir las siguientes reglas :


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.
Las conversiones se realizarán con las siguientes conversiones:
htons() - host to network short - convierte un short int de host byte order a network byte
order.
htonl() - host to network long - convierte un long int de host byte order a network byte
order.
ntohs() - network to host short - convierte un short int de network byte order a host byte
order.
ntohl() - network to host long - convierte un long int de network byte order a host byte
order.
 Estructuras a utilizar.
En los dos sockets emplearemos las estructuras siguientes:
struct sockaddr {
unsigned short sa_family; // AF_*
char sa_data[14]; // Direccion de protocolo.
};
struct sockaddr_in {
short int sin_family; // AF_INET
unsigned short sin_port; // Numero de puerto.
struct in_addr sin_addr; // Dirección IP.
unsigned char sin_zero[8]; // Relleno.
};
La primer estructura, sockaddr, almacena la dirección de protocolo para muchos tipos de
protocolos.
sa_family puede ser AF_INET, AF_UNIX u otros dominios, para nuestros ejemlos solo será
AF_INET.
sa_data contiene la dirección IP y número de puerto asignado al socket.
Se creó la esctuctura sockaddr_in para el caso de internet, para poder referenciar los
elementos de forma más fácil.
Los apuntadores a la estructura sockaddr_in deben ser precedidos con un cast tipo
*struct sockaddr antes de pasarlos como parámetros a funciones. :
 sin_family sera AF_INET
 sin_port (número de puerto) y sin_addr (dirección IP)
deberán estar en network byte order, osea habrá que usar htons().
 sin_family no debe convertirse a network byte order porque es solo
usado por el kernel y no es enviado por la red.
 sin_zero se utiliza para rellenar la estructura a la longuitud de
sockaddr, debe estar inicializada a cero con la función bzero(). Ver
la página del manual
Debemos asignarle valores a una variable tipo sockaddr_in antes de llamara las función
bind(). El siguiente ejemplo lo aclara perfectamente:
struct sockaddr_in my_addr; ...
my_addr.sin_family=AF_INET;
my_addr.sin port=htones(3490); //Número de puerto por donde escuchará el servidor.
my_addr.sin_addr.s_addr=inet_addr(\“132.241.5.10\”); //IP de la interface por donde
escuchará el servidor.
bzero(&(my_addr.sin_zero),8); //Rellenos con ceros.
Notas:
 Si se asigna el valor cero a sin_port, el sistema nos dará automáticamente un
puerto disponible.
 Se puede automatizar, la asignación de la IP, si ponemos el valor INADDR_ANY, el
sistema
asignará
la
dirección
IP
local
(my_addr.sin_addr.s_addr=htonl(INADDR_ANY); ).
 Las variables my_addr.sin_port y my_addr.sin_addr.s_addr deben estar en network
byte order ya que son valroes que viajan por la red pero my_addr.sin_family no
porque solo es utilizado por el kernel para saber qué tipo de dirección contiene la
estructura.
 La función inet_addr( ) convierte una dirección IP en notación números y puntos en
un dato de tipo unsigned long, retorna la dirección en network byte order. Retorna 1 si hubo error.
 Creación de socket.
socket( )
Para poder realizar una conexión utilizaremos un socket. Los sockets se crean llamando a
la función socket(), esta función retorna un descritpor 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
sockf= socket ( int dominio, int tipo, int protocolo );
sockfd: es el descriptor de socket devuelto. Luego se utilizará para conectarse, recibir
conexiones, enviar y recibir datos, etc.
dominio: dominio donde se realiza la conexión. Nosotros manejaremos AF_INET.
Tipo: podrá ser SOCK_STREAM o SOCK_DGRAM o SOCK_RAW.
Protocolo: 0 (cero, selecciona el protocolo más apropiado ). Si se especifica al protocolo
como cero, el sistema selecciona el protocolo apropiado de uno de los protocolos
disponibles, dependiendo del tipo de socket requerido.
bind( ) .
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 nobre, debemos
asignarle uno para poder recibir conexiones.
bind () se utiliza para darle un nombre al socket, osea una dirección IP y número de
puerto del host local por donde escuchará, al especificar una IP del host local le estamos
diciendo por cual interfaz física escuchará (el sistema puede tener varias interfaces
ethernet, ppp, etc). Es necesario llamar a bind() cuando se está programando un servidor.
Cuando se está programando un cliente generalmente no se utiliza esta función, el kernel
le asignará al socket la dirección IP y número de puerto disponible al llamar a ciertas
funciones, por ejemplo cuando llamamos a connect( ) para conectarnos con un sistema
remoto.
En el servidor es necesario llamar a bind() debido a que el número de puerto debe ser
conocido para que los clientes puedan conectarse. Por ejemplo si estamos programando
un servidor de telnet debemos llamar a bind() para asignarle al socket el puerto 23. En la
aplicación cliente se puede llamar a bind() y asignarle un número de puerto, pero no es
necesario porque nadie va a tratar ni podra conectarse con él.
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
sockfd : es el descriptor de socket devuelto por la función socket().
my_addr: es un puntero a una estuctura sockaddr que contiene la IP del host local y el
número depuerto que se va a asignar al socket.
addrlen :debe ser establecido al tamaño de la estuctura sockaddr. sizeof(struct sockaddr).
 Pasos para establecer la comunicación.
En sockets orientados a conexión el procedimiento es el siguiente:




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 hablilita 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á conectarsecon el servidor.
El servidor ejecuta la f unció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().
Cuando se programan sockets no orientados a conexión la metodología es esta:




Ambos, cliente y servidor, crean un socket mediante la función
socket( ).
El servidor debe establecer por qué número de puerto recibirá los datos, en este
caso no existe la conexión, los datos se envían como si fueran mensajes.
Para realizar transferencia de datos, utilizan las funciones sendto( ) y recvfrom( ).
No es necesario que el servidor llame a la función listen( ), ni tampoco el paso
connect( ) o accept( ).
 Funciones que figuran en la conexión.
listen()
Se llama desde el servidor, habilita el socket para que pueda recibir conexiones.Sólo se
aplica a sockets tipo SOCK_STREAM.
int listen ( int sockfd, int backlog)
sockfd :es el descriptor de socket devuelto por la función socket() que será utilizado para
recibir conexiones.
backlog :es el número máximo de conexiones en la cola de entrada de conexiones. Las
conexiones entrantes quedan en estado de espera en esta cola hasta que se aceptan
( accept () ).
accept( )
Se utiliza en el servidor, con un socket habilitado para recibir conexiones ( listen() ). Esta
función retorna un nuevo descriptor de socket al recibir la conexión del cliente en el
puerto configurado. La llamada a accept() no retornará hasta que se produce una
conexión o es interrumpida por una señal.
int accept ( int sockfd, void *addr, int *addrlen)
sockfd :e s el descriptor de socket habilitado para recibir conexiones.
addr :es un apuntador u a una estructura sockadd_in. Aquí se almacenará informacion de
la conexión entrante. Se utiliza para determinar que host está llamando y desde qué
número de puerto.
addrlen
: debe
ser establecido al tamaño de la estuctura sockaddr.
sizeof(struct sockaddr): accept() no escribirá más de addrlen bytes en addr . Si escribe
menos bytes, modifica el valor de addrlen a la cantidad de bytes escritos.
connect()
Inicia la conexión con el servidor remoto, lo utiliza el cliente para conectarse.
int connect ( int sockfd, struct sockaddr *serv_addr, int addrlen )
sockfd : es el descriptor de socket devuelto por la función socket().
serv_addr : es una estructura sockaddr que contine la dirección IP y número de puerto
destino.
addrlen : debe ser inicializado al tamaño de struct sockaddr
send() y recv()
Después de establecer la conexión, se puede comenzar con la transferencia de datos.
Estas dos funciones son para realizar transferencia de datos sobre sockets stream.
send() y recv() son identicas a write() y read(), exepto que se agrega un parámetro flags.
send ( int sockfd, const void *msg, int len, int flags )
sockfd :e el descriptor socket por donde se enviarán los datos.
msg :apuntador a los datos a ser enviados.
len :ongitud de los datos en bytes.
send() retorna la cantidad de datos enviados, la cual podrá ser menor que la cantidad de
datos que se escribieron en el buffer para enviar. send() enviará la máxima cantidad de
datos que pueda manejar y retorna la cantidad de datos enviados, es responsabilidad del
programador comparar la cantidad de datos enviandos con len y si no se enviaron todos
los datos, enviarlos en la próxima llamada a send().
recv ( int sockfd, void *buf, int len, unsigned int flags )
sockfd : es el descriptor socket por donde se recibirán los datos.
buf :apuntador a un buffer donde se almacenarán los datos recibidos.
len : es la longitud del buffer buf.
Si no hay datos a recibir en el socket , la llamada a recv() no retorna (bloquea) hasta que
llegan datos, se puede establecer al socket como no bloqueante de manera que cuando
no hay datos para recibir la función retorna -1 y establece la variable
errno=EWOULDBLOCK.
recv() retorna el número de bytes recibidos.
sendto() y recvfrom()
Funciones para realizar transferencia de datos sobre sockets datagram.
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const
struct sockaddr *to, int tolen)
sockfd : descriptor socket por donde se enviarán los datos.
Msg : apuntador a los datos a ser enviados.
len :es la longitud de los datos en bytes.
to :es un apuntador a una estructura sockaddr que contiene la dirección IP y número de
puerto destino.
tolen :debe ser inicializado al tamaño de struct sockaddr
sendto() retorna el número de bytes enviados, el cual puede ser menor que len, igual que
en send().
int recvfrom ( int sockfd, void *buf, int len, unsigned int flags, struct
sockaddr *from, int *fromlen )
sockfd :es el descriptor socket por donde se recibirán los datos.
buf :un apuntador a un buffer donde se almacenarán los datos recibidos.
len :es la longitud del buffer buf.
from :es un apuntador a una estructura sockaddr que contiene la dirección IP y número
de puerto del host origen de los datos.
fromlen :debe ser inicializado al tamaño de struct sockaddr.
Si no hay datos a recibir en el socket , la llamada a recvfrom() no retorna (bloquea) hasta
que llegan datos, se puede establecer al socket como no bloqueante de manera que
cuando no hay datos para recibir la función retorna -1 y establece la variable
errno=EWOULDBLOCK.
recvfrom() retorna el numero de bytes recibidos, igual que recv().
close () y shutdown ().
Finalizan la conexión del descriptor de socket.
close ( sockfd): despues de utilizar close, el socket queda desabilitado para
realizar lecturas o escrituras.
shutdown (sockfd, int how):permite desabilitar la comunicación en una
determinada dirección
o en ambas direcciones.
 Código fuente, compilación y ejecución de los sockets.
Ya tenemos conocimiento de las funciones, estructuras y conversiones que requerimos
para implementar sockets así que en las páginas siguientes se mostrarán en primer lugar
el código fuente para los dos tipos de socket que hemos decidido exponer:


No orientado a conexión: que está formado por los archivos clienteEco.c y
servidorEco.c .
Orientado a conexión: consta de dos archivos que son clienteTCP.c y
servidorTCP.c .
Para llevar realzar las dos últimas tarea utilizamos el sistema operativo Fedora 9 para
linux.
clienteEco.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/**********************************************************/
/* función MAIN */
/* Orden Parametros: IP destino, puerto , mensaje */
/* */
/**********************************************************/
main(int argc, char *argv[]) {
int s;
struct sockaddr_in bs,des;
char resp[255];
int *sd;
if (argc == 4) {
// Creamos el socket
s = socket(AF_INET,SOCK_DGRAM,0);
if (s != -1) {
bs.sin_family = AF_INET;
bs.sin_port = htons(0); //Coge cualquier puerto disponible en la máquina
bs.sin_addr.s_addr = htonl(INADDR_ANY); //Coge cualquier IP de la máquina
//Asigna un nombre local al socket
if( bind(s,(struct sockaddr*)&bs, sizeof(bs)) != -1) {
des.sin_family = AF_INET;
des.sin_addr.s_addr = inet_addr(argv[1]);
des.sin_port = htons(atoi(argv[2]));
}
//Envia el string
sendto(s,argv[3],strlen(argv[3])+1,0,(struct sockaddr*)&des,sizeof(des));
printf("\n\n->Enviando: %s, a: %s en el puerto: %s \n",argv[3], argv[1], argv[2]);
//Recibe el string del servidor
recvfrom(s,resp, sizeof(resp) ,0,(struct sockaddr*)&des, sd);
printf("<-Recibido: %s\n",resp);
//Cierra el socket
close(s);
} else {
printf("ERROR al nombrar el socket\n");
}
} else {
printf("ERROR: El socket no se ha creado correctamente!\n");
}
} else {
printf("\n\n\aEl número de parámetros es incorrecto\n\n");
}
servidorEco.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/**********************************************************/
/* función MAIN */
/* Orden Parametros: Puerto */
/* */
/**********************************************************/
main(int argc, char *argv[]) {
int s;
struct sockaddr_in bs, in;
char entrada[255];
int sd;
if (argc == 2) {
// Creamos el socket
s = socket(AF_INET,SOCK_DGRAM,0);
if (s != -1) {
bs.sin_family = AF_INET;
bs.sin_port = htons(atoi(argv[1])); //Asigna el puerto especificado por la línea de comandos
bs.sin_addr.s_addr = htonl(INADDR_ANY); //IP cualquiera de la máquina
//Asigna un nombre local al socket
if( bind(s,(struct sockaddr*)&bs, sizeof(bs)) != -1) {
printf("\n\aServidor ACTIVO escuchando en el puerto: %s\n",argv[1]);
//El while permite atender a múltiples clientes
while (1) {
//Recibe la cadena del cliente
if ( recvfrom(s,entrada, sizeof(entrada) ,0,(struct sockaddr*) &in, &sd)== -1)
perror("Error en recvfrom");
//Devuelve la cadena al cliente
if (sendto(s,strcat(entrada,"\0"),strlen(entrada)+1,0,(struct sockaddr*) &in, sizeof(in))
== -1)
}
perror("Error en sendto");
}
//Se cierra el socket
close(s);
} else {
printf("ERROR al nombrar el socket\n");
}
} else {
printf("ERROR: El socket no se ha creado correctamente!\n");
}
} else {
printf("\n\n\aEl número de parámetros es incorrecto\n\n");
}
Compilación y ejecución de estos sockets:
Servidor:
Cliente:
clienteTCP.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/**********************************************************/
/* función MAIN */
/* Orden Parametros: IP destino, puerto , mensaje */
/* */
/**********************************************************/
main(int argc, char *argv[]) {
int s;
struct sockaddr_in bs,des;
char resp[255];
int *sd;
if (argc == 4) {
// Creamos el socket
s = socket(AF_INET,SOCK_STREAM,0);
if (s != -1) {
bs.sin_family = AF_INET;
bs.sin_port = htons(0); //Asigna un puerto disponible dela máquina
bs.sin_addr.s_addr = htonl(INADDR_ANY); //Asigna una IP de la máquina
//Asigna un nombre local al socket
if( bind(s,(struct sockaddr*)&bs, sizeof(bs)) != -1) {
//Se prepara el nombre de la máquina remota
des.sin_family = AF_INET;
des.sin_addr.s_addr = inet_addr(argv[1]);
des.sin_port = htons(atoi(argv[2]));
//Establece la conexión con la máquina remota
connect(s,(struct sockaddr*)&des,sizeof(des));
}
//Envía el mensaje
send(s,argv[3],strlen(argv[3])+1,0);
printf("\n\n->Enviando: %s, a: %s en el puerto: %s \n",argv[3], argv[1], argv[2]);
//Recibe la respuesta
recv(s,resp, sizeof(resp) ,0);
printf("<-Recibido: %s\n",resp);
//Se cierra la conexión (socket)
close(s);
} else {
printf("ERROR al nombrar el socket\n");
}
} else {
printf("ERROR: El socket no se ha creado correctamente!\n");
}
} else {
printf("\n\n\aEl número de parámetros es incorrecto\n\n");
}
servidorTCP.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_CONN 10 //Nº máximo de conexiones en espera
/**********************************************************/
/* función MAIN */
/* Orden Parametros: Puerto */
/* */
/**********************************************************/
main(int argc, char *argv[]) {
int s,s_aux;
struct sockaddr_in bs,in, out_s;
char entrada[255];
int sd;
if (argc == 2) {
// Creamos el socket
s = socket(AF_INET, SOCK_STREAM,0);
if (s != -1) {
bs.sin_family = AF_INET;
bs.sin_port = htons(atoi(argv[1]));
bs.sin_addr.s_addr = htonl(INADDR_ANY);
//Asigna un nombre local al socket
if( bind(s,(struct sockaddr*)&bs, sizeof(bs)) != -1) {
printf("\n\aServidor ACTIVO escuchando en el puerto: %s\n",argv[1]);
//Espera al establecimiento de alguna conexión
listen(s, MAX_CONN);
//Permite atender a múltiples usuarios
while (1) {
//Establece una conexión
s_aux = accept (s,(struct sockaddr*) &in, &sd);
//Recibe el mensaje del cliente
if ( recv(s_aux,entrada, sizeof(entrada) ,0)== -1)
perror("Error en recvfrom");
//Envia el mensaje al cliente
if (send(s_aux,strcat(entrada,"\0"),strlen(entrada)+1,0) == -1)
perror("Error en sendto");
//Cierra la conexión con el cliente actual
close(s_aux);
}
//Cierra el servidor
close(s);
} else {
printf("ERROR al nombrar el socket\n");
}
} else {
printf("ERROR: El socket no se ha creado correctamente!\n");
}
} else {
printf("\n\n\aEl número de parámetros es incorrecto\n\n");
}
}
Compilación y ejecución de estos sockets.
Servidor TCP
Cliente TCP

Conclusiones.
Gracias al desarrollo de la investigación, hemos podido comprender de mejor manera la
construcción o implementación de sockets en el lenguaje C así como visualizar el
funcionamiento de los mismos.
Otro punto a resaltar es que también se comprendió la diferencia entre sockets
orientados y no orientados a conexión.
Bibliografía
Márquez García, Francisco Manuel.Programación Avanzada en Unix.México.3era Edición., 2004.
 Mesografía.





http://www.eslinux.com/articulos/8591/programacion-sockets-lenguaje-c
http://www.tutorial-enlace.net/tutorial-Programacion_de_sockets_con_C_y_linux-1841.html
http://www.eslinux.com/articulos/8591/programacion-sockets-lenguaje-c
http://www.agapea.com/libros/TCP-IP-Sockets-in-C-2nd-Edition-isbn-0123745403-i.htm
http://foro.elhacker.net/programacion_cc/introduccion_al_uso_de_sockets_en_c-t12480.0.html
Descargar