socket和socket通信与socket和websocket通信的区别

  1. socket和socket通信的数据没有经过编码,所以在socket服务端无需对接收的数据解码,和对返回的数据编码
  2. socket和socket建立连接时就使用的socket协议进行通信,而websocket建立连接时使用的HTTP协议,必须提升通信协议为websocket
  3. socket和socket通信没有握手过程,socket和websocket时,socket必须给websocket返回握手响应

附socket与socket通信参考代码

server

<?php

$host = '0.0.0.0';
$port = 12345;

$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)      or die("socket_create()函数调用失败。");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1)     or die("socket_option() failed");// 设置重用
socket_bind($master, $host, $port)                          or die("socket_bind() 函数调用失败。");
socket_listen($master, 20);
$sockets = [];
$sockets[] = $master;
while(true) {
    $activeSockets = $sockets;
    $write = $except = null;
    $status = socket_select($activeSockets, $write, $except, null);
    if ($status === 0) {
        continue;
    }
    if ($status === false) {
        echo socket_last_error() . "\r\n";
        continue;
    }
    if (in_array($master, $activeSockets)) {
        $newSocket = socket_accept($master);
        if (!$newSocket) {
            continue;
        }
        $sockets[] = $newSocket;
        $activeSockets[] = $newSocket;
        $index = array_search($master, $activeSockets);
        unset($activeSockets[$index]);
    }
    foreach($activeSockets as $activeSocket) {
        $socketId = (int) $activeSocket;
        $requestDataLength = socket_recv($activeSocket, $requestData, 2048, 0);
        if ($requestDataLength == 0) {
            socket_close($activeSocket);
            $index = array_search($activeSocket, $sockets);
            unset($sockets[$index]);
            continue;
        }
        $response = "";
        $data = json_decode($requestData, true);
        if ($data) {
            switch($data['operator']) {
                case 'add':
                    $response = $data['firstNum'] + $data['secondNum'];
                    break;
                case 'sub':
                    $response = $data['firstNum'] - $data['secondNum'];
                    break;
                case 'multi':
                    $response = $data['firstNum'] * $data['secondNum'];
                    break;
                case 'div':
                    $response = $data['firstNum'] / $data['secondNum'];
                    break;
            }
        } else {
            $response = $requestData;
        }
        socket_write($activeSocket, $response, strlen($response));
    }

};

client

<?php

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($socket, '127.0.0.1', '12345');
$raw = json_encode([
    'firstNum' => 10,
    'secondNum' => 20,
    'operator' => 'add',
]);
socket_write($socket, $raw, strlen($raw));
$result = socket_read($socket, 2048);
echo $result;
socket_close($socket);
2017/6/19 posted in  PHP

技术开发顺序

  1. 理解业务为王
  2. 业务实现技术方案第二
  3. 技术选型第三
  4. 具体实现代码第四
2017/5/20 posted in  业务

java程序cpu过高查看快速解决问题

top //查看cpu占用过高的进程 获取进程id
ps -mp pid -o THREAD,tid,time // 得到cpu占用过高的线程 获取其id

or 通过命令:top -Hp 15970
printf "%x\n" pid // 会得到一个16进制字符串
jstack pid | grep [上一步得到16进制] -A 60 //定位代码问题处
2017/5/20 posted in  JAVA

一图胜千言-开源项目源码目录结构

php和swoole目录结构

Read more   2017/5/19 posted in  一图胜千言

图片16:9缩放

function crop_image($image) {
    list($w_i, $h_i, $type) = getimagesize($image);
 
    $w_o = $w_i;
    $h_o = 9 * $w_o / 16;
 
    if ($h_i < $h_o) {
        $h_o = $h_i;
        $w_o = 16 * $h_o / 9;
    }
 
    $x_o = $w_i - $w_o;
    $y_o = $h_i - $h_o;
 
    $types = array("", "gif", "jpeg", "png");
    $ext = $types[$type];
    if ($ext) {
      $func = 'imagecreatefrom'.$ext;
      $img_i = $func($image);
    } else {
      echo 'Incorrect image';
      return false;
    }
    if ($x_o + $w_o > $w_i) $w_o = $w_i - $x_o;
    if ($y_o + $h_o > $h_i) $h_o = $h_i - $y_o;
    $img_o = imagecreatetruecolor($w_o, $h_o);
    imagecopy($img_o, $img_i, 0, 0, $x_o/2, $y_o/2, $w_o, $h_o);
    $func = 'image'.$ext;
    return $func($img_o, $image);  
}
 
