COLUNA: Agora vamos de mergulho no código de distribuição
e ter um olhar para o contexto em que o código que você escreve
vai estar em funcionamento.
No final do dia, você está indo para implementar
a totalidade do servidor web.
Mas nós fornecemos -lo com o esqueleto
código que tem algumas funcionalidades, particularmente relacionadas com a rede.
Vamos dar uma olhada.
>> Então, aqui em cima em direção ao topo do arquivo é um bando
de recurso de teste requisitos macro.
Agora, esta é apenas uma característica de c, segundo o qual de acordo com um monte de páginas man
você tem que definir alguns dos essas constantes para ser verdade
ou ser até mesmo números específicos, para que você tem acesso a determinadas funções.
Caso contrário, eles serão não declarado e você não terá acesso.
Então eu fiz isso por meio de ler as páginas do manual.
Agora lá em baixo, na linhas 15 a 17, nós
tem um monte de limites declarados.
>> E nós temos emprestado estes a partir de um servidor web popular chamado Apache.
E estes são apenas números que vão
para limitar o número total de bytes que são permitidos
em vários contextos para a solicitação HTTP que um navegador é permitido para me enviar.
Em seguida, definimos octetos.
Agora, um octeto é apenas uma maneira elegante de dizer um byte, ou oito bits.
Acontece que no passado um byte não era necessariamente oito bits,
assim octeto é sempre oito bits.
Portanto, neste caso adotamos o que é comum na rede
mundo de chamar oito bytes um octeto.
>> Aqui eu especifiquei que vai octetos ser 512, de modo que muito parecido em medicina forense
quando lemos um monte de bytes de cada vez, também aqui,
vamos ler um bando de octetos de cada vez.
Em seguida um monte de arquivos de cabeçalho.
Como eu sabia para incluir estes?
Bem, eu simplesmente ler o homem páginas para um número de funções
que vamos usar neste distribuição código e incluem aqueles em
Fui instruído a.
>> E agora nós temos um tipo de dados.
Temos declarou um octeto de ser um char.
E nós veremos mais tarde que isso é utilizado ao longo do código.
E nós temos declarado todo grupo de protótipos,
e vamos caminhar rapidamente através cada uma dessas funções.
Por último, e talvez o mais importante ter em
mente neste momento no a história, é que não
são, na realidade, um conjunto grupo de variáveis ​​globais
na parte superior do arquivo, raiz, CFD, SFD, pedido, arquivo e corpo.
>> Agora, geralmente, utilizando tantos mundial variáveis ​​ou variáveis ​​globais em tudo,
Não é a prática de volta.
Mas acontece também estamos usando um técnica chamada de manipulação de sinal mais tarde
no código, o que nos permite detectar quando o usuário atinge algo
como CTRL C e desligar o servidor graciosamente.
E, para fazer isso graciosamente e, na verdade, liberar memória,
precisamos de ter acesso a essas variáveis ​​globais.
>> E agora vamos dar uma olhada no principal, que impulsiona a totalidade deste programa.
Em primeiro lugar, no topo aqui nós ter um número variável de erro
que parece não ter um tipo, mas isso é
porque é realmente definida em um arquivo chamado
erro errno.h que está incluído mais acima.
Se você fizer o homem errno para realmente ver a definição de tal coisa,
você vai ver que este é um variável global especial que
é definido por um grupo inteiro de funções não escrito
por nós, mas pelos autores do Linux e outros sistemas para realmente definida
um número para essa variável quando algo der errado, para que possa globalmente
descobrir o que deu errado.
>> Agora, logo abaixo você verá uma nova técnica talvez usando getopt,
uma função que ajuda comando parse Argumentos da linha de modo que não fazer
tem que se preocupar em perder tempo imaginando como analisar algo como 8080,
ou traço p, ou traço h para obter ajuda.
getopt essencialmente faz isso por nós.
Veja a página de manual para mais.
>> Em seguida, fazer um pouco de erro verificação para certificar-se
que o número de porta está dentro o intervalo especificado no spec.
Em seguida, vemos uma chamada para a função começar, cuja definição vamos
olhar em um momento, e como o próprio nome sugere, este inicia o servidor web.
Aqui nós temos uma chamada a uma função chamado de sinal que diz:
se e quando você ouvir Controle C do teclado do usuário, vá em frente e chamar
um manipulador função chamada que está acontecendo coisas para, finalmente, limpar e parar
o servidor.
>> Abaixo que é o que parece ser um ciclo infinito, a primeira linha das quais
efetivamente é uma chamada a uma função chamada
redefinir, que nós mesmos implementar, mais tarde, a fim
para liberar alguns de nossos estados globais.
Depois que é uma linha de código que condicionalmente
está verificando o retorno valor do ligado.
Agora looks conectados como um predicado, algo que retorna verdadeiro ou falso.
E ele faz, mas não há algo especial em conectado
na medida em que é uma chamada de bloqueio.
Ele vai sentar lá e esperar até que o navegador do usuário
tenta se conectar a este web servidor e só então ele
retornar verdadeiro ou falso, para que possamos continuar para o interior deste if.
>> Uma vez lá, observe esta função a um função chamada de análise, o que nós escrevemos,
que analisa todos os octetos, todos dos bytes provenientes de um navegador
para o servidor, para que possamos entregar -lo de volta, em última análise o valor para outro
dessas variáveis ​​globais que lojas de todos os bytes em apenas
os cabeçalhos de que pedido, não o corpo
se não houvesse um corpo realmente a ele.
>> Agora abaixo começamos a analisar estes cabeçalhos para extrair
um subconjunto das informações que nos preocupamos.
Especificamente, o per especificação, primeiro
queria pedir linha, que é só que muito primeira linha que
espero que diz algo como get cortar ou algum caminho e, em seguida, HTTP 1.1.
Estamos usando essa metáfora de uma agulha num palheiro
procurar especial caracteres ou endereços.
E, de fato, há um número de funções em nosso código de distribuição
que você, também, podem ser úteis quando se olha para valores particulares.
>> Em última análise, nós copiar esses bytes em uma linha variável chamada,
que notar, também, nós temos alocados na pilha
por meio de uma matriz dimensionada de forma dinâmica.
E nós estamos tentando deliberadamente para evitar chamar malloc
porque de novo, porque Controlo de C sendo
uma característica potencial deste programa, não quero ter esse código de repente
interrompida pelo bater do usuário Controlo C, o resultado dos quais
é que eu não poderia ter uma chance de graça algo que eu malloced.
Então eu estou tentando usar a mesma quantidade da pilha é que eu posso aqui.
>> Em seguida, um grupo inteiro de para dos.
A especificação irá expor exatamente o que é esperado aqui,
mas os comentários dão-lhe uma dica do que está por vir.
Você primeiro precisa validar a linha de pedido
e certifique-se que ele se parece com o especificações gramática, por assim dizer,
diz que deveria.
Em seguida, você precisa extrair algo chamado a consulta, o material para fora
após um ponto de interrogação, como vimos com o nosso exemplo Google
de passagem em um parâmetro de HD.
Nós então concatenar juntos a raiz do servidor web
com o caminho que está em que a primeira linha de pedido
e formar o caminho completo o arquivo que deseja procurar.
>> Depois disso, vamos ter a certeza se o arquivo existe e é legível.
E então nós estamos indo para extrair o seu extensão de arquivo, o .html ou o .php,
ou alguma extensão que está no final da cadeia solicitado.
Em seguida é um todo monte de código que escrevemos
para gerar efectivamente PHP conteúdo gerado por você.
Em poucas palavras, este código leva no nome
do arquivo que você deseja PHP para interpretar.
Nós passá-lo por algo chamado um tubo em intérprete de PHP.
Volte a resposta como se a resposta fosse ela própria um arquivo.
E, então, interagir sobre esse arquivo de bytes, puxando-los todos em um buffer
para que possamos, em última instância imprimi-las.
>> Com efeito, todos estes chama aqui a dprintf
nos permite imprimir algo chamado de um descritor de arquivo, o que
é apenas um número inteiro que representa um arquivo.
Muito semelhante em espírito, mas fundamentalmente diferente de um arquivo
ponteiro estrela.
Observe como você pode usar a sintaxe como printf aqui para que eu possa dinamicamente
inserir algo como o comprimento para o valor de um cabeçalho HTTP
chamado Content-Length.
E, finalmente, eu usei o direito de realmente escrever função
o corpo do pedido.
>> Infelizmente, só implementado suporte para dinamicamente
arquivos PHP gerada.
Nós não implementar o suporte para arquivos estáticos, como gifs, e JPEG
e arquivos CSS e HTML.
Isso, infelizmente, é deixada para você para responder ao objectivo cliente
esta a fazer.
Então, lá você vai descobrir que não há não muita inspiração dentro desse bloco,
mas se você um pouco mais para cima com a forma como nós fomos sobre a interpretação do código PHP,
as funções que você vai usar são um pouco diferentes.
>> Na verdade, você pode pedir algumas das funcionalidades
talvez a partir dos forense conjunto de problemas, porque
no fim do dia tudo o que precisa fazer aqui é quando você sabe que abrir o arquivo
e uma vez que você sabe que é chamado Tipo MIME ou tipo de conteúdo,
você precisa ler nesses bytes e de alguma forma cuspi-los de volta para fora.
>> E agora um tour por esta outras funções do arquivo.
Até primeiro está ligado, que simplesmente retorna true
quando finalmente ouve um conexão a partir de um utilizador.
Em seguida é erro.
Erro, por sua vez, como uma função que escreveu para lidar com todas as diferentes 400
eo status HTTP 500 códigos que você pode querer
para enviar de volta para o usuário, juntamente com uma mensagem padrão.
>> Em seguida é a carga, particularmente função de carne, cujo propósito na vida
é para ler de uma estrela do ponteiro do arquivo do conteúdo de um arquivo em um buffer mundial
que declarou a nível mundial acima [? principal. ?]
Este é um pouco complexo, porque nós tem que ler os bytes do arquivo
mas verificar em cada iteração se nós já
atingiu o fim do ficheiro ou outra coisa deu errado.
E usamos realloc para se certificar de que qualquer que seja tampão estamos usando está crescendo
e crescendo e crescendo e sempre ficando à frente do número de bytes
que precisamos para caber lá dentro.
Handler, entretanto, é a função que recebe
chamado por meio de ter Controlo C registado como um sinal
que queremos interceptar.
Observe aqui no manipulador que, em última análise
chamadas de parar, o que naturalmente pára o servidor web.
E, infelizmente, lookup não está implementado.
Em espírito, este é um função bastante simples.
Dada a extensão do arquivo, ele precisa devolvê-lo está o chamado MIME
tipo ou tipo de conteúdo.
E nós especificar na especificação o que esse mapeamento deve ser.
Mas você precisa traduzir em última análise, ao código c.
>> Em seguida é a nossa função semelhante de carne chamado de análise, cujo propósito na vida
é ler, não a partir de um arquivo, mas a partir de uma conexão de rede.
Especificamente, a leitura e a análise Pedido HTTP que está vindo de um navegador
para o servidor de modo a que em última análise, podemos analisar
com apenas os cabeçalhos no pedido linha e retornar aqueles para você
por meio de uma memória temporária global que declaramos acima [? principal. ?]
>> Reset, entretanto, é um função que nós definimos
que é chamado de forma iterativa dentro do principal cada vez que você está prestes
pronto para começar a ouvir para uma nova ligação
de modo que nós sempre sabemos o estado de nossas variáveis
e para que nós também libertou qualquer memória que
pode ter sido alocado para uma conexão de rede anterior.
Em seguida é iniciado, o função que escrevemos
que contém um conjunto monte de código de rede
que, finalmente, inicia o servidor web.
>> Última up é a função chamado stop, que
faz exatamente isso, pára o servidor web.
Mas, primeiro, ele libera qualquer memória que ainda foi alocado.
Mas, em última análise chama exit sem nem mesmo retornar o controle
a nossa função principal.
Em última análise, um dos a maioria das técnicas importantes
ao implementar este servidor web é vai ser um pouco de tentativa e erro,
ter um navegador janela aberta à direita e uma janela de terminal em
à esquerda, o console de servidores janela, de modo que você
pode ver as mensagens que são sendo apresentada no ecrã.
>> Mas melhor ainda seria um terceiro janela, uma janela segundo terminal,
em que você usar o Telnet, o uso para o qual está prescrito no spec.
E Telnet é apenas um muito programa de rede simples
que permite que você fingir ser um navegador de uma janela
enquanto conversava com a outra janela.
Desta forma, você pode ver exactamente os comandos textuais
que estão voltando do servidor para o cliente
sem ter de desentupimento em torno de desenvolvedor do Chrome
ferramentas em uma outra forma Interface clunkier.