SpikeL Comunidad
Hola, bienvenido a SpikeL Foro.

Si eres nuevo, deves registrarte.

Si ya tienes una cuenta, deves ingresar.

¡Muchas gracias!

PD: Si te has registrado pero no puedes logear tienes que activar tu cuenta desde tu e-mail.


Unirse al foro, es rápido y fácil

SpikeL Comunidad
Hola, bienvenido a SpikeL Foro.

Si eres nuevo, deves registrarte.

Si ya tienes una cuenta, deves ingresar.

¡Muchas gracias!

PD: Si te has registrado pero no puedes logear tienes que activar tu cuenta desde tu e-mail.
SpikeL Comunidad
¿Quieres reaccionar a este mensaje? Regístrate en el foro con unos pocos clics o inicia sesión para continuar.

Winsock en C

Ir abajo

[ APORTE ] BIEN Winsock en C

Mensaje por PyThioN Sáb Oct 23, 2010 4:55 pm

Usaremos Sockets de Windows (Winsock) ya que todo sistema es usado mayoritariamente en este sistema operativo.

Empezaremos por lo principal, definiendo la palabra “Sockets”.

Socket designa un concepto abstracto por el cual dos programas (posiblemente situados en computadoras distintas) pueden intercambiar cualquier flujo de datos, generalmente de manera fiable y ordenada.

Un socket queda definido por una dirección IP, un protocolo de transporte y un número de puerto.
Bueno, para ello, usaremos el protocolo TCP/IP que es el protocolo normalmente usado para transferir datos, ya que con este protocolo, cada vez que se envia un dato, se espera una respuesta, llegando los paquetes en orden y sin perderse.

A continuacion procederemos a la explicación y a ver las funciones y codigos que utilizaremos.


1.- Explicación

Se conectarán dos pcs, para ello necesitan dos parametros, el
primero es la ip que sería cómo la dirección de tu casa y el otro el puerto que sería con
quien quieres hablar dentro de la casa.
Para ello uno de los dos computadores tiene que estar escuchando y esperando a que
alguien conecte, a este computador se le llama el servidor, y al que conecta se le llama el
cliente. Cuando cliente y servidor han conectado ya pueden recibir o enviar datos sin
preocuparse de nada mas, hasta que se cierre la conexión.

2.-Funciones de winsock

Aquí intentaré explicar todas las funciones que vamos a utilizar en el programa. Si vas a
programar un servidor, solo necesitas las funciones:

2.01,
2.02,
2.04,
2.06,
2.07,
2.08,
2.09 y
2.10
y si vas a programar un cliente necesitas entender las funciones:

2.01,
2.02,
2.03,
2.04,
2.05,
2.09
y 2.10.
2.01.-WSAStartup

Esta función lo que hace es inicializar el winsock en nuestro programa y definir la versión
que vamos a utilizar, lo que cambia entre versiones es que unas tienen mas funciones a
usar y otras menos, nosotros cómo vamos a lo básico sólo nos interesa compatibilidad y
por tanto usaremos la version 2.0 que viene con todos los windows.

Para ello haremos lo siguiente:

Definimos una variable para la inicialización

WSADATA wsa;
Inicializamos determinando la versión 2.0 para ello usamos MAKEWORD que pasará ese
2.0 a una variable de tipo WORD (16bits) que es lo que pide la función. También pasamos
wsa por referencia para que la modifique.

WSAStartup(MAKEWORD(2,0),&wsa);
2.02.-socket

Con la funcion socket lo que hacemos es crear un socket (una conexión para que se
entienda) definiendo el protocolo de la conexión y el tipo de información que se trasmitirá
a través de él.

Definimos un socket

SOCKET sock;
Creamos el socket de tipo AF_INET (protocolo ipv4), SOCK_STREAM (tipo de paquetes
para tcp), IPPROTOTCP (protocolo tcp).

sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
2.03.-gethostbyname

Con gethostbyname lo que hacemos es resolver un dominio cómo podría ser
[Tienes que estar registrado y conectado para ver este vínculo] saturos.org, nosomoszombies.com a la ip que le corresponde, así
luego podremos conectar.

Definimos una estructura del tipo hostent, esta estructura guardará toda la información a
bajo nivel sobre el host al que vayamos a conectar. Si a gethostbyname le pasamos una
ip directamente no la resolverá y la asignará a direc correctamente.

struct hostent *direc;
Ahora resolvemos el nombre del host y se lo asignamos a la direccion.