crop_image("screen.png");

改良后的代码(解决获取图片宽高错误)

function crop_image($image) {
    $img = imagecreatefromstring(file_get_contents($image));
    $exif = @exif_read_data($image);
    if( ! empty($exif['Orientation'])) {
        switch($exif['Orientation']) {
            case 8:
                $img = imagerotate($img, 90, 0);
                break;
            case 3:
                $img = imagerotate($img, 180, 0);
                break;
            case 6:
                $img = imagerotate($img, -90, 0);
                break;
        }
        list($_, $_, $type) = getimagesize($image);
        $types = array("", "gif", "jpeg", "png");
        $ext = $types[$type];
        $func = 'image'.$ext;
        $func($img, $image);
    }
    list($w_i, $h_i, $type) = getimagesize($image);
 
    $w_o = $w_i;
    $h_o = 9 * $w_o / 16;
 
    if ($h_i < $h_o) {
        $h_o = $h_i;
        $w_o = 16 * $h_o / 9;
    }
 
    $x_o = $w_i - $w_o;
    $y_o = $h_i - $h_o;
 
    $types = array("", "gif", "jpeg", "png");
    $ext = $types[$type];
    if ($ext) {
      $func = 'imagecreatefrom'.$ext;
      $img_i = $func($image);
    } else {
      echo 'Incorrect image';
      return false;
    }
    if ($x_o + $w_o > $w_i) $w_o = $w_i - $x_o;
    if ($y_o + $h_o > $h_i) $h_o = $h_i - $y_o;
    $img_o = imagecreatetruecolor($w_o, $h_o);
    imagecopy($img_o, $img_i, 0, 0, $x_o/2, $y_o/2, $w_o, $h_o);
    $func = 'image'.$ext;
    return $func($img_o, $image);
}
 
crop_image("1.jpg");
2017/4/15 posted in  PHP

北京联通光猫内网路由器端口转发

0x01 登录光猫

一般地址是 192.168.1.1 用户名密码参考光猫背面

0x02 配置DMZ-将报文发给内网路由器

0x03 在路由器上配置端口转发

然后就可以通过外网ip地址+2222端口访问内网ip的22端口了

2017/4/11 posted in  生产力工具

防止表单重复提交

var submited = false;
$('#submit').click(function(e) {
    if (submited) {
        return;
    }
    submited = true;
    // 自定义代码
});
2017/4/10 posted in  js

Laravel中RBAC权限控制核心技术要点

SQL设计如下

DROP SCHEMA IF EXISTS `mydb` ;
-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 ;
USE `mydb` ;
-- -----------------------------------------------------
-- Table `mydb`.`admin`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`admin` ;
CREATE TABLE IF NOT EXISTS `mydb`.`admin` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(16) NOT NULL,
  `password` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE UNIQUE INDEX `username_UNIQUE` ON `mydb`.`admin` (`username` ASC);
  
-- -----------------------------------------------------
-- Table `mydb`.`role`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`role` ;
CREATE TABLE IF NOT EXISTS `mydb`.`role` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(10) NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE UNIQUE INDEX `name_UNIQUE` ON `mydb`.`role` (`name` ASC);
  
-- -----------------------------------------------------
-- Table `mydb`.`role_admin`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`role_admin` ;
CREATE TABLE IF NOT EXISTS `mydb`.`role_admin` (
  `admin_id` INT UNSIGNED NOT NULL,
  `role_id` INT UNSIGNED NOT NULL)
ENGINE = InnoDB;
  
-- -----------------------------------------------------
-- Table `mydb`.`permission`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`permission` ;
CREATE TABLE IF NOT EXISTS `mydb`.`permission` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(10) NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE UNIQUE INDEX `name_UNIQUE` ON `mydb`.`permission` (`name` ASC);
  
-- -----------------------------------------------------
-- Table `mydb`.`role_permission`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`role_permission` ;
CREATE TABLE IF NOT EXISTS `mydb`.`role_permission` (
  `role_id` INT UNSIGNED NOT NULL,
  `permission_id` INT UNSIGNED NOT NULL)
ENGINE = InnoDB;

管理员模型

public function roles()
{
    return $this->belongsToMany('App\Role', 'role_admin', 'admin_id', 'role_id');
}
public function hasRole($roleName)
{
    foreach($this->roles()->get() as $role) {
        if ($role->name == $roleName) {
            return true;
        }
    }
    return false;
}
public function hasPermission($permissionName)
{
    foreach($this->roles()->get() as $role) {
        foreach($role->permissions as $permission) {
            if ($permission->name == $permissionName) {
                return true;
            }
        }
    }
    return false;
}

