php的socket编程详解


Posted in PHP onNovember 20, 2016

php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络服务的客户端和服务端,这和mysql的客户端和服务端是一样的,你只要理解mysql的客户端和服务端是怎么一回事,你就应该能够理解下面我要讲的东西吧。

关于socket编程所涉及到的网络协议,什么TCP啊,UDP啊,什么socket三次握手等等,这些网络协议网上有很详细的解释,这里不讲,只截个socket建立套接的过程图让你瞧瞧:

php的socket编程详解

这个图是我辛辛苦苦从别人那里盗截过来的,你一定要好好看啊,同时,在这里我也向那个被我盗截图的笔者表示感谢,本人对自己盗取你的图案表示歉意,还望你大人大量不要计较啊。本人实在太懒了,懒得画图,(其实是对自己的画图技术表示不自信,呵呵)。

socket是怎么建立连接的呢?上面已经提到过了,它建立连接的过程是与mysql的客户端和服务端的连接本质是一样的。而它与mysql不同的是,mysql的服务端和客户端都已经为我们编辑好了,我们只要应用就行了。但是,关键时刻来啦,socket它什么东西都没有提供给我们,唯一提供给我们的就是:几十个socket函数。

这言外之意就是说,socket编程就是要我们自己创建服务端和客户端,也就是说,``socket编程``——就是要我们自己建立一个类似于mysql的服务端和客户端的应用。

说到这里,我想问一句,你说这socket让人头疼不?它既不建立个服务端,也不建立个客户端给我们应用,非要让我们自己去应用socket的函数,创建一个属于我们自己的网络协议套接应用,这是不是很让你头疼呢?头疼也没办法,要是你需要自己的应用,你还是不得不跟socket打交道。呵呵,这只是题外话,不多说,下面进入正题。

在你没有被socket编程搞蒙之前,我还是让你看看socket的几个关键函数,先给你解释一下它们各自的作用。不然,要是对socket编程一点基础都没有的人看到了,我怕你看了之后,就果断跳过这篇文章,从此对socket产生恐惧症了。呵呵,又多说了。

socket的关键函数1:

   socket_create($net参数1,$stream参数2,$protocol参数3)

作用:创建一个socket套接字,说白了,就是一个网络数据流。

返回值:一个套接字,或者是false,参数错误发出E_WARNING警告

php的在线手册那里说得更清楚:

socket_create创建并返回一个套接字,也称作一个通讯节点。一个典型的网络连接由 2 个套接字构成,一个运行在客户端,另一个运行在服务器端。

上面一句话是从php在线手册那里复制过来的。看到没有,这里说得意思是不是和我上面反反复复提到的客户端与服务端一模一样?呵呵。

参数1是:网络协议,

网络协议有哪些?它的选择项就下面这三个:

AF_INET:

  IPv4 网络协议。TCP 和 UDP 都可使用此协议。一般都用这个,你懂的。

AF_INET6:

 IPv6 网络协议。TCP 和 UDP 都可使用此协议。

AF_UNIX:    

本地通讯协议。具有高性能和低成本的 IPC(进程间通讯)。

参数2:套接字流,选项有:

SOCK_STREAM

SOCK_DGRAM

SOCK_SEQPACKET

SOCK_RAW

SOCK_RDM。

这里只对前两个进行解释:

SOCK_STREAM

TCP 协议套接字。

SOCK_DGRAM

 UDP协议套接字。

欲了解更多请链接这里:http://php.net/manual/zh/function.socket-create.php

参数3:protocol协议,选项有:

SOL_TCP:

TCP 协议。

SOL_UDP:

UDP协议。

从这里可以看出,其实socket_create函数的第二个参数和第三个参数是相关联的。

比如,假如你第一个参数应用IPv4协议:AF_INET,然后,第二个参数应用的是TCP套接字:SOCK_STREAM,

那么第三个参数必须要用SOL_TCP,这个应该不难理解。

TCP 协议套接字嘛,当然只能用TCP协议了,是不是?如果你应用UDP套接字,那么第三个参数该怎么选择我就不说了,呵呵,你懂的。

关键函数2:

socket_connect($socket参数1,$ip参数2,$port参数3)

作用:连接一个套接字,返回值为true或者false

参数1:socket_create的函数返回值

参数2:ip地址

参数3:端口号

关键函数3:

socket_bind($socket参数1,$ip参数2,$port参数3)

作用:绑定一个套接字,返回值为true或者false

   

  参数1:socket_create的函数返回值

参数2:ip地址

参数3:端口号 

关键函数4:

socket_listen($socket参数1,$backlog 参数2)

作用:监听一个套接字,返回值为true或者false

参数1:socket_create的函数返回值

参数2:最大监听套接字个数

关键函数5:

socket_accept($socket)

作用:接收套接字的资源信息,成功返回套接字的信息资源,失败为false

 

   参数:socket_create的函数返回值

关键函数6:

socket_read($socket参数1,$length参数2)

作用:读取套接字的资源信息,

返回值:成功把套接字的资源转化为字符串信息,失败为false

 

   参数1:socket_create或者socket_accept的函数返回值

