Article View: es.comp.os.linux.programacion
Article #18795Re: Info sobre Sockets
From: rdiazmar
Date: Fri, 09 Jul 1999 00:00
Date: Fri, 09 Jul 1999 00:00
205 lines
8047 bytes
8047 bytes
On Sat, 3 Jul 1999 18:09:20 +0200, Tony <cheng@jet.es> wrote:
Esto lo escrib� yo para GNU-C no es que sea muy bueno pero es un comienzo..
.........................................................................
Bueno para los que no saben hacerlo paso a dar una breve explicaci�n
(basica)
A ver si nos animamos y participamos mas...
------------Como hacer un cliente por Rober Diaz :-) -----------------
Buneo los tutorials y ejemplos a veces se lian o porque no van al grano o
porque van demasiado al grano.. esto es lo basico que hay que saber para
que un cliente funcione..
Primero hemos de saber como se manejan los datos... lo mas importante es
la estructura sockaddr, que para el caso de conexiones a internet se llama
sockaddr_in (hay un tipo sockaddr general por las que no nos preocupamos
ahora).
_Todas_ las fuciones a las que deberemos de pasar o que nos pasaran
informacion sobre numero de puerto, direccion ip o familia de protocolos
usan esta estructura por eso es tan importante.. o sea que sin ella no
vamos a ningun lado..
Esta estructura tiene el siguiente aspecto: (segun los ultimos tipos
primitivos propuestos)
struct sockaddr_in {
unit8_t sin_len;
/* Longitud de la estructura: una sockaddr_in tiene _siempre_ 16 bytes
este campo se a�ade para guardar compatibilidad con todos los demas tipos
de estructura sockaddr_ */
sa_family_t sin_family;
/* Familia de protocolos: esto en nuestro caso _siempre_ es AF_INET
definido en los encabezados */
in_port_t sin_port;
/* Puerto: variable de 16 bit, compatible con IPv4-6 numero de puerto
ordenado segun el orden de red */
struct in_addr sin_addr;
/* Direccion IP propiamente dicha: 32 bit IPv4, ordenados segun el orden
de red */
char sin_zero[8];
/* Por compatibilidad con otros sockaddr_ de longitud variable */
};
O sea que las estructuras sockaddr_in _siempre_ son de 16 bytes, el orden
de los bits en los campos que guardan la direcci�n IP y el numero de
puerto estan en el orden de la red.
Ahora si alguno se pregunta que es eso del orden de la red? pues facil..
en la red la representacion siempre es Big Endian, o sea el bit mas
significativo al comienzo de la direcci�n de memoria.. mientras que en
linux es Little Endian, o sea el bit menos significativo al comienzo de la
direcci�n de memoria.
Esto plantea un problema.. hay que pasar los datos de little endian a big
endian.. esto es lo que hacen la familia de funciones htons().. (Host TO
Network Short en este caso).. es decir estas funciones solo ayudan en el
cambio de los datos a representacion de red.
Es _siempre_ necesario usarlas aunque estuviesemos en un UNIX big endian,
dado que si no nuestro cliente no seria portable a otros con
representacion little endian, en caso de otros UNIX big endian son macros
nulas.
La estructura in_addr simplemente almacena la direcci�n IP propiamente
dicha:
struct in_addr{
in_addr_t s_addr;
/* inicialmente se trat� de la union de un long mas una estructura
constituida por 4 char (quedaban definidos cada uno de los numeros
empleados en la notacion xxx.xxx.xxx.xxx) ahora se ha definido un tipo
primitivo para su implementaci�n. */
};
De los miembros de la estructura sockaddr_in los importantes y los que
debemos rellenar son: .in_addr, .sin_family y .sin_port
struct sockaddr_in serv; (pseudocodigo)
/* lo primero que debemos hacer es rellenar la estructura con ceros, eso
es importante hacerlo siempre dado que el kernel puede comprobar otros
campos adem�s de los que nosotros rellenamos para ello se puede usar o
bzero() o memset(), se recomienda memset() */
memset((struct sockaddr *) &serv, 0, sizeof(serv));
/* se procede a rellenar la estructura */
serv.sin_family = AF_INET;
serv.sin_port;
serv.sin_addr;
para rellenar serv.sin_port empleamos HostTONetworkShort htons(),
cambiando asi su representacion a big endian,
unsigned long int puerto = 119;
serv.sin_port = htons(puerto);
para rellenar serv.sin_addr podemos usar inet_aton (inet_AscciTONetwork).
char *ip;
ip = "123.124.145.223"; /* direcci�n IP necesaria */
struct in_addr server;
inet_aton(ip, &server);
/* inet_aton() nos devolvera cero si el formato de la direccion ip es
incorrecto de otro modo nos devolver� un numero mayor que cero. Menor que
cero si se produce cualquier otro error */
ser.sin_addr = server;
Ahora ya tenemos rellena la estructura con los datos necesarios podemos
pasar a establecer la conexi�n.
Un cliente es siempre muy sencillo solo usa las funciones socket() y
connect().
Hay que tener en cuenta que una conexi�n IP queda univocamente determinada
por dos puertos y dos direcciones ip (correspondientes a los dos estremos
de la comunicaci�n).. �como se especifica el primer extremo?
La respuesta es que para un cliente esto frecuentemente no es necesario,
dado que el kernel se ocupa de reservar un puerto disponible y toma la
direcci�n ip del interfac de salida, sin embargo podr�amos especificarlo
usando bind(), en este caso no vamos a hacerlo.
/* creamos un asa de comunicaci�n */
int sockfd;
sockfd = socket (AF_INET, SOCK_STREAM, 0);
/* vemos que no hemos especificado nada que no sea general, solamente la
familia de protocolos el tipo de socket y que se use el protocolo por
defecto, no se necesita nada caracteristico ni del cliente ni del
servidor. Un socket es como tener un telefono, nada mas, para usarlo no es
necesario conocer su numero. */
Ahora conectamos al servidor. Decimos a que servidor usando la estructura
sockaddr antes preparada:
connect(sockfd, (struct sockaddr *) &serv, sizeof(serv));
/* ambas funciones devuelven -1 caso de fallar y ponen errno al valor
adecuado no olvideis verificar y en caso de error usar perror() */
Cuando connect() retorna exitosamente, tras esperar una cantidad de tiempo
de hasta un minuto si es necesario nuestro sockfd queda listo para ser
usado en la comunicaci�n.
A partir de entonces simplemente se usa write() o read(), o funiones de
I/O analogas para establecer la comunicaci�n.
Este es el codigo que siempre se emplea en los clientes en el dominio
internet para una comunicaci�n TCP/IP, cierto que podriamos implementarlo
de otro modo (incluidos raw sockets puestos a ser oscuros y exotericos)
pero eso ya se ver� mas adelante.
Si hubiesemos usado bind() para nuestro socket antes de efectuar el
connect() incluso podr�amos haber hecho un spoofing (pero todav�a no hemos
llegado al punto de saber lo suficiente para caer en esa tentaci�n).
Bueno pues que se me hace tarde ma�ana sigo con un ejemplo y continuo con
un servidor b�sico. Tambi�n contar� proximamente como se cierra bien un
socket.
----------------------------------------------------------------------------
>Hay un manual sobre programaci�n de sockets en el programa "info", pero est�
>en ingl�s (como casi todo). Creo que estaba dentro del manual de las
>librer�as de C.
>
>Jorge L�pez escribi� en mensaje <377d061d@dial-in.encomix.es>...
>>Hola a todos.
>>
>>Estoy iniciandome a la programaci�n de sockets y agradecer�a si alguien
>>conoce alguna dir�cci�n interesante sobre la programaci�n de estos.
>>
>>Gracias.
>>
>>
>
>
--
Saludos
Roberto D�az <rdiazmar@nova.es>
http://www.linuxfocus.org/developer/Roberto
Technical Details
Message-ID:
<slrn7occ81.16u.rdiazmar@localhost.localdomain>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailReferences:
<377d061d@dial-in.encomix.es> <7lovdd$2r2$1@diana.bcn.ttd.net>Show Full Headers
Complete Article Headers
X-Google-Language: SPANISH,ASCII X-Google-Thread: f86c8,eebfd124c9fbd7f5 X-Google-Attributes: gidf86c8,public From: rdiazmar@localhost.localdomain () Subject: Re: Info sobre Sockets Date: 1999/07/09 Message-ID: <slrn7occ81.16u.rdiazmar@localhost.localdomain> X-Deja-AN: 499186267 Content-Transfer-Encoding: 8bit References: <377d061d@dial-in.encomix.es> <7lovdd$2r2$1@diana.bcn.ttd.net> Organization: Nova Internet Content-Type: text/plain; charset=iso-8859-1 Mime-Version: 1.0 Newsgroups: es.comp.os.linux.programacion