角色模型

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
    //
    protected $table = 'role';
    protected $fillable = ['name', 'display_name'];
    protected static $list = null;
    public static function getList($refresh = false)
    {
        if ($refresh || is_null(self::$list)) {
            self::$list = static::with('permissions')->get();
        }
        return self::$list;
    }
    public static function getById($roleId)
    {
        $key = static::getList()->search(function($role) use ($roleId) {
            return $role->id == $roleId;
        });
        return $key ? static::getList()->get($key) : null;
    }
    public function permissions()
    {
        return $this->belongsToMany('App\Permission', 'role_permission', 'role_id', 'permission_id');
    }
}

权限模型

<?php
namespace App;
use App\Role;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model
{
    //
    protected $table = 'permission';
    protected $fillable = ['name', 'display_name'];
    public function role()
    {
        foreach(Role::getList() as $role) {
            foreach($role->permissions as $permission) {
                if ($permission->id == $this->id) {
                    return $role;
                }
            }
        }
        return false;
    }
}
2017/3/29 posted in  LARAVEL

nginx的fast_cgi缓存配置

fastcgi_cache_path /var/cache levels=1:2 keys_zone=MYCACHE:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

server {
    server_name test;
    root /webroot/test; ## <-- Your only path reference.
    listen 80;



    #Cache everything by default
    set $no_cache 0;

    #Don't cache POST requests
    if ($request_method = POST)
    {
        set $no_cache 1;
    }

    #Don't cache if the URL contains a query string
    if ($query_string != "")
    {
        set $no_cache 1;
    }

    #Don't cache the following URLs
    if ($request_uri ~* "/(administrator/|login.php)")
    {
        set $no_cache 1;
    }

    #Don't cache if there is a cookie called PHPSESSID
    if ($http_cookie = "PHPSESSID")
    {
        set $no_cache 1;
    }



    location ~ '\.php$' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        include fastcgi_params;
        # Block httpoxy attacks. See https://httpoxy.org/.
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
               fastcgi_pass backend;

        fastcgi_cache MYCACHE;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $no_cache;
        fastcgi_no_cache $no_cache;
        add_header X-Cache $upstream_cache_status;
    }
}
2017/3/28 posted in  Apache/Nginx

面试题-在页面上显示一张图片

项目需求

在页面上显示一张图片,此图片是由多个部分组成:背景,小岛和海鸥。根据传入参数的不同,小岛和海鸥在背景中的位置将可以变化。

<?php

class pic
{
    private $_url;

    public function __get($name)
    {
        return $this->$name;
    }

    public function __set($name,$value)
    {
        return $this->$name = $value;
    }
}
interface layer
{
    public function loadPic(pic $pic);
}

class background implements layer
{
    private $_z = 0;
    private $_pic;
    private $_width;
    private $_height;
    private $_html;

    public function loadPic(pic $pic)
    {
        $this->_pic = $pic;
    }

    public function __get($name)
    {
        return $this->$name;
    }

    public function __set($name,$value)
    {
        return $this->$name = $value;
    }

    public function generateHtml()
    {
        $this->_html = "<img src='{$this->_pic->_url}' width='{$this->_width}' height='{$this->_height}' style='z-index: {$this->_z};'>";
        return $this->_html;
    }
}

abstract class onLayer implements layer
{
    private $_x;
    private $_y;
    private $_z;
    private $_pic;
    private $_width;
    private $_height;
    private $_html;
    private $_downLayer;

    public function loadPic(pic $pic)
    {
        $this->_pic = $pic;
    }

    public function __get($name)
    {
        return $this->$name;
    }

    public function __set($name,$value)
    {
        return $this->$name = $value;
    }

    abstract public function on(layer $newLayer);

    public function generateHtml()
    {
        $this->_html = $this->_downLayer->_html."<img src='{$this->_pic->_url}' width='{$this->_width}' height='{$this->_height}' style='z-index: {$this->_z}; position: absolute; left: {$this->_x}px; top: {$this->_y}px;'>";
        return $this->_html;
    }
}

class island extends onLayer
{
    public function on(layer $downLayer)
    {
        $this->_width = 100;
        $this->_height = 50;
        $this->_downLayer = $downLayer;
        $this->_z = $downLayer->_z + 20;
    }
}

