:TITLE: Mais canais de entrada/saída - fblocked & fconfigure
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl42.lsn,v 1.4 2000/04/24 16:17:53 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# Veja o arquivo "AVISO" com os termos da licença.
;#
;#*********************************************************
;# Portuguese translation: Lucio Agostinho Rocha
;# E-mail: outrosdiasvirao@yahoo.com.br
;# Last update: 18/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
Os comandos <B>fblocked</B> e <B>fconfigure</B> fornecem mais
controle sobre o comportamento de um canal.
<P>
O comando <B>fblocked</B> checa se um canal retornou todas as entradas
diponíveis. É útil quando você está trabalhando com um canal que
foi configurado para o modo não bloqueante, e você precisa determinar
se deveriam haver dados disponíveis, ou se o canal foi fechado do
outro lado.
<P>
O comando <B>fconfigure</B> tem muitas opções que permitem a você consultar
ou sintonizar adequadamente o comportamento de um canal, incluindo se o canal
está no modo bloqueante ou não bloqueante, o tamanho do <I>buffer</I>, o caracter
de final de linha, etc.
<DL>
<B><DT>fconfigure</B> <I>canal ?parametro1? ?valor1? ?parametro2? ?valor2?</I>
<DD>Configura o comportamento de um canal. Se nenhum valor de <I>parametro</I>
é fornecido, uma lista de configurações válidas de parâmetros e
seus valores é retornada.
<P>
Se um único parâmetro é fornecido na linha de comando, o valor daquele
parâmetro é retornado.
<P>
Se um ou mais pares de <I>parametro/valor</I> são fornecidos, aqueles
parâmetros são atribuídos ao valor requisitado.
<P>
Parâmetros que podem ser atribuídos incluem:
<UL>
<LI> -blocking . . . Determina se ou não a tarefa será bloqueada
quando o dado não puder ser movido em um canal. (Isto é, se nenhum
dado está disponível na leitura, ou o <I>buffer</I> está cheio em
uma escrita).
<LI> -buffersize . . . O número de bytes que serão <I>bufferizados</I>
antes do dado ser enviado, ou pode ser <I>bufferizado</I> antes de 
ser lido quando o dado for recebido. O valor deve ser um inteiro entre
10 e 1000000.
<LI> -translation . . . Indica como Tcl irá terminar uma linha quando
ela está na saída. Por padrão, as linhas são terminadas com um
caracter de nova linha, retorno ao início da linha (<I>carriage return</I>), ou caracter de
nova linha/retorno ao início da linha, que é apropriado para o
sistema no qual o interpretador está executando.
<P>Isso pode ser configurado para ser:
  <UL>
  <LI> auto . . . Traduz o caracter de nova linha, <I>carriage return</I>, ou
  caracter de nova linha/<I>carriage return</I> como um marcador de final de linha.
  Exibe a correta terminação de linha para a plataforma atual.
  <LI> binary . . Trata caracteres de nova linha como marcadores de final de linha.
  Não adiciona qualquer terminação para as linhas sendo enviadas para o dispositivo de
  saída.
  <LI> cr . . . . Trata <I>carriage returns</I> como marcadores de final de linha (e
  os traduz para caracteres de nova linha, internamente). As linhas na saída são
  terminadas com um caracter de <I>carriage return</I>. Este é o padrão Macintosh.
  <LI> crlf . . . Trata os pares cr/lf (<I>carriage return</I>/<I>line feed</I>)
  como marcadores de final de linha, e termina as linhas na saída com uma
  combinação <I>carriage return</I>/<I>line feed</I>. Este é o padrão Windows.
  <LI> lf . . . . Trata <I>linefeeds</I> como marcadores de final de linha, e
  termina as linhas da saída com um <I>linefeed</I>. Este é o padrão Unix.
  </UL>
</UL>
</DL>

:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
Em lição anterior foi mostrado como usar canais com arquivos e
<I>sockets</I> bloqueantes. Tcl também suporta leituras e escritas 
não bloqueantes, e permite a você configurar os tamanhos dos <I>buffers</I>
de entrada/saída, e como as linhas são terminadas.
<P>
Uma leitura ou escrita não bloqueante significa que ao invés de uma
chamada <B>gets</B> esperar até o dado estar disponível, ele será lido, e
se nenhum dado estiver disponível, a chamada <B>gets</B> irá retornar
um comprimento 0.
<P>
Se você tem muitos canais que devem ser checados para entrada, você pode
usar o comando <B>fileevent</B> para disparar em operações de leitura em
canais, e então usar o comando <B>fblocked</B> para determinar quando
todos os dados foram lidos.
<P>
Os comandos <B>fblocked</B> e <B>fconfigure</B> fornecem mais controle sob
o comportamento de um canal.
<P>
O comando <B>fblocked</B> checa se um canal retornou todas as entradas
diponíveis. É útil quando você está trabalhando com um canal que
foi configurado para o modo não bloqueante, e você precisa determinar
se deveriam haver dados disponíveis, ou se o canal foi fechado do
outro lado.
<P>
O comando <B>fconfigure</B> tem muitas opções que permitem a você consultar
ou sintonizar adequadamente o comportamento de um canal, incluindo se o canal
está no modo bloqueante ou não bloqueante, o tamanho do <I>buffer</I>, o caracter
de final de linha, etc.
<DL>
<B><DT>fconfigure</B> <I>canal ?parametro1? ?valor1? ?parametro2? ?valor2?</I>
<DD>Configura o comportamento de um canal. Se nenhum valor de <I>parametro</I>
é fornecido, uma lista de configurações válidas de parâmetros e
seus valores é retornada.
<P>
Se um único parâmetro é fornecido na linha de comando, o valor daquele
parâmetro é retornado.
<P>
Se um ou mais pares de <I>parametro/valor</I> são fornecidos, aqueles
parâmetros são atribuídos ao valor requisitado.
<P>
Parâmetros que podem ser atribuídos incluem:
<UL>
<LI> -blocking . . . Determina se ou não a tarefa será bloqueada
quando o dado não puder ser movido em um canal. (Isto é, se nenhum
dado está disponível na leitura, ou o <I>buffer</I> está cheio em
uma escrita).
<LI> -buffersize . . . O número de bytes que serão <I>bufferizados</I>
antes do dado ser enviado, ou pode ser <I>bufferizado</I> antes de 
ser lido quando o dado for recebido. O valor deve ser um inteiro entre
10 e 1000000.
<LI> -translation . . . Indica como Tcl irá terminar uma linha quando
ela está na saída. Por padrão, as linhas são terminadas com um
caracter de nova linha, retorno ao início da linha (<I>carriage return</I>), ou caracter de
nova linha/retorno ao início da linha, que é apropriado para o
sistema no qual o interpretador está executando.
<P>Isso pode ser configurado para ser:
  <UL>
  <LI> auto . . . Traduz o caracter de nova linha, <I>carriage return</I>, ou
  caracter de nova linha/<I>carriage return</I> como um marcador de final de linha.
  Exibe a correta terminação de linha para a plataforma atual.
  <LI> binary . . Trata caracteres de nova linha como marcadores de final de linha.
  Não adiciona qualquer terminação para as linhas sendo enviadas para o dispositivo de
  saída.
  <LI> cr . . . . Trata <I>carriage returns</I> como marcadores de final de linha (e
  os traduz para caracteres de nova linha, internamente). As linhas na saída são
  terminadas com um caracter de <I>carriage return</I>. Este é o padrão Macintosh.
  <LI> crlf . . . Trata os pares cr/lf (<I>carriage return</I>/<I>line feed</I>)
  como marcadores de final de linha, e termina as linhas na saída com uma
  combinação <I>carriage return</I>/<I>line feed</I>. Este é o padrão Windows.
  <LI> lf . . . . Trata <I>linefeeds</I> como marcadores de final de linha, e
  termina as linhas da saída com um <I>linefeed</I>. Este é o padrão Unix.
  </UL>
