名字相似但完全不同的WebSocket
尽管名字里也带"Socket",WebSocket并不是本页讲的操作系统层面的套接字,而是专门为浏览器和服务器之间保持持续双向通信而设计的一种独立的应用层协议,常用于聊天应用和实时更新功能。WebSocket连接底层实际上仍然是建立在普通的TCP套接字之上的。
套接字、防火墙和端口转发其实是同一件事的不同侧面
防火墙规则封锁某个端口,本质上是阻止在该端口上建立新的套接字;而端口转发的原理,则是把路由器收到的套接字连接转发给内网中的特定设备。一旦理解了套接字这个概念,这些原本看似要分别记忆的规则,其实都是同一套原理的不同表现。
如何读懂netstat或ss的输出
在Windows上运行netstat -an,或在Linux上运行ss -tan,会看到一份套接字列表,包含本地地址、远端地址和状态。状态为LISTEN的行是监听套接字,显示服务器在哪个地址上等待;0.0.0.0或[::]表示所有网卡,127.0.0.1则表示只有本机能访问。ESTABLISHED的行是正在进行的会话,每一条都是本地与远端端点的唯一组合。TIME_WAIT和CLOSE_WAIT表示连接正在结束。如果某个程序持有大量CLOSE_WAIT套接字,往往说明它没有正确关闭连接,这是服务端代码里常见的缺陷。掌握这些状态,就更容易判断服务到底有没有在监听,这也是连不上时首先要回答的问题。
使用套接字时的常见错误
初学者常把连接失败和端口关闭混为一谈:连接被拒绝说明有机器作出了应答但那里没有程序在监听,而超时通常意味着防火墙丢弃了数据包,或主机不可达。另一个陷阱是把服务器绑定到127.0.0.1,然后纳闷为什么别的机器连不上。忘记TCP是字节流而不是消息流,会导致一次发送被分成两次读取,或两次发送被合并成一次到达的缺陷。最后,端口已被占用的错误通常是另一个程序,或上一次运行遗留的TIME_WAIT占着这个地址。
常见问题
套接字的端口号需要自己指定吗?
不需要。服务器一侧使用的知名端口(如80、443)由程序或管理员设定,但客户端连接时使用的临时端口是操作系统自动分配的,用户不需要自己配置。
服务器会出现套接字不够用的情况吗?
会的。在极短时间内建立和断开大量连接的服务器上,可能会出现临时端口暂时不够用的"套接字耗尽"现象。这种情况通常可以通过调整服务器端的连接复用(Keep-Alive)设置来缓解。
一台设备有多少个端口?
TCP和UDP各有65536个端口号(0~65535)。0号端口是保留的,不用于正常通信。设备并不会用到全部端口,大多数端口在任意时刻都是空闲的。
两个程序能监听同一个端口吗?
在同一地址和协议上通常不行,后启动的程序会收到地址已被使用的错误。也有让多个进程在同一端口上接受连接来分担负载的选项,但必须显式开启。TCP和UDP的端口空间是分开的,所以一个程序可以用TCP 53,另一个用UDP 53。
套接字就是连接吗?
很接近,但不完全相同。套接字是程序持有的一个端点,连接则是两个端点的配对。监听套接字在客户端到来之前没有任何连接。