先承接前面的设定:
- IP地址 = 大楼地址
- 端口号 = 大楼里房间的门牌号
Socket = 电话听筒,是操作系统给应用程序(PHP、MySQL、Nginx)提供的通信“手柄”。
通俗拆解
一台机器上的程序想要打电话(收发网络数据),不能直接操作网卡、TCP协议栈,必须向操作系统申请一个听筒(socket)。
操作系统负责底层所有复杂的事情:三次握手、分片、序列号、ACK、重传、IP包封装。
而应用程序(PHP),只需要拿着这个听筒,做两件简单的事:往听筒里写数据、从听筒读数据。
分两种角色:服务端Socket 和 客户端Socket
1. 服务端(比如MySQL):守在房间等电话
MySQL进程,向操作系统申请一个socket,绑定到本机IP+3306端口(房间号),然后执行listen监听。
相当于:在3306房间放好电话听筒,一直挂机等待别人打进来。
- 有人发起连接(fsockopen发起TCP握手)
- 操作系统内核完成三次握手,建立连接
- 内核新建一个新的socket听筒,专门用来和这个来电的PHP客户端通话
- 原来监听用的听筒继续留在3306房间,继续等待下一个新来电
关键点:监听socket只负责“接电话”;真正收发数据,用新建出来的通信socket。
2. 客户端(PHP fsockopen):主动拨打电话
$fp=fsockopen("192.168.1.100",3306,$errno,$errstr,30);执行fsockopen的时候:
- PHP向操作系统申请创建一个socket听筒(客户端socket)
- 内核拿着这个听筒,拨打目标大楼+房间号
192.168.1.100:3306 - 完成TCP三次握手,电话接通
- 返回资源句柄
$fp,这个$fp就是PHP代码层面拿到的听筒引用
之后PHP操作:
fwrite($fp, $sql):对着听筒说话,把SQL语句发出去fgets($fp):拿起听筒听对方的回复(MySQL返回的结果)fclose($fp):挂断电话,关闭socket,释放操作系统资源
Socket的本质
Socket =IP + 端口 + 协议(TCP/UDP)的组合标识,是应用层和操作系统内核网络协议栈之间的接口。
对于TCP连接来说,一条完整TCP连接由一组四元组唯一确定:
源IP、源端口、目标IP、目标端口
这四样合在一起,就是两端一对socket。
区分容易混淆的点
❌ Socket就是端口号
✅ 端口只是房间号;Socket是你用来通话的听筒。一个端口可以产生很多socket(MySQL可以同时接待上百个PHP客户端连接,每个连接都有独立socket)。❌ 只有TCP才有Socket
✅ UDP也有socket。UDP的听筒是无连接的,类似发短消息,不用先拨号握手,直接发消息。❌ PHP的
$fp就是socket本身
✅$fp只是PHP暴露给代码的资源句柄,相当于听筒的编号;真正的socket对象存在操作系统内核里。
串起完整通话流程(PHP连MySQL)
- MySQL启动:创建监听socket,绑定0.0.0.0:3306,守在房间等来电
- PHP执行fsockopen:创建客户端socket,呼叫目标IP:3306
- 内核完成三次握手,电话接通,生成一对通信socket
- PHP fwrite,把SQL写入socket → 内核TCP分片、打包、IP发送
- MySQL服务端socket收到字节流,解析SQL、执行查询
- MySQL把结果写入自己这边socket,传回PHP
- PHP读取socket拿到结果
- 通信结束,fclose,关闭socket,挂断TCP连接(四次挥手)
一句话浓缩
Socket就是操作系统给程序的电话听筒;服务端拿听筒守在端口等待呼叫,客户端用听筒主动拨号。程序不用关心底层TCP/IP复杂细节,只需要通过socket读写数据。