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 相关文章推荐
基于mysql的论坛(1)
Oct 09 PHP
PHP Google的translate API代码
Dec 10 PHP
php 中英文语言转换类
Sep 07 PHP
apache和php之间协同工作的配置经验分享
Apr 08 PHP
百度地图API应用之获取用户的具体位置
Jun 10 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
Dec 12 PHP
微信公众号OAuth2.0网页授权问题浅析
Jan 21 PHP
form表单传递数组数据、php脚本接收的实例
Feb 09 PHP
ThinkPHP实现转换数据库查询结果数据到对应类型的方法
Nov 16 PHP
php实现微信分享朋友链接功能
Feb 18 PHP
tp5.1 框架查询表达式用法详解
May 25 PHP
解决PhpStorm64不能启动的问题
Jun 20 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
各种咖啡的英文名子是什么
2021/03/03 新手入门
BBS(php &amp; mysql)完整版(八)
2006/10/09 PHP
php Sql Server连接失败问题及解决办法
2009/08/07 PHP
PHP CURL模拟GET及POST函数代码
2010/04/25 PHP
MySQL连接数超过限制的解决方法
2011/07/17 PHP
PHP中使用register_shutdown_function函数截获fatal error示例
2015/04/21 PHP
Mootools 1.2教程(3) 数组使用简介
2009/09/14 Javascript
IE bug table元素的innerHTML
2010/01/11 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
JavaScript中定义函数的三种方法
2015/03/12 Javascript
nodejs简单实现中英文翻译
2015/05/04 NodeJs
ECHO.js 纯javascript轻量级延迟加载的实例代码
2016/05/24 Javascript
AngularJS实现的base64编码与解码功能示例
2018/05/17 Javascript
angular4 获取wifi列表中文显示乱码问题的解决
2018/10/20 Javascript
使用pm2自动化部署node项目的方法步骤
2019/01/28 Javascript
nodejs使用async模块同步执行的方法
2019/03/02 NodeJs
JavaScript中的 new 命令
2019/05/22 Javascript
如何在JavaScript中谨慎使用代码注释
2019/06/21 Javascript
vue使用websocket的方法实例分析
2019/06/22 Javascript
vue如何实现自定义底部菜单栏
2019/07/01 Javascript
原生JS实现京东查看商品点击放大
2020/12/21 Javascript
[00:32]2018DOTA2亚洲邀请赛Liquid出场
2018/04/03 DOTA
用Python实现筛选文件脚本的方法
2018/10/27 Python
python提取具有某种特定字符串的行数据方法
2018/12/11 Python
HTML5实现移动端弹幕动画效果
2019/08/01 HTML / CSS
NUK奶瓶美国官网:NUK美国
2016/09/26 全球购物
FirstCry阿联酋儿童和婴儿产品网上购物:FirstCry.ae
2021/02/22 全球购物
平民服装店创业计划书
2014/01/17 职场文书
检察机关个人对照检查材料
2014/09/15 职场文书
搞笑婚前保证书
2015/02/28 职场文书
女方离婚起诉书
2015/05/18 职场文书
电影建国大业观后感
2015/06/01 职场文书
观看禁毒宣传片后的感想
2015/08/11 职场文书
《确定位置》教学反思
2016/02/18 职场文书
Python编程源码报错解决方法总结经验分享
2021/10/05 Python
mysqldump进行数据备份详解
2022/07/15 MySQL