class bird extends onLayer
{
    public function on(layer $downLayer)
    {
        $this->_x = 20;
        $this->_y = 30;
        $this->_width = 20;
        $this->_height = 20;
        $this->_downLayer = $downLayer;
        $this->_z = $downLayer->_z + 21;
    }
}

$inland_x = isset($_REQUEST['_x']) ? $_REQUEST['_x'] : 0;
$inland_y = isset($_REQUEST['_y']) ? $_REQUEST['_y'] : 0;

No.1

开始写代码,显示由背景、小岛和海鸥三个图片组合而成的背景图

/*
背景图片为: sea.jpg
岛的图片为: island.jpg
鸟的图片为: bird.jpg
*/
$pic = new pic();
$pic->_url = 'sea.jpg';
$background = new background();
$background->loadPic($pic);
$background->_width = '400';
$background->_height = '300';
$background->generateHtml();


$pic1 = new pic();
$pic1->_url = 'island.jpg';
$island = new island();
$island->loadPic($pic1);
$island->_x = $inland_x;
$island->_y = $inland_y;
$island->on($background);
$island->generateHtml();

$pic2 = new pic();
$pic2->_url = 'bird.jpg';
$bird = new bird();
$bird->loadPic($pic2);
$bird->on($island);
$bird->_x = $inland_x;
$bird->_y = $inland_y;


$seaPic = $bird->generateHtml();
echo $seaPic;
//end_code

?>

<form action="#" method="post" style="">
    <input name="_x" type="text">
    <input name="_y" type="text">
    <input type="submit">
</form>

三张素材图

2017/3/15 posted in  面试题 PHP

Laravel中利用中间表处理多对多的关系

今天谈谈Laravel中非常有用但是又非常难以理解的特性:中间表

拿博客和博客的标签举例:一个博客有多个标签,形成了多对多的关系,使用中间表来表示这种关系,数据库结构设计如下:

博文表:blog

– id
– title
- content

标签表:tag

- id
- name

博文和标签的关联表:blog_tag

- blog_id
- tag_id

然后我们在模型中使用BelongsToMany()来使用中间表表示博文和标签关系
博文模型app/Blog.php:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    protected $table = 'blog';
    public $timestamps = false;

    public function tag()
    {
        return $this->belongsToMany('App\Tag');
    }
}

标签模型app/Tag.php:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    protected $table = 'tag';
    public $timestamps = false;

    public function blog()
    {
        return $this->belongsToMany('App\Blog');
    }
}

我们可以进一步指定中间表的表名和关联的字段:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    //
    protected $table = 'blog';
    public $timestamps = false;

    public function tag()
    {
        return $this->belongsToMany('App\Tag', 'blog_tag', 'blog_id', 'tag_id');
    }
}

博文新关联一个标签

$blog = Blog::find($blogId);
$blog->tag()->attach($tagId);// $tagId就是需要关联的标签的id

博文删除关联的一个标签

$blog = Blog::find($blogId);
$blog->tag()->detach($tagId);// $tagId就是需要删除的关联的标签的id

删除所有与标签的关联

$blog = Blog::find($blogId);
$blog->tag()->detach();

注意:attach和detach的参数都可以是一个数组,表示添加或者删除多个关联的标签。

博文使用新的标签关联替换原有的关联:

$blog->tag()->sync([1, 2, 3]);

参考资料

Pivot tables and many-to-many relationships

2017/3/15 posted in  LARAVEL

mysql 常用命令

set names utf8
source

select语句 into outfile '外部文件路径' fields terminated by '|' enclosed by '"' lines terminated by '\r\n' ;
load data infile '外部文件路径' into table 表名 fields terminated by '|' enclosed by '"' lines terminated by '\r\n' ;

mysqldump -u 用户名 -p 数据库名 > 导出的文件名
mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名

只导出表结构
mysqldump -u 用户名 -p -d --add-drop-table 数据库名 > 导出的文件名

mysqldump  -uroot -p --databases test mysql #空格分隔
mysqldump  -uroot -p -all-databases
mysql -uroot -proot test < test.sql

查看锁等待

SELECT 
    r.trx_id waiting_trx_id,
    r.trx_mysql_thread_id waiting_thread,
    r.trx_query waiting_query,
    b.trx_id blocking_trx_id,
    b.trx_mysql_thread_id blocking_thread,
    b.trx_query blocking_query
FROM
    information_schema.innodb_lock_waits w
        INNER JOIN
    information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
        INNER JOIN
    information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
2017/3/10 posted in  SQL