zoukankan      html  css  js  c++  java
  • PHP socket上传文件图片

    最近了解了下下socket方面的东西,想做一个socket上传文件的例子。

    在网上搜了搜代码执行后,图片数据传输了一半,图片的下半部分是灰色的。然后就自己仿着搜来的代码和php.net 中socket方法的介绍写了一个可以完整上传文件的代码。这里以图片为例。

    client.php

    /**
     * client.php
     */
    define("token", "1k8o3u4h5t6uv8a53uz4210mz"); # 通过appkey 与appsecret动态生成上传凭证,
    $filePath = "C:\Users\Administrator\Desktop\socketIMg\";
    $fileName =  "chorme.png";
    $fp = fsockopen("127.0.0.1", 1688, $errno, $errstr, 30);
    if (is_resource($fp)) {
        $fileSize = filesize($filePath . $fileName);
        fwrite($fp, json_encode(['filename' => $fileName, 'filesize' => $fileSize, 'token' => token]));   # 发送文件名、上传凭证、文件大小
        $out = file_get_contents($filePath . $fileName);
        $receiveFileSize = fwrite($fp, $out);   # 发送文件if ($receiveFileSize == $fileSize) {
            echo 'send success';
        } else {
            echo 'data uncomplete!';
        }
        
    //     while (!feof($fp)) {
    //        echo fgets($fp, 128);
    //    }
        fclose($fp);
    }

    server.php

    /**
     * server.php
     */
    define("token", "1k8o3u4h5t6uv8a53uz4210mz"); # 约定好的token凭证,通过appkey动态生成,这里演示固定值
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_bind($socket, '127.0.0.1', 1688);
    $listening = socket_listen($socket);
    if ($listening) {
        echo "status OK 
    ";
    } else {
        echo "fail";
        exit();
    }
    while (true) {
        $connection = socket_accept($socket);
        if ($connection) {
            $buffer = '';
            $begin = TRUE;
            $fileSize = 0; # 接收的数据大小
            $sendFilesize = 0; # 发送文件自带文件大小
            while (socket_recv($connection, $buffer, 1024, 0)) { # 一直保持连接且接受数据,1024字节大小为一个接收包
                if ($begin) { # 客户端发送文件名,
                    $fileInfo = json_decode($buffer, TRUE);
                    if ($fileInfo['token'] != token) {
                        echo "token  valid false !
    ";
                        break;
                    }
                    $file_name = $fileInfo["filename"];
                    $sendFilesize = $fileInfo["filesize"];
                    $fp = fopen($file_name, "wb"); //写入方式+二进制模式写入
                    if (!$fp) {
                        echo "Create file error!
    ";
                        break;
                    }
                    $begin = FALSE;
                    continue;
                }
                #客户端发送 文件数据,fwrite 写入数据
                $fileSize+=strlen($buffer);
                fwrite($fp, $buffer);
            }
            
            # 发送大小与接收大小相同=保存成功
            if ($sendFilesize != 0 && $fileSize == $sendFilesize) {
                echo "receive success!
    ";
            } else {
                echo "receive fail!
    ";
            }
            #socket_write($connection, "aaa",  strlen("aaa"));
            isset($fp) && fclose($fp);
            socket_close($connection);
        }
    }
    socket_close($socket);

    cmder 切换到server.php目录路径

    在看s1根目录下文件:

    问题:

    上传文件成功后,服务端应该给客户端返回一个响应,通过socket_write发送。客户端通过fgets接收,但是打开代码中注释的:

    socket_write($connection, "aaa",  strlen("aaa"));
         while (!feof($fp)) {
            echo fgets($fp, 128);
        }

    会直接导致程序堵塞,暂未解决fgets堵塞发方法。

    昨天又看了个workerman PHP socket 服务器框架   的确很“socket” ,不用手写了,用到socket功能的鞋童建议直接使用这个框架。

    在workerman给的手册中也有上传文件的例子,在这里我把文件搬过来。

    链接: http://doc3.workerman.net/protocols/example.html

    新建协议查看文档说明,目录结果如下:

    跟目录放一个漂亮的美女图片,新增一个tmp目录

    我们先用二进制方法上传文件

    打开cmder运行 :php upimgserBinary.php启动服务

    cmder 运行uploadclientBinary.php +文件001.jpg

    提示上传成功,查看tmp目录是否有图片

    相同的方法执行text协议上传。

    代码如下:

    upimgserBinary.php

    use WorkermanWorker;
    require_once dirname(__DIR__) . '/Workerman/Autoloader.php';
    
    
    $worker = new Worker('BinaryTransfer://0.0.0.0:8333');
    // 保存文件到tmp下
        $worker->onMessage = function($connection, $data)
    {
        $save_path = 'tmp/'.$data['file_name'];
        file_put_contents($save_path, $data['file_data']);
        $connection->send("upload success. save path $save_path");
    };
    
    Worker::runAll();

    uploadclientBinary.php

    /** 上传文件客户端 **/
    // 上传地址
    $address = "127.0.0.1:8333";
    // 检查上传文件路径参数
    if(!isset($argv[1]))
    {
       exit("use php client.php $file_path
    ");
    }
    // 上传文件路径
    $file_to_transfer = trim($argv[1]);
    // 上传的文件本地不存在
    if(!is_file($file_to_transfer))
    {
        exit("$file_to_transfer not exist
    ");
    }
    // 建立socket连接
    $client = stream_socket_client($address, $errno, $errmsg);
    if(!$client)
    {
        exit("$errmsg
    ");
    }
    // 设置成阻塞
    stream_set_blocking($client, 1);
    // 文件名
    $file_name = basename($file_to_transfer);
    // 文件名长度
    $name_len = strlen($file_name);
    // 文件二进制数据
    $file_data = file_get_contents($file_to_transfer);
    // 协议头长度 4字节包长+1字节文件名长度
    $PACKAGE_HEAD_LEN = 5;
    // 协议包
    $package = pack('NC', $PACKAGE_HEAD_LEN  + strlen($file_name) + strlen($file_data), $name_len) . $file_name . $file_data;
    // 执行上传
    fwrite($client, $package);
    // 打印结果
    echo fread($client, 8192),"
    ";

    ------------------------

    upimgserText.php

    use WorkermanWorker;
    require_once dirname(__DIR__) . '/Workerman/Autoloader.php';
    
    
    $worker = new Worker('TextTransfer://0.0.0.0:8333');
    // 保存文件到tmp下
    $worker->onMessage = function($connection, $data)
    {
        $save_path = 'tmp/'.$data['file_name'];
        file_put_contents($save_path, $data['file_data']);
        $connection->send("upload success. save path $save_path");
    };
    
    Worker::runAll();

    uploadclientText.php

    /** 上传文件客户端 **/
    // 上传地址
    $address = "127.0.0.1:8333";
    // 检查上传文件路径参数
    if(!isset($argv[1]))
    {
       exit("use php client.php $file_path
    ");
    }
    // 上传文件路径
    $file_to_transfer = trim($argv[1]);
    // 上传的文件本地不存在
    if(!is_file($file_to_transfer))
    {
        exit("$file_to_transfer not exist
    ");
    }
    // 建立socket连接
    $client = stream_socket_client($address, $errno, $errmsg);
    if(!$client)
    {
        exit("$errmsg
    ");
    }
    stream_set_blocking($client, 1);
    // 文件名
    $file_name = basename($file_to_transfer);
    // 文件二进制数据
    $file_data = file_get_contents($file_to_transfer);
    // base64编码
    $file_data = base64_encode($file_data);
    // 数据包
    $package_data = array(
        'file_name' => $file_name,
        'file_data' => $file_data,
    );
    // 协议包 json+回车
    $package = json_encode($package_data)."
    ";
    // 执行上传
    fwrite($client, $package);
    // 打印结果
    echo fread($client, 8192),"
    ";

    打包的7zip附件文件:

     http://files.cnblogs.com/files/dcb3688/workerman-upload-file.7z

  • 相关阅读:
    GIT使用方法
    结对-结对编项目贪吃蛇-设计文档
    结对-结对编项目贪吃蛇-开发环境搭建过程
    《团队-爬取豆瓣电影TOP250-需求分析》
    《团队-爬取豆瓣电影TOP250-成员简介及分工》
    结对-结对编项目贪吃蛇-需求分析
    20170906-构建之法:阅读问题
    20170906-构建之法:现代软件工程-阅读笔记
    团队名称:极限定理
    软件工程初识
  • 原文地址:https://www.cnblogs.com/dcb3688/p/4608032.html
Copyright © 2011-2022 走看看