Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://w ww.troub...
Troubleshooters.Com e código canto presentes
Programação Socket Os 10% que você precisa preci sa - de 90% do seu trabalho Copyright (C) 2001 por Steve Litt
Steve Litt é o autor de técnicas de resolução de problemas do Sucesso Tecnólogo, Rapid Learning: Learning: Arma Secreta Secre ta do Sucesso Tecnólogo, e Samb Samba a Unleashed.
Introdução Agradecimentos Olá Mundo A implementação implementação bidirecional bidireci onal com cliente Telnet A implementação implementação bidirecional bidire cional com c om cliente personaliz personalizado ado C Notícias negativas
Introdução Sockets são interfaces que podem "plug em" uns aos outros através de uma rede. Logo modo "ligado "ligado à corrente", tão ligado ligado à comunicar programas. programas. Este artigo aborda apenas apena s os aspectos simples simples do fluxo inet sockets (não se preocupe com c om exatamente o que é certo agora). Para os fins deste artigo, um "servidor" é exposto através a través de um programa programa ligado a um determinado socket / etc / número de serviços portuários. portuários. Um "cliente", "cliente", em seguida, seguida, o programa programa pode ligar ligar o seu próprio servidor do socket para o soquete, soquete , momento em que o cliente do programa escreve para pa ra o socket são lidas como como stdin para o programa do servidor, a partir do servidor e stdout são lidas a partir do programa programa cli c liente ente do soquete lê. Este é um subconjunto subconjunto de soquete de programação, mas é talvez o mais fácil de dominar, dominar, pelo que esta é onde você deve começar.
Diagrama Diagrama cliente-servidor do socket conexão c onexão via xinetd. Note que o cliente comunica através da leitura e da escrita à tomada, mas o programa do servidor comunica comunica via stdin e stdout. Este tutorial requer uma máquina Linux. Não tem sido testado em outros tipos de UNIX, mas acho que pode funcionar. Este tutorial está centrado ce ntrado em torno de um sistema sistema usando o xinetd, mas seria muito simples o suficiente para adaptá-la ao inetd sistemas mais antigos. Este tutorial não irá funcionar sob Windows. Acho que
1 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
é importante que este tipo de programação complexas ser aprendido sobre os mais confiáveis, sistema simples possível, para Windows está fora. Para os fins deste tutorial, o servidor de aplicação será a porta 3333. Note que você pode executar tanto o cliente eo servidor em um único computador, caso em que o cliente está conectado a uma porta no computador que contém ambos o cliente eo servidor. Então se você tem apenas uma máquina Linux você ainda pode fazer este tutorial.
Agradecimentos Este material foi-me dito pelo FC LEAP-membros Mark e Alexander Nickolai Zeldovich. Outros LEAPsters forneceram informações adicionais. Um grande gritar a todos os meus amigos em Linux Entusiastas e Profissionais de Central Florida (LEAP-CF). Com a lista de discussão e reuniões, eles (nós) formam um supercomputador paralelo 70 cé rebro. E, naturalmente, graças à ajuda e apoio de Troubleshooters.Com 's visitantes.
Olá Mundo Nossa primeira aplicação usa um soquete simples escrever-Shell apenas como um servidor de aplicação, bem como o cliente telnet. Esta é a mais simples possível implementação. Eu testei este mandrágora em uma casa, e eu ia imaginar que iria trabalhar em qualquer máquina Linux usando xinetd. Se a sua casa ainda mais antiga inetd usa o sistema, a única diferença é que você modifique inetd.conf, em vez de um arquivo / etc / xinetd.d, e você reiniciar inetd em vez do xinetd. As seguintes etapas estão envolvidas: 1. 2. 3. 4. 5. 6. 7. 8.
Crie o servidor de aplicação (um simples Shell) Teste o servidor de aplicação na linha de comando Decidir sobre um número de porta e serviço de nome Declare a porta e nome no arquivo / etc / services Crie um arquivo para este serviço no arquivo / etc / xinetd.d Reinicie o xinetd Telnet para o serviço, e de ver server do app da saída Rever o que você aprendeu
Crie o servidor de aplicação (um simples Shell) Queremos que o mais simples possível para este script Olá Mundo, então aqui está: #! / bin / bash / bin / echo-n "Olá Mundo:" | / usr / bin / tee / tmp / log.log / bin / date | / usr / bin / tee-a / tmp / log.log
Salvar o script como hello.sh anterior, em seu diretório home (iremos assumir o seu ID do utilizador é myuid). Nota várias coisas. A linha superior, mostrando o programa para ler o script, é absolutamente essencial. Embora a maioria dos ambientes correr sem que shellscripts top line, os mesmos não irão saída scripts quando chamado através de sockets como certos usuários (usuário nobody, por exemplo). Por uma razão semelhante, certifique-se de todos os executáveis é declarado com um caminho completo, e não é um link. Com um usuário como usuário nobody, você não sabe o que o caminho será semelhante. Da mesma forma, o arquivo de log é completamente especificada, para que você sabe onde encontrá-lo. Se você não especificar isso, ele fica no diretório home do usuário em forma de gancho para o serviço por xinetd. Melhor para especificá-lo assim que você sabe exatamente onde encontrá-lo. / Tmp é um excelente lugar, porque na maioria dos sistemas universais, tem permissões ler e escrever. Este script escreve uma única linha que contém "Olá Mundo:" seguido por uma hora, e à stdout tanto para um
2 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
arquivo de log chamado / tmp / log.log. O arquivo de log irá tornar-se essencial na tomada depuração, porque quando o programa é executado sob uma socket o programa não tem nenhum terminal. Por motivos de segurança, eu recomendo que você executar o cliente eo servidor no mesmo computador, e que você desligue temporariamente o computador de sua rede. A última coisa que queremos é uma sub-desenvolvimento de serviços expostos à rede local, e talvez de toda a Internet.
Certifique-se de definir o script como exe cutável por todos. Lembre-se, você não sabe o usuário será executa-lo. Também, não se esqueça árvore habitação em todo o dire tório do script é executável por todos, ou então, outros usuários não serão capazes de atravessar a árvore para executar o arquivo.
Teste o servidor de aplicação na linha de comando Executar o programa, e este deve emitir a frase Olá mundo seguido por uma hora. Quando você olha para / tmp / log.log, deverá conter as mesmas informações. Veja a sessão abaixo: [myuid @ mydesk myuid] $. / hello.sh Olá Mundo: Tue Jan 23 12:27:08 EST 2001 [myuid @ mydesk myuid] $ cat / tmp / log.log Olá Mundo: Tue Jan 23 12:27:08 EST 2001 [myuid @ mydesk myuid] $
Se não for possível obter os resultados mostrados acima, solucionar problemas até que você o faça.
Decidir sobre um número de porta e serviço de nome Primeiro, o número da porta precisa ser inutilizados. O número da porta que você escolher não deveria existir no arquivo / etc / services. Além disso, por razões de segurança o número de porta não deve ser inferior a 1024. Para este exercício eu uso porta 3333. Você pode querer usar uma porta diferente alguém tão sabendo que você tenha tido esse tutorial não sabe de uma porta aberta em seu sistema. Mas, neste tutorial vou usar 3333. A primeira coisa a fazer é ter certeza de que o número de porta não está contido no arquivo / etc / services arquivo. Faz isso como se segue: [myuid @ mydesk myuid] $ cat / etc / services | grep 3333 [myuid @ mydesk myuid] $
Se não houver saída, não existe tal número de porta. Se não há saída, investigar minuciosamente, e você provavelmente vai querer escolher um número diferente. Também é necessário verificar a existência de um serviço xinetd declaradas com um número de porta combinando declarado o novo. Faça isso com um repertório amplo grep: [myuid @ mydesk myuid] $ grep-r 3333 / etc / xinetd.d / * [myuid @ mydesk myuid] $
Mais uma vez, não significa a inexistência dessa porta de saída é declarado. Se há saída, investigar e alterar o seu novo número de porta, se necessário. Tanto quanto o nome do serviço, nós estamos indo para ligar para o serviço "Olá". Veja como estamos a verificar a existência de um serviço corrente chamada "Olá": [myuid @ mydesk myuid] $ / sbin / chkconfig - Lista | Olá grep-i [myuid @ mydesk myuid] $
Mais uma vez, se não houver saída, não há necessidade de tal serviço ainda, de modo que você está livre para usar esse serviço nome.
3 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Assim que tiver decidido sobre um número de porta e um serviço de nome (3333 e Olá, neste tutorial), continuam em ...
Declare a porta e nome no arquivo / etc / services Adicione a seguinte linha ao arquivo
/ etc / services arquivo: Olá Olá 3333/tcp # tutorial, quando terminar apagar
O primeiro campo é o nome do serviço. O segundo campo é o número da porta e do tipo de protocolo (TCP, neste caso). Nada à esquerda de uma marca hash (#) é um comentário. CUIDADO: A página diz que um homem xinetd xinetd invocada serviço não necessitam de ser declaradas no arquivo / etc / services. Isso não corresponde à minha experiência. Eu não era capaz de fazer este trabalho sem o declarar no arquivo / etc / services, mesmo utilizando o
=
parâmetro
xinetd porto.
Faça a sua vida fácil. Declará-lo no arquivo / etc
/ serviços
para os
efeitos deste tutorial. Então, se quiser, vá em frente e achar uma maneira de retirá-lo do arquivo / etc / serviços, mantendo o serviço.
Crie um arquivo para este serviço no arquivo / etc / xinetd.d Como usuário root, crie o seguinte arquivo no arquivo / etc / xinetd.d: # Default: em # Descrição: Olá Mundo socket servidor Olá serviço ( Port = 3333 Socket_type = stream = Não espere User = ninguém server = / home / slitt / hello.sh Log_on_success + = UserID Log_on_failure + = UserID Disable = no )
Como raiz, salve o arquivo como precedente / etc / xinetd.d / Olá. Deve ler / escrever para o dono e leitura para o grupo e os outros: [root @ mydesk xinetd.d] # ls-ldF Olá -rw-r - r - 1 raiz raiz 303 Jan 23 13:14 Olá [root @ mydesk xinetd.d] #
Depois de salvar o arquivo corretamente, você está pronto para "transformar em" ao reiniciar o servidor xinetd ...
Reinicie o xinetd Segundo a página man xinetd existem muitas maneiras de "reconfigurar" xinetd. Xinetd Na página man pesquise SIGUSR2 e você encontrará alguns dos métodos menos invasivos. Mas na minha experiência, não há substituto para um estado conhecido. Prefiro um reinício completo. Veja como pode fazê-lo em uma caixa Mandrake: [root @ mydesk xinetd.d] # / etc / rc.d / init.d / xinetd reiniciar Interrompendo xinetd: [OK] Iniciando xinetd: [OK] [root @ mydesk xinetd.d] #
Diferentes distribuições Linux usam diferentes comandos ea saída de um texto diferente. Portanto, sua milhagem pode variar. Assim que tiver reiniciado xinetd, o seu novo serviço é teoricamente trabalho. Utilizando o telnet tempo para testar como um cliente ... 4 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Telnet para o serviço, e de ver server do app da saída Execute o seguinte comando: telnet 192.168.100.2 3333
O endereço IP é o endereço do servidor que contém o servidor Olá mundo. O 3333 é o número da porta. Aqui está um exemplo do que pode acontecer: [myuid @ mydesk myuid] 192.168.100.2 tentando telnet: Não é possível [myuid @ mydesk myuid]
$ telnet 192.168.100.2 3333 ... conectar a máquina remota: Conexão recusada $
No anterior, regista-se o "Conexão recusada" mensagem. Significa isto há um problema básico com o serviço, eo usuário listados no arquivo / etc / xinetd.d / Olá não pode ser executado hello.sh. Note que o arquivo de log não terá sido reescrito, portanto, se existe uma velha que tem um timestamp (é por isso que colocar o timestamp no script do servidor). Aqui estão algumas coisas para verificar: Certifique-se que o serviço eo nome são listados no arquivo / etc / services. No arquivo / etc / xinetd.d / Olá, certifique-se: Os = portuário linha do valor corresponder o número da porta no arquivo / etc / services. O serviço de nome (mesmo antes da embaralhado chavetas) está correta. Se há uma = desativar, seu valor deve ser não. Se há um padrão: linha, o seu valor deve ser ligado. O usuário = uma linha nomes de usuário válido. O servidor = linha deve apontar para o script para ser executado (hello.sh). Tem de ser totalmente pathed. Depois de corrigir eventuais problemas, reinicie o xinetd: / etc / rc.d / init.d / xinetd reiniciar
Se nenhuma das opções acima ajude, tente mudar temporariamente o usuário = linha de raiz. Isso deverá corrigir quaisquer problemas permissão. Mas tenha certeza de que antes de modificá-lo de raiz, se desconectar da Internet. Senão o script kiddies será que você gosta de esquilos em uma árvore. Se nenhuma das opções acima ajuda, use a Solução de problemas Universal Process para diagnosticar o problema. Tentar encontrar maneiras para diminuir os problemas, e maneiras de dividir e conquistar. Uma vez que você realmente chegar a ligação a funcionar, poderá ser confrontado com um sem-saída executado, conforme mostrado abaixo: [myuid @ mydesk myuid] $ telnet 192.168.100.2 3333 192.168.100.2 tentando ... Conectado ao 192.168.100.2. Escape personagem é'^]'. Conexão fechada pelo host estrangeiro. [myuid @ mydesk myuid] $
No anterior, a ligação foi feita, mas não há saída foi recebida. There's provavelmente algo de errado com o script em si. O mais provável do início da linha que declara o script intérprete (/ bin / bash neste exemplo) está faltando ou está errado. Também poderia ser um problema com o pathing "executar serviço como" usuário, e é por isso que é tão importante a caminho completamente todos os arquivos no script. Note que o arquivo de log não terá sido reescrito, portanto, se existe uma velha que tem um timestamp (é por isso que colocar o timestamp no script do servidor). Verifique se o nome do script é o mesmo que foi nomeado no arquivo / etc / xinetd.d / Olá, que é executável para todos, que é o seu diretório executável todo o caminho até o caminho, e que ele contém o #! / Bin / bash linha no topo, e que realmente há um / bin / bash, e que ele é um comando do intérprete. Verifique se todos os arquivos no script são totalmente pathed. Além disso, resolver problemas.
5 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Depois de conseguir isso funcionando, você pode obter resultados como os seguintes: [myuid @ mydesk myuid] $ telnet 192.168.100.2 3333 192.168.100.2 tentando ... Conectado ao 192.168.100.2. Escape personagem é'^]'. / usr / bin / tee: / tmp / log.log: Permissão negada Olá Mundo: / usr / bin / tee: / tmp / log.log: Permissão negada Terça-feira Jan 23 13:26:44 EST 2001 Conexão fechada pelo host estrangeiro. [myuid @ mydesk myuid] $
Você pode dizer que você está fechado. Você está ligando, e você está chegando saída obviamente proveniente de seu script. Mas você tem um problema criando / tmp / log.log. Isso não surpreende, pois em uma etapa anterior que você criou-a como usuário myuid, eo usuário não tem ninguém as permissões para apagar a antiga. Como root ou outro usuário permissioned para apagar / tmp / log.log, elimine a um velho manualmente e você deve limpar o problema. Depois que todos os problemas tenham sido apurados, a sessão telnet deveria olhar como se segue: [myuid @ mydesk myuid] $ telnet 192.168.100.2 3333 192.168.100.2 tentando ... Conectado ao 192.168.100.2. Escape personagem é'^]'. Olá Mundo: Tue Jan 23 13:33:55 EST 2001 Conexão fechada pelo host estrangeiro. [myuid @ mydesk myuid] $
Se você obter o resultado anterior, parabéns - você apenas implementou um Olá Mundo soquetes setup. Portanto, vamos rever ...
Rever o que você aprendeu Sockets são uma metodologia de software para conectar diferentes processos (programas) no mesmo computador ou em computadores diferentes. O nome "soquete" nos lembra que, uma vez que "plug in" um processo em outro processo da tomada, eles podem conversar entre si por meio de leitura e escrita ao soquete. Sockets são um enorme e diversificado tema. Este tutorial trata do subconjunto em que um dos dois processos é um "servidor", em virtude da sua configuração a xinetd (inetd ou se você estiver executando uma distro Linux ou UNIX mais antigos). Nesse cenário, o "servidor" processo, o que, no nosso exemplo é uma simples Shell, está associado a um número de porta e um nome através de um processo de configuração no arquivo / etc / xinetd.d diretório. No nosso caso, o arquivo é / etc / xinetd.d / Olá. Além disso, o número da porta é associado com o nome do serviço e do protocolo TCP através de uma entrada no arquivo / etc / services. Assim que essas associações são feitas, reiniciando xinetd torna o script disponível como um serviço na porta especificada. Pictoricamente, isso é algo como isto:
Diagrama cliente-servidor do socket conexão via xinetd. Note que o cliente comunica através da leitura e da escrita à tomada, mas o programa do servidor comunica via stdin e stdout.
6 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
No caso do nosso tutorial, vamos utilizar o programa cliente como o telnet, conectando-lo para a porta 3333 em 192.168.100.2 como segue: telnet 192.168.100.2 3333
O script do servidor de saída, em seguida, aparece no programa telnet da saída. Esta tem sido uma simples aplicação, de fato. Você não código do cliente, mas, em vez utilizado telnet. E da comunicação vai apenas um caminho. É a saída do servidor de telnet na app e ler. No entanto, você está a cargo do maior hurdle.The próximo passo é socket comunicação bidireccional. Leia mais ...
A implementação bidirecional com cliente Telnet Agora vamos fazer um programa bidirecional. Iremos simplesmente anexar um novo script, chamada hellobidirectional.sh, ao Olá serviço. Primeiro, vamos fazer o hellobidirectional.sh script: #! / bin / bash logfile = "/ tmp / log.log" firstname = "iniciação" LastName = "iniciação" / bin / echo "LOG: $ (/ bin / data)"> $ logfile / bin / echo>> $ logfile enquanto teste 1; do # # # Forever, consulte a quebrar no caso declaração / Bin / echo>> $ logfile / bin / echo "Começar Ciclo: $ (/ bin / date) **********">> $ logfile / Bin / echo / bin / echo "Por favor, escreva Linux Celebridades nome abaixo:" | / usr / bin / tee-a $ Leia firstname ##### Próxima declaração remove extra CTRL + M ponha em pelo telnet ##### ##### Programador: certifique-se que o char é CTRL + M, e não um quilate e uma M! ##### firstname = $ (/ bin / echo $ (firstname) | / bin / sed-e 's / ^ M $//') / bin / echo ": $ firstname," | / usr / bin / tee-a $ logfile Case "$ firstname", em (richard) apelido = "Stallman";; (Linus) apelido = "Torvalds";; (Maddog) apelido = "hall";; (q *) apelido = "fechar"; break;; (*) Apelido = "Desconhecido celeb";; Esac / bin / echo "$ apelido" | / usr / bin / tee-a $ logfile feito / Bin / echo | / usr / bin / tee-a $ logfile / bin / echo "Concluído" | / usr / bin / tee-a $ logfile
Aviso: A ^ M é um CTRL + M, um único personagem. Infelizmente, esta página html pode representá-la apenas como um quilate seguido por um M. Se você copiar e colar este script no VI, certifique-se de alterar os quilates e M para uma verdadeira CTRL + M! Se o se u script trabalha na linha de comando, mas aparece para deturpar o primeiro nome no Telnet, não se esqueça de verificar a existência de um legítimo CTRL + M.
Este script é uma reiteradamente que as consultas para primeiro nome, e por três celebridades Linux ele retorna seu último nome. Para outras pessoas ele retorna a string "celeb Desconhecido", e para qualquer primeiro nome começa com q ele termina, como se pode ver no caso da declaração. Faça o script executável por todos, e mais uma vez, certifique-se de sua diirectory é executável todo o caminho até a árvore. Agora executá-la na linha de comando. O resultado deve parecer algo como o seguinte, mantendo-se em conta que o texto em negrito é o que foi digitado em: [myuid @ mydesk myuid] $. / hellobidirectional.sh Por favor, escreva Linux Celebridades nome abaixo: richard
: richard,
7 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Stallman Por favor, escreva Linux Celebridades nome abaixo: Linus
: Linus, Torvalds Por favor, escreva Linux Celebridades nome abaixo: q
: q, Concluídos [myuid @ mydesk myuid] $
Agora você sabe que tenho um trabalho script. O próximo passo é atribuir este script para o Olá serviço. Basta editar / etc / xinetd.d / Olá, e substituir a seguinte linha: server = / home / slitt / hello.sh
Com a seguinte linha: server = / home / slitt / hellobidirectional.sh
Agora reinicie xinetd com o seguinte comando: / etc / rc.d / init.d / xinetd reiniciar
E finalmente, como usar o telnet do cliente. O seguinte mostra a sessão telnet com o texto digitado em negrito: [myuid @ mydesk myuid] $ telnet 192.168.100.2 3333 192.168.100.2 tentando ... Conectado ao 192.168.100.2. Escape personagem é'^]'. Por favor, escreva Linux Celebridades nome abaixo: richard
: richard, Stallman Por favor, escreva Linux Celebridades nome abaixo: maddog
: maddog, hall Por favor, escreva Linux Celebridades nome abaixo: q
: q, Concluídos Conexão fechada pelo host estrangeiro. [myuid @ mydesk myuid] $
Se os primeiros nomes retornado pelo script (o primeiro após os nomes que você digitar no) estão ilegíveis, suspeitam que o comando sed não está removendo o telnet da escova CTRL + M personagens, e investigar. Resolva os problemas que for necessário.
A implementação bidirecional com cliente personalizado C Usar exatamente o mesmo que usou no hellobidirectional.sh Uma Aplicação bidirecional com o Telnet Client seção. Mas desta vez vamos acessá-lo com um cliente C. Não é tão simples como pode parecer. Se esta seção faz o seu trabalho bem, você vai aprender algumas dicas do soquete comm, o modo de reconhecê-los, a forma de superá-las, e por força profissional soquete clientes e servidores devem saber sobre uns dos outros protocolos.
8 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Arquivo de bloqueio, e Deadly Abraça Um problema que você verá em sua carreira como uma tomada programador está bloqueando o arquivo. Se você tentar ler um soquete vazio, você vai esperar até que o servidor envia mais dados. Definitivamente, se necessário. Isso é chamado Arquivo de bloqueio, e é o comportamento padrão de tomadas. Digamos que o seu cliente tem um código "ler todos os dados enviados" função contendo código algo como isto: enquanto ((len = read (sd, buf, buflen))> 0) Write (1, buf, len);
Isso é normal Programação 101, e funciona perfeitamente com arquivos normais. Mas com sockets, o comportamento padrão (chamado bloqueio) é que, quando se lê o que teria retornado 0 é tentada, a ler para esperam dados de vir polegadas Então o que há de errado nisso ? O cliente está à espera de dados do servidor, e não irá enviar os dados para o servidor até que ele recebe dados do servidor. Mas o servidor não irá enviar os dados para o cliente até que ele receba os dados do cliente. Deadly abraço! O código anterior trecho vai travar um soquete cliente em condições normais. Bloqueio pode ser removido com ioctl (), ou a memória pode ser espiei em selecionar com () ou sondagem (). Mas tudo isso é bastante complicado. Olá Mundo como uma solução compatível (kludge realmente), em vez passado o efeito da leitura de dados, vamos ler até ao fim dos dados pelos encerra o ciclo quando lemos menos, o número solicitado de bytes: enquanto ((len = read (sd, buf, buflen))> = buflen) Write (1, buf, len);
Curiosamente, apesar de ter solicitado a ler o passado fim de dados, ele retorna somente até o final dos dados. Bloqueio não ocorrerá até que você tente ler um encaixe drenar completamente. Há um bug no código anterior. Se os dados no soquete é um múltiplo exacto de buflen, o circuito não irá encerrar no final de dados, mas vai tentar mais uma lida em um buffer vazio, fazendo com que o anteriormente descrito abraço mortal. Ainda em produção código que seria imperdoável, neste Olá Mundo exercício nós simplesmente minimizar a probabilidade de isso acontecer, tirando o buffer grande no que diz respeito à espera de dados. 512 é um bom número, e isso é o que iremos usar no cliente.
Questões de calendário - o sono () Solução Imagine isto. Depois que o usuário entradas de dados para o cliente, o cliente envia os dados para o servidor e, em seguida, o loop itera rapidamente e agarra servidor de dados para fora do soquete. O único problema é, o servidor não tenha enviado os dados porque ainda não tenha recebido os dados do cliente. Então o cliente diz "o servidor não me deu os dados", e prossegue até o próximo solicitar para entrada de usuário. Algum tempo durante a entrada de usuário que o servidor recebe o anterior iteração de dados do cliente, e envia de volta uma resposta. Este servidor é o modo como as respostas podem ser continuamente uma iteraçã o atrás do cliente, fazendo confusão de utilizador e uma enxaqueca Troubleshooter. Porque este é um exercício só para ensinar a teoria, "resolve" o problema com um expediente kludge - vamos inserir um sleep () imediatamente após o comando grava os dados do cliente para o soquete. Dessa forma, garantimos que o servidor recebe dados do cliente e retorna a sua resposta perante o cliente tenta agarrar a resposta. Por uma razão semelhante, um sleep () é inserido imediatamente após o cliente se conecta ao soquete. Para uma tomada para ligação a um servidor da mesma casa, dormir um 1 segundo é suficiente. Pesadamente em uma rede de tráfico, esse intervalo pode ter de ser reforçado. Lembre-se, a propósito deste kludge é assim que você pode aprender programação fundimentals socket sem necessidade de aprender sobre protocolos, deixar de caracteres, o bloqueio, ioctl (), e uma série de outras coisas. Com o passar do tempo vou acrescentar conteúdo a esta página e descrevendo passos através do caminho certo para realizar estas coisas.
O código do cliente
9 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Então, aqui, sem mais adeus, é código do cliente: # # # # # #
include include include include include include
# define buflen 512 unsigned int portno = 3333; char hostname [] = "192.168.100.2"; char * buf [buflen]; / * para evitar a pilha global declaramos * / void dia (char * sz) (printf ( "Dia% s \ n", sz);) int printFromSocket (int sd, char * buf) ( Int len buflen = +1; Continueflag int = 1; enquanto ((len> = buflen) & & (continueflag)) / * quit b4 U ler um soquete vazia * / ( Len = read (sd, buf, buflen); Write (1, buf, len); buf [buflen-1] = '\ 0'; / * Observe se bug "Concluído" termina o buffer * / continueflag = (strstr (buf, "Concluído") == NULL); / * servidor termina se diz "Concluíd ) Retorno (continueflag); ) main () ( int sd = socket (AF_INET, SOCK_STREAM, 0); / * init socket descritor * / Struct sockaddr_in pecado; struct hostent * host = gethostbyname (host); Char buf [buflen]; Int len; / *** DADOS NO LOCAL sockaddr_in struct *** / memcpy (& sin.sin_addr.s_addr, hospedar-> h_addr, hospedar-> h_length); Sin.sin_family = AF_INET; Sin.sin_port = htons (portno); / *** SOCKET LIGAÇÃO AO SERVIÇO descrito por sockaddr_in struct *** / if (connect (sd, (struct sockaddr *) & sin, sizeof (pecado)) <0) ( Perror ( "conexão"); Exit (1); ) Sono (1); / * servidor dar tempo de resposta * / Ao mesmo tempo (1) ( Printf ( "\ n \ n"); If (! PrintFromSocket (sd, buf)) break; fgets (buf, buflen, stdin); / * lembre-se, acrescenta o fgets newline * / Escrever (sd, buf, strlen (buf)); sono (1); / * servidor dar tempo de resposta * / ) Close (sd); )
A principal rotina pode ser dividido em duas partes aproximadamente: 1. Socket inicialização com conexão, que termina a sua ligação com a declaração de erro manuseio e associados 2. Interação com o servidor via socket, começando com o primeiro sono () comando.
10 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
Acredite ou não, parte 1 é o mais simples. Basicamente, você preparar um soquete descritor (sd), criando-la, uma inicialização hostent struct (host) e um sockaddr_in struct (pecado). Várias cópias e outras chamadas preparar o soquete descritor e, em seguida, ligue a declaração conecta o socket descritor com o serviço definido no sockaddr_in estrut. Uma vez que se conectar feito, o soquete descritor pode ser tratado muito bem como um arquivo ou arquivo descritor alça. Eles são ambos inteiros, e eles podem ser usados tanto em ler () e write () convites. A segunda parte é o desafio. Mais evidente, não há um caminho limpo para terminar o ciclo, a menos que obtenha uma pista a partir do servidor. Neste caso, o servidor imprime a palavra "Concluído" quando ele foi concluído. Nós criamos uma função chamada printFromSocket () para lidar com todos os aspectos da leitura servidor do socket de dados, bem como informando círculo quando o principal "Concluído" foi recebido para que possamos encerrar o ciclo. Para prevenir abraço mortal, o printFromSocket () faz a função "ao fim, mas não fora" ler discutido anteriormente. Além disso, as pesquisas para a palavra "Concluído" depois de ler todos. Quando se verifica que a string que termine o seu ciclo e também retorna ao facto de ter apurado que a corda, de modo que o loop principal pode rescindir. Um entendimento da printFromSocket () função retorna uma boa compreensão do presente programa cliente. Diferente do acima exposto, a única parte difícil é que um sleep () é inserido após a ligação, e depois de cada transmissão de dados a partir do cliente. Isto é para evitar que o timing problemas anteriormente discutidos.
Conclusão Embora os exercícios anteriores foram obviamente académicas, utilizando soluções inaceitáveis na produção código, após a sua conclusão você tem um excelente entendimento do socket básico. Nesse ponto, você pode tirar vantagem da mais avançada soquete documentação para aprender a fazer produção código. E melhor ainda, nos próximos meses, vou estar adicionando mais informações a esta página ...
Notícias negativas Vou estar colocando mais algum conteúdo desta página, nos próximos meses. Esse conteúdo vai abordar os aspectos práticos da produção código, eliminando a necessidade de o kludges óbvio que você vê nos exercícios anteriores. Alguns dos temas que serão abordados são: A desativação do bloqueio com ioctl () Tampão com introspecção selecionar () e poll () Usando o termo de transmissão e de fim de programa para executar bytecodes síncrono o timing certo modo, em vez do sono () contorno. Discutir as diferenças entre síncronas e assíncronas comunicação entre cliente e servidor. Comunicação assíncrona ocorre quando o cliente possa responder ao servidor de dados a qualquer momento, independentemente do estado do cliente. E vice-versa - o servidor poderá responder aos dados do cliente a qualquer momento, independentemente do estado do servidor. O Telnet é um excelente exemplo de comunicação cliente-servidor assíncrono. Criando um servidor Perl app Criando um cliente Perl
Um servidor de soquete Perl #! / usr / bin / perl-w uso estrito; meu ($ logfile) = "/ tmp / log.log"; meu ($ firstname) = "iniciação"; meu ($ apelido) = "iniciação";
11 d 12
28/11/2008 11 00
Programação Socket
http://74.125.93.104/translate_c?hl=pt-BR&sl=en&u=http://www.troub...
sub dia ( # Print "dia $ _ [0] \ n"; ) sub teeappendlog ( system ( "/ bin / echo $ _ [0] | / usr / bin / tee-a $ logfile"); ) sub appendlog ( system ( "/ bin / echo". $ _ [0]. ">>". $ logfile); ) dia "b4 log tronco"; system ( "/ bin / echo> $ logfile"); dia "b4 bin data para iniciar sessão tronco"; appendlog "LOG:". `/ bin / date`; dia "afer bin data para iniciar sessão tronco"; appendlog ""; ao mesmo tempo (1) # # # Forever, consulte a quebrar no caso declaração ( Appendlog ""; dia "b4 begincycle"; Meu ($ temp) = `/ bin / date`; Chomp ($ temp); Appendlog "Começar Ciclo: $ temp **********"; teeappendlog "Por favor, escreva Linux Celebridades nome abaixo:"; $ Firstname = ; dia "depois de ler"; ##### Próxima declaração remove extra CTRL + M ponha em pelo telnet ##### ##### Programador: certifique-se que o char é CTRL + M, e não um quilate e uma M! ##### $ Firstname = ~ s / $ / /; Chomp ($ firstname); dia "após chomp"; Teeappendlog ": perlversion: $ firstname,"; $ Apelido = "Desconhecido celeb"; if ($ firstname eq "richard") ($ apelido = "Stallman";) elsif ($ firstname eq "Linus") ($ apelido = "Torvalds";) elsif ($ firstname eq "maddog") ($ apelido = "hall") elsif ($ firstname = ~ / ^ q /) ($ apelido = "fechar"; passada;) Teeappendlog "$ apelido"; Dia "endloop". $ apelido. ",". $ firstname; ) teeappendlog "$ logfile"; teeappendlog "Concluído";
[Troubleshooters.com | Código Canto | Enviar Steve Litt] Copyright (C) 2000 por Steve Litt - Legal
12 d 12
28/11/2008 11 00