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
}