# Comunicação TCP/IP

Vamos supor que um determinado computador "A", chamado **client**, queira enviar uma mensagem a outro computador "B", chamado **server**. A mensagem que o client envia, também chamada de *request*, precisa ser transportada através de algum tipo de rede, ou *network*. O server, por sua vez, pode enviar uma resposta ao client, chamada de *response*.

![](https://user-images.githubusercontent.com/385640/148705095-b6402218-bb2a-46ce-b1c3-4de928a38c0d.png)

### Rede

Mas o quê é esta "rede" que fica ali no meio de dois computadores distintos? Podem ser diversos tipos de redes, públicas e privadas, mas quando estamos falando de uma rede global e **descentralizada**, nos referimos à **Internet**, onde computadores conectados de lugares distintos no planeta podem se comunicar.

![](https://user-images.githubusercontent.com/385640/148705746-33439d8d-aa83-41ea-a8d5-43617c09f169.png)

Mas do quê a Internet é composta? Quais são as ferramentas e conceitos existentes na Internet que *garantem* que as mensagens são entregues da forma esperada?

Vamos dividir estes conceitos e ferramentas em **camadas**.

### Camada 1: Física

Para criamos uma rede, precisamos definir a infra estrutura física através de **arquitetura de rede**, utilizando o cabeamento correto e roteamento de mensagens dentro da rede. Esta camada envolve apenas a parte física e envolve tecnologias como *Ethernet, Bluetooth, ondas de rádio, fibra optica*, entre outros.

### Camada 2: Rede (IP)

Como um client poderia enviar uma mensagem a um server? E se enviarmos num formato que muitos de nós já conhecemos, como as **correspondências**?

![](https://user-images.githubusercontent.com/385640/148706026-40a657d1-73f0-4045-967c-05c6d0c0aedc.png)

E se por acaso algum computador na rede, mal-intencionado ou esquecido, resolve enviar uma mensagem com formato errado, difícil de interpretar?

![](https://user-images.githubusercontent.com/385640/148706123-4d7b93fd-d650-4d67-8b08-43048da41b43.png)

Neste caso a mensagem talvez nem conseguiria ser entregue ao destino, pois tem um formato inválido.

No caso da Internet, esta camada se chama [Internet Protocol](https://en.wikipedia.org/wiki/Internet_Protocol), ou IP, e define um protocolo para que as mensagens tenham um determinado padrão de envio.

### Camada 3: Transporte (TCP, UDP)

Como então garantir que as mensagens chegam de um lado para o outro? Serão *transportadas* de forma correta? Na ordem correta?

Esta camada define o formato de **transmissão** das mensagens, onde pode ser definido se há confirmações ou não de envio, tentativas em caso de falhas, dentre outras formas de garantia de envio. Nesta camada, fica um dos protocolos de envio mais conhecidos, o [TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol).

### Camada 4: Aplicação

E se quisermos criar uma abstração por cima do formato da mensagem onde podemos suportar outros formatos e protocolos de mensagens? Como suportar multi-formatos? Envio de "correspondências virtuais" (e-mails) com garantia de entrega?

![](https://user-images.githubusercontent.com/385640/148706687-f7401eca-f8f1-4bf8-b848-e85218d414a3.png)

A camada de aplicação é responsável por definir protocolos de *formatos de mensagens* que serão enviados através de TCP/IP. Dentre estes protocolos, podemos destacar [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol), [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol), [FTP](https://en.wikipedia.org/wiki/File_Transfer_Protocol) dentre outros.

Então aqui temos o resumo das 4 camadas definidas no standard TCP/IP:

![](/files/fxJmLZytJjh3OrsuFJik)

### Computadores e TCP/IP

Como um computador consegue enviar e receber mensagens na rede? Indo além, como um computador consegue **conectar** com outro computador?

Os sistemas operacionais fornecem uma funcionalidade para que possamos utilizar recursos de rede em diversos "pontos". Tais pontos são chamados de "endpoints", ou **sockets**.

<div align="center"><img src="https://user-images.githubusercontent.com/385640/148707068-8af0ef4d-d021-435c-9857-ab7b2d31ae1a.png" alt=""></div>

Com sockets conseguimos conectar a outro computador, e também enviar e receber mensagens. O sistema operacional também permite que alguns endpoints possam receber um identificador único no computador, também chamado de **porta**.

```bash
=> lsof -i tcp:3000

COMMAND     PID    USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
com.docke 21027 leandro  104u  IPv6 0xd7f6748eef91a4e7      0t0  TCP localhost:hbci->localhost:53696 (CLOSED)
com.docke 21027 leandro  106u  IPv6 0xd7f6748ee3098827      0t0  TCP localhost:hbci->localhost:53697 (CLOSED)
com.docke 21027 leandro  112u  IPv6 0xd7f6748ef2704e87      0t0  TCP localhost:hbci->localhost:53702 (CLOSED)
com.docke 21027 leandro  124u  IPv6 0xd7f6748ef0efbe87      0t0  TCP *:hbci (LISTEN)
```

Destaque para a coluna `FD`, que representa o endpoint, ou socket. E a `DEVICE`, que representa o dispositivo físico de rede do computador.

### Comunicação TCP/IP em Ruby

Ruby fornece uma API já incluída no pacote standard para manipulacão de sockets TCP/IP.

Vamos criar um TCP server muito simples em Ruby, que abre um socket na porta 3000:

`server.rb`

```ruby
require 'socket'

# Abre o socket e atribui na porta 3000
socket = TCPServer.new('0.0.0.0', 3000)

# Socket aberto à espera de novas conexões na rede
# O programa fica bloqueado nesta linha enquanto não houver nova conexão
client = socket.accept

# Uma vez que uma nova conexão chega, o programa continua
# E aqui podemos fazer a leitura de mensagens que chegaram no socket
request = client.gets

# Envia uma mensagem para o client através do socket aberto
client.puts('Yo, client')

# Fecha a conexão com o client
client.close

# Encerra o socket e liberta a porta 3000 para ficar livre no sistema operacional
socket.close
```

Agora, um client TCP simples em Ruby:

`client.rb`

```ruby
require 'socket'

# Conecta em algum socket já aberto na porta 3000
server = TCPSocket.new('0.0.0.0', 3000)

# Envia mensagem ao server através do socket
server.puts('Yo, server!') 

# Recebe mensagem do server através do docket
response = server.gets

# Fecha o socket deste lado do client
server.close
```

### Server em loop

Obviamente, não podemos ter um servidor que encerra o socket na porta a cada conexão. Para resolver isto, podemos colocar o server em loop, onde a cada vez que uma conexão é **fechada**, o server volta para o início do loop e fica *bloqueado a espera de uma nova conexão*.

`server.rb`

```ruby
...
loop do
  client     = server.accept
  request = client.gets

  client.puts 'My response'
  client.close
end
```

### Padrão TCP/IP

Podemos reparar que o padrão de envio de mensagens através de TCP/IP é:

1. server abre socket em alguma porta de rede
2. server fica bloqueado a espera de conexão no socket
3. server recebe mensagem do client
4. server envia mensagem para o client
5. server fecha conexão com client
6. server fica novamente bloqueado a espera de nova conexão

O quê acontece quando o mesmo client tenta novamente conectar no servidor? Nosso servidor consegue se "lembrar" quem era o primeiro client?

Por definição, o server não guarda informações dos clients nesta camada de rede, não há *estado*, o que caracteriza que o TCP/IP é **stateless** pode definição. Este conceito será importante para que possamos entender, posteriormente, as particularidades de aplicações Web que rodam através de HTTP.

### Pull Request

<https://github.com/leandronsp/yatax/pull/1>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yatax.leandronsp.com/comunicacao-tcp-ip.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
