Sockets en Windows

Tema Sockets Versión 1.01
Resumen Este documento describe como iniciar una conexión TCP usando la API de winsock
Sistema Operativo WINDOWS 9x, Me, NT, 2000, XP
Autor Gonzalo D. Merayo Fecha 23/8/2001
Búsqueda Socket – WSAStartup –setsockopt – bind – connect – send – recv

1) Inicialización de Winsock

Antes de llamar a cualquier función de la API de winsock hay que iniciarla.

Inicialización de la API Winsock:

La misma se crea mediante el uso de la función WSAStartup. La misma recibe 2 parámetros:

1. wVersionRequested: La versión más reciente de winsock el programador puede usar, para lo que necesitamos es suficiente con MAKEWORD(1, 1).

2. lpWSAData: un puntero a una estructura WSADATA que recibirá detalles sobre la versión de Winsock.

2) Creación y Configuración del Socket

Antes de iniciar la conexión hay que crear y configurar un socket

Creación del Socket:

La misma se logra usando la función Socket con los siguientes parámetros:

1. af: Formato de las direcciones, debe ser AF_INET.

2. type: Tipo de conexión, existen muchas características sobre la conexión para configurar, básicamente alcanza con SOCK_STREAM.

3. protocol: Protocolo a usar, en caso de comunicaciones por internet puede ser IPPROTO_TCP o IPPROTO_UDP. Existen otros tipos de protocolo para redes IPX y otros, pero no son compatibles con internet. 0 si no se desea especificar protocolo.

El valor devuelto es del tipo SOCKET, en realidad es int, y si no hubo error es distinto de 0

Configuración del Socket

Para configurar el socket se usa setsockopt con los siguientes parámetros:

1. s: el socket que configuraremos.

2. level: para nosotros IPPROTO_TCP

3. optname: opciones de la comunicación SO_REUSEADDR | SOCK_STREAM.

4. optval: Puntero a buff donde se guardan las opciones.

5. optlen: tamaño del buffer.

Binding del Socket

Antes de conectarse con el servidor remoto, se debe obtener un puerto local para la conexión. Para esto se usa la función bind que toma:

1. s: Socket al que se le asignara el puerto.

2. addr: Dirección local del socket.

3. namelen: Longitud de addr.

Devuelve 0 si todo sale bien

3) Conexión del Socket

Conexión del Socket

Esta es a través de la función connect con los siguientes parámetros:

1. s: Socket al que se le asignara el puerto.

2. name: Dirección remota del socket.

3. namelen: Longitud de name.

Devuelve 0 si todo sale bien.

4) Transferencia de datos

Envío de datos

Se hace a través de send con estos parámetros:

1. s: Identificador del Socket.

2. buf: Puntero a la información a enviar.

3. len: Longitud de los datos a enviar.

4. flags: no se necesita ninguno para sock stream, 0

Devuelve la cantidad de bytes enviados exitosamente.

Recepción de datos

Se hace a través de recv:

1. s: Identificador del socket

2. buff: buffer donde se recibirán los datos

3. len: longitud del buffer

4. flags: 0

Devuelve la cantidad de bytes puestos en el buffer, 0 significa que la conexión se cerro. Si el socket no tiene ninguna información esperando, entonces recv espera que llegue algún paquete.

Si tiene alguna cantidad de bytes, pone tantos como puede en el buffer y sale.

5) Destrucción del Socket

Para cerrar un socket se llama a la función closesocket que recibe un único parámetro que es el numero de socket.

6) Ejemplo

Este ejemplo se conecta a el servidor de http de yahoo y baja el contenido del index a la pantalla:

#include <winsock.h>
#include <iostream.h>
 int c;
 void main (void)
{
 SOCKADDR_IN remend; //info del servidor remoto
 SOCKADDR_IN lclend; //info de la maquina local
  WORD wVersionRequested; //para inicializar el winsock
 WSADATA wsaData; //para inicializar el winsock
 wVersionRequested = MAKEWORD(1, 1); //para inicializar el winsock
 WSAStartup(wVersionRequested, &wsaData); //para inicializar el winsock
  SOCKET remot = socket(AF_INET, SOCK_STREAM, 0);//creo un socket
 // if(remot!=INVALID_SOCKET) cout <<"ok";
 setsockopt (remot, IPPROTO_TCP, SO_REUSEADDR | SOCK_STREAM, (char*)&c, sizeof(int));
 // le cargo las caracteristicas de la coneccion
 // | TCP_NODELAY
  lclend.sin_family = AF_INET; //tipo de comunicacion
 u_short alport = IPPORT_RESERVED; //ultimo port asignablw
 lclend.sin_addr.s_addr = 0; //direccion local
 do {
   remend.sin_port = htons(alport);
   alport--;
 }while (bind (remot, (LPSOCKADDR)&lclend, sizeof (SOCKADDR_IN)) != 0);
  // servidor de http de yahoo
 remend.sin_addr.s_addr = (64) | (58<<8) | (76<<16) | (227<<24);
 remend.sin_port = ntohs(80); //port del http
 remend.sin_family = AF_INET;
  /*cout <<*/ connect(remot, (LPSOCKADDR)&remend, sizeof (SOCKADDR_IN)); //conectarse
 char *buff = new char[100];
 strcpy(buff, "GET /index.html\n");
 send (remot, buff, strlen(buff), 0); //pedido de info
  while (recv(remot, buff, 1, 0)) //copio de a 1 por que no es un string
 // y sino al tirarlo a la pantalla hace fruta
  cout << (char)*buff; //mandar todo lo recibido a la panrtalla
 delete[] buff;
  //la comunicacion tcp esta terminada cuando recv devolvio 0
 closesocket (remot); //cierra el socket
}