direc=gethostbyname("[Tienes que estar registrado y conectado para ver este vínculo]
Nota: Si no quisieramos resolver el nombre de dominio podriamos usar la función
inet_addr para transformar la ip de cadena de caracteres a una variable de tipo in_addr.

Pero es mejor utilizar esta función siempre, tiene la misma utilidad que in_addr y además
te resuelve nombres de dominio.

2.04.-htons

Con esta funcion guardaremos el puerto al que vamos a conectar mas adelante.

En el protocolo de red los puertos no se expresan igual que los expresamos nosotros, no
entraremos en detalles pero si tienes curiosidad busca big endian, little endian o tcp/ip
network byte order en google.

un unsigned short se ajusta exactamente al rango en el que pueden ir los puertos, desde
1 hasta 65535.

u_short puerto;
Así transformamos el puerto 9999 “al lenguaje que entenderá” el socket.

puerto=htons(9999);
2.05.-connect

Con esta función conseguiremos conectar con la máquina remota, esta es la parte mas
delicada, intentaré explicarla lo mas detalladamente posible. Para ello haremos uso de las
funciones explicadas anteriormente.

Definimos una variable del tipo sockaddr_in que contendrá la información final de la
dirección a la que vamos a conectar.

struct sockaddr_in remoto;
definimos que la direccion remota usa el protocolo ipv4

remoto.sin_family = AF_INET;
definimos el puerto al que vamos a conectar usando la función htons explicada
anteriormente.

remoto.sin_port = htons(9999);
Ahora viene lo mas delicado, tenemos que la estructura hostent definida anteriormente
tiene un elemento que es la dirección ip (h_addr) usamos -> en lugar de ‘.’ para el
elemento puesto que direc es un puntero.

Pero el h_addr podemos tratarlo cómo un
in_addr (son estructuras diferentes pero pueden usarse igual) pero el compilador para
sin_addr sólo admite in_addr así que le decimos que lo trate cómo tal con (struct in_addr
*) a esto que hemos hecho se le llama casting, ahora tenemos que direc->h_addr es un
puntero a un in_addr.

Pero con esto no nos basta, ya que sin_addr tiene que ser un valor
no un puntero así que a todo le añadimos * delante para que guarde el contenido del
puntero, no el puntero en sí.

Se que si no has tratado mucho con punteros y castings puede resultar un poco
rebuscado pero lo he explicado lo mejor que he podido.

remoto.sin_addr = *((struct in_addr *)direc->h_addr);
Tal y cómo se define en la msdn inicializamos el elemento sin_zero con zeros.

memset(remoto.sin_zero,0,Cool;
Ya podemos usar el connect con sock creado con la función socket, y la estructura remoto
que hemos inicializado, pero connect necesita de un puntero a sockaddr no de un
sockaddr_in así que volvemos a hacer el casting cogiendo la dirección de memoria de
remoto con & y pasandole un puntero a esta direccion tratada como sockaddr.

Además tenemos que pasarle a la función el tamaño de la estructura.

connect(sock, (sockaddr *)&remoto, sizeof(sockaddr));
Una vez hecho esto si no se ha producido ningún error(cómo que la dirección a conectar
no existe.)

ya podemos empezar a enviar y recibir datos.

2.06.-bind

La función bind lo que hace es asociar un socket a una dirección local (por si tubieramos
varias) en nuestro caso podemos considerar que estamos preparando el socket para
ponerlo a la escucha.

Para ello utilizaremos algunas de las funciones explicadas anteriormente.
Definimos una variable del tipo sockaddr_in que contendrá la información de nuestro pc
para que puedan conectar.

struct sockaddr_in local;
definimos que estamos usando el protocolo ipv4

local.sin_family = AF_INET;
Definimos la ip local “por defecto”

local.sin_addr.s_addr = INADDR_ANY;
Definimos el puerto que vamos a poner a la escucha.

local.sin_port = htons(puerto);
Llamamos a la funcion bind con el socket que habiamos creado la dirección local definida
pasada cómo puntero y tratada como SOCKADDR, podríamos decir para entendernos
que SOCKADDR y sockaddr_in son comptabiles y por tanto podemos tratarlo así.

Además pasamos el tamaño de la estructura (cosas internas para la función).

bind(sock, (SOCKADDR*) &local, sizeof(local))
2.07.-listen

Con esta función pondremos definitivamente el socket a la escucha, no se saldrá de ésta
función hasta que alguien haya conectado o se produzca un error.

Ponemos a la escucha el socket creado y le decimos que sólo espere a una conexión.

listen(sock,1);
2.08.-accept

Una vez alguien a conectado a nuestro puerto que estaba a la escucha, tenemos que
aceptar dicha conexión, esto lo hacemos con la función accept.

int len;
len=sizeof(struct sockaddr);
Al aceptar la conexión local contendrá la información de la conexión que se ha establecido
una vez mas tiene que tratarse como sockaddr.

sock=accept(sock,(sockaddr*)&local,&len);
Ahora ya hemos establecido la conexión y estamos preparados para enviar y recibir
datos.

2.09.-recv

Con esta función recibiremos datos de la máquina remota cuando los envie.

int i;
char Buffer[1025];
Le decimos el socket del que queremos recibir datos, la cadena que recibirá la
información, el número de carácteres (bytes) que cómo máximo queremos recibir, el
último parámetro es un flag que marca cómo va actuar la función.

Le daremos o que es lo mas normal.

La función devolverá el número de carácteres recibidos, -1 si se ha producido un error o 0
si se ha cerrado el socket.

i=recv(sock, buffer, 1024, 0);
Lógicamente la función recv no nos guarda el final de cadena en el buffer, lo haremos
nosotros a partir de los carácteres recibidos. (cuidado con ésto, hay que controlar que i no
valga -1 antes de seguir con todo el tratamiento).

buffer=0;
2.10.-send

Usando esta función enviaremos datos a la máquina remota.

char Buffer[]="SaturoS";
Le decimos que envie al socket conectado sock la cadena “SaturoS” tenemos que
decirle cuantos carácteres hay que enviar de la cadena.

El último parámetro definiria el
comportamiento de los paquetes al ser enviados, le daremos 0 que es lo mas normal.
La función devolverá el número de carácteres que se han enviado o -1 en caso de que ya
no estemos conectados.

int enviado=0;
enviado=send(sock,Buffer,strlen(Buffer), 0);
Con esto, ya hemos aprendido a usar Sockets en C, y podríamos hacer el tipico ejemplo de un Chat.
Luego colgaré un par de codigos con ejemplos de SOCKET en C.

Saludos.
avatar
PyThioN
Nivel 6
Nivel 6

Medallas
Winsock en C Prensa1

Mensajes Mensajes : 65
Puntos Puntos : 49751
Reputación Reputación : 3
Sexo Sexo : Masculino

Fecha de inscripción Fecha de inscripción : 17/10/2010
Edad Edad : 25
País País : Argentina

Localización Localización : En mi casa

Volver arriba Ir abajo

Volver arriba


 
Permisos de este foro:
No puedes responder a temas en este foro.