Beruflich Dokumente
Kultur Dokumente
uses
SysUtils,Winsock;
var
wsa: WSADATA;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
end.
Temos nossa primeira varivel:
var
wsa: WSADATA;
Uma varivel do tipo WSADATA armazena informaes sobre a inicializao do
Winsock. Esta passada como segundo argumento da funo WSAStartup:
if(WSAStartup($101,wsa) = -1) then // Se ocorrer um erro
begin
writeln('Ocorreu um erro ao inicializar o Winsock.'); // Mostra mensagem
exit; // Encerra
end;
No trecho acima, tentamos inicializar a verso 1.1 do Winsock (o smbolo $ utilizado
para nmeros hexadecimais. $101 = 257).
Veja a sintaxe:
WSAStartup(VERSO: WORD,var VARIVEL_WSA: WSADATA);
VERSO:
verso do winsock a ser inicializada;
VARIVEL_WSA:
varivel do tipo WSADATA.
A funo ir retornar o valor -1 se falhar. Do contrrio, retornar ZERO.
A funo WSAStartup(), na verdade, requer um ponteiro para uma varivel do tipo
WSADATA como segundo parmetro, no entanto, s necessrio passar o nome da
varivel. Isso se explica devido declarao do parmetro:
var VARIVEL_WSA: WSADATA);
Quando temos "var" antes do parmetro, significa que ser passado o endereo
(ponteiro) da varivel, e no o seu valor =)
Muito bem, aps inicializarmos o Winsock, podemos utilizar as funes contidas na
Winsock API.
Temos agora que criar um socket:
program programa1;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
sock: integer;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
end.
Temos mais uma varivel declarada:
sock: integer;
Esta varivel ir armazenar a identificao do nosso socket criado. Geralmente, ao invs
do tipo Integer (inteiro), variveis deste tipo so declaradas como SOCKET. Entretanto,
"SOCKET" apenas um "novo nome" para o tipo inteiro, ou seja, o tipo "SOCKET" ,
na verdade, o tipo inteiro =)
Vejamos a criao do socket:
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
O trecho acima tenta criar um socket para ser utilizado com o protocolo TCP. Isto
definido pelo segundo parmetro: SOCK_STREAM.
Sintaxe:
sock := socket(FAMLIA: Integer,PROTOCOLO: Integer,TIPO: Integer);
sock:
varivel do tipo inteiro que ir identificar o socket;
FAMLIA:
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
addr.sin_family := AF_INET;
addr.sin_port := htons(1234);
addr.sin_addr.S_addr := INADDR_ANY;
if(bind(sock,addr,sizeof(addr)) = -1) then
begin
writeln('Ocorreu um erro ao configurar o socket.');
exit;
end;
if(listen(sock,1) = -1) then
begin
writeln('Ocorreu um erro ao colocar o socket na escuta.');
exit;
end;
sock := accept(sock,nil,nil);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao aceitar uma conexo.');
exit;
end;
writeln('Um cliente conectou-se!');
closesocket(sock);
WSACleanup();
end.
Antes de tudo, para configurarmos um socket, devemos declarar uma estrutura do tipo
SOCKADDR_IN:
addr: sockaddr_in;
Vamos ver como o socket configurado:
addr.sin_family := AF_INET; // Corresponde famlia a qual o socket pertence
addr.sin_port := htons(1234); // Corresponde porta na qual o socket ir aguardar
conexes
addr.sin_addr.S_addr := INADDR_ANY; // Permite que o socket aceite conexo de
qualquer host
H dois detalhes que devem ser observados:
addr.sin_port := htons(1234); // Correto
O membro "sin_port", da estrutura "addr", um inteiro de 2 bytes e requer um valor
expresso em network byte. Para convertemos um valor para tal, utilizamos a funo
htons(). A forma abaixo estaria incorreta:
uma nova varivel (inteiro) que ir armazenar a identificao do novo socket; se o nome
do prprio socket for utilizado, no ser possvel aceitar novas conexes;
sock:
nome do nosso socket;
pt_addr:
ponteiro para uma varivel do tipo "SOCKADDR" que ir armazenar informaes sobre
o cliente que se conectou;
tamanho:
ponteiro para uma varivel do tipo inteiro que armazena o tamanho da estrutura
"SOCKADDR";
A funo ir retornar o valor -1 se falhar. Do contrrio, retornar ZERO.
No nosso exemplo, usamos:
sock := accept(sock,nil,nil);
No caso, a varivel "sock" ser utilizada para armazenar a identificao do novo socket
aps um pedido de conexo ter sido feito. Observe que, como no iremos armazenar
informaes sobre o cliente, passamos os dois ltimos argumentos como NULOS, isto
, passando o ponteiro nulo: "nil".
Vejamos agora:
closesocket(sock);
WSACleanup();
So duas funes ainda no vistas anteriormente. Utiliza-se a funo closesocket() para
fechar um socket aps seu uso e WSACleanup() para finalizar o uso do Winsock.
Sintaxe:
closesocket(sock);
sock:
nome do socket.
A funo WSACleanup() no possui parmetros.
Mais adiante, quando abordaremos algumas funes, veremos como obter informaes
do cliente conectado.
No exemplo acima, criamos um socket para atuar com servidor. A seguir, iremos criar
um socket para atuar como cliente:
program programa2;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
sock: integer;
addr: sockaddr_in;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
addr.sin_family := AF_INET;
addr.sin_port := htons(1234);
addr.sin_addr.S_addr := inet_addr('127.0.0.1');
if(connect(sock,addr,sizeof(addr)) = -1) then
begin
writeln('Ocorreu um erro ao conectar-se.');
exit;
end;
writeln('Conectado!');
closesocket(sock);
WSACleanup();
end.
Como voc pode observar, o cdigo necessrio para tal bem menor
Vejamos as diferenas:
addr.sin_addr.S_addr := inet_addr('127.0.0.1');
A linha acima configura o socket para se conectar no IP "127.0.0.1".
Em seguida, fazemos com que o socket tente conectar-se:
if(connect(sock,addr,sizeof(addr)) = -1) then
begin
writeln('Ocorreu um erro ao conectar-se.');
exit;
end;
A sintaxe da funo connect() similar da funo bind() - que no necessria quando
estamos trabalhando com um socket cliente - veja:
connect(sock: Integer; var addr: sockaddr_in; tamanho: Integer);
sock:
nome do nosso socket;
addr:
var
buffer: array[0..99] of char;
begin
ZeroMemory(@buffer,100); // Limpa o buffer, necessrio incluir "Windows" na
clsula "Uses".
recv(sock,buffer,100,0);
end.
A sintaxe :
recv(sock: Integer; var Buf; tam_buffer: Integer; Flags: Integer);
sock:
nome do nosso socket;
Buf:
buffer que ir armazenar os dados recebidos;
tam_buffer:
tamanho do buffer;
flags:
valores opcionais que especificam o modo de recebimento.
A funo, em situao normal, retorna o nmero de bytes recebidos. Se algum erro
ocorrer, a funo retorna -1.
Vejamos um exemplo:
servidor:
program servidor;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock, Windows; // Windows -> para usar ZeroMemory()
var
wsa: WSADATA;
sock: integer;
addr: sockaddr_in;
buffer: array[0..100] of char; // Buffer para enviar/receber dados
envia: string; // Armazenar uma string digitada
bytes: integer; // Nmero de bytes recebidos
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
addr.sin_family := AF_INET;
addr.sin_port := htons(1234);
addr.sin_addr.S_addr := INADDR_ANY;
if(bind(sock,addr,sizeof(addr)) = -1) then
begin
writeln('Ocorreu um erro ao configurar o socket.');
exit;
end;
if(listen(sock,1) = -1) then
begin
writeln('Ocorreu um erro ao colocar o socket na escuta.');
exit;
end;
sock := accept(sock,nil,nil);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao aceitar uma conexo.');
exit;
end;
bytes := 0; // 0 byte recebido
while(bytes <> -1) do // Enquanto o nmero de bytes retornando for diferente de -1 =
conectado
begin
ZeroMemory(@buffer,100); // Zera buffer
recv(sock,buffer,100,0); // Recebe dados do cliente
writeln(buffer); // Mostra-os
ZeroMemory(@buffer,100); // Limpa o buffer novamente
readln(envia); // L uma string
StrLCopy(buffer,PChar(envia),100); // Copia at 100 caracteres para o buffer
send(sock,buffer,strlen(buffer),0); // Envia os dados
end;
// Encerra
closesocket(sock);
WSACleanup();
end.
cliente:
program cliente;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock, Windows; // Windows -> para usar ZeroMemory()
var
wsa: WSADATA;
sock: integer;
addr: sockaddr_in;
buffer: array[0..100] of char; // Buffer para enviar/receber dados
envia: string; // Armazenar uma string digitada
bytes: integer; // Nmero de bytes recebidos
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_STREAM,0);
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
addr.sin_family := AF_INET;
addr.sin_port := htons(1234);
addr.sin_addr.S_addr := inet_addr('127.0.0.1');
if(connect(sock,addr,sizeof(addr)) = -1) then
begin
writeln('Ocorreu um erro ao conectar-se.');
exit;
end;
bytes := 0; // 0 byte recebido
while(bytes <> -1) do // Enquanto o nmero de bytes retornando for diferente de -1 =
conectado
begin
ZeroMemory(@buffer,100); // Limpa o buffer
addr: sockaddr_in;
begin
...
host := gethostbyname('www.google.com.br');
if(host = nil) then
writeln('Erro ao resolver o host!')
else
writeln('O IP e: ' + inet_ntoa(PInAddr(host.h_addr^)^));
No exemplo acima, tentamos resolver o host "www.google.com.br" e mostrar o seu
respectivo IP. Como vimos anteriormente, a expresso "PInAddr(host.h_addr^)^"
retorna o endereo IP de um host como valor "in_addr" - justamente o tipo de valor
requirido pela funo inet_ntoa().
FIM da primeira parte
Na continuao do artigo, veremos melhor como trabalhar com a funo
gethostbyname() e outras funes. Veremos ainda o uso do protocolo UDP.
Pois bem, continuemos com o nosso artigo.
Abaixo segue uma pequena lista de aspectos abordados no artigo anterior:
1) Vimos o que necessrio para trabalhar com a API do Winsock (WSA) no Delphi;
2) Foram mostrados os passos que devem ser seguidos para criar um socket
simples, abordando, exclusivamene, o protocolo TCP;
3) Ainda com base no protocolo TCP, foram ilustrados exemplos de um programa
que atuava como cliente e um outro servidor;
4) Utilizando as funes send() e recv(), aprendemos a como enviar e receber
dados, respectivamente atravs de um socket;
5) Algumas noes de variveis, estruturas, funes e converses;
Neste ltimo item, ficou pendente a explicao do uso de funo gethostbyname()
aplicada em outras situaes, alm de outras funes do ramo, como
getservbyport(), que tambm ser aborda nesta parte do artigo.
Para comear, vamos retomar o ltimo exemplo da primeira parte do tutorial:
var
...
host: PHostEnt; // PHostEnt = ponteiro para a estrutura hostent
addr: sockaddr_in;
begin
...
host := gethostbyname('www.google.com.br');
if(host = nil) then
writeln('Erro ao resolver o host!')
else
writeln('O IP e: ' + inet_ntoa(PInAddr(host.h_addr^)^));
No exemplo acima, tentamos resolver o host "www.google.com.br" e mostrar o seu
respectivo IP. Como vimos anteriormente, a expresso "PInAddr(host.h_addr^)^"
retorna o endereo IP de um host como valor "in_addr" - justamente o tipo de valor
requirido pela funo inet_ntoa().
Como se sabe, devemos especificar dados sobre um host remoto para que seja
possvel uma conexo entre o computador local e este. Sabemos ainda que, para
tanto, devemos utilizar uma estrutura denominada "sockaddr_in", que contm trs
principais membros:
sin_family -> indica a famlia do socket;
sin_port -> indica a porta na qual o socket ir atuar;
sin_addr -> indica o endereo utilizado pelo socket, seja este local ou remoto;
Dando nfase ao ltimo, sabemos que o utilizamos quando queremos, por exemplo,
estabelecer uma conexo entre o computador local e um outro remoto cujo IP
200.123.123.123:
addr.sin_addr.S_addr = inet_addr('200.123.123.123');
Como se sabe, com o auxlio da funo inet_addr(), podemos converter um
endereo IP escrito na forma de string ('200.123.123.123') para seu valor
correspondente na forma in_addr (network byte) que a adequada.
Existem casos, no entanto, em que no sabemos o endereo IP do computador
remoto, e pior ainda: s vezes, at sabemos, entretanto, este IP pode ser
dinmico, isto , no-fixo. Em situaes assim, se tivssimos que tomar como base
apenas o endereo IP de hosts remotos, teramos grande dificuldades de
comunicao. Felizmente, podemos utlizar o "hostname" de um computador como
referncia, dessa forma, no importa qual endereo IP que este computador esteja
utlizando, pois, ao contrrio de endereos IPs, o hostname fixo, ou seja, mesmo
que o endereo IP de um servidor seja alterado, atravs do seu hostname podemos
acess-lo.
Mas a questo : como aplicar isso em nossos programas? para responder a essa
pergunta que este artigo foi comeado com ltimo exemplo da parte 1 do tutorial
xD
Vamos fazer uma anlise rpida no seguinte trecho:
var
wsa: WSADATA; // Para inicializar o winsock
host: PHostEnt; // PHostEnt = ponteiro para a estrutura hostent
begin
if(WSAStartup($101,wsa) = -1) then
exit; // Encerra se falhar
host := gethostbyname('www.google.com.br');
end.
um exemplo um pouco que repetitivo, eu diria. Mas continuemos:
var
wsa: WSADATA;
host: PHostEnt; // PHostEnt = ponteiro para a estrutura hostent
begin
if(WSAStartup($101,wsa) = -1) then
exit;
host := gethostbyname('www.google.com.br');
if(host = nil) then
// Erro
else
// Host resolvido com sucesso xD
end.
Quando a funo gethostbyname() falha em resolver um hostname, um ponteiro
nulo (nil) retornado. Fazemos o tratamento de erros com base nessa propriedade.
var
wsa: WSADATA;
host: PHostEnt; // PHostEnt = ponteiro para a estrutura hostent
addr: sockaddr_in; // Uma estrutura do tipo sockaddr_in
begin
if(WSAStartup($101,wsa) = -1) then
exit;
host := gethostbyname('www.google.com.br');
if(host = nil) then
exit // Encerra se falhar
else
addr.sin_addr := PInAddr(host.h_addr^)^;
end.
Com base no cdigo acima, voc consegue responder a questo inicial xD ?
O que exatamente ocorre que, ao utilizar a funo gethostbyname() passando
como parmetro o hostname 'www.google.com.br', esta funo tentar resolver
este hostname, isto , obter seu endereo IP, seu nome oficial, dentre outros
dados. Como vimos na parte anterior do texto (e no incio desta), a combinao
PInAddr(host.h_addr^)^ nos retorna o endereo IP de um host j convertido para
"in_addr" que nos possibilita us-lo como valor para o membro "sin_addr" da
estrutura "sockaddr_in".
A partir deste ponto, j se pode utilizar a funo connect(), por exemplo, para criar
uma conexo com o computador cujo hostname utlizamos.
Veja o exemplo:
program exemplo;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
sock: integer;
addr: sockaddr_in;
host: PHostEnt;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_STREAM,0);
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
serv := getservbyport(htons(80),'tcp'); // Tenta obter o servico associado porta
80 tcp
if(serv = nil) then // Falha ao obter
writeln('Servico desconhecido')
else
writeln('Servico: ' + serv.s_name); // Imprime o nome do servio
WSACleanup();
end.
Neste exemplo, tentamos obter o nome do servio associado porta 80 sob o
protocolo TCP. Para tal, usamos a funo getservbyport(), cuja sintaxe simpificada
:
getservbyname (porta_em_network_byte,protocolo_string);
porta_em_network_byte:
a porta utilizada pelo servio que queremos obter, convertida para network byte
(htons());
protocolo_string:
o protocolo sob o qual o servio atua;
Geralmente, quando a funo retorna um ponteiro nulo, porque no foi
encontrado um servio associado porta especificada. No entanto, a funo
tambm pode retornar este tipo de ponteiro mesmo que o servio exista. Veja
como isso possvel:
program exemplo;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
serv: PServEnt;
begin
{
Comentamos esta parte do cdigo responsvel pela inicializao do Winsock;
Como se sabe, sem esta inicializao prvia, todas as outras funes
dependentes retornaro em erro, assim como getservbyname()
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
}
serv := getservbyport(htons(80),'tcp');
if (serv = nil) then
writeln('Servico desconhecido.')
else
writeln('Servico: ' + serv.s_name);
WSACleanup();
end.
Provalmente, ao executar o primeiro cdigo, a sada do programa deveria ter sido:
Servico: http
E neste ltimo, a sada seria:
Servico desconhecido
Como se v no cdigo, o programa no chama pela funo WSAStartup() e, por
esta razo, a funo getservbyname() retornou em erro. Se, por algum motivo, o
cdigo fosse aplicado em um programa, o bug estaria evidenciado.
Para resolver este impasse, podemos utitilizar uma funo muito til:
WSAGetLastError(), que nos retorna um inteiro (integer) com ltimo cdigo de erro
ocorrido no uso do winsock.
Veja:
program exemplo;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
serv: PServEnt;
begin
{
Comentamos esta parte do cdigo responsvel pela inicializao
do Winsock;
Como se sabe, sem esta inicializao prvia, todas as outras funa
dependentes retoraram em erro, assim como getservbyname()
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
}
serv := getservbyport(htons(80),'tcp');
if (serv = nil) and (WSAGetLastError() = 0) then
writeln('Servico desconhecido.')
wsa: WSADATA;
nome_local: array[0..99] of char;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
if(gethostname(nome_local,100) = 0) then
writeln('Host Name local: ' + nome_local)
else
writeln('Erro ao obter o hostname local.');
WSACleanup();
end.
Observe que declaramos o array de char "nome_local" de 100 caracteres. neste
buffer em que o hostname local do computador ser armazenado. A sintaxe da
funo :
gethostname(buffer,tamanho);
buffer:
um array de char no qual o hostname local ser armazenado;
tamanho:
o tamanho do buffer em bytes
Se a funo falhar, o valor retornado -1; em caso de xito, a funo retornar
ZERO.
Muito bem. Vamos abordar o uso do protocolo UDP atravs do winsock. Porm,
antes de faz-lo, vejamos algumas diferenas bsica entre os protocolo TCP e este
ltimo:
Protocolo TCP
1) um protocolo orientado a conexo, isto , um fluxo de dados entre
cliente/servidor s poder ser feito caso haja uma conexo entre estes dois hosts;
2) Por retransmitir pacotes de dados perdidos, considerado um protocolo confivel
no aspecto de entrega/recibo de dados;
3) Como conseqncia das duas caractersticas acima, o protocolo TCP mais lento
do que o UDP
Protocolo UDP
1) No orientado a conexo, ou seja, so somente necessrias as informaes de
porta/endereo remoto para que dados possam ser enviados/recebidos
2) Por no ser um protocolo dependente de conexo, no h garantia de entrega de
um determinado pacote enviado (ao contrrio do TCP) o que torna o protocolo noconfivel.
3) Em contra-partida, o protocolo mais rpido do que o TCP quando se trata de
fluxo de dados.
Uma vez em que o protocolo UDP no orientado a conexo, podemos deduzir que
o uso da funes connect() e listen()/accept() so desnecessrias em sua aplicao.
Como foi dito anteriormente, basta saber o endereo remoto de um host e sua
porta para que possamos enviar dados para este, utilizando o protocolo UDP. O
mesmo se aplica entrada de dados. Com o protocolo TCP, utitlizamos,
respectivamente, as funes send() e recv(). No protocolo UDP, as coisas mudam
um pouco: utiliza-se sendto() para o envio de dados, e recvfrom() para recebermos
dados. Segue abaixo um cdigo que mostra a criao de um socket que trabalhe
sob o protocolo UDP:
program exemplo;
{$APPTYPE CONSOLE}
uses
SysUtils,Winsock;
var
wsa: WSADATA;
sock: integer;
addr: sockaddr_in;
buffer: array [0..99] of char;
begin
if(WSAStartup($101,wsa) = -1) then
begin
writeln('Ocorreu um erro ao inicializar o Winsock.');
exit;
end;
sock := socket(AF_INET,SOCK_DGRAM,0); // Utilizamos SOCK_DGRAM e no
SOCK_STREAM
if(sock = -1) then
begin
writeln('Ocorreu um erro ao criar o socket.');
exit;
end;
addr.sin_family := AF_INET;
addr.sin_port := htons(1234);
addr.sin_addr.S_addr := inet_addr('200.123.123.123');
buffer := 'Enviando um string atravs do protocolo UDP!';
if(sendto(sock,buffer,strlen(buffer), 0,addr,sizeof(addr)) = -1) then
begin
writeln('Erro ao enviar dados!');
exit;
end;
closesocket(sock);
WSACleanup();
end.
O primeiro ponto a ser observado no cdigo acima que, ao invs de utilizarmos
SOCK_STREAM como segundo parmetro da funo socket(), utilizamos
SOCK_DGRAM que a constante correta para o protocolo UDP.
Nada de novo. Apenas configura-se localmente o socket de tal forma que este
utilize a porta 1234 para receber/enviados dados.
ZeroMemory(@buffer,100);
tam_addr := sizeof(sockaddr_in);
if(recvfrom(sock,buffer,100,0,addr_remoto,tam_addr ) = -1) then
begin
writeln('Erro na funcao recvfrom()');
exit;
end;
Neste trecho, preenche-se com zero todo o buffer, ou podemos simplesmente dizer
que limpa-se o "buffer" para que ele possa armazenar ocasionais dados. Na
prxima linha, estamos atribuindo varivel "tam_addr" o tamanho, em bytes, da
estrutura "sockaddr_in". E, desmembrando um pouco mais o cdigo, temos:
if(recvfrom(sock,buffer,100,0,addr_remoto,tam_addr ) = -1) then
begin
writeln('Erro na funcao recvfrom()');
exit;
end;
no trecho acima que, de fato, aguardamos por dados vindos de algum cliente.
Vejamos a sintaxe:
recvfrom(sock: Integer; var Buf; tam_buffer: Integer; flags: Integer,
addr:sockaddr_in, var tam);
sock:
nome do nosso socket;
Buf:
buffer que ir armazenar os dados recebidos;
tam_buffer:
tamanho do buffer;
flags:
valores opcionais que especificam o modo de recebimento.
addr:
varivel do tipo sockaddr_in que contm as informaes de endereo/porta do host
remoto;
tam_addr:
varivel que armazena o tamanho da estrutura sockaddr_in;
A funo, assim como recv(), retornar o nmero de bytes recebidos, exceto
quando algum erro ocorrer, onde o valor -1 retornado.
Para finalizar:
writeln('Dados recebidos!' + #10);
writeln('IP: ' + inet_ntoa(addr_remoto.sin_addr));
writeln('Porta: ' + inttostr(ntohs(addr_remoto.sin_port)));
writeln('Dados:' + buffer);