大家好,今天小编来为大家解答以下的问题,关于“PHP”从一个简单的套接字服务器开始,这个很多人还不知道,现在让我们一起来看看吧!
在PHP中,有两套函数可以控制socket,一套是socket_系列函数,一套是stream_系列函数。 Socket_是PHP直接用C语言复制socket得到的实现,而stream_系统是PHP利用流的概念进行封装的。下面使用socket_*系列函数来简单开始本系列文章。
我们先来做一个最简单的socket服务器:
?php$主机=’0.0.0.0′;$端口=9999; //创建TCP 套接字$listen_socket=socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); //将socket绑定到IP:端口socket_bind( $listen_socket, $host, $port );//开始监听socketsocket_listen( $listen_socket );//进入while循环,不用担心死循环崩溃,因为程序会阻塞在下面的socket_accept()函数上while( true ){ //这里它将被阻塞,直到有客户端来连接服务器。被阻塞的进程不会占用CPU //所以你不必担心while循环会导致机器宕机,没有$connection_socket=socket_accept( $listen_socket ); //向客户端发送helloworld $msg=’helloworld\r\n’; socket_write( $connection_socket, $msg, strlen( $msg ) ); socket_close( $connection_socket );}socket_close( $listen_socket );将文件保存为server.php,然后执行php server.php来运行它。我们可以在客户端使用telnet。打开另一个终端并执行telnet 127.0.0.1 9999 并按Enter。运行结果如下:
我们简单分析一下上面的代码来解释一下tcp socket server的流程:
1. 首先,根据协议族(或地址族)、套接字类型和特定协议创建套接字。 2. 其次,将上一步中创建的套接字绑定到ip: 端口。 3. 第三,打开监听。 4、第四,让服务器代码进入死循环而不退出。当没有客户端连接时,程序在接受时阻塞。只有当有连接进来时才会向下执行,然后再次循环为客户端提供持久化服务。上述案例有两个很大的缺陷:
1. 一次只能提供一个客户端。如果在将helloworld 发送到第一个客户端时有第二个客户端连接,则第二个客户端必须等待一段时间。 2、容易受到攻击,造成拒绝服务。分析完上面的问题,我们就想到了前面提到的多进程。然后我们可以在accpet收到请求后fork一个子进程来处理客户端的请求。这样,在接受第二个客户端之后,我们就可以fork一个子进程了。处理第二个客户端的请求的流程,这样不就解决问题了吗?好的!让我们用一些代码来演示:
?php$主机=’0.0.0.0′;$端口=9999; //创建TCP 套接字$listen_socket=socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); //将socket绑定到IP:端口socket_bind( $listen_socket, $host, $port );//开始监听socketsocket_listen( $listen_socket );//进入while循环,不用担心死循环崩溃,因为程序会阻塞在下面的socket_accept()函数上while( true ){ //这里它将被阻塞,直到有客户端来连接服务器。被阻塞的进程不会占用CPU //所以你不必担心while循环会导致机器宕机,没有$connection_socket=socket_accept( $listen_socket ); //当接受新的客户端连接时, fork 创建一个专门处理的子进程$pid=pcntl_fork(); //在子流程中处理当前连接的请求业务if( 0==$pid ){ //向客户端发送helloworld $msg=’helloworld\r\ n’; socket_write( $connection_socket, $msg, strlen( $msg ) ); //休眠5秒,可用于同时观察和服务多个客户端echo time().’第:章一个新的客户端’.PHP_EOL;睡眠(5); socket_close( $connection_socket );出口; }}socket_close( $listen_socket );将代码保存为server.php,然后执行php server.php。客户端仍然使用telnet 127.0.0.1 9999,只是这次我们打开两个终端来执行telnet。值得注意的是,第一个客户端连接后,第二个客户端也可以连接。运行结果如下:
通过接收客户端请求的时间戳,可以看到服务器现在可以同时为N个客户端提供服务。但是,转念一想,如果有一万个客户来请求怎么办?这时服务器会fork出10000个子进程来处理每个客户端连接,这会害死人的。 fork本身就是一个系统调用,浪费系统资源。 10,000 个分叉就足以导致系统崩溃。即使系统能承受1000次fork,fork出来的1000个子进程也足够喝掉一盆系统内存了。最后,还好吗?容易fork出的子进程在处理完当前客户端后会被关闭,下次请求时还得再次fork。这本身就是一种浪费,也不符合社会主义主流价值观。如果出现恶意攻击,系统分叉的数量会线性增加,直至系统崩溃。
于是,我们再次提出了增强的解决方案。我们可以预估业务量,然后在服务启动时fork固定数量的子进程。每个子进程都处于无限循环中,并在接受时被阻止。当客户端连接挤入时,就会处理客户请求。处理完成后,连接仅关闭但不销毁,而是继续等待下一个客户端请求。这样既避免了进程重复fork造成的巨大资源浪费,又可以通过固定数量的子进程来保护系统不因无限fork而崩溃。
?php$主机=’0.0.0.0′;$端口=9999; //创建TCP 套接字$listen_socket=socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); //将socket绑定到IP:端口socket_bind( $listen_socket, $host, $port );//开始监听socketsocket_listen( $listen_socket );//更改主进程名称cli_set_process_title( ‘phpserver master process’ ) ;//根据数量fork出固定数量的子进程for( $i=1; $i=10; $i++ ){ $pid=pcntl_fork(); if( 0==$pid ){ cli_set_process_title( ‘phpserver 工作进程’ ); while( true ){ $conn_socket=socket_accept( $listen_socket ); $msg=’你好世界\r\n’; socket_write( $conn_socket, $msg, strlen( $msg ) ); socket_close( $conn_socket ); } }}//主进程无法退出。代码演示很粗糙。为了不保证直接退出运行一个while循环,休眠一秒//其实主进程真正应该做的就是收集子进程的pid,监控每个子进程的状态等. while( true ){ sleep( 1 );}socket_close( $connection_socket ) ;保存文件为server.php然后执行php server.php,然后使用ps -ef | grep phpserver | grep phpserver | grep phpserver grep -v grep 查看服务器进程状态:
可以看到master进程存在。另外还有10个等待服务的子进程,可以同时为10个客户端提供服务。我们通过telnet 127.0.0.1 9999来尝试一下,结果如下:
好了,PHP新征程系列就从简单的介绍开始吧!下一篇文章将介绍一些更深刻的理论基础。
原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/199106.html
用户评论
拉扯
想学一学网络编程,这篇文章感觉还不错入门!Socket协议挺复杂的,不过这个简单示例看起来还是能理解的,准备跟着来实践一下!
有12位网友表示赞同!
凉月流沐@
终于找到一个合适的教程了,我一直在找一些关于PHP socket服务器的学习资源,之前网上看到的要么过于基础没内容,要么太复杂直接看不懂。这篇文章刚好适合我这种初学者。
有5位网友表示赞同!
有阳光还感觉冷
socket编程在php里感觉有点不太常用啊,很多时候我们用的都是第三方库或服务的接口吧?不过还是要了解一下原理的,说不定以后用到。
有15位网友表示赞同!
昂贵的背影
这确实是一个很好的入门示例,但如果想进行更复杂的应用场景处理,比如并发连接、数据加密等等,还需要学习更多高级知识啊。这篇博客只介绍了最基础的Socket服务器搭建方法,不够全面。
有17位网友表示赞同!
搞搞嗎妹妹
PHP本来就是为了web开发而生的,搞个socket服务器是不是有点 overkill? 感觉用其他的语言更合适吧?
有19位网友表示赞同!
Hello爱情风
这个例子写的太简单了,完全没有考虑到安全性问题啊!生产环境下肯定需要做身份验证、数据加密等处理才能确保安全。
有5位网友表示赞同!
酒笙倾凉
PHP写socket其实还是挺好用的,速度也不慢!感觉比python的socket更快一点吧?
有19位网友表示赞同!
我没有爱人i
这段代码确实写的很简洁易懂,我刚学的php,跟着这个例子很容易理解Socket编程的基本原理和步骤。点赞!
有5位网友表示赞同!
花花世界总是那么虚伪﹌
作者能不能解释下这个服务器是如何处理客户端请求的?我看代码里就一个接收数据块的部分,但是好像没有看到具体的处理逻辑
有7位网友表示赞同!
花海
感觉这篇文章挺有启发性的,我之前一直以为PHP只能用来开发网站,没想到还可以用来写socket服务! 真是眼界开阔了!
有7位网友表示赞同!
轨迹!
希望作者能够更新一下这个教程,添加一些更深入的讲解和示例吧!比如如何实现并发连接、数据加密等等。
有14位网友表示赞同!
醉婉笙歌
其实对于初学者来说,先学会基础的Socket的概念以及C语言实现的Socket程序,然后再学习PHP实现Socket服务器会更加直观易懂。这篇文章就适合作为入门指南来了解一下基本思想和API。
有14位网友表示赞同!
怀念·最初
这个例子只能处理单线程连接,如果想要实现并发服务,还需要学习其他高级技术,比如异步IO或者使用Nginx或Apache这样高性能 web 服务器作为代理服务器。<br/>PHP本身并不能很好的完成高并发处理的Socket服务器构建。
有17位网友表示赞同!
黑夜漫长
这篇文章很能帮助我理解Socket的基本概念,但是我觉得作者可以添加一些实例讲解,比如怎么用Socket来实现聊天室或者文件传输等功能 会更有实际意义!
有9位网友表示赞同!
猫腻
PHP写socket服务器还是比其他语言简单很多,因为它本身就提供了很多web开发相关的处理和框架。 如果想要快速搭建一个简单的网站后端或API接口,可以考虑使用PHP + socket 的方案!
有14位网友表示赞同!
放肆丶小侽人
我感觉PHP Socket编程的局限性比较大,在处理高并发或者复杂业务场景时性能瓶颈明显,不如使用其他语言或框架更合适。但是对于简单的应用需求,学习一下 PHP Socket 确实很有帮助可以积累一些基础知识
有19位网友表示赞同!
全网暗恋者
这个例子对我来说太基础了,我想学习如何使用socket来实现多线程编程和数据安全机制。 希望作者能进一步更新教程!
有7位网友表示赞同!