Professional Documents
Culture Documents
DEFINICIN DE SOCKET
Un socket es un punto de comunicacin por el cual un proceso puede emitir o
recibir informacin. En el interior de un proceso, se identificar por un descriptor de la
misma naturaleza que los que identifican los archivos.
Caractersticas de un socket
A cada una de ellas le corresponde una constante simblica predefinida en el
archivo <sys/socket.h>.
Dominio de un socket:
Conjunto de sockets con los cuales se podr establecer una comunicacin por medio
de l. Asimismo, especifica el formato de las direcciones que se podrn dar al socket y los
diferentes protocolos soportados por las comunicaciones va los sockets de este conjunto.
La estructura genrica para el formato de una direccin de socket es:
struct sockaddr{
u_short
char
};
sa_family;
/* familia de direccin */
sa_data[14]; /* 14 octetos de direccin (mximo) */
struct sockaddr_in{
short
sin_family;
u_short
sin_port;
struct in_addr sin_addr;
char
sin_zero[8];
};
Para comunicar utilizando los protocolos Internet, el primer campo tendr como
valor AF_INET. El segundo campo ser un nmero de puerto; en el caso de servicios
estndares, se podr utilizar un nombre simblico para designar el puerto
(IPPORT_TCP o IPPORT_TELNET) y en el caso contrario, un nmero de puerto
nulo o superior a IPPORT_RESERVED. El tercer campo es una direccin Internet (en
representacin estndar) o el valor INADDR_ANY (en el caso de que el sistema local
sea una pasarela y, por tanto, disponga de varias direcciones diferentes). El ltimo campo
sirve para hacer coincidir el tamao de esta estructura con la de la estructura de direccin
genrica sockaddr (14 octetos de direccin mximo-).
Tipo de un socket:
Define las propiedades de las comunicaciones en las cuales est implicado.
Propiedades de comunicacin
1. Fiabilidad de la transmisin. Ningn dato transmitido se pierde.
2. Conservacin del orden de los datos. Los datos llegan en el orden en el
que han sido emitidos.
3. No duplicacin de datos. Slo llega al destino un ejemplar de cada dato
emitido.
4. Comunicacin en modo conectado. Se establece una conexin entre dos
puntos antes del principio de la comunicacin. A partir de entonces, una
emisin desde un extremo est implcitamente destinada al otro extremo
conectado.
5. Conservacin de los lmites de los mensajes. Los lmites de los mensajes
emitidos se pueden encontrar en el destino.
6. Envo de mensajes <<urgentes>>. Corresponde a la posibilidad de enviar
datos fuera del flujo normal y por consecuencia accesibles
inmediatamente (datos fuera de flujo u out of band).
Tipos disponibles
SOCK_DGRAM Sockets destinados a la comunicacin en modo
no conectado para el envo de datagramas de tamao limitado. Las
comunicaciones correspondientes tienen la propiedad 5. En el dominio
Internet, el protocolo subyacente es el protocolo UDP.
Supresin:
Un socket es suprimido cuando ya no hay ningn proceso que posea un descriptor
para accederlo. Esta supresin es el resultado de, al menos, una llamada a la primitiva
close.
Enlazamiento socket-direccin
Primitiva bind:
Despus de su creacin, un socket no es accesible ms que por los procesos que
conocen su descriptor. La primitiva bind permite con una sola operacin dar un nombre
a un socket:
int bind (sock, p_direccion, lg)
int
sock;
struct sockaddr *p_direccion;
int
lg;
/* descriptor de socket */
/* puntero de memoria a la direccin */
/* longitud de la direccin */
El dominio Unix:
Los sockets de este dominio no se destinan ms que a una comunicacin local. Por
tanto, les corresponden direcciones locales que son referencias UNIX idnticas a las de los
archivos.
Un socket de este dominio aparecer despus del nombrado en los resultados
producidos por la orden ls con el tipo s. La supresin de una referencia de este tipo es por
medio de la orden rm o de la primitiva unlink.
La orden siguiente ilustra la creacin y conexin de un socket del dominio UNIX:
$ sockunix /tmp/a &
[1] 17271
enlazamiento conseguido
$ cat sockunix.c
/* Orden de creacin y nombrado de un socket del dominio UNIX.
El nombre del socket se da como parmetro */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
void main (int n, char *v[])
{
int sock; /* descriptor del socket */
static struct sockaddr_un adr; /* direccin del socket */
if (n != 2) {
fprintf(stderr, error de parmetro\n);
exit(2);
}
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock == -1) {
perror(socket);
exit(2);
}
adr.sun_family = AF_UNIX;
bcopy(v[1], adr.sun_data, strlen(v[1]));
if (bind(sock, &adr, sizeof(adr)) == -1) {
perror(bind);
exit(2);
}
printf(enlazamiento conseguido\n);
while (1);
}
El dominio Internet:
La conexin a una direccin Internet de un socket de este dominio necesita la
preparacin de un objeto que tenga la estructura sockaddr_in. Esto supone:
- el conocimiento de la direccin de la mquina local (primitiva gethostname y
funcin gethostbyname) o la eleccin del valor INADDR_ANY;
- la eleccin de un nmero de puerto. Puerto de un servicio existente (funcin
getservbyname), cualquier nmero de puerto (>=IPPORT_RESERVED) elegido por
el usuario o eleccin del sistema (valor 0 en el campo sin_port).
En ciertas circunstancias, un proceso puede disponer de un descriptor de un socket
conectado o enlazado a una direccin, pero sin saber cul es (si la conexin ha sido
realizada por otro proceso y el proceso ha heredado el descriptor o si la conexin ha sido
realizada sin especificar el nmero de puerto).
La primitiva getsockname permite recuperar la direccin relacionada con el socket
de descriptor sock.
int getsockname (sock, p_adr, p_lg)
int
sock; /* descriptor del socket */
struct sockaddr *p_adr; /* puntero a la zona de direccin */
int
*p_lg; /* puntero a la longitud de la direccin */
Cuando se llama a esta primitiva, el tercer parmetro se utiliza como dato y como
resultado:
- en la llamada, *p_lg tiene como valor el tamao de la zona reservada a la
direccin p_addr para recuperar la direccin del socket;
- en el retorno de la llamada, *p_lg tiene como valor el tamao efectivo de la
direccin.
El valor de retorno de la primitiva es 0 -1, segn si la llamada ha tenido xito o
no.
A continuacin, se muestra el cdigo de una funcin crearsock, que permite la
creacin y la conexin de un socket del dominio Internet:
$ cat crearsock.c
/* Funcin de creacin de un socket.
Nmero de puerto dado como parmetro (modificado si 0).
Se devuelve como resultado el descriptor del socket. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int crearsock (int *port, int type)
{
int desc; /* descriptor del socket */
struct sockaddr_in nom; /* direccin del socket */
int longitud; /* longitud de la direccin */
/* creacin del socket */
if ( (desc = socket(AF_INET, type, 0) == -1) {
perror(creacin imposible del socket);
exit(2);
}
/* preparacin de la direccin */
bzero((char *)&nom, sizeof(nom));
nom.sin_port = *port;
nom.sin_addr.s_addr = INADDR_ANY;
nom.sin_family = AF_INET;
if ( bind(desc, &nom, sizeof(nom)) == -1 ) {
perror(nombrado del socket imposible);
exit(3);
}
longitud = sizeof(nom);
if ( getsockname(desc, &nom, &longitud) == -1 ) {
perror(obtencin del nombre del socket);
exit(4);
}
*port = ntohs(nom.sin_port);
return (desc);
}
lgdest;
Aadir que no es necesario que un socket est nombrado para que pueda ser
utilizado para enviar un mensaje con la primitiva sendto. El sistema realiza
automticamente su conexin durante el primer envo.
Es prctico utilizar la primitiva sendmsg en el caso que un proceso deba realizar
una sucesin de envos de mensajes. El inters de utilizar esta primitiva es que se realiza el
envo de varios mensajes con una sola llamada al sistema, lo que mejora el rendimiento. La
forma de esta primitiva es:
int sendmsg (sock, msg, opcion)
int
sock;
struct msghdr msg[];
int
opcion;
/* direccin opcional */
/* tamao de la direccin */
/* tabla de mensajes */
/* n de elementos en msg_iov */
/* inutilizada para los sockets */
/* inutilizada para los sockets */
Primitiva recvfrom:
int recvfrom (sock, msg, lg, opcion, p_exp, p_lgexp)
int
char
sock;
*msg;
Esta primitiva permite a un proceso extraer un mensaje de un socket del cual posea
un descriptor. Para que haya un mensaje, naturalmente es preciso que este socket haya sido
enlazado o conectado a una direccin (o pseudoconectado en su creacin con la primitiva
socketpair) y que un proceso haya enviado un mensaje despus de que haya tenido lugar
este enlace.
El papel del parmetro lg es el de dar el tamao del espacio reservado para
memorizar el mensaje que ser extrado. Es preciso no perder de vista que se extraer del
socket un mensaje completo, que corresponde exactamente a la informacin enviada en una
sola operacin sendto. La informacin recibida provendr de un solo mensaje y los
caracteres del mensaje se perdern si el parmetro lg es menor que la longitud del mensaje
recibido. La primitiva devuelve el nmero de caracteres recibidos (-1 en caso de error).
Adems, la llamada es bloqueante si no hay ningn mensaje para extraer del socket salvo
peticin contraria formulada previamente con una llamada a la primitiva ioctl de la forma:
#include <sys/ioctl.h>
.
.
int sock;
int on = 1;
.
.
ioctl(sock, FIONBIO, &on);
.
.
En el caso en el que el puntero p_exp es distinto de NULL, a la vuelta, la zona de
direccin p_exp contiene la direccin del socket emisor. Es esencial en el caso en que la
llamada *p_lgexp contiene el tamao de la zona reservada a la direccin p_exp; a la vuelta,
*p_lgexp tiene el valor de la longitud efectiva de la direccin. El proceso receptor tiene
entonces la posibilidad de responder, si hay necesidad de ello, al mensaje recibido por
medio de la primitiva sendto (recordemos que los sockets permiten la comunicacin en los
dos sentidos).
Esto queda esquemticamente en el dominio Internet:
.
.
struct sockaddr_in adr;
int sock, n, lg, lgrep;
char msg[1024], rep[1024];
.
.
lg = sizeof(struct sockaddr_in);
n = recvfrom(sock, msg, 1024, 0, &adr, &lg);
.
.
n = sendto(sock, rep, lgrep, 0, &adr, lg);
.
.
La opcin MSG_PEEK permite consultar el socket: se lee un mensaje, pero no se
extrae como es el caso sin esta opcin.
La primitiva recvmsg permite realizar una serie de recepciones de mensajes:
int recvmsg (sock, msg, opcion)
int
sock;
struct msghdr msg[];
int
opcion;
Ejemplo completo
El siguiente ejemplo completo pone en relacin un proceso cliente con un proceso
servidor (un proceso <<demonio>>). Los dos procesos intercambian datagramas en el
dominio. El proceso servidor est en espera de recepcin de mensajes sobre un socket
enlazado a un puerto UDP conocido por los clientes que quieren dirigirse a l (aqu,
PORT = 2222). Una peticin formulada por un cliente consiste simplemente en una cadena
de caracteres que el cliente quiere saber si corresponde a la identificacin de un usuario
sobre el sistema al que pertenece el servidor, y si es ste el caso, obtener las informaciones
(contenidas en el archivo /etc/passwd) relativas a este usuario.
El servidor:
El cdigo del servidor comporta las siguientes etapas:
1. Creacin y enlace al puerto de servicio de un socket (se utiliza la funcin
crearsock descrita anteriormente).
2. Desconexin del servidor de su terminal de lanzamiento o ejecucin.
3. Bucle infinito en el cual el servidor:
Espera una peticin.
La trata (llamada a la funcin estndar getpwnam que
permite consultar el archivo /etc/passwd).
Pone la forma de respuesta (el campo type permite distinguir
el caso que el usuario es desconocido (1) y el que no lo es (2).
Enva la respuesta.
El servidor se ejecuta en background.
$ cat quienesd.c
/* Servidor Internet en el puerto UDP nmero 2222 que devuelve las */
/* informaciones relativas a un usuario cuyo nombre se le ha dado */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <pwd.h>
#define LGUSER 20
#define LGREP 256
#define PORT 2222
void main (int n, char *v[])
{
int lg, sock, port, n;
int d;
char user[LGUSER]; /* el mensaje recibido */
struct sockaddr_in adr; /* direccin del socket remoto */
struct passwd *getpwnam(), *p;
/* la respuesta enviada */
struct respuesta {
char type; /* 1: error; 2: OK */
char info[LGREP]; /* las informaciones pedidas si type = 2 */
} rep;
port = PORT;
if ( (sock = crearsock(&port, SOCK_DGRAM)) == -1 ) {
fprintf(stderr, Fallo en la creacin/conexin del socket\n);
exit(2);
}
/* desconexin del servidor del terminal */
close(0); close(1); close(2);
if ( (d = open(/dev/tty)) > -1 ) {
ioctl(d, TIOCNOTTY, 0);
close(d);
}
setpgrp();
while (1) { /* espera de pregunta sobre el socket */
lg = sizeof(adr);
bzero(user, LGUSER);
bzero((char *)&rep, sizeof(rep));
n = recvfrom(sock, user, LGUSER, 0, &adr, &lg);
if ( (p = getpwnam(user)) == NULL)
rep.type = 1;
else {
rep.type = 2;
sprintf(rep.info, %d %d %s %s %s\n, p->pw_uid,
p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
}
/* envo de la respuesta */
El Cliente:
Su cdigo comporta las siguientes etapas:
1. Creacin del socket local (su enlace o conexin no es necesario, ya que
el cliente comenzar emitiendo y el enlace se realizar
automticamente).
2. Preparacin de la direccin del servidor.
3. Envo del mensaje.
4. Espera del resultado.
5. Explotacin del resultado.
$ cat user.c
/* Programa que permite obtener las informaciones contenidas en el
archivo /etc/passwd de una mquina de nombre dado como primer
parmetro, concernientes a un usuario que se da como segundo
parmetro.
El servicio correspondiente en la mquina remota est asociado al
puerto 2222 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#define PORT 2222
#define LGREP 256
void main (int n, char *v[])
{
int lg, sock, uid, gid, n;
char p[LGREP];
struct sockaddr_in adr;
struct hostent *hp;
struct {
char type;
char info[LGREP];
} rep;
if (n < 3) {
fprintf(stderr, nmero de parmetros incorrecto\n); exit(2); }
/* preparacin de la direccin del socket destino */
if ( (hp = gethostbyname(v[1])) == NULL ) {
perror(nombre de la mquina);
exit(2);
}
bzero((char *)&adr, sizeof(adr));
sock = socket(AF_INET, SOCK_DGRAM, 0);
adr.sin_family = AF_INET;
adr.sin_port = htons(PORT);
bcopy(hp->h_addr, &adr.sin_addr, hp->h_length);
/* envo del mensaje constituido por el nombre del usuario */
if ( sendto(sock, v[2], strlen(v[2]), 0, &adr, sizeof(adr)) == -1 ) {
perror(sendto);
exit(2);
}
/* espera de la respuesta por parte del servidor */
lg = sizeof(adr);
n = recvfrom(sock, (char *)&rep, sizeof(rep), 0, &adr, &lg);
/* explotacin de la respuesta */
if ( rep.type == 1 )
fprintf(stderr, %s: usuario desconocido en %s\n, v[2], v[1]);
else {
printf(usuario %s en %s\n\n, v[2], v[1]);
sscanf(rep.info, %d %d % [^\n], &uid, &gid, p);
printf( uid = %d gid = %d \n, uid, gid);
printf( %s \n, p);
}
}
$ user germinal dupond
dupond: usuario desconocido en germinal
$ user germinal jmr
usuario jmr en germinal
uid = 102 gid = 20
Rifflet Jean-Marie /ens/jmr /bin/csh
La estructura hostent se encuentra predefinida en netdb.h y corresponde a una
entrada en el archivo /etc/hosts:
struct hostent{
char
char
int
int
*h_name;
**h_aliases;
h_addrtype;
h_length;
char
**h_addr_list; /* lista de direcciones */
#define h_addr h_addr_list[0]
/* la primera direccin de la lista */
};
Las <<pseudoconexiones>>
Este mecanismo permite simplemente alegar la escritura de aplicaciones en el caso
de que un socket del tipo SOCK_DGRAM no se utilice ms que para comunicar slo con
otro. Sin embargo, es necesario tener en cuenta que una pseudocomunicacin de este tipo
no modifica en nada las caractersticas generales del modo de comunicacin (en particular
en lo que concierne a su fiabilidad).
Primitiva connect:
Utilizada con sockets del tipo SOCK_DGRAM, permite asociar un socket de
direccin dada a un socket local (dado por su descriptor). Se ver que tiene un papel
diferente con los sockets SOCK_STREAM.
int connect (sock, p_adr, lgadr)
int
sock;
struct sockaddr *p_adr;
int
lgadr;
Primitiva socketpair:
Permite crear dos sockets y asociarlos.
int socketpair (dominio, tipo, protocolo, p_sock)
int dominio; /* AF_UNIX */
int tipo;
/* SOCK_DGRAM, SOCK_STREAM */
int protocolo; /* 0 */
int *p_sock; /* tabla de dos enteros */
Se recupera en la direccin *p_sock el valor de los descriptores de los dos sockets
creados. Adems, con esta primitiva no se puede trabajar ms que localmente (es decir, en
el dominio UNIX).
Primitiva send:
La direccin de destino es implcita.
int send (sock, msg, lg, opcion)
int
char
int
int
sock;
*msg;
lg;
opcion;
Primitiva recv:
La direccin de origen es implcita.
int recv (sock, msg, lg, opcion)
int
char
sock;
*msg;
int
lg;
int
opcion;
la fiabilidad;
el aspecto continuo de la informacin (<<flujo>>).
Creacin de un subproceso
fork
PADRE
HIJO
Tratamiento de la demanda
Primitiva listen:
Esta primitiva permite a un servidor sealar a un sistema que acepta las peticiones
de conexin.
Para llamar con xito a la primitiva listen (por tanto, con valor de retorno 0), el
proceso debe disponer de un descriptor de socket del tipo SOCK_STREAM. Si el socket no
est previamente enlazado a un puerto, el sistema procede a este enlace. En este caso, ser
necesario hacer una llamada a la primitiva getsockname para conocer el nmero del puerto
atribuido.
int listen (sock, nb)
int sock;
int nb;
Primitiva accept:
Esta primitiva permite extraer una conexin pendiente en el archivo asociado a un
socket para la cual se ha realizado una llamada a listen. De esta manera, el sistema toma
conocimiento de un enlace realizado. Como se ha dicho, el enlace con el socket del cliente
se realiza con un nuevo socket cuyo descriptor se enva como resultado de la funcin:
int accept (sock, p_adr, p_lgadr)
int
sock;
/* descriptor del socket */
struct sockaddr *p_adr;
/* direccin del socket conectado */
int
*p_lgadr; /* puntero al tamao de la zona reservada a */
/* p_adr */
El socket de servicio creado se enlaza a un nuevo puerto (tomado del conjunto de
puertos no reservados).
A la vuelta, tambin se recupera en memoria, en la zona apuntada por p_adr, la
direccin del socket del cliente con el cual se ha establecido la conexin. El valor de
/* preparacin de la direccin */
bzero((char *)&nom, sizeof(nom));
nom.sin_port = *port;
nom.sin_addr.s_addr = INADDR_ANY;
nom.sin_family = AF_INET;
if ( bind(desc, &nom, sizeof(nom)) == -1 ) {
perror("nombrado del socket imposible");
exit(3);
}
longitud = sizeof(nom);
if ( getsockname(desc, &nom, &longitud) == -1 ) {
perror("obtencin del nombre del socket");
exit(4);
}
*port = ntohs(nom.sin_port);
return (desc);
}
void main (int n, char *v[])
/* Servidor Internet en el puerto TCP nmero 1234 */
{
int sock_escucha, sock_service;
struct sockaddr_in adr;
int lgadr = sizeof(adr);
int d;
int port = PORT;
/* creacin del socket de escucha */
if ( (sock_escucha = crearsock(&port, SOCK_STREAM)) == -1 ) {
fprintf(stderr, "Fallo en la creacin/conexin del socket\n");
exit(2);
}
/* desconexin del servidor del terminal */
close(0); close(1); close(2);
if ( (d = open("/dev/tty", O_RDWR)) > 0 ) {
ioctl(d, TIOCNOTTY, 0);
close(d);
}
/* eliminacin de procesos de servicio que terminan; */
/* el proceso servidor ignora la seal SIGCLD */
signal(SIGCLD, SIG_IGN);
/* creacin de la cola de conexiones pendientes */
listen(sock_escucha, 5);
/* bucle de aceptacin de la conexin */
while (1) {
lgadr = sizeof(adr);
sock_service = accept(sock_escucha, &adr, &lgadr);
if (fork() == 0) {
/* el proceso de servicio no utiliza el socket de escucha */
close(sock_escucha);
/* llamada a la funcin de servicio */
service(sock_service);
exit(0);
}
/* el proceso padre no utiliza el socket de servicio */
close(sock_service);
}
}
Fallo
Demanda de conexin
connect
xito
Dilogo con el servidor
Primitiva connect:
Toda conexin entre dos sockets del tipo SOCK_STREAM, en un dominio distinto
del UNIX, es el resultado de una llamada con xito a esta primitiva (en el dominio UNIX,
una llamada a la primitiva socketpair crea un par de sockets conectados). As, se crea un
circuito virtual entre los dos procesos cuyos extremos son los sockets. Este circuito permite
intercambios bidireccionales.
La forma de la primitiva es idntica a la que hemos dado para la pseudoconexin de
sockets dedicados al intercambio de datagramas:
int connect (sock, p_adr, lgadr)
int
sock;
struct sockaddr *p_adr;
int
lgadr;
La emisin:
La escritura sobre un socket conectado es directamente realizable por medio de la
primitiva de escritura estndar write:
int write (sock, msg, lg)
int sock;
char *msg;
int lg;
Sin embargo, una operacin de este tipo no permite utilizar plenamente los
mecanismos ofertados por los protocolos particulares (por ejemplo, para el protocolo TCP,
la posibilidad de enviar informaciones urgentes). En el caso en que se desea explotar estas
posibilidades, es necesario utilizar la primitiva especfica send:
int send (sock, msg, lg, opcion)
int sock;
char *msg;
int lg;
int opcion;
La recepcin:
Igual que para la emisin sobre un socket, es posible utilizar la primitiva estndar de
lectura:
int read (sock, msg, lg)
int sock;
char *msg;
int lg;
y la primitiva recv que permite, por una parte, la extraccin de informacin urgente
(MSG_OOB) y, por otra parte, la consulta sin extraccin (MSG_PEEK).
int recv (sock, msg, lg, opcion)
int sock;
char *msg;
int lg;
int opcion;
El corte de la conexin:
La primitiva:
int shutdown (desc, sens)
int desc;
int sens;
/* descriptor de socket */
/* 0, 1 2 */
permite a un proceso especificar que ya no desea recibir (sens = 0), emitir (sens = 1) o ni
recibir ni emitir (sens = 2) sobre un socket conectado de descriptor desc.
$ cliente germinal 1234
$ hostname
germinal
$ ^D
$
/* en la mquina remota */
/* volvemos a la mquina local */
$ cat cliente.c
/* Programa que recibe como parmetros el nombre de la mquina remota y el puerto de
escucha al que solicita una conexin. A continuacin, lee una orden del teclado, la transmite
y lee la respuesta en el socket; finalmente visualiza el resultado en la pantalla. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#define TAMANO 256
void main (int n, char *v[])
{
int desc; /* descriptor del socket creado */
struct sockaddr_in nom; /* direccin del socket destino */
struct hostent *hp, *gethostbyname();
char com[TAMANO]; /* para las comunicaciones */
if (n != 3) {
fprintf(stderr, "nmero de parmetros incorrecto\n"); exit(1); }
/* creacin del socket */
if ( (desc = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
perror("creacin del socket imposible"); exit(2); }
/* bsqueda de la direccin internet del servidor */
if ( (hp = gethostbyname(v[1])) == NULL ) {
fprintf(stderr, "%s: lugar desconocido\n", v[1]);
exit(3);
}
/* preparacin de la direccin del socket destino */
bcopy(hp->h_addr, &nom.sin_addr, hp->h_length);
nom.sin_family = AF_INET;
nom.sin_port = htons(atoi(v[2]));
/* demanda de conexin */
if ( connect(desc, &nom, sizeof(nom)) == -1 ) {
perror("connect"); exit(4); }
bzero(com, TAMANO);
while ( scanf("%s", com) != EOF ) {
com[strlen(com)] = '\n'; /* Indispensable al shell!!! */
send(desc, com, strlen(com), 0);
bzero(com, TAMANO);
recv(desc, com, TAMANO, 0);
printf("%s", com);
bzero(com, TAMANO);
}
}