</UL>
</DL>
O exemplo é similar ao exemplo da lição 40 com um <I>socket</I> cliente
e servidor no mesmo script. Ele mostra um canal servidor
sendo configurado para ser não bloqueante, e usar o estilo de
<I>bufferização</I> padrão - dados não estão disponíveis para o
script até que um caracter de nova linha esteja presente, ou
até que o <B>buffer</B> esteja cheio.
<P>
Quando o primeiro escreve:
<CODE>puts -nonewline $sockCliente "Uma linha de teste"</CODE> 
o comando <B>fileevent</B> dispara a leitura, mas o <B>gets</B>
não pode ler caracter porque não há o caracter de nova linha.
O <CODE>gets</CODE> retorna um -1, e <CODE>fblocked</CODE> retorna um 1. 
Quando um caracter de nova linha é enviado, o dado no <I>buffer</I> de
entrada se tornará disponível, e o <CODE>gets</CODE> retorna 
<CODE>18</CODE>, e <CODE>fblocked</CODE> retorna 0.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Por padrão, <B>gets</B> e <B>puts</B> irão esperar até que o dado
possa ser movido no canal ou lido de um canal antes que eles possam
retornar. Isso é chamado <I>modo bloqueante de entrada/saída</I>, uma
vez que o programa é bloqueado na execução até que o dado seja
transferido.
<P>
Este modo de operação pode levar a impasses (<I>deadlocks</I>) quando
dois programas querem escrever um em cada lado através de um
canal compartilhado, e nenhum pode escrever porque o outro ainda
não leu.
<P>
O <I>modo não bloqueante de entrada/saída</I> permite que você "fuja"
desse dilema iniciando uma escrita, vendo que ela falha, realizando a
leitura, e então escrevendo depois que o outro programa estiver pronto para
ler.
<P>
As lições anteriores mostraram como usar canais com arquivos
e <I>sockets</I> bloqueantes. Tcl também suporta leitura e
escrita não bloqueante, e permite que você configure os
tamanhos dos <I>buffers</I> de entrada/saída, e como as linhas
são terminadas.
<P>
Uma leitura ou escrita não bloqueante significa que ao invés de uma
chamada <B>gets</B> esperar até o dado estar disponível, ele será lido, e
se nenhum dado estiver disponível, a chamada <B>gets</B> irá retornar
um comprimento 0.
<P>
Se você tem muitos canais que devem ser checados para entrada, você pode
usar o comando <B>fileevent</B> para disparar em operações de leitura em
canais, e então usar o comando <B>fblocked</B> para determinar quando
todos os dados foram lidos.
<P>
Os comandos <B>fblocked</B> e <B>fconfigure</B> fornecem mais controle sob
o comportamento de um canal.
<P>
O comando <B>fblocked</B> checa se um canal retornou todas as entradas
diponíveis. É útil quando você está trabalhando com um canal que
foi configurado para o modo não bloqueante, e você precisa determinar
se deveriam haver dados disponíveis, ou se o canal foi fechado do
outro lado.
<P>
O comando <B>fconfigure</B> tem muitas opções que permitem a você consultar
ou sintonizar adequadamente o comportamento de um canal, incluindo se o canal
está no modo bloqueante ou não bloqueante, o tamanho do <I>buffer</I>, o caracter
de final de linha, etc.
<DL>
<B><DT>fconfigure</B> <I>canal ?parametro1? ?valor1? ?parametro2? ?valor2?</I>
<DD>Configura o comportamento de um canal. Se nenhum valor de <I>parametro</I>
é fornecido, uma lista de configurações válidas de parâmetros e
seus valores é retornada.
<P>
Se um único parâmetro é fornecido na linha de comando, o valor daquele
parâmetro é retornado.
<P>
Se um ou mais pares de <I>parametro/valor</I> são fornecidos, aqueles
parâmetros são atribuídos ao valor requisitado.
<P>
Parâmetros que podem ser atribuídos incluem:
<UL>
<LI> -blocking . . . Determina se ou não a tarefa será bloqueada
quando o dado não puder ser movido em um canal. (Isto é, se nenhum
dado está disponível na leitura, ou o <I>buffer</I> está cheio em
uma escrita).
<LI> -buffersize . . . O número de bytes que serão <I>bufferizados</I>
antes do dado ser enviado, ou pode ser <I>bufferizado</I> antes de 
ser lido quando o dado for recebido. O valor deve ser um inteiro entre
10 e 1000000.
<LI> -translation . . . Indica como Tcl irá terminar uma linha quando
ela está na saída. Por padrão, as linhas são terminadas com um
caracter de nova linha, retorno ao início da linha (<I>carriage return</I>), ou caracter de
nova linha/retorno ao início da linha, que é apropriado para o
sistema no qual o interpretador está executando.
<P>Isso pode ser configurado para ser:
  <UL>
  <LI> auto . . . Traduz o caracter de nova linha, <I>carriage return</I>, ou
  caracter de nova linha/<I>carriage return</I> como um marcador de final de linha.
  Exibe a correta terminação de linha para a plataforma atual.
  <LI> binary . . Trata caracteres de nova linha como marcadores de final de linha.
  Não adiciona qualquer terminação para as linhas sendo enviadas para o dispositivo de
  saída.
  <LI> cr . . . . Trata <I>carriage returns</I> como marcadores de final de linha (e
  os traduz para caracteres de nova linha, internamente). As linhas na saída são
  terminadas com um caracter de <I>carriage return</I>. Este é o padrão Macintosh.
  <LI> crlf . . . Trata os pares cr/lf (<I>carriage return</I>/<I>line feed</I>)
  como marcadores de final de linha, e termina as linhas na saída com uma
  combinação <I>carriage return</I>/<I>line feed</I>. Este é o padrão Windows.
  <LI> lf . . . . Trata <I>linefeeds</I> como marcadores de final de linha, e
  termina as linhas da saída com um <I>linefeed</I>. Este é o padrão Unix.
  </UL>
