Continuem pujant la pila. La capa d'Internet (04-03) movia paquets entre màquines; la capa de transport connecta processos entre si: el navegador de la Marta amb el servidor web de la intranet, el client de correu d'en Jon amb el servidor SMTP, cadascun identificat per un port. Els dos llogaters d'aquesta capa — TCP i UDP — ja els vas disseccionar a 02-04 (handshake, números de seqüència, finestra, datagrames), així que aquí no en repetirem la mecànica interna. El que aporta aquesta lliçó és la capa vista des del teclat: com un programa fa servir TCP a través de sockets (amb pseudocodi línia a línia), com es llegeixen els estats de connexió amb ss i netstat, què significa operativament cada estat, i què passa quan dos processos es barallen pel mateix port — el famós "address already in use" que un dia aturarà la intranet de Meridiano. És important perquè, per a un desenvolupador o un administrador, la capa de transport no és teoria: és la interfície amb què el seu codi toca la xarxa cada dia.
Contingut
- Què viu a la capa de transport
- TCP i UDP: dos serveis, un repàs en una taula
- Sockets: la capa vista pel programador
- Un servidor TCP mínim, línia a línia
- Un client TCP mínim, línia a línia
- Estats de connexió a la pràctica:
ssinetstat - Ports en ús i conflictes: "address already in use"
- TCP vs UDP com a decisió d'arquitectura
Què viu a la capa de transport
La capa de transport de TCP/IP correspon a la capa 4 d'OSI (03-05) i té dos habitants principals:
- TCP (Transmission Control Protocol): servei orientat a connexió i fiable — estableix una sessió amb el three-way handshake, numera els bytes, confirma amb ACK, retransmet allò perdut i regula el ritme amb la finestra (tot plegat vist a 02-04).
- UDP (User Datagram Protocol): servei sense connexió i sense garanties — envia datagrames solts i se'n desentén. Ràpid, lleuger, i honest sobre allò que no promet.
Tots dos comparteixen l'aportació clau de la capa: el multiplexatge per ports. IP lliura el paquet a la màquina 192.168.10.10; el número de port de destinació decideix a quin procés d'aquella màquina va el contingut. La parella completa que identifica una conversa és el socket pair: (IP origen, port origen, IP destinació, port destinació) — i en TCP, a més, el protocol. Per això el servidor de la intranet pot atendre la Marta i l'Ana alhora al mateix port 443: les dues converses difereixen en la IP i el port d'origen.
CAPA DE TRANSPORT a 192.168.10.10
+---------------------------------------------------+
paquet | port 443 -> procés nginx (intranet HTTPS) |
IP --> | port 22 -> procés sshd (administració) |
| port 3306 -> procés mysqld (base de dades) |
+---------------------------------------------------+
una màquina, una IP, molts processos: els ports
són el "número de pis" dins de l'edificiTCP i UDP: dos serveis, un repàs en una taula
Sense repetir la mecànica de 02-04, fixem el contrast com a contracte de servei que la capa ofereix a les aplicacions:
| Propietat | TCP | UDP |
|---|---|---|
| Connexió prèvia | Sí (handshake de 3 passos) | No: s'envia i prou |
| Fiabilitat | Garantida (ACK + retransmissió) | Cap: allò que es perd, perdut queda |
| Ordre d'arribada | Garantit (números de seqüència) | No garantit |
| Unitat que veu l'app | Flux de bytes continu | Datagrames amb fronteres |
| Control de flux/congestió | Sí (finestra) | No |
| Cost d'arrencada | 1 RTT extra pel handshake | Zero |
| Capçalera | 20+ bytes | 8 bytes |
| Segment/PDU | Segment TCP | Datagrama UDP |
Un matís que a 02-04 va quedar implícit i que ara, amb la mirada de programador, importa molt: TCP lliura un flux, no missatges. Si el client fa dos send() de 100 bytes, el servidor els pot rebre en un sol recv() de 200, o en tres trossos de 80+80+40. Les fronteres les posa l'aplicació (per exemple, HTTP amb el seu Content-Length). En UDP, en canvi, cada datagrama arriba sencer o no arriba: un send = un recv.
Sockets: la capa vista pel programador
Un socket és l'objecte que el sistema operatiu ofereix als programes per fer servir la capa de transport. Recorda de 04-01 que la pila TCP/IP viu dins del kernel: el teu programa no construeix segments ni calcula ACK; demana al SO "dona'm un socket TCP", hi escriu bytes, i el kernel fa tota la resta (segmentar, numerar, retransmetre, i passar-ho a la capa d'Internet).
L'API de sockets (nascuda a l'Unix BSD dels anys 80 i calcada des d'aleshores en C, Python, Java, Go, JavaScript...) gira al voltant d'un grapat d'operacions:
| Operació | Qui la fa servir | Què fa |
|---|---|---|
socket() |
tots dos | Crear el socket (triar TCP o UDP) |
bind() |
servidor | Reservar una IP local i un port |
listen() |
servidor | Declarar-se disposat a acceptar connexions |
accept() |
servidor | Esperar i acceptar una connexió entrant |
connect() |
client | Iniciar el handshake cap a IP:port remots |
send() / recv() |
tots dos | Escriure/llegir bytes del flux |
close() |
tots dos | Acabar la connexió (dispara el tancament TCP) |
L'asimetria és la del món real: el servidor espera en un port conegut; el client truca. Vegem-ho en pseudocodi.
Un servidor TCP mínim, línia a línia
Així arrenca, en essència, el servidor de la intranet de Meridiano (el real és nginx + una API, però l'esquelet de sockets és aquest):
1 s = socket(TCP) # demana al kernel un socket TCP
2 bind(s, 192.168.10.10, 8080) # reserva la IP local i el port 8080
3 listen(s) # "estic obert al públic"
4 bucle infinit:
5 c = accept(s) # es BLOQUEJA fins que arribi una connexió
6 peticio = recv(c) # llegeix bytes del flux (p. ex. una petició HTTP)
7 send(c, resposta) # escriu la resposta al flux
8 close(c) # tanca AQUESTA conversa (no el socket d'escolta)Línia a línia, amb allò que passa per sota:
- Línia 1 —
socket(TCP): el kernel crea l'estructura interna i torna un identificador (en Unix, un descriptor de fitxer: per al programa, un socket es llegeix i s'escriu gairebé com un fitxer). - Línia 2 —
bind(...): reserva el port 8080 a la IP192.168.10.10. És l'únic punt on pot saltar l'error "address already in use" (ho veurem a l'apartat 7). Molts servidors fan bind a0.0.0.0("totes les meves IP") en lloc d'una de concreta. - Línia 3 —
listen(s): a partir d'aquí el kernel completa els handshakes tot sol. Quan el SYN de la Marta arribi (02-04), el kernel respon SYN-ACK i encua la connexió acabada, sense que el programa faci res. El socket passa a l'estatLISTEN. - Línia 5 —
accept(s): treu d'aquesta cua una connexió ja establerta i torna un socket nou (c) exclusiu per a aquella conversa. Detall crucial: el socket d'escoltascontinua viu i acceptant; per això el servidor atén molts clients amb un sol port. Si no hi ha connexions pendents,acceptes bloqueja (el procés dorm fins que arribi algú). - Línies 6-7 —
recv/send: llegir i escriure al flux. Recorda: flux de bytes, no missatges;recvpot tornar "mitja petició" i l'aplicació ha de saber recompondre-la. - Línia 8 —
close(c): inicia el tancament ordenat de TCP (intercanvi de FIN/ACK, vist conceptualment a 02-04). Aquest tancament és l'origen de l'estatTIME_WAITque de seguida veuràs ass.
Els servidors reals hi afegeixen concurrència (un fil o tasca per connexió acceptada) i bucles de lectura, però l'esquelet — socket → bind → listen → accept → recv/send → close — és idèntic en qualsevol llenguatge.
Un client TCP mínim, línia a línia
I així es veu el costat de la Marta quan el seu navegador (o un script seu) demana alguna cosa a la intranet:
1 c = socket(TCP) # socket TCP, com al servidor
2 connect(c, 192.168.10.10, 8080) # dispara el three-way handshake
3 send(c, "GET /api/proyectos ...") # escriu la petició al flux
4 resposta = recv(c) # llegeix la resposta
5 close(c) # tancament ordenat- Línia 1 — igual que al servidor: el socket és la mateixa peça a tots dos costats.
- Línia 2 —
connect(...): aquí passa el handshake complet de 02-04 (SYN → SYN-ACK → ACK). Quanconnectretorna sense error, la connexió estàESTABLISHEDa tots dos extrems. Fixa't en allò que el client no va fer: capbind. El kernel li assigna tot sol un port efímer d'origen (típicament entre 32768 i 60999 a Linux) — per això a les captures els clients sempre parlen "des de" ports alts i estranys. - Línies 3-5 — simètriques al servidor: escriure, llegir, tancar.
Una fallada a connect és diagnòstic pur, i ja la coneixes de 03-05: rebuig immediat (RST) = la màquina és viva però ningú no escolta en aquell port; timeout = la màquina o la xarxa no responen. La capa de transport et parla; cal saber escoltar-la.
Estats de connexió a la pràctica: ss i netstat
Tota connexió TCP viu en una màquina d'estats (el handshake i el tancament són transicions dins seu). No cal memoritzar-la sencera: en el dia a dia, tres estats expliquen el 95 % del que veuràs. L'eina moderna a Linux és ss (substituta de netstat, que continua existint i és el que hi ha a Windows).
Al servidor de la intranet, un dimarts qualsevol:
$ ss -tn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 192.168.10.10:443 192.168.10.21:52814
ESTAB 0 0 192.168.10.10:443 192.168.10.35:49102
TIME-WAIT 0 0 192.168.10.10:443 192.168.20.7:51230
$ ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 0.0.0.0:443 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*Desglossament de les opcions: -t = només TCP, -n = números sense resoldre (no tradueix 443 a "https" ni IP a noms — més ràpid i sense ambigüitat), -l = només sockets a l'escolta. A Windows, netstat -ano dona la vista equivalent (la -o hi afegeix el PID del procés).
Els tres estats clau, llegits operativament:
| Estat | Què significa | Lectura operativa |
|---|---|---|
LISTEN |
Socket de servidor esperant connexions (després de listen()) |
"El servei està arrencat i acceptant". Si esperaves un LISTEN al 443 i no hi és, el problema és el procés, no la xarxa |
ESTABLISHED |
Handshake completat; flux obert en tots dos sentits | Una conversa viva. La primera línia de dalt és la Marta (.10.21) navegant per la intranet ara mateix |
TIME_WAIT |
La connexió ja s'ha tancat; l'extrem que va tancar primer reté el socket pair uns 60 s | Normal i sa: evita que segments ressagats de la connexió vella es colin en una de nova amb el mateix socket pair. Veure molts TIME_WAIT en un servidor amb trànsit és rutina, no fuita |
La tercera línia de l'exemple explica una història completa: en Jon (192.168.20.7, Bilbao) va consultar la intranet a través de la VPN, va acabar, i la seva connexió és en TIME_WAIT esperant el seu minut de quarantena abans de desaparèixer.
Altres estats que veuràs de passada: SYN-SENT (client esperant el SYN-ACK; si s'acumulen, la destinació no respon), CLOSE-WAIT (l'altre costat va tancar i la teva aplicació encara no ha cridat close() — si s'acumulen durant hores, sospita d'un bug a l'aplicació: sockets sense tancar).
Ports en ús i conflictes: "address already in use"
L'incident clàssic a Meridiano: l'Ana desplega una versió nova de l'API de la intranet i l'arrencada mor amb:
Traducció exacta: el bind() de la línia 2 del servidor va demanar un port que un altre socket ja té reservat. Les dues causes habituals, de més a menys freqüent:
-
El procés vell continua viu. El desplegament no va matar la versió anterior, que conserva el seu
LISTENal port. Diagnòstic en una línia:$ ss -tlnp | grep :8080 LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=1147,fd=3))L'opció
-p(requereix root) delata l'ocupant: procéspython3, PID 1147. Solució: aturar aquell procés ordenadament (el gestor de serveis —systemctl restart— existeix precisament per no arribar aquí). A Windows:netstat -ano | findstr :8080i buscar el PID a l'Administrador de tareas. -
Connexions residuals del procés anterior (
TIME_WAITamb aquell port com a origen local en certs escenaris de reinici ràpid). Per això els servidors ben escrits activen l'opció de socketSO_REUSEADDRabans delbind: diu al kernel "permet-me reutilitzar el port encara que quedin restes enTIME_WAIT". És la primera línia que un desenvolupador afegeix a un servidor després de patir això una vegada.
Regla operativa: "address already in use" no és mai un problema de xarxa — és un problema local de la màquina, entre processos. La xarxa ni se n'ha assabentat.
I el seu cosí germà al client: si un client obre i tanca milers de connexions per segon cap a la mateixa destinació, pot arribar a esgotar els ports efímers (tots en TIME_WAIT). És estrany en una pime com Meridiano, però explica per què les aplicacions intensives reutilitzen connexions (connection pooling, HTTP keep-alive) en lloc d'obrir-ne una per petició.
TCP vs UDP com a decisió d'arquitectura
Triar transport no és una preferència: és una decisió de disseny que es pren responent dues preguntes — em puc permetre perdre dades? i em puc permetre esperar? Repassem els serveis reals de Meridiano:
| Servei de Meridiano | Transport | Per què |
|---|---|---|
Intranet HTTPS (GET /api/proyectos) |
TCP (443) | Una resposta JSON amb un byte perdut és brossa: fiabilitat obligatòria |
Fitxers compartits (SMB, servidor .10.10) |
TCP (445) | Un document corrupte és inacceptable; a més són transferències llargues: la finestra de TCP les regula |
| Correu (SMTP/IMAP) | TCP (587/993) | Perdre un correu a mitges no és una opció |
| SSH al router i al servidor | TCP (22) | Cada tecla ha d'arribar, i en ordre |
| DNS (consultes de resolució) | UDP (53) | Pregunta i resposta caben en un datagrama; si es perd, el client torna a preguntar al cap d'uns 2 s. El handshake de TCP costaria més que la consulta sencera (TCP queda de reserva per a respostes grans) |
| DHCP (el DORA de 02-05) | UDP (67/68) | El client encara no té IP: impossible mantenir una connexió; són 4 datagrames de difusió |
| Videotrucades València–Bilbao | UDP (RTP) | Un fotograma que arriba tard ja no serveix: val més perdre'l que aturar el vídeo esperant una retransmissió. L'app ho corregeix a la seva manera (ajusta la qualitat) |
| Monitoratge del router (SNMP) | UDP (161) | Sondes petites i freqüents; una de perduda es repeteix al cicle següent |
El patró que emergeix és fiable com una llei: dades que han d'arribar íntegres → TCP; temps real o intercanvis minúsculs on tornar-ho a provar surt més barat que garantir-ho → UDP. I una tercera via moderna que convé conèixer de nom: QUIC, el transport d'HTTP/3, que corre sobre UDP però reimplementa fiabilitat, ordre i xifratge a la mateixa aplicació — la prova que quan UDP "no dona garanties" en realitat està donant llibertat per construir les teves.
Errors Comuns i Consells
- Creure que TCP lliura "missatges". Lliura un flux de bytes: dos
send()poden arribar com un solrecv()o com diversos trossos. Les fronteres de missatge les defineix el protocol d'aplicació. Aquest malentès és la causa número u de bugs de xarxa en codi de principiants. - Espantar-se pels
TIME_WAIT. Són el funcionament correcte del tancament TCP, no connexions penjades ni fuites. Preocupa't, en canvi, pelsCLOSE-WAITacumulats: aquests sí que indiquen que la teva aplicació no tanca sockets. - Buscar a la xarxa un "address already in use". És sempre un conflicte local entre processos per un port.
ss -tlnp(onetstat -ano) identifica l'ocupant en segons. - Confondre el socket d'escolta amb les connexions. El
LISTENdel port 443 és un; cada client acceptat té el seu propi socketESTABLISHED. Tancar una connexió no afecta elLISTEN, i matar elLISTENno talla les connexions ja establertes. - Triar UDP "perquè és més ràpid" sense pla B. UDP no és TCP-sense-llast: és un contracte diferent. Si tries UDP, la fiabilitat que necessitis la programes tu (o assumeixes les pèrdues, com fa el vídeo).
- Consell: memoritza el trio
ss -tln(què escolta?),ss -tn(què conversa?),ss -tlnp(quin és el procés?). Amb aquestes tres ordres es resol la majoria de dubtes de "està aixecat el servei?" abans de tocar res més.
Exercicis
-
L'Ana executa al servidor de la intranet
ss -tni veu la líniaSYN-SENT 0 1 192.168.10.10:41230 192.168.20.7:443repetida durant 30 segons, fins que desapareix amb un error. (a) Qui està actuant com a client i qui com a servidor en aquest intent? (b) Què significa que l'estat es quedi clavat enSYN-SENT? (c) Dona dues hipòtesis compatibles, fent servir allò après a 03-05. -
Al pseudocodi del servidor de l'apartat 4, explica què passaria exactament (i què veuria la Marta des del seu navegador) si: (a) s'elimina la línia 3 (
listen); (b) el programa es queda processant una petició lenta a la línia 6 i mentrestant arriben tres clients nous; (c) s'elimina la línia 8 (close) i el servidor atén centenars de peticions. -
Meridiano muntarà dos serveis nous: (a) un sistema de còpia de seguretat nocturna que puja els fitxers del servidor de València a un emmagatzematge a Bilbao a través de la VPN; (b) un panell a recepció que mostra la temperatura de la sala de servidors, actualitzada cada 2 segons des d'un sensor. Tria transport per a cadascun i justifica-ho amb les dues preguntes de l'apartat 8.
Solucions
-
(a) El servidor de la intranet actua aquí com a client: el port d'origen és efímer (41230) i la destinació és el 443 del PC d'en Jon o d'algun equip de Bilbao (
192.168.20.7) — probablement un chequeig o una integració. Els rols client/servidor són per connexió, no per màquina. (b)SYN-SENTclavat significa que es va enviar el SYN i no va arribar mai el SYN-ACK: el handshake no arrenca; el kernel reintenta el SYN diverses vegades i acaba rendint-se (aquest és l'error al cap d'uns 30 s). (c) Hipòtesis compatibles amb un timeout (03-05): la màquina.20.7està apagada o inabastable (VPN caiguda? — comprovable ambping), o un tallafoc descarta silenciosament els SYN cap a aquell port. Si el port simplement estigués tancat amb la màquina viva, hauria arribat un RST i l'error seria immediat ("connection refused"), no un timeout. -
(a) Sense
listen, el socket no entra mai en estatLISTENi el kernel respon als SYN entrants amb RST: la Marta veuria un "connexió rebutjada" immediat. (Segons el llenguatge, a més, l'acceptde la línia 5 fallaria en executar-se.) (b) Res de greu a curt termini: el kernel completa els handshakes pel seu compte i encua les tres connexions ja establertes (dins del límit del backlog); els tres clients veuen la seva connexió oberta però sense resposta fins que el servidor acabi i torni a l'accept. Perceben lentitud, no rebuig — així es veu un servidor monofil saturat. Si la cua es desborda, els SYN següents sí que es descarten. (c) Cada connexió atesa queda oberta per sempre: elsESTABLISHED(i al client, esperes penjades) s'acumulen, i amb ells els descriptors de fitxer del procés, fins a esgotar el límit del SO i fer queacceptcomenci a fallar. És la fuita de sockets clàssica: es diagnostica veient centenars de connexions velles ass -tnassociades al procés. -
(a) Còpia de seguretat: TCP. Puc perdre dades? No — un backup corrupte és pitjor que no tenir backup. Puc esperar? Sí — és nocturn, la latència tant se val; i la finestra de TCP, a més, aprofitarà bé el túnel VPN regulant el ritme. (b) Panell de temperatura: UDP és raonable. Puc perdre dades? Sí — si es perd la lectura de les 10:00:02, la de les 10:00:04 la substitueix; la dada vella caduca sola. Puc esperar? No té sentit retransmetre una lectura obsoleta. Un datagrama petit cada 2 s sense handshake és l'ajust natural. (TCP tampoc no seria incorrecte aquí — amb tan poc trànsit gairebé no es notaria — però UDP expressa millor el disseny: l'última lectura guanya.)
Conclusió
La capa de transport és on la xarxa deixa de ser lampisteria i es converteix en interfície de programació: TCP i UDP són dos contractes de servei — flux fiable davant de datagrames sense promeses — i el socket és la porta per on qualsevol programa els fa servir, amb el ritual socket → bind → listen → accept al servidor i socket → connect al client, mentre el kernel fa la feina bruta de 02-04 per sota. Ja saps llegir l'estat d'aquesta maquinària (ss -tln per a allò que escolta, ss -tn per a allò que conversa), interpretar operativament LISTEN, ESTABLISHED i TIME_WAIT, desarmar un "address already in use" en dues ordres, i triar transport com el que és: una decisió d'arquitectura que es respon amb dues preguntes. Ens queda un últim esglaó a la pila: la capa d'aplicació, on viuen els protocols que la Marta i en Jon fan servir sense saber-ho — i on veurem, pas a pas, què passa des que el codi de la intranet demana GET /api/proyectos fins que aquells bytes entren al socket que acabes d'aprendre a obrir.
Curs de Xarxes
Mòdul 1: Introducció a les Xarxes
Mòdul 2: Protocols de Comunicació
- Introducció als Protocols de Comunicació
- Protocols d'Enllaç de Dades
- Protocols de Xarxa
- Protocols de Transport
- Protocols d'Aplicació
Mòdul 3: El Model OSI
- Introducció al Model OSI
- Capa Física
- Capa d'Enllaç de Dades
- Capa de Xarxa
- Capa de Transport
- Capa de Sessió
- Capa de Presentació
- Capa d'Aplicació
Mòdul 4: El Model TCP/IP
- Introducció al Model TCP/IP
- Capa d'Accés a la Xarxa
- Capa d'Internet
- Capa de Transport
- Capa d'Aplicació
- Comparativa entre OSI i TCP/IP
