【轻松掌握】Swoole简单入门教程,让你成为PHP高手!

Swoole简单入门示例

Swoole可以让PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。

前提

使用Composer构建项目,构建好项目。

或者利用搜索引擎。

本篇介绍以下几个示例:

一、​​使用Swoole发送邮件​​

二、使用Swoole实现在线聊天

三、使用Systemctl管理Swoole服务

四、使用Swoole实现毫秒级定时任务

五、使用Websocket上传文件

使用composer安装邮件发送组件:phpmailer

composer require phpmailer/phpmailer

Copy

主程序

在目录:src/app/下建立Mail.php,用作Swoole服务端主程序。


namespace Shanhubei\Swoole;use swoole_server;
use Redis;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;class Mail
{protected $serv;protected $host = '127.0.0.1';protected $port = 9502;// 进程名称protected $taskName = 'swooleMailer';// PID路径protected $pidPath = '/run/swooleMail.pid';// 设置运行时参数protected $options = ['worker_num' => 4, //worker进程数,一般设置为CPU数的1-4倍  'daemonize' => true, //启用守护进程'log_file' => '/data/logs/swoole.log', //指定swoole错误日志文件'log_level' => 0, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR'dispatch_mode' => 1, //数据包分发策略,1-轮询模式'task_worker_num' => 4, //task进程的数量'task_ipc_mode' => 3, //使用消息队列通信,并设置为争抢模式//'heartbeat_idle_time' => 600, //一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭//'heartbeat_check_interval' => 60, //启用心跳检测,每隔60s轮循一次];// 邮件服务器配置protected $mailConfig = ['smtp_server' => 'smtp.163.com','username' => 'username@163.com','password' => '密码/口令',// SMTP 密码/口令'secure' => 'ssl', //Enable TLS encryption, `ssl` also accepted'port' => 465, // tcp邮件服务器端口];// 安全密钥protected $safeKey = 'MDDGnQE33ytd2jDFADS39DSEWsdD24sK';public function __construct($mailConfig, $options = []){// 构建Server对象,监听端口$this->serv = new swoole_server($this->host, $this->port);if (!empty($options)) {$this->options = array_merge($this->options, $options);}$this->serv->set($this->options);$this->mailConfig = $mailConfig;// 注册事件$this->serv->on('Start', [$this, 'onStart']);$this->serv->on('Connect', [$this, 'onConnect']);$this->serv->on('Receive', [$this, 'onReceive']);$this->serv->on('Task', [$this, 'onTask']);  $this->serv->on('Finish', [$this, 'onFinish']);$this->serv->on('Close', [$this, 'onClose']);// 启动服务//$this->serv->start();}protected function init(){//}public function start(){// Run worker$this->serv->start();}public function onStart($serv){// 设置进程名cli_set_process_title($this->taskName);//记录进程id,脚本实现自动重启$pid = "{$serv->master_pid}\n{$serv->manager_pid}";file_put_contents($this->pidPath, $pid);}//监听连接进入事件public function onConnect($serv, $fd, $from_id){$serv->send($fd, "Hello {$fd}!" );}// 监听数据接收事件public function onReceive(swoole_server $serv, $fd, $from_id, $data){$res['result'] = 'failed';$key = $this->safeKey;$req = json_decode($data, true);$action = $req['action'];$token = $req['token'];$timestamp = $req['timestamp'];if (time() - $timestamp > 180) {$res['code'] = '已超时';$serv->send($fd, json_encode($res));exit;}$token_get = md5($action.$timestamp.$key);if ($token != $token_get) {$res['msg'] = '非法提交';$serv->send($fd, json_encode($res));exit;}$res['result'] = 'success';$serv->send($fd, json_encode($res)); // 同步返回消息给客户端$serv->task($data);  // 执行异步任务}/*** @param $serv swoole_server swoole_server对象* @param $task_id int 任务id* @param $from_id int 投递任务的worker_id* @param $data string 投递的数据*/public function onTask(swoole_server $serv, $task_id, $from_id, $data){$res['result'] = 'failed';$req = json_decode($data, true);$action = $req['action'];echo date('Y-m-d H:i:s')." onTask: [".$action."].\n";switch ($action) {case 'sendMail': //发送单个邮件$mailData = ['emailAddress' => '2823175272@qq.com','subject' => 'swoole demo','body' => '测试This is the HTML message body <b>in bold!</b>,<br/>欢迎访问<a href="http://www.shanhubei.com/">www.shanhubei.com</a>'];$this->sendMail($mailData);break;case 'sendMailQueue': // 批量队列发送邮件$this->sendMailQueue();break;default:break;}}/*** @param $serv swoole_server swoole_server对象* @param $task_id int 任务id* @param $data string 任务返回的数据*/public function onFinish(swoole_server $serv, $task_id, $data){//}// 监听连接关闭事件public function onClose($serv, $fd, $from_id) {echo "Client {$fd} close connection\n";}public function stop(){$this->serv->stop();}private function sendMail($mail_data = []){$mail = new PHPMailer(true);try {$mailConfig = $this->mailConfig;//$mail->SMTPDebug = 2;        // 启用Debug$mail->isSMTP();   // Set mailer to use SMTP$mail->Host = $mailConfig['smtp_server'];  // SMTP服务$mail->SMTPAuth = true;                  // Enable SMTP authentication$mail->Username = $mailConfig['username'];    // SMTP 用户名$mail->Password = $mailConfig['password'];     // SMTP 密码/口令$mail->SMTPSecure = $mailConfig['secure'];     // Enable TLS encryption, `ssl` also accepted$mail->Port = $mailConfig['port'];    // TCP 端口$mail->CharSet  = "UTF-8"; //字符集$mail->Encoding = "base64"; //编码方式//Recipients$mail->setFrom($mailConfig['username'], 'Shanhubei'); //发件人地址,名称$mail->addAddress($mail_data['emailAddress'], '亲');     // 收件人地址和名称//$mail->addCC('hellowebanet@163.com'); // 抄送//Attachmentsif (isset($mail_data['attach'])) {$mail->addAttachment($mail_data['attach']);         // 添加附件}//$mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name//Content$mail->isHTML(true);                                  // Set email format to HTML$mail->Subject = $mail_data['subject'];$mail->Body    = $mail_data['body'];//$mail->AltBody = '这是在不支持HTML邮件客户端的纯文本格式';$mail->send();return true;} catch (\Exception $e) {echo 'Message could not be sent. Mailer Error: '. $mail->ErrorInfo;return false;}}// 邮件发送队列private function sendMailQueue(){$redis = new Redis();$redis->connect('127.0.0.1', 6379);//$password = '123';//$redis->auth($password);swoole_timer_tick(1000, function($timer) use ($redis) { // 启用定时器,每1秒执行一次$value = $redis->lpop('mailerlist');if($value){//echo '获取redis数据:' . $value;$json = json_decode($value, true);$start = microtime(true);$rs = $this->sendMail($json);$end = microtime(true);if ($rs) {echo '发送成功!'.$value.', 耗时:'. round($end - $start, 3).'秒'.PHP_EOL;} else { // 把发送失败的加入到失败队列中,人工处理$redis->rpush("mailerlist_err", $value);}}else{swoole_timer_clear($timer); // 停止定时器echo "Emaillist出队完成";}});}}

Copy

运行服务端

在public/目录下建立mailServer.php,代码如下:


require dirname(__DIR__) . '/vendor/autoload.php';use Shanhubei\Swoole\Mail;$config = ['smtp_server' => 'smtp.163.com','username' => 'xxxxx@163.com','password' => 'xxxx',// SMTP 密码/口令'secure' => 'ssl', //Enable TLS encryption, `ssl` also accepted'port' => 465, // tcp邮件服务器端口
];
$server = new Mail($config);
$server->start();

Copy

你可以注册一个163邮箱,然后开通smtp功能。我DEMO中使用的是163邮箱发邮件发多了被封号了,所以在线演示demo没上传了。配置好邮件服务器参数后,运行:

php mailServer.php

Copy

此时再使用命令​​netstat -lntp​​查看进程。

运行客户端

在public/目录下新建mailClient.php,代码如下:

class Client
{private $client;public function __construct() {$this->client = new swoole_client(SWOOLE_SOCK_TCP);}public function connect($type) {if( !$this->client->connect("127.0.0.1", 9502 , 1) ) {echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";}// fwrite(STDOUT, "请输入消息 Please input msg:");// $msg = trim(fgets(STDIN));$action = 'sendMail';if($type == 'q'){$action = 'sendMailQueue';}$time = time();$key = 'MDDGnQE33ytd2jDFADS39DSEWsdD24sK';$token = md5($action.$time.$key);$data = ['action' => $action,'token' => $token,'timestamp' => $time];$msg = json_encode($data);$this->client->send( $msg );$message = $this->client->recv();echo "Get Message From Server:{$message}\n";}
}$type = 'q';  //区分批量和单个发送标志if($type == 'q'){$redis = new \Redis();$redis->connect('127.0.0.1', 6379);//$password = '123456x';///$redis->auth($password);$arr = [];$arr[0] = ['subject' => '注册cloudfog-HA','emailAddress' => '2823175272@qq.com','body' => '您好,您的CloudFog使用的用户名是:123, 密码是:123。<br/>请不要将此邮件泄漏给他人,并尽快登录CloudFog更换新密码。如有疑问请联系管理员。'];$arr[1] = ['subject' => '注册cloudfog2','emailAddress' => '2823175272@qq.com','body' => '<a href="https://www.shanhubei.com" target="_blank">网易邮箱</a>'];foreach ($arr as $k=>$v) {$redis->rpush("mailerlist", json_encode($v, JSON_UNESCAPED_UNICODE));}   
}$client = new Client();
$client->connect($type);

Copy

运行命令启动客户端:

php mailClient.php

Copy

此时在命令行窗口会返回如下信息:

[root@localhost public]# php mailClient.php 
Get Message From Server:{"result":"success"}

Copy

这样就已经执行邮件发送任务了,如果出现故障,可以查看日志文件​​/data/logs/swoole.log​​。

然后你可以去查看对方邮箱是否收到相关邮件。

本文中使用了redis作为简单队列,你也可以使用复杂点的队列rabbitmq。你也可以使用Crontab来做定时任务,不过它最小粒度是分钟级别的。当然对于批量发送邮件,如果你不用php的话,可以用Python或者Java,它们都有相当成熟的解决方案。

二、使用Swoole实现在线聊天

建立服务端主程序

准备工作就绪后,我们开始来撸代码。

首先在项目目录:src/app/ 下建立​​Chat.php​​,用作Swoole服务端主程序。

Chat.php文件的主体结构是这样的:


namespace Shanhubei\Swoole;
use swoole_websocket_server;
class Chat
{protected $ws;protected $host = '0.0.0.0';protected $port = 9504;// 进程名称protected $taskName = 'swooleChat';// PID路径protected $pidFile = '/run/swooleChat.pid';// 设置运行时参数protected $options = ['worker_num' => 4, //worker进程数,一般设置为CPU数的1-4倍  'daemonize' => true, //启用守护进程'log_file' => '/data/logs/chatswoole.log', //指定swoole错误日志文件'log_level' => 3, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR'dispatch_mode' => 1, //数据包分发策略,1-轮询模式];public function __construct($options = []){$this->ws = new swoole_websocket_server($this->host, $this->port);if (!empty($options)) {$this->options = array_merge($this->options, $options);}$this->ws->set($this->options);$this->ws->on("open", [$this, 'onOpen']);$this->ws->on("message", [$this, 'onMessage']);$this->ws->on("close", [$this, 'onClose']);}public function start(){// Run worker$this->ws->start();}public function onOpen(swoole_websocket_server $ws, $request){// 设置进程名cli_set_process_title($this->taskName);//记录进程id,脚本实现自动重启$pid = "{$ws->master_pid}\n{$ws->manager_pid}";file_put_contents($this->pidFile, $pid);echo "server: handshake success with fd{$request->fd}\n";}public function onMessage(swoole_websocket_server $ws, $frame){//$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));$connets = $ws->connections;echo count($connets)."\n";echo $frame->data. "\n";if ($frame->data == '美女') {$mmpic = ['http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg','http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg','http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'];$picKey = array_rand($mmpic);$ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);} else {$ws->push($frame->fd, $this->reply($frame->data));}}public function onClose($ws, $fid){echo "client {$fid} closed\n";foreach ($ws->connections as $fd) {$ws->push($fd, $fid. '已离开!');}}private function reply($str) {$str = mb_strtolower($str);switch ($str) {case 'hello':$res = 'Hello, Friend.';break;case 'fuck':$res = 'Fuck bitch.';break;case 'ping':$res = 'PONG.';break;case 'time':$res = date('H:i:s');break;default:$res = $str;break;}return $res;}
}

Copy

我们需要往​​onMessage()​​方法里填代码。在这里,服务端接收客户端消息,并作出相应动作。Websocket可以向客户端发送字符串、二进制等形式消息。

public function onMessage(swoole_websocket_server $ws, $frame){//$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));if ($frame->data == '美女') {$mmpic = ['http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg','http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg','http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'];$picKey = array_rand($mmpic); //随机返回一张图片$ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);} else {$ws->push($frame->fd, $this->reply($frame->data));}}private function reply($str) {$str = mb_strtolower($str);switch ($str) {case 'hello':$res = 'Hello, Friend.';break;case 'fuck':$res = 'Fuck bitch.';break;case 'ping':$res = 'PONG.';break;case 'time':$res = date('H:i:s');break;default:$res = $str;break;}return $res;}

Copy

将上面代码加入到Chat.php中,用来处理接收消息并响应回复。响应回复的内容可以根据实际情况修改,本代码只是用来演示。

启动服务端

在public/目录下建立chatServer.php,代码如下:

require dirname(__DIR__) . '/vendor/autoload.php';use Shanhubei\Swoole\Chat;$opt = ['daemonize' => true
];
$ws = new Chat($opt);
$ws->start();

Copy

然后运行以下代码启动服务端:​​php chatServer.php​​ 如果一切正常,你可以netstat -lntp看一下,系统会监听进程名为swooleChat,端口为9504的服务。

启动客户端

我们使用HTML5的websocket客户端来连接服务端,本地建立wsClient.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Client</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"><link rel="stylesheet" href="css/chat.css">
</head>
<body><div id="chat-wrap"><div id="result"></div><ul class="chat-thread"><li class="you"><img class="head" src="images/head1.jpg" alt=""><p>Are we meeting today?</p></li><li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li><li class="me"><img class="head" src="images/head1.jpg" alt=""><p>一部分保持在行尾,另一部分换到下一行。</p></li><li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li><li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li></ul></div><div class="send"><form action=""><input type="text" class="form-control" id="m" autocomplete="off" placeholder="请输入内容"><button type="submit" class="btn btn-info">发送</button></form></div>
<!-- <div><div id="result"></div><form class="form-inline" action=""><div class="form-group"><input type="text" class="form-control" id="m" autocomplete="off" placeholder="请输入内容"></div><button type="submit" class="btn btn-info">发送</button></form>
</div> -->
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script>
if ("WebSocket" in window) {var ws = new WebSocket("ws://192.168.3.105:9504");var result = document.querySelector('#result');var chatthread = document.querySelector('.chat-thread');chatthread.scrollTop = chatthread.scrollHeight;ws.onopen = function() {result.innerHTML = '已连接上!';$('#result').show().html('已连接上!').fadeOut(1500);console.log('已连接上!');}document.querySelector('form').onsubmit = function(e) {var msg = document.querySelector('#m').value;ws.send(msg);$('.chat-thread').append('<li class="me"><img class="head" src="images/head1.jpg" alt=""><p>'+msg+'</p></li>');chatthread.scrollTop = chatthread.scrollHeight;document.querySelector('#m').value = '';return false;}ws.onmessage = function(e) {if(e.data instanceof Blob) {// var img = document.createElement("img");// img.src = window.URL.createObjectURL(e.data);// result.appendChild(img);// var d = window.URL.createObjectURL(e.data);// console.log(d);var img = '<img src="'+window.URL.createObjectURL(e.data)+'" width="180"/>';$('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+img+'</p></li>');}else {// var p = document.createElement("p");// p.innerHTML = e.data;// result.appendChild(p);$('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+e.data+'</p></li>');}chatthread.scrollTop = chatthread.scrollHeight;}ws.onclose = function() {console.log('连接已关闭!');}
} else {alert('您的浏览器不支持 WebSocket!');
}
</script>
</body>
</html>

Copy

然后用浏览器打开wsClient.html,你可以看到一个聊天窗口,一开始会提示连接成功,然后你可以在输入框中输入你想说的话,如“美女”等等。

三、使用Systemctl管理Swoole服务

配置Swoole服务

有了Systemctl,我们可以轻松配置我们的Swoole服务,下面以Swoole聊天服务为例:

首先在​​/usr/lib/systemd/system/​​目录下,新建文件swoolechat.service,并加入以下代码:

[Unit]
Description=Swoole Chat Server
After=network.target syslog.target[Service]
Type=forking
LimitNOFILE=65535
ExecStart=/usr/local/php/bin/php /home/web/swoole/public/chatServer.php
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always[Install]
WantedBy=multi-user.target graphical.target

Copy

然后保存好文件,并使用如下命令重新载入所有的[Unit]文件,确保我们添加进去的service能被系统加载并生效。

systemctl  daemon-reload

Copy

验证

现在我们来验证服务,首先启动swoole服务:

systemctl start swoolechat.service

Copy

然后使用以下命令查看swoole服务是否正常:

systemctl status swoolechat.service

Copy

四、使用Swoole实现毫秒级定时任务

接着服务端代码 ​​public\taskServer.php​​ :


require dirname(__DIR__) . '/vendor/autoload.php';use Shanhubei\Swoole\Task;$opt = ['daemonize' => false
];
$ser = new Task($opt);
$ser->start();

Copy

客户端代码 public\taskClient.php :

class Client
{private $client;public function __construct() {$this->client = new swoole_client(SWOOLE_SOCK_TCP);}public function connect() {if( !$this->client->connect("127.0.0.1", 9506 , 1) ) {echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";}fwrite(STDOUT, "请输入消息 Please input msg:");$msg = trim(fgets(STDIN));$this->client->send( $msg );$message = $this->client->recv();echo "Get Message From Server:{$message}\n";}
}$client = new Client();
$client->connect();

Copy

验证效果

1.启动服务端:

php taskServer.php

Copy

2.客户端输入:

另开命令行窗口,执行

[root@localhost public]# php taskClient.php 
请输入消息 Please input msg:hello
Get Message From Server:{"result":"success"}

Copy

五、使用Websocket上传文件

服务端

我们继续使用Swoole实验室:1-使用Composer构建项目构建好的项目,新建文件\src\app\Uploader.php:

namespace Shanhubei\Swoole;
use swoole_websocket_server;class Uploader
{protected $ws;protected $host = '0.0.0.0';protected $port = 9505;// 进程名称protected $taskName = 'swooleUploader';// PID路径protected $pidFile = '/run/swooleUploader.pid';// 设置运行时参数protected $options = ['worker_num' => 4, //worker进程数,一般设置为CPU数的1-4倍  'daemonize' => true, //启用守护进程'log_file' => '/data/logs/uploadswoole.log', //指定swoole错误日志文件'log_level' => 3, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR'dispatch_mode' => 1, //数据包分发策略,1-轮询模式];public function __construct($options = []){$this->ws = new swoole_websocket_server($this->host, $this->port);if (!empty($options)) {$this->options = array_merge($this->options, $options);}$this->ws->set($this->options);$this->ws->on("open", [$this, 'onOpen']);$this->ws->on("message", [$this, 'onMessage']);$this->ws->on("close", [$this, 'onClose']);}public function start(){// Run worker$this->ws->start();}public function onOpen(swoole_websocket_server $ws, $request){// 设置进程名cli_set_process_title($this->taskName);//记录进程id,脚本实现自动重启$pid = "{$ws->master_pid}\n{$ws->manager_pid}";file_put_contents($this->pidFile, $pid);echo "server: handshake success with fd{$request->fd}\n";$msg = '{"msg": "connect ok"}';$ws->push($request->fd, $msg);}public function onMessage(swoole_websocket_server $ws, $frame){$opcode = $frame->opcode;if ($opcode == 0x08) {echo "Close frame received: Code {$frame->code} Reason {$frame->reason}\n";} else if ($opcode == 0x1) {echo "Text string\n";} else if ($opcode == 0x2) {echo "Binary data\n"; //} else {echo "Message received: {$frame->data}\n";}$filename = './files/aaa.jpg';file_put_contents($filename, $frame->data);echo "file path : {$filename}\n";$ws->push($frame->fd, 'upload success');}public function onClose($ws, $fid){echo "client {$fid} closed\n";foreach ($ws->connections as $fd) {$ws->push($fd, $fid. '已断开!');}}
}

Copy

$frame->opcode,WebSocket的OpCode类型,可以通过它来判断传输的数据是文本内容还是二进制数据。

新建public/uploadServer.php,用于启动服务端脚本:


require dirname(__DIR__) . '/vendor/autoload.php';use Shanhubei\Swoole\Uploader;$opt = ['daemonize' => false
];
$ws = new Uploader($opt);
$ws->start();

Copy

客户端

在本地站点建立客户端文件upload.html。只需在页面中放置一个文件选择控件和一个用于输出上传信息的div#log。

<input type="file" id="myFile">
<div id="log"></div>

Copy

当选择好本地文件后,触发onchange事件,这个时候客户端尝试与服务端建立websocket连接,然后开始读取本地文件,读取完成后将数据发送给服务端。

$('#myFile').on('change', function(event) {var ws = new WebSocket("ws://192.168.3.106:9505");ws.onopen = function() {log('已连接上!');}ws.onmessage = function(e) {log("收到服务器消息:" + e.data + "'\n");if (e.data == 'connect ok') {log('开始上传文件');} if (e.data == 'upload success') {log('上传完成');ws.close();} else {var file = document.getElementById("myFile").files[0];var reader = new FileReader();reader.readAsArrayBuffer(file);reader.onload = function(e) {ws.send(e.target.result);log('正在上传数据...');}}}ws.onclose = function() {console.log('连接已关闭!');log('连接已关闭!');}
});
//在消息框中打印内容
function log(text) {$("#log").append(text+"<br/>");
}

Copy

这里讲一下HTML5的FileReader 对象,FileReader允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。FileReader提供了几种读取文件的方法:

  • ​​reader.readAsArrayBuffer(file|blob)​​:用于启动读取指定的 Blob 或 File 内容。读取文件后,会在内存中创建一个ArrayBuffer对象(二进制缓冲区),将二进制数据存放在其中。当读取操作完成时,readyState 变成 DONE(已完成),并触发 loadend 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。通过此方式,可以直接在网络中传输二进制内容。此外对于大文件我们可以分段读取二进制内容上传。
  • ​​reader.readAsDataURL(file|blob)​​:该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
  • ​​FileReader.readAsText(file|blob)​​:可以将 Blob 或者 File 对象转根据特殊的编码格式转化为内容(字符串形式)。当转化完成后, readyState 这个参数就会转换 为 done 即完成态, event(“loadend”) 挂载的事件会被触发,并可以通过事件返回的形参得到中的 FileReader.result 属性得到转化后的结果。
  • ​​FileReader.readAsBinaryString()​​:读取文件内容为二进制字符串,已废除,不要用了。

运行服务端

php uploadServer.php

Copy

运行客户端

在本地站点目录,打开upload.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224696.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业异地组网选新型技术SD-WAN还是传统方式MPLS?

案例背景&#xff1a; 某集团企业决定扩大其商业版图&#xff0c;在国内新开了几家分公司。然而&#xff0c;在面对如何进行组网的问题上&#xff0c;陷入了纠结。究竟选择传统的MPLS&#xff08;多协议标签交换&#xff09;还是尝试SD-WAN&#xff08;软件定义广域网这个新兴…

LeetCode 每日一题 Day 12 (Hard)|| 二维前缀和二维差分

2132. 用邮票贴满网格图 给你一个m x n的二进制矩阵 grid &#xff0c;每个格子要么为 0 &#xff08;空&#xff09;要么为 1 &#xff08;被占据&#xff09;。 给你邮票的尺寸为 stampHeight x stampWidth 。我们想将邮票贴进二进制矩阵中&#xff0c;且满足以下 限制 和 …

PhotoMaker——通过堆叠 ID 嵌入定制逼真的人像照片

论文网址链接&#xff1a;https://arxiv.org/abs/2312.04461 详情网址链接&#xff1a;PhotoMaker 开源代码网址链接&#xff1a;GitHub - TencentARC/PhotoMaker: PhotoMaker 文本到图像AI生成的最新进展在根据给定文本提示合成逼真的人类照片方面取得了显着进展。然而&#…

Ubuntu20.04 配置NTP服务器

# 安装ntp服务 sudo apt-get install ntp ntpdate # 修改ntp服务配置文件 sudo vi /etc/ntp.conf # /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help # driftfile记录时间差异 driftfile /var/lib/ntp/ntp.drift# Leap seconds definition provided by tz…

day17 二叉树的所有路径

void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) { path.push_back(cur->val); // 中&#xff0c;中为什么写在这里&#xff0c;因为最后一个节点也要加入到path中 // 这才到了叶子节点 if (cur->left NULL &&a…

Java: OpenWeatherMap json Deserialization of Java Objects

openweathermap.json {"coord": {"lon": 114.0683, "lat":22.5455},"weather":[ {"id": 803, "main":"Clouds", "description":"多云", "icon":"04d"}],&quo…

使用Java实现PDF填充图片功能

一、引言 在软件开发中&#xff0c;将图片填充至PDF文件是一项常见的需求。为了满足这一需求&#xff0c;我们可以使用Java编程语言和相关的库来实现。本文将介绍如何使用Java和iText库来实现PDF填充图片的功能。 二、准备工作 在开始之前&#xff0c;我们需要确保已经安装了…

FAQ:Inheritance 篇——What your mother never told you

文章目录 1、How can I set up my class so it won’t be inherited from&#xff1f;&#xff08;如何设置类&#xff0c;使它不会被继承?&#xff09;2、How can I set up my member function so it won’t be overridden in a derived class? &#xff08;如何设置成员函数…

cgal教程 3D Alpha Wrapping

文章目录 3D Alpha Wrapping (3D alpha 包裹)1 介绍2 方法2.1 算法2.2 保证 3 接口4 选择参数4.1 alpha4.2 Offset4.3 关于“双面”包裹的注意事项 5 性能6 例子 3D Alpha Wrapping (3D alpha 包裹) 原文地址: https://doc.cgal.org/latest/Alpha_wrap_3/index.html#Chapter_3D…

springcloudalibaba01

整合springcloud 和 springcloudalibaba&#xff0c;&#xff0c;&#xff0c; 版本对应关系 <dependencyManagement><dependencies><!--每个springcloud的工具都有一个版本每个springcloud alibaba的工具都有一个版本统一版本--> <!-- 整合…

vivado约束方法6

生成的时钟 定时约束向导建议在的输出上创建一个生成的时钟顺序单元&#xff0c;当它直接或通过驱动其他顺序单元的时钟引脚时一些互连逻辑。与PLL或MMCM不同&#xff0c;用户逻辑不能将主时钟&#xff0c;因此向导仅提供指定除法系数的选项&#xff0c;如中所示如下图所示&am…

SpringMVC框架是干什么的

动态SQL之Foreach是什么 Foreach是Mybatis中动态SQL语句中的一种特殊标签&#xff0c;它可以用于对Java集合类型进行遍历&#xff0c;并将集合中的元素作为参数传递给SQL语句中的占位符。 Foreach标签一般包含三个属性&#xff1a; collection&#xff1a;指定要遍历的Java集…

音视频参数介绍

一、视频参数概念 单个视频帧&#xff1a;可以简单地理解成为一张图片 单个视频帧主要的参数概念&#xff1a; 分辨率&#xff1a; 分辨率是指图像或显示器上像素的数量&#xff0c;通常用横向像素数乘以纵向像素数表示。例如&#xff0c;1920x1080 表示宽度为1920像素&…

奖励Reward系统设计

介绍 一般来说系统前期&#xff0c;发放奖励&#xff0c;就简单的发放道具就可以&#xff0c;基本上是&#xff0c;遇到一个配置一个&#xff0c;不同的系统可能配置的方法不一样&#xff0c;每次活动更是加不同的配置。 经历里这些不同的需求&#xff0c;我们需要设计一个系统…

linux系统命令

linux常用命令 端口相关文件目录管理文件查看文件属性日志查看系统命令防火墙相关命令 端口相关 netstat -ntpl # 查询linux系统tcp端口情况 fuser -n tcp 80 # 查询80端口是否被占用 lsof -i:<port> lsof -i:9099 | grep java lsof -i :9099 | awk {print $2, $1, $3}文…

DTC 故障严重程度

文章目录 简介DTC严重性 位定义DTC 类别定义参考 简介 DTCSeverityMask&#xff08;DTC严重性掩码&#xff09;/ DTCSeverity&#xff08;DTC严重性&#xff09;包含了DTC严重性和DTC类别信息。 DTCSeverityMask&#xff08;DTC严重性掩码&#xff09;&#xff0f;DTCSeverit…

人工智能_机器学习066_SVM支持向量机_对偶问题转化_强对偶问题_弱对偶问题_弱对偶问题详解---人工智能工作笔记0106

上一节我们就得到了9,这个公式,这个公式要求,先去求maxL(x,lamada) ,也就是求,lamada是多少的时候,对应的, L(x,lamada) = f(x) + h(x) * lamada <=P 中的这个h(x) * lamada,最大,因为h(x)是小于0的也就是,lamada是什么的时候,h(x) * lamada最大,也就是越接近于0对吧. 然…

【Qt5】ui文件最后会变成头文件

2023年12月14日&#xff0c;周四下午 我也是今天下午偶然间发现这个的 在使用Qt的uic&#xff08;User Interface Compiler&#xff09;工具编译ui文件时&#xff0c;会生成对应的头文件。 在Qt中&#xff0c;ui文件是用于描述用户界面的XML文件&#xff0c;而头文件是用于在…

CMS—评论功能设计

一、需求分析 1.1、常见行为 1.敏感词过滤 2.新增评论&#xff08;作品下、评论下&#xff09; 3.删除评论&#xff08;作品作者、上级评论者、本级作者&#xff09; 4.上级评论删除关联下级评论 5.逻辑状态变更&#xff08;上线、下线、废弃...&#xff09; 6.上逻辑状态变更…

UG NX二次开发(C++)-库缺少需要的入口点的原因与解决方案

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、“库缺少需要的入口点”错误展示3、可能出现的原因与解决方案3.1 对于采用CTRL+U方式调用3.2 对于menu菜单下调用1、前言 在UG NX二次开发过程中,有时会遇到形形色色的bug,比如有个读…