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 相关文章推荐
一键删除顽固的空文件夹 软件下载
Jan 26 PHP
发款php蜘蛛统计插件只要有mysql就可用
Oct 12 PHP
微信公众平台消息接口校验与消息接口响应实例
Dec 23 PHP
CodeIgniter实现从网站抓取图片并自动下载到文件夹里的方法
Jun 17 PHP
浅谈COOKIE和SESSION区别
Jul 19 PHP
Windows2003下php5.4安装配置教程(IIS)
Jun 30 PHP
关于PHP定时发送服务的解决办法
Apr 23 PHP
PHP数组式访问接口ArrayAccess用法分析
Dec 28 PHP
php实现微信发红包功能
Jul 13 PHP
PHP实现的函数重载功能示例
Aug 03 PHP
定位地理位置PHP判断员工打卡签到经纬度是否在打卡之内
May 23 PHP
解决Laravel使用验证时跳转到首页的问题
Nov 17 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 长文章分页函数 带使用方法,不会分割段落,翻页在底部
2009/10/22 PHP
PHP图片处理之图片背景、画布操作
2014/11/19 PHP
详谈PHP程序Laravel 5框架的优化技巧
2016/07/18 PHP
php判断手机浏览还是web浏览,并执行相应的动作简单实例
2016/07/28 PHP
Cookie 注入是怎样产生的
2009/04/08 Javascript
用最通俗易懂的代码帮助新手理解javascript闭包 推荐
2012/03/01 Javascript
理解JAVASCRIPT中hasOwnProperty()的作用
2013/06/05 Javascript
js修改input的type属性问题探讨
2013/10/12 Javascript
JS 页面计时器示例代码
2013/10/28 Javascript
解析img图片没找到onerror事件 Stack overflow at line: 0
2013/12/23 Javascript
js使用removeChild方法动态删除div元素
2014/08/01 Javascript
js读取csv文件并使用json显示出来
2015/01/09 Javascript
js改变style样式和css样式的简单实例
2016/06/28 Javascript
最细致的vue.js基础语法 值得收藏!
2016/11/03 Javascript
基于JS实现bookstore静态页面的实例代码
2017/02/22 Javascript
基于jquery日历价格、库存等设置插件
2020/07/05 jQuery
vue封装swiper代码实例解析
2019/10/08 Javascript
js中的面向对象之对象常见创建方法详解
2019/12/16 Javascript
Vue+Node服务器查询Mongo数据库及页面数据传递操作实例分析
2019/12/20 Javascript
Vue this.$router.push(参数)实现页面跳转操作
2020/09/09 Javascript
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
python连接远程ftp服务器并列出目录下文件的方法
2015/04/01 Python
菜鸟使用python实现正则检测密码合法性
2016/01/05 Python
Python增量循环删除MySQL表数据的方法
2016/09/23 Python
对django views中 request, response的常用操作详解
2019/07/17 Python
Python SELENIUM上传文件或图片实现过程
2019/10/28 Python
python中的Elasticsearch操作汇总
2019/10/30 Python
金融行业务员的自我评价
2013/12/13 职场文书
2014年行政助理工作总结
2014/11/19 职场文书
中学教师师德师风承诺书
2015/04/28 职场文书
2016年大学生社会实践心得体会
2015/10/09 职场文书
《搭石》教学反思
2016/02/18 职场文书
端午节将至,用Python爬取粽子数据并可视化,看看网友喜欢哪种粽子吧!
2021/06/11 Python
使用 Apache 反向代理的设置技巧
2022/01/18 Servers
Python first-order-model实现让照片动起来
2022/06/25 Python
CSS中使用grid布局实现一套模板多种布局
2022/07/15 HTML / CSS