</UL>
</DL>
O exemplo é similar ao exemplo da lição 40 com um <I>socket</I> cliente
e servidor no mesmo script. Ele mostra um canal servidor
sendo configurado para ser não bloqueante, e usar o estilo de
<I>bufferização</I> padrão - dados não estão disponíveis para o
script até que um caracter de nova linha esteja presente, ou
até que o <B>buffer</B> esteja cheio.
<P>
Quando o primeiro escreve:
<CODE>puts -nonewline $sockCliente "Uma linha de teste"</CODE> 
o comando <B>fileevent</B> dispara a leitura, mas o <B>gets</B>
não pode ler caracter porque não há o caracter de nova linha.
O <CODE>gets</CODE> retorna um -1, e <CODE>fblocked</CODE> retorna um 1. 
Quando um caracter de nova linha é enviado, o dado no <I>buffer</I> de
entrada se tornará disponível, e o <CODE>gets</CODE> retorna 
<CODE>18</CODE>, e <CODE>fblocked</CODE> retorna 0.
:TEXT_END:

:CODE_START:

;# Isso é chamado quando um servidor recebe uma conexão
proc abrirServidor {canal endereco porta} {
  puts "Canal: $canal - do Endereco: $endereco  Porta: $porta"
  puts "O estado padrão para bloquear é: [fconfigure $canal -blocking]"
  puts "O tamanho padrão do buffer é: [fconfigure $canal -buffersize ]"

  ;# Configura este canal para ser não bloqueante

  fconfigure $canal -blocking 0
  set bl [fconfigure $canal -blocking]
  puts "Depois de fconfigure, o estado para bloquear é: $bl"
  
  ;# Muda o tamanho do buffer para ser menor

  fconfigure $canal -buffersize 12
  puts "Depois de fconfigure, o tamanho do buffer é: [fconfigure $canal -buffersize ]\n"

  ;# Quando a entrada estiver disponível, leia-a
  fileevent $canal readable "linhaLida servidor $canal"
  }

;# Um proc para ler uma linha de um canal
proc linhaLida {quemChamou canal} {
  global lido
  global bloqueado

  puts "Há uma entrada para $quemChamou no $canal"

  set tamanho [gets $canal linha]
  set bloqueado [fblocked $canal]
  puts "Caracteres lidos: $tamanho Fblocked: $bloqueado"

  if {$tamanho < 0} {
    if {$bloqueado} {puts "Entrada está bloqueada"
      } else {
      puts "O socket foi fechado - fechando meu final"
      close $canal
      }
    } else {
    puts "$tamanho caracteres lidos: $linha"
    puts $canal "Este é um retorno"
    flush $canal
    }
  incr lido
  }

;# Configura um servidor para ouvir na porta 33000
set sockServidor [socket -server abrirServidor 33000]

after 120 update
;#Conecta o cliente à porta 33000
set sockCliente [socket 127.0.0.1 33000]

set bl [fconfigure $sockCliente -blocking] 
set bu [fconfigure $sockCliente -buffersize]
puts "Configuração original para o sockCliente: Sock bloqueante: $bl Tamanho do buffer: $bu"

fconfigure $sockCliente -blocking No
fconfigure $sockCliente -buffersize 8

set bl [fconfigure $sockCliente -blocking] 
set bu [fconfigure $sockCliente -buffersize]
puts "Configuração modificada para o sockCliente: Sock bloqueante: $bl Tamanho do buffer: $bu\n"

# Envia uma linha para o servidor -- Note o flush
set lido 0
puts -nonewline $sockCliente "Uma linha de teste"
flush $sockCliente

# Executa um laço até que as duas leituras tenham sido feitas

while {$lido < 2} {
  ;# Espera até que a variável 'lido' seja atribuída
  vwait lido
  if {$bloqueado} {
    puts $sockCliente " - Nova linha"
    flush $sockCliente
    puts "NOVA LINHA ENVIADA"
  }
}
  
;# Lido o retorno, o exibe
set tamanho [gets $sockCliente linha]
puts "Linha de retorno: $tamanho -- $linha"
close $sockCliente
vwait lido
catch {close $sockServidor}
:TEXT_END:



