PHP的Socket网络编程入门指引


Posted in PHP onAugust 11, 2015

什么是TCP/IP、UDP?

         TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
         UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
        这里有一张图,表明了这些协议的关系。

PHP的Socket网络编程入门指引

TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IP与UDP的关系了吧。
Socket在哪里呢?

在图1中,我们没有看到Socket的影子,那么它到底在哪里呢?还是用图来说话,一目了然。

PHP的Socket网络编程入门指引

原来Socket在这里。
Socket是什么呢?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
你会使用它们吗?

前人已经给我们做了好多的事了,网络间的通信也就简单了许多,但毕竟还是有挺多工作要做的。以前听到Socket编程,觉得它是比较高深的编程知识,但是只要弄清Socket编程的工作原理,神秘的面纱也就揭开了。

一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理,也许TCP/IP协议族就是诞生于生活中,这也不一定。

PHP的Socket网络编程入门指引

PHP的Socket编程概述
php5.3自带了socket模块,使得php具有socket通信能力,具体api可以参考官方手册:http://php.net/manual/zh/function.socket-create.php, 具体实现跟c非常类似,只是少了内存分配和网络字节序转换这种底层操作

同时,php的pcntl模块和posix模块配合可以实现基本的进程管理、信号处理等操作系统级别的功能。这里有两个非常关键的函数,pcntl_fork()和posix_setsid()。fork()一个进程,则表示创建了一个运行进程的副本,副本被认为是子进程,而原始进程被认为是父进程。当fork()运行之后,则可以脱离启动它的进程和终端控制等,也意味着父进程可以自由退出。pcntl_fork()返回值,-1表示执行失败,0表示在子进程中,大于0表示在父进程中。setsit(),它首先使新进程成为一个新会话的“领导者”,最后使进程不再控制终端。这也是成为守护进程最关键一步,这意味着,不会随着终端关闭而强制退出进程。对于一个不会被中断的常驻进程来说,这是很关键的一步。进行最后一次fork(),这一步不是必须的,但通常都这么做,它最大的意义是防止获得控制终端

什么是守护进程?一个守护进程通常被认为是一个不对终端进行控制的后台任务。它有三个很明显的特征:

  1.     在后台运行
  2.     与启动他的进程脱离
  3.     无须终端控制

最常见的实现方法:fork() -> setsid() -> fork(), 代码里run_server()方法实现了守护进程。

server端socket监听代码

<?php 
   
  // 接受客户端请求,回复固定的响应内容 
  function server_listen_socket ($address, $port) 
  { 
    $buffer = "Msg from wangzhengyi server, so kubi..."; 
    $len = strlen($buffer); 
     
    // create, bind and listen to socket 
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 
    if (! $socket) { 
      echo "failed to create socket:" . socket_strerror($socket) . "\n"; 
      exit(); 
    } 
     
    $bind_flag = socket_bind($socket, $address, $port); 
    if (! $bind_flag) { 
      echo "failed to bind socket:" . socket_strerror($bind_flag) . "\n"; 
      exit(); 
    } 
     
    $backlog = 20; 
    $listen_flag = socket_listen($socket, $backlog); 
    if (! $listen_flag) { 
      echo "failed to listen to socket:" . socket_strerror($listen_flag) . "\n"; 
      exit(); 
    } 
     
    echo "waiting for clients to connect\n"; 
     
    while (1) { 
      if (($accept_socket = socket_accept($socket)) == FALSE) { 
        continue; 
      } else { 
        socket_write($accept_socket, $buffer, $len); 
        socket_close($accept_socket); 
      } 
    } 
  } 
   
  function run_server () 
  { 
    $pid1 = pcntl_fork(); 
    if ($pid1 == 0) { 
      // first child process 
       
      // 守护进程的一般流程:fork()->setsid()->fork() 
      posix_setsid(); 
       
      if (($pid2 = pcntl_fork()) == 0) { 
        $address = "192.168.1.71"; 
        $port = "8767"; 
        server_listen_socket($address, $port); 
      } else { 
        // 防止获得控制终端 
        exit(); 
      } 
    } else { 
      // wait for first child process exit 
      pcntl_wait($status); 
    } 
  } 
   
  // server守护进程 
  run_server();

运行效果
启动服务器端socket进程,看是否在后台运行,效果如图:

PHP的Socket网络编程入门指引

客户端访问,可以通过浏览器或者curl访问,这里直接用curl访问了

PHP的Socket网络编程入门指引

PHP 相关文章推荐
利用递归把多维数组转为一维数组的函数
Oct 09 PHP
php文字水印和php图片水印实现代码(二种加水印方法)
Dec 25 PHP
PHP检测移动设备类mobile detection使用实例
Apr 14 PHP
php出现内存位置访问无效错误问题解决方法
Aug 16 PHP
PHP中使用sleep造成mysql读取失败的案例和解决方法
Aug 21 PHP
php使用正则表达式获取图片url的方法
Jan 16 PHP
php创建、获取cookie及基础要点分析
Jan 26 PHP
php递归删除指定文件夹的方法小结
Apr 20 PHP
[原创]ThinkPHP中SHOW_RUN_TIME不能正常显示运行时间的解决方法
Oct 10 PHP
PHP数组操作简单案例分析
Oct 15 PHP
PHP基于堆栈实现的高级计算器功能示例
Sep 15 PHP
PHP设计模式概论【概念、分类、原则等】
May 01 PHP
php实现的农历算法实例
Aug 11 #PHP
PHP发送短信代码分享
Aug 11 #PHP
php实现可逆加密的方法
Aug 11 #PHP
PHP实现获取某个月份周次信息的方法
Aug 11 #PHP
PHP实现删除字符串中任何字符的函数
Aug 11 #PHP
详解php的socket通信
Aug 11 #PHP
Java中final关键字详解
Aug 10 #PHP
You might like
隐性调用php程序的方法
2009/03/09 PHP
php下保存远程图片到本地的办法
2010/08/08 PHP
Laravel学习教程之model validation的使用示例
2017/10/23 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
Gambit vs CL BO3 第一场 2.13
2021/03/10 DOTA
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
jQuery学习笔记之Helloworld
2010/12/22 Javascript
jQuery 1.5最新版本的改进细节分析
2011/01/19 Javascript
jquery focus(fn),blur(fn)方法实例代码
2011/12/16 Javascript
jquery indexOf使用方法
2013/08/19 Javascript
JS+CSS实现弹出全屏灰黑色透明遮罩效果的方法
2014/12/20 Javascript
基于Jquery实现仿百度百科右侧导航代码附源码下载
2015/11/27 Javascript
解决angular的post请求后SpringMVC后台接收不到参数值问题的方法
2015/12/10 Javascript
纯JS代码实现气泡效果
2016/05/04 Javascript
原生JS版和jquery版实现checkbox的全选/全不选/点选/行内点选(Mr.Think)
2016/10/29 Javascript
JavaScript 最佳实践:帮你提升代码质量
2016/12/03 Javascript
微信小程序 开发MAP(地图)实例详解
2017/06/27 Javascript
BootStrap导航栏问题记录
2017/07/31 Javascript
react native带索引的城市列表组件的实例代码
2017/08/08 Javascript
浅谈ElementUI中switch回调函数change的参数问题
2018/08/24 Javascript
vue 项目中使用Loading组件的示例代码
2018/08/31 Javascript
Vue中使用Lodop插件实现打印功能的简单方法
2019/12/19 Javascript
JavaScript遍历数组的方法代码实例
2020/01/14 Javascript
微信小程序实现可拖动悬浮图标(包括按钮角标的实现)
2020/12/29 Javascript
python中将一个全部为int的list 转化为str的list方法
2018/04/09 Python
python3.4控制用户输入与输出的方法
2018/10/17 Python
10行Python代码计算汽车数量的实现方法
2019/10/23 Python
pycharm第三方库安装失败的问题及解决经验分享
2020/05/09 Python
python中JWT用户认证的实现
2020/05/18 Python
Python 如何批量更新已安装的库
2020/05/26 Python
北欧最好的童装网上商店:Babyshop
2019/09/15 全球购物
函授本科自我鉴定
2014/02/04 职场文书
公司成本主管岗位责任制
2014/02/21 职场文书
幼儿园见习报告
2014/10/30 职场文书
HTML+CSS 实现顶部导航栏菜单制作
2021/06/03 HTML / CSS
简单且有用的Python数据分析和机器学习代码
2021/07/02 Python