Sockets
Introdução¶
Um socket e um ponto final (endpoint) de comunicacao entre processos em uma rede.
Ele combina um endereco IP, uma porta e um protocolo de transporte (TCP ou UDP).
Sockets pertencem a camada de aplicacao, mas dependem diretamente da camada de transporte.
Em geral, uma aplicacao abre um socket, define para onde deseja enviar ou de onde deseja receber dados, e troca mensagens com outra aplicacao.
Conceitos essenciais¶
Processo, porta e socket¶
Processo: programa em execucao que deseja enviar ou receber dados utilizando a rede.
Porta: identificador lógico para diferenciar servicos no mesmo host.
Socket: par
IP:porta+protocolo. Exemplo:192.0.2.10:8080/TCP.
Tipos de socket¶
TCP (stream): confiável, orientado a conexão, entrega ordenada.
UDP (datagram): nao orientado a conexão, menor sobrecarga, sem garantia de entrega ou ordem.
Estados comuns em TCP¶
LISTEN: servidor aguardando conexões.
ESTABLISHED: conexao ativa entre cliente e servidor.
CLOSE_WAIT / TIME_WAIT: fechamento em progresso.
Como a comunicacao acontece¶
TCP¶
Servidor cria socket e escuta em uma porta.
Cliente cria socket e conecta ao servidor.
O TCP realiza o handshake (SYN, SYN-ACK, ACK) e inicia uma conexão.
Dados sao enviados como um fluxo de bytes.
Conexao é encerrada com controle de fechamento.
UDP¶
Servidor cria socket e associa a uma porta.
Cliente envia datagramas para o
IP:porta.Cada datagrama e independente (nao há conexão).
Relacao com as camadas TCP/IP¶
Aplicacao: define o formato e o significado dos dados enviados.
Transporte: provê TCP ou UDP
TCP: controle de fluxo e confiabilidade.
Rede: entrega dos pacotes pelo IP.
Enlace e Fisica: transmitem os bits no meio.
Práticas¶
Pratica 1: Chat simples com netcat (TCP)¶
Objetivo: criar uma comunicacao cliente-servidor usando TCP.
Abra 3 terminais (para o Servidor, Cliente e Análise):
No terminal para análise execute:
netstat -a -n | grep 9000Observe se existem aplicações utilizando a porta
9000.
No terminal para o Servidor, execute:
nc -l 9000Volte ao terminal de Análise, e observe novamente a porta
9000.
netstat -a -n | grep 9000Em que estado está a conexão TCP?
No terminal do Cliente, execute:
nc 127.0.0.1 9000Volte ao terminal de Análise, e observe novamente a porta
9000.
netstat -a -n | grep 9000Em que estado está a conexão TCP?
Digite mensagens nos terminais conectados e observe se elas são entregues ao outro host.
Prática 2: Envio de datagramas com netcat (UDP)¶
Objetivo: comparar UDP e TCP.
Inicie o Servidor UDP:
nc -u -l 9001Em outro terminal, envie datagramas com um cliente UDP:
nc -u 127.0.0.1 9001Envie mensagens e observe se há conexão estabelecida.
o que é possível concluir aqui?
Pratica 3: Cliente e servidor (TCP)¶
Objetivo: implementar um servidor simples que responde mensagens.
servidor:
criar socket TCP
bind em 0.0.0.0:9002
listen
aceitar conexao
receber ate 1024 bytes
enviar "OK: " + dados
fechar conexaocliente:
criar socket TCP
conectar em 127.0.0.1:9002
enviar "ola socket"
receber resposta
imprimir resposta// Servidor
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(9002);
Socket conn = server.accept();
InputStream in = conn.getInputStream();
OutputStream out = conn.getOutputStream();
byte[] buf = new byte[1024];
int n = in.read(buf);
if (n > 0) {
out.write(("OK: " + new String(buf, 0, n)).getBytes());
}
conn.close();
server.close();
}
}// Cliente
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1", 9002);
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
out.write("ola socket".getBytes());
byte[] buf = new byte[1024];
int n = in.read(buf);
if (n > 0) {
System.out.println(new String(buf, 0, n));
}
s.close();
}
}# Servidor
import socket
HOST = "0.0.0.0"
PORT = 9002
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
data = conn.recv(1024)
conn.sendall(b"OK: " + data)# Cliente
import socket
HOST = "127.0.0.1"
PORT = 9002
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b"ola socket")
print(s.recv(1024).decode())// Servidor
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(9002);
bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
listen(server_fd, 1);
int client_fd = accept(server_fd, NULL, NULL);
char buf[1024];
int n = read(client_fd, buf, sizeof(buf));
if (n > 0) {
write(client_fd, "OK: ", 4);
write(client_fd, buf, n);
}
close(client_fd);
close(server_fd);
return 0;
}
// Cliente
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(9002);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);
connect(sockfd, (struct sockaddr*)&server, sizeof(server));
write(sockfd, "ola socket", 10);
char buf[1024];
int n = read(sockfd, buf, sizeof(buf));
if (n > 0) {
write(1, buf, n);
}
close(sockfd);
return 0;
}Execute o servidor e depois o cliente. Observe o papel de bind, listen, accept, connect, sendall/write e recv/read.
Boas práticas e erros comuns¶
Sempre escolha portas acima de
1024para testes locais.Trate erros de conexao: host inexistente, porta fechada, timeout.
No TCP, lembre que dados chegam como fluxo (não em mensagens).
No UDP, considere perdas e reordenação de pacotes.
Desenvolva uma aplicacao cliente/servidor em que o cliente envia uma mensagem ao servidor contendo uma expressao com operadores + e * e operandos inteiros nao negativos. O servidor deve responder com o resultado da expressao, processando-a da esquerda para a direita.
Opcional: implementar a prioridade entre operadores.
2+3*420Processando da esquerda para a direita: (2+3)=5, 5*4=20.
7*2+1151+2+3+410