◆ Noções básicas de soquete
PHP usa a biblioteca de soquetes da Berkley para criar suas conexões. Um soquete nada mais é do que uma estrutura de dados. Você usa essa estrutura de dados de soquete para iniciar uma sessão entre o cliente e o servidor. Este servidor está sempre ouvindo e se preparando para gerar uma nova sessão. Quando um cliente se conecta ao servidor, ele abre uma porta na qual o servidor está escutando uma sessão. Neste momento, o servidor aceita a solicitação de conexão do cliente e então executa um ciclo. Agora o cliente pode enviar informações ao servidor e o servidor pode enviar informações ao cliente.
Para gerar um Socket, você precisa de três variáveis: um protocolo, um tipo de soquete e um tipo de protocolo público. Existem três protocolos para escolher ao gerar um soquete. Continue lendo abaixo para obter o conteúdo detalhado do protocolo.
Definir um tipo de protocolo público é um elemento essencial da conexão. Na tabela abaixo, damos uma olhada nos tipos de protocolo comuns.
Tabela 1: Nome do Protocolo/Descrição da Constante
AF_INET Este é o protocolo usado pela maioria dos soquetes, usando TCP ou UDP para transmissão, e é usado em endereços IPv4.
AF_INET6 é semelhante ao acima, mas é usado para endereços IPv6.
Protocolo local AF_UNIX, usado em sistemas Unix e Linux. Raramente é usado quando o cliente e o servidor estão na mesma máquina. Tabela 2: Nome do tipo de soquete/descrição da constante.
SOCK_STREAM Este protocolo é uma conexão baseada em fluxo de bytes sequencial, confiável e integrada a dados. Este é o tipo de soquete mais comumente usado. Este soquete usa TCP para transmissão.
SOCK_DGRAM Este protocolo é uma chamada de transferência de comprimento fixo e sem conexão. Este protocolo não é confiável e usa UDP para suas conexões.
SOCK_SEQPACKET Este protocolo é uma conexão confiável de duas linhas que envia pacotes de dados de comprimento fixo para transmissão. Este pacote deve ser aceito completamente antes de poder ser lido.
SOCK_RAW Este tipo de soquete fornece acesso único à rede. Este tipo de soquete usa o protocolo público ICMP. (ping e traceroute usam este protocolo)
SOCK_RDM Este tipo raramente é usado e não é implementado na maioria dos sistemas operacionais. Ele é fornecido para uso pela camada de enlace de dados e não garante a ordem dos pacotes. Tabela 3: Nome do protocolo público/descrição constante.
Protocolo de mensagens de controle da Internet ICMP, usado principalmente em gateways e hosts para verificar as condições da rede e relatar mensagens de erro
Protocolo de datagrama de usuário UDP, que é um protocolo de transmissão sem conexão e não confiável
O protocolo de controle de transmissão TCP, que é o protocolo público confiável mais comumente usado, pode garantir que o pacote de dados possa chegar ao destinatário. Se ocorrer um erro durante o processo de transmissão, ele reenviará o pacote de erro.
Agora que você conhece os três elementos que geram um soquete, usamos a função socket_create() em PHP para gerar um soquete. Esta função socket_create() requer três parâmetros: um protocolo, um tipo de soquete e um protocolo público. A função socket_create() retorna um tipo de recurso contendo o soquete se for executado com sucesso. Se falhar, retornará falso.
Recursos socket_create(int protocol, int socketType, int commonProtocol);
Agora você cria um soquete, e daí? PHP fornece diversas funções para manipulação de soquetes. Você pode vincular um soquete a um IP, ouvir a comunicação de um soquete e aceitá-lo. Agora vamos ver um exemplo para entender como a função gera, aceita e escuta um soquete;
<?php
$commonProtocol = getprotobyname("tcp");//Use o nome do protocolo público para obter um tipo de protocolo
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);//Gera um soquete e retorna uma instância do recurso de soquete
socket_bind($socket, 'localhost', 1337); // Vincula o soquete ao computador local
socket_listen($socket); //Ouve todas as conexões de soquete recebidas
// Mais funcionalidades de soquete estão por vir
?>
O exemplo acima gera seu próprio lado do servidor. A primeira linha do exemplo,
$commonProtocol = getprotobyname("tcp");
Use o nome do protocolo público para obter um tipo de protocolo. O protocolo público TCP é usado aqui. Se você quiser usar o protocolo UDP ou ICMP, então você deve alterar os parâmetros da função getprotobyname() para "udp" ou "icmp". Outra alternativa é especificar SOL_TCP ou SOL_UDP na função socket_create() em vez de usar a função getprotobyname().
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
A segunda linha do exemplo cria um soquete e retorna uma instância do recurso de soquete. Depois de ter uma instância do recurso de soquete, você deverá vincular o soquete a um endereço IP e a uma porta.
socket_bind($socket, 'localhost', 1337);
Aqui você liga o soquete ao computador local (127.0.0.1) e liga o soquete à sua porta 1337. Então você precisa ouvir todas as conexões de soquete de entrada.
socket_listen($socket);
Após a quarta linha, você precisa entender todas as funções do soquete e seu uso.
Tabela 4: Descrição do nome da função da função de soquete
socket_accept() aceita uma conexão Socket
socket_bind() vincula o soquete a um endereço IP e porta
socket_clear_error() limpa o erro de soquete ou o último código de erro
socket_close() fecha um recurso de soquete
socket_connect() inicia uma conexão de soquete
socket_create_listen() abre um soquete escutando na porta especificada
socket_create_pair() gera um par de soquetes indistinguíveis em um array
socket_create() gera um soquete, que é equivalente a gerar uma estrutura de dados de soquete
socket_get_option() Obtém opções de soquete
socket_getpeername() Obtém o endereço IP de um host remoto semelhante
socket_getsockname() obtém o endereço IP do soquete local
socket_iovec_add() adiciona um novo vetor a uma matriz dispersa/agregada
socket_iovec_alloc() Esta função cria uma estrutura de dados iovec que pode enviar, receber, ler e escrever
socket_iovec_delete() exclui um iovec alocado
socket_iovec_fetch() retorna os dados do recurso iovec especificado
socket_iovec_free() libera um recurso iovec
socket_iovec_set() define o novo valor dos dados iovec
socket_last_error() obtém o último código de erro do soquete atual
socket_listen() escuta todas as conexões do soquete especificado
socket_read() lê dados de comprimento especificado
socket_readv() lê dados da matriz dispersa/agregada
socket_recv() encerra os dados do soquete para o cache
socket_recvfrom() aceita dados do soquete especificado. Se não for especificado, o padrão é o soquete atual.
socket_recvmsg() recebe mensagens do iovec
socket_select() seleção múltipla
socket_send() Esta função envia dados para o soquete conectado
socket_sendmsg() envia mensagem para socket
socket_sendto() envia uma mensagem para o soquete no endereço especificado
socket_set_block() define o soquete para modo de bloqueio
socket_set_nonblock() Define o soquete para modo sem bloqueio
socket_set_option() define opções de soquete
socket_shutdown() Esta função permite fechar a leitura, escrita ou o soquete especificado
socket_strerror() retorna o erro detalhado com o número do erro especificado
socket_write() grava dados no cache do soquete
socket_writev() grava dados em arrays dispersos/agregados. Todas as funções acima estão relacionadas a soquetes em PHP. Para usar essas funções, você deve abrir seu soquete. Se você não o abriu, edite seu arquivo php.ini. seguinte comentário antes desta linha:
extensão=php_sockets.dll
Se você não conseguir remover o comentário, use o código a seguir para carregar a biblioteca de extensões:
<?php
if(!extension_loaded('soquetes')) {
if(strtoupper(substr(PHP_OS, 3)) == “WIN”) {
dl('php_sockets.dll');
}outro{
dl('soquetes.so');
}
}
?>
Se você não sabe se o seu soquete está aberto, você pode usar a função phpinfo() para determinar se o soquete está aberto. Você pode verificar se o soquete está aberto verificando as informações do phpinfo.
Ver informações do phpinfo() sobre socket ◆ Gerar um servidor Agora vamos melhorar o primeiro exemplo. Você precisa ouvir um soquete específico e lidar com as conexões do usuário.
<?php
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337);
socket_listen($socket);
//Aceita qualquer conexão de entrada com o servidor
$conexão = socket_accept($socket);
if($conexão){
socket_write($connection, "Você se conectou ao soquete...nr");
}
?>
Você deve usar seu prompt de comando para executar este exemplo. A razão é porque um servidor será gerado aqui, não uma página da Web. Se você tentar executar este script usando um navegador da web, há uma boa chance de que ele exceda o limite de 30 segundos. Você pode usar o código abaixo para definir um tempo de execução infinito, mas é recomendado usar o prompt de comando para executar.
set_time_limit(0);
Basta testar este script em seu prompt de comando:
Php.exe exemplo01_server.php
Se você não definiu o caminho para o interpretador php nas variáveis de ambiente do seu sistema, você precisará especificar o caminho para php.exe. Ao executar o servidor, você pode testá-lo conectando-se à porta 1337 via telnet.
Existem três problemas com o lado do servidor acima: 1. Ele não pode aceitar múltiplas conexões. 2. Ele completa apenas um comando. 3. Você não pode se conectar a este servidor por meio de um navegador da web.
Este primeiro problema é mais fácil de resolver, você pode usar um aplicativo para se conectar ao servidor sempre. Mas o próximo problema é que você precisa usar uma página da Web para se conectar ao servidor, o que é mais difícil. Você pode fazer com que seu servidor aceite a conexão, grave alguns dados no cliente (se for necessário), feche a conexão e aguarde a próxima conexão.
Melhore o código anterior e gere o seguinte código para fazer seu novo servidor:
<?php
//Configura nosso soquete
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337); //socket_bind() vincula o soquete a um endereço IP e porta
socket_listen($socket);
//Inicializa o buffer
$buffer = "SEM DADOS";
enquanto(verdadeiro) {
//Aceita qualquer conexão que venha neste soquete
$connection = socket_accept($socket); //socket_accept() aceita uma conexão Socket
printf("Soquete conectadorn");
//Verifica se há algo no buffer
if($buffer != ""){
printf("Algo está no buffer...enviando dados...rn");
socket_write($connection, $buffer . "rn"); //socket_write() grava dados no cache do soquete
printf("Escreveu no soquetern");
}outro {
printf("Nenhum dado no bufferrn");
}
//Obtém a entrada
while($data = socket_read($connection, 1024, PHP_NORMAL_READ))//socket_read() lê dados de comprimento especificado
{
$buffer = $dados;
socket_write($connection, "Informações recebidasrn");
printf("Buffer: " . $buffer . "rn");
}
socket_close($connection); //socket_close() fecha um recurso de soquete
printf("Soquete fechadornrn");
}
?>
O que este servidor deve fazer? Inicializa um soquete e abre um cache para enviar e receber dados. Ele aguarda uma conexão e, uma vez estabelecida a conexão, imprime "Socket conectado" na tela do lado do servidor. Este servidor verifica o buffer e se houver dados no buffer, ele os envia para o computador conectado. Em seguida, ele envia uma mensagem de aceitação para esses dados. Depois de aceitar a mensagem, ele salva a mensagem nos dados, informa o computador conectado sobre a mensagem e, finalmente, fecha a conexão. Quando a conexão é encerrada, o servidor começa a processar a próxima conexão.
◆ É fácil gerar um cliente para lidar com o segundo problema. Você precisa gerar uma página php, conectar-se a um soquete, enviar alguns dados para seu cache e processá-los. Então você terá os dados processados aguardando e poderá enviá-los para o servidor. Em outra conexão do cliente, ele processará esses dados.
O exemplo a seguir demonstra o uso de soquetes:
<?php
//Cria o socket e conecta
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$conexão = socket_connect($socket,'localhost', 1337);
while($buffer=socket_read($socket, 1024, PHP_NORMAL_READ)) {
if($buffer == "SEM DADOS") {
echo(“<p>SEM DADOS</p>”);
quebrar;
}outro{
//Faça algo com os dados no buffer
echo(“<p>Dados do buffer: “ . $buffer . “</p>”);
}
}
echo(“<p>Escrevendo no Socket</p>”);
// Escreve alguns dados de teste em nosso soquete
if(!socket_write($socket, “ALGUNS DADOSrn”)){
echo(“<p>Falha na gravação</p>”);
}
// Lê qualquer resposta do soquete
while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)){
echo(“<p>Os dados enviados foram: SOME DATA<br> A resposta foi:” . $buffer . “</p>”);
}
echo(“<p>Leitura concluída do soquete</p>”);
?>
Este código de exemplo demonstra o cliente se conectando ao servidor. O cliente lê os dados. Se esta for a primeira conexão a chegar neste ciclo, o servidor enviará “NO DATA” de volta ao cliente. Se isso acontecer, o cliente estará no topo da conexão. O cliente envia seus dados para o servidor, os dados são enviados para o servidor e o cliente aguarda uma resposta. Assim que a resposta for recebida, ele a grava na tela.