企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
php网络主要有[网络核心扩展函数](https://www.kancloud.cn/a173512/php_note/1690697)和[curl扩展函数](https://www.kancloud.cn/a173512/php_note/1690685)构成,具体参看函数参考--其他服务--网络(核心)和cURL扩展 >注意区分PHP流包装器和基于流的套接字函数的套接字传输器(套接字传输协议名称) **PHP 带有很多内置 URL 风格的封装协议,如:** * [file://](https://www.php.net/manual/zh/wrappers.file.php)— 访问本地文件系统 * [http://](https://www.php.net/manual/zh/wrappers.http.php)— 访问 HTTP(s) 网址 * [ftp://](https://www.php.net/manual/zh/wrappers.ftp.php)— 访问 FTP(s) URLs * [php://](https://www.php.net/manual/zh/wrappers.php.php)— 访问各个输入/输出流(I/O streams) * [zlib://](https://www.php.net/manual/zh/wrappers.compression.php)— 压缩流 * [data://](https://www.php.net/manual/zh/wrappers.data.php)— 数据(RFC 2397) * [glob://](https://www.php.net/manual/zh/wrappers.glob.php)— 查找匹配的文件路径模式 * [phar://](https://www.php.net/manual/zh/wrappers.phar.php)— PHP 归档 * [ssh2://](https://www.php.net/manual/zh/wrappers.ssh2.php)— Secure Shell 2 * [rar://](https://www.php.net/manual/zh/wrappers.rar.php)— RAR * [ogg://](https://www.php.net/manual/zh/wrappers.audio.php)— 音频流 * [expect://](https://www.php.net/manual/zh/wrappers.expect.php)— 处理交互式的流 这些封装协议可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 ``` $handle = fopen("/home/rasmus/file.txt", "r");//同fopen("file:///home/rasmus/file.txt", "r") $handle = fopen("/home/rasmus/file.gif", "wb"); $handle = fopen("http://www.example.com/", "r"); $handle = fopen("ftp://user:password@example.com/somefile.txt", "w"); ``` 除了这些封装协议,还能通过[stream\_wrapper\_register()](https://www.php.net/manual/zh/function.stream-wrapper-register.php)来注册自定义的封装协议。 # **流与套接字** //初始化一个套接字连接到指定主机(hostname) ``` $handle=fsockopen ("www.test.com" $port=80 , $errno, $errstr, $timeout = ini_get("default_socket_timeout")) //或者: $handle=fstream_socket_client("tcp://www.test.com:80", $errno, $errstr, 30) ``` >fsockopen()**将返回一个文件句柄**,之后可以被其他文件类函数调用(例如:fgets(),fgetss(),fwrite(),fclose()还有feof())。如果调用失败,将返回FALSE 要得到自己的 PHP 版本中所安装的传输器列表,使用 stream_get_transports() ``` var_dump(stream_get_transports());//array(8) { [0]=> string(3) "tcp" [1]=> string(3) "udp" [2]=> string(3) "ssl" [3]=> string(5) "sslv3" [4]=> string(3) "tls" [5]=> string(7) "tlsv1.0" [6]=> string(7) "tlsv1.1" [7]=> string(7) "tlsv1.2" } ``` **所支持的套接字传输器(Socket Transports)列表** ## **Internet 领域:** ``` 127.0.0.1 fe80::1 www.example.com tcp://127.0.0.1 默认是 tcp:// 所以可以省略哦 tcp://fe80::1 tcp://www.example.com udp://www.example.com ssl://www.example.com 自 PHP 4.3 起可用 sslv2://www.example.com 自 PHP 5.0.2 起可用 sslv3://www.example.com 自 PHP 5.0.2 起可用 tls://www.example.com 自 PHP 4.3 起可用 ``` ## **Unix 领域:** 进程间通信方式有很多,套接字(Socket)就是其中的一种。但传统的套接字的用法都是基于TCP/IP协议栈的,需要指定IP地址。 如果不同主机上的两个进程进行通信,当然这样做没什么问题。但是,如果只需要在一台机器上的两个不同进程间通信,还要用到IP地址就有点多余。 而这个Unix域套接字的类别,专门用来解决这个问题 ``` unix:///tmp/mysock 自 PHP 3 起可用 udg:///tmp/mysock 自 PHP 5 起可用。 ``` >[danger]以上各种 URL 风格的套接字传输器 用于基于流的套接字函数,如fsockopen()和stream_socket_client() >这些传输器 不适用于 Sockets 扩展库 Internet 领域套接字在目标地址中还期望有一个端口号。在 fsockopen()中在第二个参数中指定,这样就不会影响传输器的 URL。然而在 stream_socket_client()和相关的函数中是用传统的 URL,端口号在传输器 URL 后面以冒号分隔而指定 ``` tcp://127.0.0.1:80 tcp://[fe80::1]:80 IPv6 tcp://www.example.com:80 ``` ~~~ $handle=fsockopen ("www.test.com" $port=80 , $errno, $errstr, $timeout = ini_get("default_socket_timeout")) //或者: $handle=fstream_socket_client("tcp://www.test.com:80", $errno, $errstr, 30) ~~~ >[danger]**注意:** ssl://和 tls://传输器(仅在 openssl 支持已编译入 PHP 后可用)是 tcp://传输器加入 SSL 加密后的扩展。在 PHP 4.3.0 中 OpenSSL 支持必须被静态编译入 PHP,在 PHP 5.0.0 中可以编译为模块或者静态的。 ssl://将根据远程服务器的兼容性和参数设置尝试与之建立 SSL V2 或 SSL V3 链接 sslv2://和 sslv3://将明确的选择 SSL V2 或 SSL V3 协议进行连接。 **ssl:// 和 tls:// 传输器的上下文选项(自 PHP 4.3.2 起)** | 名称 | 用法 | 默认值 | | --- | --- | --- | | *verify\_peer* | &true; 或 &false;。用于 SSL 证书请求验证。 | &false; | | *allow\_self\_signed* | &true; 或 &false;。允许自签名的证书。 | &false; | | *cafile* | 本地文件系统中证书授权机构文件的位置,应和*verify\_peer*上下文选项一起使用来认证远端的身份。 |   | | *capath* | 如果没有指定*cafile*或者如果该处没找到证书,则在*capath*指定的目录中搜索相配的证书。*capath*必须是一个正确的被散列化的证书目录。 |   | | *local\_cert* | 文件系统中本地证书文件的路径。必须是一个用 PEM 编码并包含你的证书和私人密钥的文件。可以选择包括发行者的证书链。 |   | | *passphrase* | 你的*local\_cert*文件编码的 passphrase。 |   | | *CN\_match* | 所期待的 Common Name。PHP 能进行有限的通配符匹配。如果 Common Name 与此不匹配,连接尝试会失败。 | >[danger]Note: 因为 ssl://是 https:// 和 ftps:// 封装协议的底层传输器,适用于 ssl://的任何上下文选项也适用于 https://和 ftps://。 **套接字传输器**适用于fsockopen 和 流 却不适用于socket扩展 # **套接字(socket)** 套接字扩展在流行的BSD套接字的基础上实现了套接字通信功能的低级接口,从而可以充当套接字服务器和客户端。有关更通用的客户端套接字接口,请参见`stream_socket_client()`, `stream_socket_server()`, `fsockopen()`, 和 `pfsockopen()` **示例代码** 套接字: ~~~ ... $main_socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Cannot create socket.\n"); @socket_bind($main_socket, $host, $port) or die("Could not bind to socket $host : $port.\n"); @socket_listen($main_socket, 5) or die("Could not set up socket listener\n"); ... ~~~ 流: ~~~ ... $main_socket = @stream_socket_server ("tcp://$host:$port", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN) or die("Cannot create socket.\n"); $clients = array($main_socket); $clients_peername = array(array('port' => $port)); fputs(STDOUT, "Waiting for connections...\n"); ... ~~~ 可以看到的重点是: * 可以使用任一**套接字**(sockets)函数或任一**流**(Streams)函数来创建客户机和服务器 * Streams是PHP核心的一部分,而Sockets是扩展 套接字和流之间有什么区别? 相比较而言fsockopen 和 流 而言,socket更底层的。可以在创建套接字时更好进行更细粒度的控制,并且可以选择SOCK_STREAM,SOCK_DGRAM,SOCK_SEQPACKET等。 我能想到的唯一常见例外是ICMP。例如,`ping`。但是,似乎目前还没有从PHP进行ICMP的安全方法。此类调用需要通过套接字扩展名进行SOCK\_RAW,套接字扩展名需要具有**root权限**才能执行。另外,并非所有路由器都会路由TCP,UDP和ICMP之外的其他数据包类型。这限制了套接字扩展的用途。 好理解的比喻: socket 水泥、沙子,底层的东西 fsockopen 水泥预制件,可以用来搭房子 curl 毛坯房,自己装修一下就能住了 stream_socket_client 和 fsockopen 没有本质上的区别 socket 是一个封装了 TCP/IP 操作的工具包 stream_socket_client 和 fsockopen 分属不同流派的对 socket 的封装 fsockopen 是比较底层的调用,属于网络系统的socket调用,而curl经过的包装支持HTTPS认证,HTTP POST方法, HTTP PUT方法,FTP上传, kerberos认证,HTTP上传,代理服务器, cookies,用户名/密码认证,下载文件断点续传,上载文件断点续传,http代理服务器管道( proxy tunneling),甚至它还支持IPv6, socks5代理服务器,,通过http代理服务器上传文件到FTP服务器等等,功能十分强大。fsockopen 返回的是没有处理过的数据,包括数据的长度数据内容和数据的结束符。而curl是处理后的内容 使用时,curl 更加方便,但其参数很多,配置稍微复杂,fsockopen 则有固定的几个参数,简单,但获取结果可能需要再做处理 **file_get_contents呢?** 有些时候用 file_get_contents() 调用外部文件容易超时报错。curl 效率比 file_get_contents() 和 fsockopen() 高一些,原因是CURL会自动对DNS信息进行缓存。 file_get_contents / curl / fsockopen 在当前所请求环境下选择性操作,没有一概而论。 file_get_contents 需要php.ini里开启allow_url_fopen,请求http时,使用的是http_fopen_wrapper,不会keeplive的话curl是可以的。 file_get_contents()单个执行效率高,返回没有头的信息。  这个是读取一般文件的时候并没有什么问题,但是在读取远程问题的时候有可能就会出现问题。如果是要打一个持续连接,多次请求多个页面。那么[file_get_contents](http://www.nowamagic.net/academy/tag/file_get_contents)和fopen就会出问题。取得的内容也可能会不对。所以做一些类似采集工作的时候,肯定就有问题了。  fsockopen 较底层,可以设置基于UDP或是TCP协议去交互,配置麻烦,不易操作。返回完整信息。  总之,file_get_contents 和 curl 能干的,socket都能干。socket能干的,curl 就不一定能干了。file_get_contents 更多的时候只是去拉取数据。效率比较高也比较简单。  只讨论 [curl](http://www.nowamagic.net/academy/tag/curl) 与file_get_contents 的话,有这么一些结论: 1.    fopen /file_get_contents 每次请求都会重新做DNS查询,并不对DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。 2.    fopen /file_get_contents在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。 3.    fopen / file_get_contents函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。 4.    curl可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。 PS:file_get_contents()函数获取https链接内容的时候,需要php 中mod_ssl的支持(或安装opensll)。 结论就是,curl 效率及稳定都比 file_get_contents() 要好,fsockopen 也很强大,但是比较偏底层。 参考:[stream\_context\_create()模拟POST/GET](http://www.nowamagic.net/librarys/veda/detail/2585)