参数2:读取的字符串的长度

关键函数7:

socket_write($socket参数1,$msg参数2,$strlen参数3)

作用:把数据写入套接字中

返回值:成功返回字符串的字节长度,失败为false

 

   参数1:socket_create或者socket_accept的函数返回值

参数2:字符串

参数3:字符串的长度

关键函数8:

socket_close($socket)

作用:关闭套接字

返回值:成功返回true,失败为false

 

   参数:socket_create或者socket_accept的函数返回值

这八个函数是socket的核心函数,下面列举两个个比较重要的函数

socket_last_error($socket),参数为socket_create的返回值,作用是获取套接字的最后一条错误码号,返回值套接字code

socket_strerror($code),参数为socket_last_error函数的返回值,获取code的字符串信息,返回值也就是套接字的错误信息

这两个函数在socket编程中还是很重要的,在写socket编程的时候,我觉得你还是得利用起来,特别是新手,可以当做调试用

下面就是代码了,注意注意,请认真看我的注释,注释很重要,注释很重要,注释很重要,重要的事情要大喊三遍,呵呵。

服务端脚本,D:\vhost\test\socket\server_socket.php 

<?php
//创建服务端的socket套接流,net协议为IPv4,protocol协议为TCP
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);

  /*绑定接收的套接流主机和端口,与客户端相对应*/
  if(socket_bind($socket,'127.0.0.1',8888) == false){
    echo 'server bind fail:'.socket_strerror(socket_last_error());
    /*这里的127.0.0.1是在本地主机测试,你如果有多台电脑,可以写IP地址*/
  }
  //监听套接流
  if(socket_listen($socket,4)==false){
    echo 'server listen fail:'.socket_strerror(socket_last_error());
  }
//让服务器无限获取客户端传过来的信息
do{
  /*接收客户端传过来的信息*/
  $accept_resource = socket_accept($socket);
  /*socket_accept的作用就是接受socket_bind()所绑定的主机发过来的套接流*/

  if($accept_resource !== false){
    /*读取客户端传过来的资源,并转化为字符串*/
    $string = socket_read($accept_resource,1024);
    /*socket_read的作用就是读出socket_accept()的资源并把它转化为字符串*/

    echo 'server receive is :'.$string.PHP_EOL;//PHP_EOL为php的换行预定义常量
    if($string != false){
      $return_client = 'server receive is : '.$string.PHP_EOL;
      /*向socket_accept的套接流写入信息,也就是回馈信息给socket_bind()所绑定的主机客户端*/
      socket_write($accept_resource,$return_client,strlen($return_client));
      /*socket_write的作用是向socket_create的套接流写入信息,或者向socket_accept的套接流写入信息*/
    }else{
      echo 'socket_read is fail';
    }
  /*socket_close的作用是关闭socket_create()或者socket_accept()所建立的套接流*/
    socket_close($accept_resource);
  }
}while(true);
socket_close($socket);

 

小提示:请注意上面的socket_bind,socket_listen,socket_accept三个函数的执行顺序不可更改,也就是说

必须先执行socket_bind,再执行socket_listen,最后才执行socket_accept

客户端脚本,D:\vhost\test\socket\client_socket.php

<?php
  //创建一个socket套接流
  $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  /****************设置socket连接选项,这两个步骤你可以省略*************/
   //接收套接流的最大超时时间1秒,后面是微秒单位超时时间,设置为零,表示不管它
  socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 1, "usec" => 0));
   //发送套接流的最大超时时间为6秒
  socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 6, "usec" => 0));
  /****************设置socket连接选项,这两个步骤你可以省略*************/

  //连接服务端的套接流,这一步就是使客户端与服务器端的套接流建立联系
  if(socket_connect($socket,'127.0.0.1',8888) == false){
    echo 'connect fail massege:'.socket_strerror(socket_last_error());
  }else{
    $message = 'l love you 我爱你 socket';
    //转为GBK编码,处理乱码问题,这要看你的编码情况而定,每个人的编码都不同
    $message = mb_convert_encoding($message,'GBK','UTF-8');
    //向服务端写入字符串信息

    if(socket_write($socket,$message,strlen($message)) == false){
      echo 'fail to write'.socket_strerror(socket_last_error());

    }else{
      echo 'client write success'.PHP_EOL;
      //读取服务端返回来的套接流信息
      while($callback = socket_read($socket,1024)){
        echo 'server return message is:'.PHP_EOL.$callback;
      }
    }
  }
  socket_close($socket);//工作完毕,关闭套接流

 

怎么测试这两个脚本呢?

首先打开windows的dos窗口,就是cmd黑窗口,然后,运行php D:\vhost\test\socket\server_socket.php,

让服务端的的黑窗口持续运行的,

其次,php的客户端脚本可以通过浏览器运行,也可以再开一个cmd黑窗口运行

php D:\vhost\test\socket\client_socket.php

 

   在这里请注意:php这个运行命名必须加入windows的环境变量中,假如不知道怎么加,

