socket编程 - 使用socket与其他服务建立TCP连接并发送指令-zookeeper

以zookeeper服务为例

绝大部分的服务都会提供基于TCP的长连接接口,供其他程序连接并提供服务,zookeeper也不例外,我们就可以使用这些接口
来通过php或者c封装成扩展。

一般不会使用http/https这种无状态的连接,因为我们连接上服务后需要做很多次请求的,需要保持着连接,所以要用长连接
的形式,然后最终使用完后要在析构函数主动释放连接,php回收机制会在销毁这个对象的同时断开连接。

基于网络socket来实现tcp连接。

socket_read() 本身会阻塞,等待接收信息,但是当收到指定字节的信息(可能没接收完全,服务端还没发送完)就不再阻塞了
,所以需要重复多次来读取信息直到完全接收。

如果服务端一直未发送消息,socket_read 将会一直阻塞着。

如果服务端断开连接,客户端 socket_read 也不会阻塞了。

zookeeper服务端使用 socketServer 服务来代替。

代码仓库:https://gitee.com/phprao/socket.git

<?php

class ZookeeperTest
{
    protected $errorCode;
    protected $errorMsg;
    protected $len = 8129;// 每次读取数据的字节数
    protected $client = null;
    protected $rcvtimeo = 3;
    protected $sndtimeo = 3;

    /**
     * @return mixed
     */
    public function getErrorCode()
    {
        return $this->errorCode;
    }

    /**
     * @return mixed
     */
    public function getErrorMsg()
    {
        return $this->errorMsg;
    }

    public function __construct($host, $port, $rcvtimeo = null, $sndtimeo = null)
    {
        $this->connectTo($host, $port);
        $this->setTimeout($rcvtimeo, $sndtimeo);
    }

    protected function setTimeout($rcvtimeo, $sndtimeo){
        if(!is_null($rcvtimeo) && is_int($rcvtimeo)){
            $this->rcvtimeo = $rcvtimeo;
        }
        if(!is_null($sndtimeo) && is_int($sndtimeo)){
            $this->sndtimeo = $sndtimeo;
        }
        socket_set_option($this->client, SOL_SOCKET, SO_RCVTIMEO, ['sec'=>$this->rcvtimeo, 'usec'=>0]);  // 发送超时
        socket_set_option($this->client, SOL_SOCKET, SO_SNDTIMEO, ['sec'=>$this->sndtimeo, 'usec'=>0]);  // 接收超时
    }

    protected function connectTo($host, $port)
    {
        // 1. 创建
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

        if ($socket == FALSE) {
            $this->setError(1000, socket_strerror(socket_last_error()));
            return false;
        }

        // 2. 链接
        $result = socket_connect($socket, $host, $port);
        if ($result == FALSE) {
            $this->setError(10001, 'connect failed');
            return false;
        } else {
            $this->client = $socket;
            return true;
        }
    }

    protected function setError($code, $msg)
    {
        $this->errorCode = $code;
        $this->errorMsg  = $msg;
    }

    protected function sendCmdAndReturn($cmd)
    {
        // 发送指令
        if (!socket_write($this->client, $cmd, strlen($cmd))) {
            $this->setError(10002, socket_strerror(socket_last_error()));
            return false;
        }

        // 接收结果
        $getMsg = '';

        // 3. 从服务端读取全部的数据
        do {
            $out    = @socket_read($this->client, $this->len);
            $getMsg .= $out;
            if (strlen($out) < $this->len) {
                break;
            }
        } while (true);

        return $this->initResult($getMsg);
    }

    protected function initResult($msg)
    {
        return $msg;
    }

    public function set($key, $value)
    {
        $cmd = "set {$key} {$value}";
        return $this->sendCmdAndReturn($cmd);
    }

    public function get($key, $value)
    {
        $cmd = "get {$key}";
        return $this->sendCmdAndReturn($cmd);
    }

    public function __destruct()
    {
        socket_close($this->client);
    }
}

$zk = new ZookeeperTest('127.0.0.1', 8888);
var_dump($zk);
$re = $zk->set('name', 'rao');
var_dump($re);
var_dump($zk->getErrorMsg());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值