请进入php运行命令目录用绝对命令运行,也可以百度把php命令加入环境变量中

这里是我的情况,你的文件地址可能和我不一样,请按照你的地址情况来操作,否则,后果自负,呵呵

上面已经说过了,socket编程必须要有服务端才能交流,所以服务端的黑窗口是必须让它持续开着的。

后记补充:

socket_set_option($socket参数1 ,$level 参数2,$optname 参数3,$optval 参数4)

这个函数的作用是给套接字设置数据流选项,还是一个很重要的函数。

参数1:socket_create或者socket_accept的函数返回值

参数2:SOL_SOCKET,好像只有这个选项

参数3与参数4是相关联的,

参数3可为:SO_REUSEADDR

SO_RCVTIMEO     S0_SNDTIMEO

解释一下:

SO_REUSEADDR

是让套接字端口释放后立即就可以被再次使用

参数3假如是这个,则参数4可以为true或者false

SO_RCVTIMEO

 是套接字的接收资源的最大超时时间

SO_SNDTIMEO

 是套接字的发送资源的最大超时时间

参数3假如是这两个,则参数4是一个这样的数组array('sec'=>1,'usec'=>500000)

数组里面都是设置超时的最大时间,不过,一个是秒为单位,一个是微秒单位,作用都一样 

PHP 相关文章推荐
生成缩略图
Oct 09 PHP
PHP通过COM使用ADODB的简单例子
Dec 31 PHP
检查php文件中是否含有bom的函数
May 31 PHP
PHP curl 并发最佳实践代码分享
Sep 05 PHP
php实现查询百度google收录情况(示例代码)
Aug 02 PHP
php调用shell的方法
Nov 05 PHP
php的dl函数用法实例
Nov 06 PHP
Laravel 5框架学习之向视图传送数据
Apr 08 PHP
php文件上传类完整实例
May 14 PHP
谈谈PHP连接Access数据库的注意事项
Aug 12 PHP
Laravel网站打开速度优化的方法汇总
Jul 16 PHP
php的无刷新操作实现方法分析
Feb 28 PHP
PHP内置加密函数详解
Nov 20 #PHP
php PDO异常处理详解
Nov 20 #PHP
php.ini中date.timezone设置详解
Nov 20 #PHP
centos 7.2下搭建LNMP环境教程
Nov 20 #PHP
浅析php中array_map和array_walk的使用对比
Nov 20 #PHP
php解决DOM乱码的方法示例代码
Nov 20 #PHP
使用Yii2实现主从数据库设置
Nov 20 #PHP
You might like
介绍一些PHP判断变量的函数
2012/04/24 PHP
php中++i 与 i++ 的区别
2012/08/08 PHP
深入探讨:PHP使用数据库永久连接方式操作MySQL的是与非
2013/06/05 PHP
php利用事务处理转账问题
2015/04/22 PHP
PHP生成可点击刷新的验证码简单示例
2016/05/13 PHP
简单解析PHP程序的运行流程
2016/06/23 PHP
PHP中检查isset()和!empty()函数的必要性
2019/02/13 PHP
TP5(thinkPHP5)框架使用ajax实现与后台数据交互的方法小结
2020/02/10 PHP
基于JQuery框架的AJAX实例代码
2009/11/03 Javascript
关于JavaScript的面向对象和继承有利新手学习
2013/01/11 Javascript
jqueryMobile使用示例分享
2016/01/12 Javascript
基于Bootstrap的UI扩展 StyleBootstrap
2016/06/17 Javascript
浅谈js for循环输出i为同一值的问题
2017/03/01 Javascript
微信小程序 蓝牙的实现实例代码
2017/06/27 Javascript
vue组件实现文字居中对齐的方法
2017/08/23 Javascript
vue-cli3使用 DllPlugin 实现预编译提升构建速度
2019/04/24 Javascript
js实现批量删除功能
2020/08/27 Javascript
如何通过Proxy实现JSBridge模块化封装
2020/10/22 Javascript
Python日期操作学习笔记
2008/10/07 Python
python的dict,set,list,tuple应用详解
2014/07/24 Python
django实现前后台交互实例
2017/08/07 Python
Tensorflow 同时载入多个模型的实例讲解
2018/07/27 Python
Python实现读取txt文件中的数据并绘制出图形操作示例
2019/02/26 Python
Pandas中Series和DataFrame的索引实现
2019/06/27 Python
VSCode配合pipenv搞定虚拟环境的实现方法
2020/05/17 Python
Linux常见面试题
2016/10/04 面试题
服装公司总经理岗位职责
2013/11/30 职场文书
军训感想500字
2014/02/20 职场文书
环保倡议书500字
2014/05/15 职场文书
医院义诊活动总结
2014/07/04 职场文书
庆祝新中国成立65周年“向国旗敬礼”网上签名寄语
2014/09/27 职场文书
2015年女职工工作总结
2015/05/15 职场文书
趣味运动会赞词
2015/07/22 职场文书
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android
python+pytest接口自动化之token关联登录的实现
2022/04/06 Python
Golang 对es的操作实例
2022/04/20 Golang