Below you will find pages that utilize the taxonomy term “程序开发”
August 14, 2025
Rust 里 thread::park() 与 thread::yield_now() 的区别
"\u003cp\u003e在看 tokio 调度源码时,会有一些操作线程park的函数,而在rust标准库里也同样有类似的方法,那就是 \u003ca href=\"https://doc.rust-lang.org/std/thread/fn.park.html\"\u003ethread::park()\u003c/a\u003e ,同时还有一个咋一看效果类似的函数 \u003ca href=\"https://doc.rust-lang.org/std/thread/fn.yield_now.html\"\u003ethread::yield_new()\u003c/a\u003e, 两个函数都有实现 **\u003ccode\u003e类似\u003c/code\u003e**暂停执行代码的效果,那它们到底又何区别呢?\u003c/p\u003e\n\u003cp\u003e希望通过这篇文章可以让大家搞明白它们两者的区别和使用场景。\u003c/p\u003e\n\u003cp\u003e我们先看一下 \u003ccode\u003ethread::park() \u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"threadpark\"\u003ethread:park()\u003c/h2\u003e\n\u003cp\u003e对于 park 函数的作用主要是实现当前线程的阻塞,并出让CPU,这时OS调度器会将其它线程调度到CPU,继续执行其它任务。但是一旦调用这个函数后,后续线程将一直处于阻塞状态,也就是说此线程将无法获取CPU处理任务,直到调用 unpark() 函数,才恢复正常。\u003c/p\u003e\n\u003cp\u003e从线程状态角度来看,它的转换\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erunning ---\u0026gt; [thread::park()] ---\u0026gt; blocked (等待唤醒)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eblocked ---\u0026gt; [thread::unpark()]---\u0026gt; runnable ---\u0026gt; running (被unpark唤醒后)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e总结\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e …\u003c/li\u003e\u003c/ul\u003e"
July 10, 2025
从Vec的 swap_remove 方法中学到的性能优化
"\u003cp\u003e今天在看 tokio 源码时,发现一个 \u003ca href=\"https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/scheduler/multi_thread/idle.rs#L129-L145\"\u003eunpark_worker_by_id\u003c/a\u003e 函数里调用了标准库Vec 的 \u003ca href=\"https://github.com/rust-lang/rust/blob/master/library/alloc/src/vec/mod.rs#L2014-L2036\"\u003eswap_remove\u003c/a\u003e方法,\u003ccode\u003eswap_remove\u003c/code\u003e 实现如下\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eswap_remove\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003emut\u003c/span\u003e self, index: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e) -\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003eT\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[cold]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[cfg_attr(not(panic = \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;immediate-abort\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e), inline(never))]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e#[optimize(size)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eassert_failed\u003c/span\u003e(index: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e, len: \u003cspan style=\"color:#66d9ef\"\u003eusize\u003c/span\u003e) -\u0026gt; \u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003epanic!\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;swap_remove index (is \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{index}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e) should be \u0026lt; len (is \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{len}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e)\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e len \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e self.len();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e index \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e len { …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
June 10, 2025
理解 Solana 中的 Slot、Block、Epoch、Entry、Shred 和 PoH
"\u003cp\u003e对于刚刚接触Solana的开发者来讲,会经常遇到 Slot Block Epochs Entry 和 Shred等一些概念术语,但很验证记住它们的意思和作用。\u003c/p\u003e\n\u003cp\u003e本篇将通过 Solana 的交易原理,让大家轻记信它们并了解它们之间的联系,并加深对Solana交易的理解。由于能力有限,文章中难免有误,大家可以在评论区留言,共同学习进步!\u003c/p\u003e\n\u003cp\u003e好了,下面让我们开始彻底搞明白这些术语及它们在Solana交易中的作用吧!\u003c/p\u003e\n\u003cp\u003e在开始之前我们先看一下在Soalna链中一笔交易是如何进行的。\u003c/p\u003e\n\u003ch2 id=\"交易流程\"\u003e交易流程\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://www.helius.dev/_next/image?url=%2Fapi%2Fmedia%2Ffile%2Fturbine-in-solana-transaction-lifecycle.webp\u0026amp;w=3840\u0026amp;q=90\" alt=\"Visualization of where Turbine lies in the lifecycle of a Solana transaction\"\u003e\u003c/p\u003e\n\u003ch3 id=\"交易流程-1\"\u003e\u003cstrong\u003e交易流程\u003c/strong\u003e\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e用户客户端发起一笔交易,并使用钱包私钥进行签名\u003c/li\u003e\n\u003cli\u003e通过rpc协议将交易发送到用户指定的 Solana RPC 节点。这里RPC节点在区块链网络中存在多个,起到了负载均衡的作用\u003c/li\u003e\n\u003cli\u003eRPC节点验证交易合法性,如进行一系列的检查 ,一般指签名验证/账户检查(账户是否存在,读取权限合法)/账户余额是否足够支付手续费等,最后进行交易模拟执行,就是我们经常说的模拟交易阶段(这一步可以手动配置 \u003ccode\u003e--skip-preflight\u003c/code\u003e 或 \u003ccode\u003ekipPreflight: true\u003c/code\u003e 跳过)。如果这一步失败,则整个交易直接失败, …\u003c/li\u003e\u003c/ol\u003e"
May 17, 2025
零拷贝bytemuck与 borsh
"\u003cp\u003e在上一篇博文《\u003ca href=\"https://blog.haohtml.com/posts/serde-vs-bincode-vs-borsh-in-the-rust/\"\u003e深入理解 Serde、Bincode 与 Borsh 的关系与区别\u003c/a\u003e》介绍了常用的几种解析二进制数据的方法,主要有 bincode 与 borsh, 并提到过在区块链领域里一般推荐使用 borsh 解析数据。但随着合约的开发使用borsh的地方越来越多,会经常遇到提示超出 4K Stack 大小的错误。这是因为在solana里,虚拟机 sbf 限制了一个合约最大允许使用的statck大小上限为 4k。尽管我们使用完一个大变量通过一些方法,如变量作用域、通过Box将内存移动到heap、或手动drop立即释放内存。但仍有些场景是没有采用这种办法的,这时应该如何办呢?\u003c/p\u003e\n\u003cp\u003e如果经常看一些优秀的开源项目的话,会发现有一个 \u003ccode\u003ebytemuck\u003c/code\u003e 的crate,它是一个 \u003ccode\u003ezerocopy\u003c/code\u003e 库,可以避免内存复制带来的开销,加速解析数据速度,这里给出一个测试代码\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e borsh::{BorshDeserialize, BorshSerialize};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e bytemuck::{Pod, Zeroable};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e solana_program::pubkey::Pubkey;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
April 22, 2025
深入理解 Serde、Bincode 与 Borsh 的关系与区别
"\u003cp\u003e在Rust开发中,无论是构建网络服务、存储数据还是开发区块链程序,**序列化(Serialization)和反序列化(Deserialization)**都是不可或缺的操作。序列化是将内存中的数据结构(struct)转换成字节序列或者其他格式(JSON, vec\u003cu8\u003e),以便存储或传输;反序列化则是将字节序列还原成原来的数据结构。\u003c/p\u003e\n\u003cp\u003eRust 生态中常用的序列化工具包括 \u003cstrong\u003eSerde\u003c/strong\u003e、\u003cstrong\u003eBincode\u003c/strong\u003e 和 \u003cstrong\u003eBorsh\u003c/strong\u003e。初学者在阅读文档或实际开发中可能会发现它们名字都很熟悉,但它们的定位、使用方式和特点却不完全相同。\u003c/p\u003e\n\u003cp\u003e本文将系统梳理三者的关系、差异和使用场景。\u003c/p\u003e\n\u003ch2 id=\"serde\"\u003eSerde\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eSerde(Serialization / Deserialization)\u003c/strong\u003e 是 Rust官方生态最流行的序列化框架。它提供了一种 \u003cstrong\u003e抽象接口\u003c/strong\u003e,让你可以将 Rust 类型序列化为多种格式,而不关心底层具体实现。\u003c/p\u003e\n\u003ch3 id=\"特点\"\u003e特点\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e通用性强\u003c/strong\u003e:支持 JSON、YAML、TOML、Bincode 等多种格式。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e灵活\u003c/strong\u003e:可以自定义序列化逻辑。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e宏支持\u003c/strong\u003e:通过 \u003ccode\u003e#[derive(Serialize, Deserialize)]\u003c/code\u003e 自动生成序列化代码。 …\u003c/li\u003e\u003c/ul\u003e"
March 28, 2025
solana中MEV监听交易的几种方法
"\u003ch1 id=\"策略分类\"\u003e策略分类\u003c/h1\u003e\n\u003cp\u003e在 Solana 上 \u003cstrong\u003eMEV(最大可提取价值)\u003c/strong\u003e 的几种策略主要有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e套利(Arbitrage)\u003c/li\u003e\n\u003cli\u003e清算(Liquidation)\u003c/li\u003e\n\u003cli\u003e抢跑(Front-Running)\u003c/li\u003e\n\u003cli\u003e三明治攻击(Sandwich Attack)\u003c/li\u003e\n\u003cli\u003e后置插队(Back-Running)\u003c/li\u003e\n\u003cli\u003eJito MEV 竞标\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"套利arbitrage\"\u003e套利(Arbitrage)\u003c/h2\u003e\n\u003cp\u003e价格差异猎手 想象你是一个精明的商人,在不同的市场上发现同一件商品价格不同。比如,在A市场一个苹果卖1元,在B市场卖1.2元。你会怎么做?立即在A市场买入,然后在B市场卖出,赚取0.2元的差价。\u003c/p\u003e\n\u003cp\u003e在加密世界中,这就是套利。交易员快速在不同交易所或流动性池之间捕捉加密货币价格差异,瞬间完成买卖,赚取微小但稳定的利润。\u003c/p\u003e\n\u003ch2 id=\"清算liquidation\"\u003e清算(Liquidation)\u003c/h2\u003e\n\u003cp\u003e充当风险管理者角色。想象银行放贷时,借款人需要提供抵押物品,如果抵押物品价值下跌到无法覆盖贷款,银行会立即收回资产。\u003c/p\u003e\n\u003cp\u003e在加密借贷平台,当用户的抵押品价值跌破安全线,MEV机器人(\u003cstrong\u003e清算人Liquidator)\u003c/strong\u003e 通常可以以折扣价买入资产。这是因为在借贷平台(如 \u003cstrong\u003eSolend\u003c/strong\u003e、\u003cstrong\u003eMango Markets\u003c/strong\u003e)中,如果用户的抵押资产价值不足以覆盖 …\u003c/p\u003e"
March 27, 2025
SPL-Token CLI 使用入门教程
"\u003cp\u003e本篇文章将对官方教程的基本上进行整理和完善,同时对一些官方未提到的一些知识点和实践进行一些介绍,方便一些刚入门solana开发的同学能够对solana开发有更完整的了解。\u003c/p\u003e\n\u003cp\u003e本篇文章使用 \u003ccode\u003espl-token\u003c/code\u003e 命令行进行演示操作,分别介绍 Mint Account 和 token Account 的创建、转账、关闭账户并回收租金SOL等操作。\u003c/p\u003e\n\u003cp\u003e这里假如用户本机已经安装好solana命令行,并通过 \u003ccode\u003esolana-test-validator\u003c/code\u003e 命令在本地启动开发集群。\u003c/p\u003e\n\u003ch1 id=\"环境准备\"\u003e环境准备\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e打开一个终端,在本地创建一个新集群\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003ebase\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ➜ ~ solana-test-validator --ledger test-ledger -r\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLedger location: test-ledger\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLog: test-ledger/validator.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e⠠ Initializing... …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
February 25, 2025
Solana中的 Native Programs
"\u003cp\u003e在Solana中有一些少量的内置原生程序,它们的程序ID格式一般为 \u003ccode\u003exxx11111111111111111111111111111111\u003c/code\u003e。它们与第三方自定义程序不同,原生程序是 \u003cstrong\u003evalidator node\u003c/strong\u003e 运行所必须的一部分。同时它们也是集群升级的一部分,这些升级可能包括新功能的添加、BUG修复,又或者是性能的优化提升。这些内置原生程序极少的发生变化,目前提供的所有内置原生程序可以在 \u003ca href=\"https://docs.anza.xyz/runtime/programs\"\u003ehttps://docs.anza.xyz/runtime/programs\u003c/a\u003e 找到。\u003c/p\u003e\n\u003cp\u003e其中有两个非常重要的程序很值得我们关注,因为我们在开发中,需要经常用到他们。\u003c/p\u003e\n\u003ch1 id=\"system-program\"\u003eSystem Program\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e作用:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e创建新帐户\u003c/li\u003e\n\u003cli\u003e分配帐户数据\u003c/li\u003e\n\u003cli\u003e将帐户分配给所属的程序,即指定账户与程序的对应关系\u003c/li\u003e\n\u003cli\u003e转账最小 lamports 给账户(租金),防止账户被系统回收\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eProgram id: \u003ccode\u003e11111111111111111111111111111111\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eInstructions: \u003ca href=\"https://docs.rs/solana-program/2.2.0/solana_program/system_instruction/enum.SystemInstruction.html\"\u003eSystemInstruction\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"bpf-loader\"\u003eBPF Loader\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e作用:\n\u003cul\u003e\n\u003cli\u003e部署所有自定义程序, …\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e"
February 15, 2025
Solana中 PDA、ATA 与 普通Account 的区别与关系
"\u003ch1 id=\"普通账户地址\"\u003e普通账户地址\u003c/h1\u003e\n\u003cp\u003e对于账户地址的创建是由一个密钥对来生成的,但在Solana中账户地址与以太坊中的账户地址还是有一些区别的。\u003c/p\u003e\n\u003ch2 id=\"以太坊账户地址\"\u003e以太坊账户地址\u003c/h2\u003e\n\u003cp\u003e以太坊账户地址的生成过程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e通过私钥生成公钥\u003c/li\u003e\n\u003cli\u003e对公钥进行 Keccak-256 哈希\u003c/li\u003e\n\u003cli\u003e取哈希值的最后 160 位(20 字节)作为地址\u003c/li\u003e\n\u003cli\u003e将地址以 \u003ccode\u003e0x\u003c/code\u003e 开头,并根据需要选择是否使用 EIP-55 格式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e地址中通常是小写字母,但也有大写字母的变种,称为 \u003cstrong\u003eEIP-55\u003c/strong\u003e 格式。在 EIP-55 中,某些字符会根据哈希值的大小写进行区分,从而增加地址的错误检查能力。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"solana-账户地址\"\u003eSolana 账户地址\u003c/h2\u003e\n\u003cp\u003eSolana账户地址的生成过程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e通过私钥生成公钥,一般通过调用 Keypair.generate() 生成\u003c/li\u003e\n\u003cli\u003e公钥直接映射为账户的地址,长度为 32 字节\u003c/li\u003e\n\u003cli\u003e为了使用方便,一般对其进行 Base58 编码,将公钥转换为地址字符串\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-typescript\" data-lang=\"typescript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e { \u003cspan style=\"color:#a6e22e\"\u003eKeypair\u003c/span\u003e } \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erequire\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;@solana/web3.js\u0026#39;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// 生成一个新的密钥对\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ekeypair\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eKeypair\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003egenerate\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// 获取公 …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
January 10, 2025
Solana中如何实现转账
"\u003cp\u003e在 Solana 中转账有两种方式。\u003c/p\u003e\n\u003ch1 id=\"修改结构体字段\"\u003e修改结构体字段\u003c/h1\u003e\n\u003cp\u003e一种是在不调用(\u003ccode\u003einvoking\u003c/code\u003e )系统程序( \u003ccode\u003eSystem Program\u003c/code\u003e )的情况下,将 \u003ccode\u003elamports\u003c/code\u003e 从一个账户转移到另一个账户。它的实现是直接通过修改结构体的 \u003ccode\u003elamports\u003c/code\u003e 字段值来实现的。\u003c/p\u003e\n\u003cp\u003e这种方法可以实现将 lamports 从任何由您的程序\u003cstrong\u003e拥有\u003c/strong\u003e的账户转移到任何账户。\u003ca href=\"https://solana.com/zh/developers/cookbook/programs/transfer-sol\"\u003e文档\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e/// Transfers lamports from one account (must be program owned)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e/// to another account. The recipient can by any account\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etransfer_service_fee_lamports\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e from_account: \u003cspan style=\"color:#66d9ef\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e to_account: \u003cspan style=\"color:#66d9ef\"\u003e\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e amount_of_lamports: \u003cspan style=\"color:#66d9ef\"\u003eu64\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) -\u0026gt; \u003cspan style=\"color:#a6e22e\"\u003eProgramResult\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e// Does the from account have enough …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 22, 2024
Solana中账户类型 Account、AccountInfo与 SystemAccount 的区别
"\u003cp\u003e在Solana中 Account 的角色很重要,它就像Linux中\u003ccode\u003e一切皆文件\u003c/code\u003e的概念一样,无处不在。了解它也是开发Solana的基础,本节主要介绍我们最经常使用的 \u003ccode\u003eAccount\u003c/code\u003e 、\u003ccode\u003eAccountInfo\u003c/code\u003e 和 \u003ccode\u003eSystemAccount\u003c/code\u003e 这三种账户类型的区别与使用场景。\u003c/p\u003e\n\u003cp\u003e当然除此之外还有一些账户类型也很重要,如 \u003ccode\u003eUncheckedAccount\u003c/code\u003e、\u003ccode\u003eSigner\u003c/code\u003e、\u003ccode\u003eTokenAccount\u003c/code\u003e、\u003ccode\u003eMint\u003c/code\u003e、\u003ccode\u003eCpiAccount\u003c/code\u003e、\u003ccode\u003eLoader\u003c/code\u003e、\u003ccode\u003eProgram\u003c/code\u003e、\u003ccode\u003eAssociatedToken\u003c/code\u003e 等,我们这里就不再一一讲解,有兴趣的话可以参考官方相关文档。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e由于多数情况下都是使用anchor框架开发Solana合约,因此本文主要是根据 anchor-lang 文档里介绍账户来讲解\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"账户类型\"\u003e账户类型\u003c/h1\u003e\n\u003cp\u003e以下我们分别对这三种账户类型做一些简单的介绍。\u003c/p\u003e\n\u003ch2 id=\"accountinfo\"\u003eAccountInfo\u003c/h2\u003e\n\u003cp\u003e在 Solana 中 \u003ccode\u003eAccountInfo\u003c/code\u003e 是最基础的账户类型。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/accountinfo.svg\" alt=\"AccountInfo\"\u003e\u003c/p\u003e\n\u003cp\u003e其它几种账户类型都是对它的封装,它的\u003ca href=\"https://docs.rs/anchor-lang/0.30.1/anchor_lang/prelude/struct.AccountInfo.html\"\u003e定义\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#[repr(C)]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eAccountInfo\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e\u0026#39;a\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e key: …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 6, 2024
什么是Layer2网络
"\u003cp\u003e我们平时提到的比特币、以太坊、Solana,它们都属于Layer 1网络,而Layer 2(L2) 网络是指基于Layer1网络之上构建的一层网络,它很类似于Layer 1 网络,也是一个独立的区块链。但它的主要目的并不是为了代替 Layer 1 ,而是为了通过扩展 Layer 1 层网络从而解决一些在 Layer 1 网络中存在的一些问题,它同时继承了 Layer 1 网络的安全性和去中心化性。\u003c/p\u003e\n\u003ch1 id=\"以太坊存在的问题\"\u003e以太坊存在的问题\u003c/h1\u003e\n\u003cp\u003e这里以以太坊为例,在 L1 网络上随着交易量越来越大,交易频率也越来越频繁,导致Gas(网络交易费)越来越高,一笔交易可能在网络繁忙的时候高达十几美元,导致一些交易可能需要花费好久才可以真正成交到区块网络。\u003c/p\u003e\n\u003cp\u003e这两个问题大大提高了用户使用门槛,那有没有好的解决办法呢?\u003c/p\u003e\n\u003ch1 id=\"解决方案\"\u003e解决方案\u003c/h1\u003e\n\u003cp\u003e区块链的三个核心特性是 \u003ccode\u003e去中心化\u003c/code\u003e、\u003ccode\u003e安全性\u003c/code\u003e和\u003ccode\u003e可扩展性\u003c/code\u003e,一般简单的区块链架构只能实现其中两个特性(这一点很类似于分布式中的CAP理论)。想要一个安全且去中心化的区块链的话,只能牺牲可扩展性,而这也正是第二层网络发挥作用的地方。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e以太坊生态系统坚定认为,第 2 层扩展是解决可扩展性三难问题的唯一途径,同时保 …\u003c/strong\u003e\u003c/p\u003e"
December 4, 2024
Solana中如何解析指令
"\u003cp\u003e开发过Solodity的同学都知道在合约开发中,不同指令对应的不同前端Endpoint(API接口),这种开发模式特别的清晰且易维护。那在开发Solana合约时没有有对应的方法呢?\u003c/p\u003e\n\u003ch1 id=\"solana开发方式\"\u003eSolana开发方式\u003c/h1\u003e\n\u003cp\u003e开发 Solana 合约,一般分 Native 和 Anchor 框架开发。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eNative\u003c/code\u003e 主要是开发者通过SDK 手动实现所有业务逻辑。 这种模式一般对开发者要求比较高,除了需要了解相关概念外,最重要的还需要知道对应的SDK实现,如PDA账户的创建。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eAnchor框架\u003c/code\u003e 推荐使用,只需要一些宏即可以实现一些逻辑,不需要用户关心底层实现。这种开发方式对于指令的处理基本与Solidity中一致,开发者只要搞明白了基本用法就可以了。\u003c/p\u003e\n\u003cp\u003e下面主要讲一下在 Native 这种方式下,如何实现指令或附加数据的解析。\u003c/p\u003e\n\u003cp\u003e如果你对 \u003ccode\u003e指令\u003c/code\u003e这个概念不太理解的话,可以将其视为路由。其类于似在mvc开发中控制器路由,如 \u003ccode\u003e/user/info\u003c/code\u003e、 \u003ccode\u003e/user/base\u003c/code\u003e、\u003ccode\u003e/user/changepwd\u003c/code\u003e 之类。\u003c/p\u003e\n\u003ch1 id=\"示例介绍\"\u003e示例介绍\u003c/h1\u003e\n\u003cp\u003e我们先看一个在 \u003ca href=\"https://beta.solpg.io\"\u003ehttps://beta.solpg.io\u003c/a\u003e 网站上创建的一个 Native …\u003c/p\u003e"
December 3, 2024
解决编译solana程序 rustc版本号过低的问题
"\u003cp\u003e本方主要介绍在编译solana程序时,提示 rustc 版本号过低无法编译通过的问题。\u003c/p\u003e\n\u003ch1 id=\"问题描述\"\u003e问题描述\u003c/h1\u003e\n\u003cp\u003e在参考官方教程 \u003ca href=\"https://github.com/solana-developers/program-examples/tree/main/basics/favorites/native\"\u003ehttps://github.com/solana-developers/program-examples/tree/main/basics/favorites/native\u003c/a\u003e 在本地执行命令\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ native git:\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emain\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ✗ cargo build-sbf --manifest-path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/Cargo.toml --sbf-out-dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/target/so\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e报错\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ native git:\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emain\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ✗ cargo build-sbf --manifest-path\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/Cargo.toml --sbf-out-dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e./program/target/so\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eerror: package \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003esolana-program v2.1.7\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e cannot be built because it requires rustc 1.79.0 or newer, \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e the currently active …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 2, 2024
在Solana中为什么Token Account没有owner属性
"\u003cp\u003e在上一篇\u003ca href=\"https://blog.haohtml.com/posts/understanding-the-difference-between-ata-accounts-and-token-accounts-in-solana/\"\u003e《了解 Solana 中ATA账户与普通账户的关系》\u003c/a\u003e中,我们介绍了在Solana中,ATA账户与Token Account 的区别,其中在浏览器记录查看 user2 用户详细的时候,发现它与前两个账户有所区别,它没有 Owner 属性,这在正常情况下是不应该出现的,所以,我们来分析一下,为什么Token Account没有 \u003ccode\u003eOwner\u003c/code\u003e 属性?\u003c/p\u003e\n\u003cp\u003e在 Soalna中,默认情况下所有的新账户都属于 \u003ca href=\"https://solana.com/docs/core/accounts#system-program\"\u003eSystem Program\u003c/a\u003e,也只有系统程序拥有的账户才可以作为交易费用支付者(也就是账户里必须的原生币sol)。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/system-account.svg\" alt=\"系统账户\"\u003e\u003c/p\u003e\n\u003cp\u003e因此示例中正常的 Token Account\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/image-20250107144557450.png\" alt=\"Token Accoun\"\u003e\u003c/p\u003e\n\u003cp\u003e异常账号\n\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com/uploads/2025/image-20250107145307758.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e出现我这种情况主要有两种情况:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e交易还在处理中,尚未完成,这种情况下一般只需要等待一会就会正常。\u003c/li\u003e\n\u003cli\u003e账户未被初始化,需要初始化后才恢复正常。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e常见的初始化方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e空投原生币\u003c/li\u003e\n\u003cli\u003e转账原生币\u003c/li\u003e\n\u003cli\u003e通过 SystemProgram.createAccount 创建账号·\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e在上篇文章里,我们为了演示转账记录,对 payer 和 user1 用户都进行了空投,在空投时将自动对账户进行初始化操作, …\u003c/p\u003e"
December 1, 2024
了解 Solana 中ATA账户与普通账户的关系
"\u003cp\u003e本文主要通过示例让大家理解在 Solana 中 \u003ccode\u003eATA\u003c/code\u003e 账户与普通账户的关系。\u003c/p\u003e\n\u003ch1 id=\"目的\"\u003e目的\u003c/h1\u003e\n\u003cp\u003e主篇内容目的是为了让开发者加深对 solana 中 Account 这一概念的理解,同时搞清楚 \u003ccode\u003e关联代币账户(ATA) \u003c/code\u003e 在 Solana 开发中的使用场景和用法,以及在多个账户之间的交易和手续费扣除情况。\u003c/p\u003e\n\u003cp\u003e本篇实现源码会在 \u003ca href=\"https://github.com/cfanbo/solana-repos/tree/main/tokenaccount-and-ata\"\u003egithub.com/cfanbo/solana-repos/\u003c/a\u003e 中找到。\u003c/p\u003e\n\u003cp\u003e这里用到的一些api 函数可以在以下地址找到:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://solana-labs.github.io/solana-web3.js/index.html\"\u003e@solana/web3.js\u003c/a\u003e 用户实现通过 Solana JSON RPC API 与 Solana 网络上的帐户和程序进行交互。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://solana-labs.github.io/solana-program-library/token/js/index.html\"\u003e@solana/spl-token\u003c/a\u003e 用于实现与 SPL Token 和 Token-2022 程序交互。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e本文通过脚本实现 SPL Token 标准功能,并不需要调用已创建好的智能合约,因此不需要 programId.\u003c/p\u003e\n\u003ch1 id=\"设置网络环境\"\u003e设置网络环境\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ my-solana-program git:\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003emaster\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e ✗ solana config get\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eConfig File: …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
August 10, 2024
Rust学习教程清单
"\u003cp\u003e今年又一次重新学习RUST这门编程语言,并从零开发了一个kv存储系统 \u003ca href=\"https://github.com/cfanbo/minkv\"\u003eminKV\u003c/a\u003e,慢慢的越来越有感觉了。\u003c/p\u003e\n\u003cp\u003e本篇主要将日常学习中收集的一些入门教程进行一下汇总,希望对于一些想学习这门开发语言的同学有所帮助。\u003c/p\u003e\n\u003cp\u003e下面教程按照推荐顺序,由浅到深依次列出。以下内容将不定期的更新,请自行收藏。 如果您有更多好的教程的话,也可以在评论区列出,大家相互学习。\u003c/p\u003e\n\u003ch1 id=\"入门教程\"\u003e入门教程\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://doc.rust-lang.org/book/\"\u003eRust 程序设计语言 https://doc.rust-lang.org/book/\u003c/a\u003e / (\u003ca href=\"https://kaisery.github.io/trpl-zh-cn/\"\u003e中文版\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e官方教程,强烈推荐,同时还有非官方翻译的中文版。遗憾的是这个教程有许多概念介绍的都有点不清不楚,只能通过下方的一些资料自行补习。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://play.rust-lang.org/\"\u003ehttps://play.rust-lang.org/\u003c/a\u003e 在线 RUST 程序 Playground,类似golang的 Playground,非常的方便\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://cheats.rs/#data-layout\"\u003eRust Language Cheat Sheet\u003c/a\u003e 看完官方的教程后,紧接着就看这篇,先了解一些内存布局,后面再看其它教程就更容易理解了\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://doc.rust-lang.org/cargo/index.html#the-cargo-book\"\u003eThe Cargo Book\u003c/a\u003e Cargo 是RUST 中的包管理工具, …\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e"
August 10, 2024
在rust中实现自定义错误
"\u003cp\u003e\u003ca href=\"https://blog.haohtml.com/posts/error-hanlding-unwrap-and-expect-in-rust/#google_vignette\"\u003e上一篇\u003c/a\u003e 我们介绍了一些错误处理的最基本的用法,主要是指对 \u003ccode\u003epanic!\u003c/code\u003e 、\u003ccode\u003eunwrap\u003c/code\u003e、\u003ccode\u003eexpect\u003c/code\u003e 和 \u003ccode\u003e?\u003c/code\u003e 这些宏或函数的介绍。但这仅仅是一些最基本的处理方法,对于自定义错误这一块并没有做任何介绍。\u003c/p\u003e\n\u003cp\u003e实际开发中可能默认的错误类型,并无法满足我们的业务需求,这时一般需要通过定义自己的错误类型来实现。在rust中错误类型是通过 \u003ccode\u003eenum\u003c/code\u003e 枚举定义的,对此官方文档也做了一些简介,本文主要介绍一些业务开发过程中对错误的处理方案,当然主要是一些最基本的用法。\u003c/p\u003e\n\u003ch1 id=\"自定义-error\"\u003e自定义 Error\u003c/h1\u003e\n\u003cp\u003e在 Rust 中,自定义错误类型是一种常见的类型,特别是当你需要提供比标准错误类型更具体的错误信息时。Rust 中的错误处理是通过 \u003ccode\u003eResult\u003c/code\u003e 和 \u003ccode\u003eError\u003c/code\u003e trait 来实现的。以下是如何实现一个自定义错误的示例:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e定义一个错误枚举类型。\u003c/li\u003e\n\u003cli\u003e实现 \u003ccode\u003estd::fmt::Display\u003c/code\u003e 为自定义错误提供用户友好的错误信息。\u003c/li\u003e\n\u003cli\u003e实现 \u003ccode\u003estd::error::Error\u003c/code\u003e trait,这通常是通过派生 \u003ccode\u003eError\u003c/code\u003e trait 来完成的。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e下面是一个简单的示例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse\u003c/span\u003e std::fmt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003euse …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
July 27, 2024
一款管理 .gitignore 的CLI工具- gitig
"\u003cp\u003e\u003ccode\u003egitig\u003c/code\u003e 是一款基于 \u003ca href=\"https://github.com/github/gitgnore\"\u003ehttps://github.com/github/gitgnore\u003c/a\u003e 仓库开发的\u003ccode\u003e.gitignore\u003c/code\u003e 客户端CLI 管理工具,也是每个开发者必不可少的提高工作效率的必具工具。\u003c/p\u003e\n\u003cp\u003e它基于官方仓库 \u003ca href=\"https://github.com/github/gitgnore\"\u003ehttps://github.com/github/gitgnore\u003c/a\u003e 丰富的 \u003ccode\u003e.gitignore\u003c/code\u003e 数据源,帮助开发者快速实现添加各类开发项目的git版本控制忽略文件清单。\u003c/p\u003e\n\u003ch1 id=\"开发背景\"\u003e开发背景\u003c/h1\u003e\n\u003cp\u003e工作中,经常需要开发各类项目,如基于 vscode 编写 rust 项目,这时为了方便进行Git管理控制,有些项目文件可能并不需要提交到git仓库,需要将一些文件写入 \u003ccode\u003e.gitignore\u003c/code\u003e 文件进行忽略。\u003c/p\u003e\n\u003cp\u003e如果手动编辑 \u003ccode\u003e.gitignore\u003c/code\u003e文件可能有些麻烦,另外也能会有一些文件项被遗忘或写错,这时如果有一些工具可以将行业能用的忽略配置项一键写入 \u003ccode\u003e.gitignore\u003c/code\u003e 文件似乎是一个不错的主意。\u003c/p\u003e\n\u003cp\u003e其中著名的 \u003ca href=\"https://github.com/github/gitignore\"\u003ehttps://github.com/github/gitignore\u003c/a\u003e 就是一个专门收集各类开发语句或IDE 需要忽略的 \u003ccode\u003e.gitignore\u003c/code\u003e 推荐配置的仓库,目前star …\u003c/p\u003e"
July 15, 2024
Rust 中常见的几种错误处理方法
"\u003cp\u003eRust 中错误可分为两大类:\u003cstrong\u003e可恢复的\u003c/strong\u003e(\u003cem\u003erecoverable\u003c/em\u003e)和 \u003cstrong\u003e不可恢复的\u003c/strong\u003e(\u003cem\u003eunrecoverable\u003c/em\u003e)错误。\u003c/p\u003e\n\u003cp\u003e对于一个可恢复的错误,比如文件未找到或权限不足的错误,我们很可能只想向用户报告问题,让用户来决定后续操作。\u003c/p\u003e\n\u003cp\u003e不可恢复的错误总是 bug 出现的征兆,比如试图访问一个超过数组末端的位置,因此我们要立即停止程序,主要通过 \u003ccode\u003epanic!\u003c/code\u003e 实现。\u003c/p\u003e\n\u003ch1 id=\"panic\"\u003epanic!\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003epanic!\u003c/code\u003e属于不可恢复错误类型,一旦发生程序将立即退出。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003epanic!\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;crash and burn\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里由用户调用 \u003ccode\u003epanic!\u003c/code\u003e 宏来实现程序的中止,同时自定义错误信息。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ cargo run\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Compiling hello-world v0.1.0 \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e/Users/sxf/workspace/rust/hello-world\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Finished \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003edev\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e profile \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eunoptimized + debuginfo\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e target\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003es\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e in 0.68s\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Running \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003etarget/debug/hello-world\u003cspan style=\"color:#e6db74\"\u003e` …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
July 10, 2024
在Rust中如何调用一个模块或方法
"\u003cp\u003e在 Rust 中有 \u003ccode\u003e包\u003c/code\u003e、\u003ccode\u003ecrate\u003c/code\u003e、\u003ccode\u003e模块\u003c/code\u003e 概念,本文我们介绍一下它们之间的关系和调用方法。\u003c/p\u003e\n\u003ch1 id=\"包-和-crate\"\u003e包 和 Crate\u003c/h1\u003e\n\u003cp\u003e在Rust中,\u003cem\u003e包\u003c/em\u003e(\u003cem\u003epackage\u003c/em\u003e)是提供一系列功能的一个或者多个 crate。一个包会包含一个 \u003ccode\u003eCargo.toml\u003c/code\u003e 文件,阐述如何去构建这些 crate。\u003c/p\u003e\n\u003cp\u003e我们先看一下通过 \u003ccode\u003ecargo new\u003c/code\u003e 创建一个 \u003ccode\u003emy_project\u003c/code\u003e 包。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ cargo new my_project \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Creating binary \u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003eapplication\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003emy_project\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e package\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enote: see more \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003eCargo.toml\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e➜ rust tree my_project \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emy_project\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├── Cargo.toml\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e└── src\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e └── main.rs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e directories, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e files\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e它将创建一个 \u003ccode\u003eCargo.toml\u003c/code\u003e文件,内容:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e[ …\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
June 25, 2024
Rust中将一个结构体拆分成多个文件
"\u003cp\u003e官方文档将\u003ca href=\"https://kaisery.github.io/trpl-zh-cn/ch07-05-separating-modules-into-different-files.html\"\u003e一个模块拆分成多个文件\u003c/a\u003e时,介绍的是将原来多个模块写在同一个文件中,拆分成了每个模块一个文件。不过还有一种情况没有提到,如果一个模块中的某个 struct 实现代码过多时,仍写在同一个模块文件的话,维护成本就显的比较高了,这时我们可能还需要对这个 struct 的实现按某种粒度拆分成多个文件来实现。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e✗ tree\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e.\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├── main.rs\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e├── model\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e│ ├── article.rs // 文章相关\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e│ └── user.rs // 用户相关\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e└── model.rs\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里是按官方教程拆分后的样子\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003earticle.rs\u003c/code\u003e 是文件模块相关实现 -\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003euser.rs\u003c/code\u003e 是与用户相关的实现\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emodel.rs\u003c/code\u003e 公开模块\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ccode\u003emodel.rs \u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// src/model.rs\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emod\u003c/span\u003e article;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003epub\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emod\u003c/span\u003e user;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003epub\u003c/code\u003e 关键字表示该模块是公开的,可以被其他模块访问。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003emod article\u003c/code\u003e 声明了一个名为 \u003ccode\u003earticle\u003c/code\u003e 的模块,并且 Rust 编译器会在同文件名的目录下( \u003ccode\u003esrc/model/\u003c/code\u003e )找到一个名为 \u003ccode\u003earticle.rs …\u003c/code\u003e\u003c/p\u003e"
May 13, 2024
记录一次排查vpn无法通讯的过程
"\u003cp\u003e今天收到一个项目重构的需求,项目源码使用私有 gitlab 托管平台,但由于考虑安全原因,必须通过vpn软件才可以访问。公司用的vpn客户端是 \u003ca href=\"https://github.com/pritunl/pritunl-client-electron\"\u003ePritunl\u003c/a\u003e, 看了一下项目主页 \u003ca href=\"https://github.com/pritunl/pritunl-client-electron\"\u003ehttps://github.com/pritunl/pritunl-client-electron\u003c/a\u003e,发现它是一个 OpenVPN 客户端,是基于Golang+Electron 框架开发的一个跨平台的客户端。\u003c/p\u003e\n\u003cp\u003e以前主要接触的是 \u003ca href=\"https://github.com/WireGuard/wireguard-go\"\u003ewireGuard\u003c/a\u003e 和 \u003ca href=\"https://github.com/OpenVPN/openvpn\"\u003eopenvpn\u003c/a\u003e 这两个项目,这个客户端还是第一次听说。不过后面发现使用这个客户端会经常出现DNS无法解析的情况,不清楚具体是什么原因引起的,因此不推荐这个客户端。另外从性能方面考虑openvpn也不是推荐方案,推荐优先考虑 wireGuard 这个项目,它的客户端也是跨平台的,而且性能要比openvpn好太多,代码也少很好,无论维护和开发成本都要低的多。个人有很长一段时间一直用wireGuard作为内网穿透方案,不过此方案需要一个公网IP地址,所以后期换成了更节约成本的解决方案,当然这是另一个话题了,不是本文要介绍的内容。\u003c/p\u003e\n\u003ch1 id=\"遇到问题\"\u003e遇到问题\u003c/h1\u003e\n\u003cp\u003e当在macOS上安装好客户 …\u003c/p\u003e"
May 12, 2024
git 操作中那些常常被忽略的用法
"\u003ch1 id=\"git-merge-与-git-rebase--的区别\"\u003egit merge 与 git rebase 的区别\u003c/h1\u003e\n\u003cp\u003e对于两者的区别,网上已经有很多文章做了介绍,不过有些初学者没有亲自实验过,多数也是作为八股文死记硬背而已。本文为了让大家彻底搞懂两者的区别,所以搞了一个实验环境并模拟了一些真实环境的操作。\u003c/p\u003e\n\u003cp\u003e实验环境主要用到两个分支,其中 main 分支做了主要分支,而 dev 作为开发功能分支。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e在生产环境中需要选择合适的分支,这里只是实验环境,所以分支名不是本文关注的重点。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ctable\u003e\n \u003cthead\u003e\n \u003ctr\u003e\n \u003cth\u003emain\u003c/th\u003e\n \u003cth\u003edev\u003c/th\u003e\n \u003cth\u003e说明\u003c/th\u003e\n \u003c/tr\u003e\n \u003c/thead\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd\u003emkdir git-demo \u0026amp;\u0026amp; cd git-demo \u0026amp;\u0026amp; git init\u003c/td\u003e\n \u003ctd\u003e\u003c/td\u003e\n \u003ctd\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003etouch 1.txt \u0026amp;\u0026amp; git add . \u0026amp;\u0026amp; git commit -m \u0026lsquo;add 1.txt\u0026rsquo; …\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e"
April 29, 2024
kubernetes 网络中DNS解析原理
"\u003cp\u003e当我们通过域名(例如 \u003ca href=\"https://www.example.com\"\u003ewww.example.com\u003c/a\u003e)访问一个网站时,第一步就是通过DNS服务器找到目的服务器IP地址(例如 93.184.215.14),接着再将请求数据包发送到这个 IP 服务器。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2024/04/watermark%2Ctype_ZmFuZ3poZW5naGVpdGk%2Cshadow_10%2Ctext_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDMwNzcyMQ%3D%3D%2Csize_16%2Ccolor_FFFFFF%2Ct_70.jpeg\" alt=\"img\"\u003e\u003c/p\u003e\n\u003cp\u003e而要想通过 DNS 服务器进行域名,必须得先知道 DNS 服务器地址才行,而这一般是通过读取配置文件实现,在 \u003ccode\u003e*nux\u003c/code\u003e 操作系统中,DNS 服务器一般配置在 \u003ccode\u003e/etc/resolv.conf\u003c/code\u003e文件,如\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003esearch default.svc.cluster.local svc.cluster.local cluster.local\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003enameserver 10.96.0.10\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eoptions ndots:5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e用户可以通过 nameserver 指定多个 DNS 服务器,依次对域名进行解析,如果解析成功,则解析操作立即中止,如果解析不到的话,则将回退到公网 DNS 服务器进行解析,这个公网 DNS 服务器一般是由网络运营商来定的,用户不需要关心。如果公网 DNS 仍解析失败的话,则直接响应域名无法解析,此时用户将无法正常访问域名。\u003c/p\u003e\n\u003ch1 id=\"什么是-fqdn\"\u003e什么是 FQDN\u003c/h1\u003e\n\u003cp\u003e在介绍域名解析前, …\u003c/p\u003e"
April 22, 2024
Kubernetes集群扩缩容方案
"\u003cp\u003e动态扩缩容主要包括两个层级的动态扩缩容。一个层级是应用本身级别的扩缩容,如HPA、VPA。当应用负载过高时,可以通过HPA多部署几个Pods副本;或者通过VPA对当前Pod硬件资源进行扩容,以此来减少应用负载。\u003c/p\u003e\n\u003cp\u003e另一层是对集群自身的扩容,如 worker 节点的扩容。如部署Pods应用时,如果出现无可用节点资源可用时,则通过 Cluster Autoscaler 加入一些新的节点,并在新节点上重建Pods。\u003c/p\u003e\n\u003cp\u003e本文主要看一下应用这个层级的扩缩容方案。\u003c/p\u003e\n\u003ch1 id=\"水平扩展hpa--垂直扩展vpa\"\u003e水平扩展HPA \u0026amp;\u0026amp; 垂直扩展VPA\u003c/h1\u003e\n\u003ch2 id=\"hpa\"\u003eHPA\u003c/h2\u003e\n\u003cp\u003e在 Kubernetes 中,\u003ca href=\"https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/\"\u003eHPA\u003c/a\u003e(HorizontalPodAutoscaler)也称为水平扩缩容,它将根据当前应用程序工作负载,自动更新工作负载资源 (例如 \u003ca href=\"https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/\"\u003eDeployment\u003c/a\u003e 或者 \u003ca href=\"https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/\"\u003eStatefulSet\u003c/a\u003e)以满足当前需求。简单讲的话,就是如果集群检测到当前应用程序的n个Pod负载如果比较高的话,就再创建几个Pod副本,以减少当前负载,也就是我们平时说的水平扩容。相反如果应用程序Pod负载比较低的话,则将Pod副本数量进行减少,节省服务器资源,这个就是水平缩容。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2024/04/image-20240424145020517.png\" alt=\"image-20240424145020517\"\u003e\u003c/p\u003e\n\u003cp\u003e它的工 …\u003c/p\u003e"
April 10, 2024
kubernetes中overlay网络与underlay网络的区别
"\u003cp\u003eKubernetes 中的 overlay 网络和 underlay 网络是两个不同的网络层面。\u003c/p\u003e\n\u003ch1 id=\"underlay-网络\"\u003eUnderlay 网络\u003c/h1\u003e\n\u003cp\u003e在 Kubernetes 网络架构中,Underlay 网络是指承载 Kubernetes 网络流量的物理网络或底层网络。这个网络通常由物理交换机、路由器和其他网络硬件组成,它们之间通过各种路由协议(例如 OSPF、BGP 等)连接在一起组成的传统网络。\u003c/p\u003e\n\u003cp\u003eUnderlay 网络负责为 Kubernetes 节点提供基本的网络连接,它为上层的 overlay 网络提供支持。\u003c/p\u003e\n\u003cp\u003e总之,Kubernetes 的网络流量,例如 Pod 到 Pod、Pod 到 Service 等都将在这个 Underlay 网络上进行传输。\u003c/p\u003e\n\u003ch1 id=\"overlay-网络\"\u003eOverlay 网络\u003c/h1\u003e\n\u003cp\u003e对于 \u003ccode\u003eOverlay\u003c/code\u003e 网络也被称为 \u003ccode\u003e覆盖网络\u003c/code\u003e,想必只要接触过一点 kubernetes 网络知识的同学都不陌生,它主用来解决 \u003cstrong\u003e不同节点\u003c/strong\u003e 中 \u003cstrong\u003ePod\u003c/strong\u003e 之间通讯的一种网络解决方案。\n\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2024/04/image_1chvp7s4g15n0134iv1tvag1mkd8g.png\" alt=\"Overlay\"\u003e\u003c/p\u003e\n\u003cp\u003e在上图可以看到 \u003ccode\u003eOverlay\u003c/code\u003e 网络是构建在 \u003ccode\u003eunderlay\u003c/code\u003e 网络之上的一层虚拟网络,它通过封装数据包(如VXLAN)通过物理网络进行传输,到达目标网络 …\u003c/p\u003e"
March 19, 2024
如何实现访问k8s集群服务之原理
"\u003cp\u003e当我们想将 k8s 集群里的服务向外暴露时,一般是将 k8s service 指定 \u003ccode\u003eLoadBalancer\u003c/code\u003e类型。目前大多数云厂商会绑定云平台的负载均衡器,并为其分配一个固定的公网 IP 从而向外提供服务。而对于我们自建的 kubernetes 裸机集群则只能选择类似 MetalLB 这类解决方案,这种情况下如何让用户可以通过这个 IP 访问到自建 k8s 的服务呢,本文来分析一下其实现原理。\u003c/p\u003e\n\u003cp\u003e本文的环境安装了 MetallB,它指定分配 IP Pool 为内网 IP 地址,实验环境为 \u003ca href=\"https://blog.haohtml.com/posts/install-kubernetes-in-raspberry-pi/\"\u003ehttps://blog.haohtml.com/posts/install-kubernetes-in-raspberry-pi/\u003c/a\u003e。\u003c/p\u003e\n\u003ch1 id=\"将外部请求流入集群节点\"\u003e将外部请求流入集群节点\u003c/h1\u003e\n\u003cp\u003e当我们需要访问一台机器时,无论是使用 IP 地址还是域名,最终都需要将其解析为 IP 地址。而要真正建立连接并传输数据,我们必须获取目标 IP 地址对应的 MAC 地址,这是由于 TCP/IP 协议分层机制决定的。\u003c/p\u003e\n\u003cp\u003e在 TCP/IP 协议栈的链路层,数据是通过封装成数据帧的方式在局域网内传输的。数据帧中包含了目标 MAC 地址,用于标识应该将数据 …\u003c/p\u003e"
February 2, 2024
Raspberry Pi 安装Kubernetes
"\u003cp\u003e这里是 arm64 架构,\u003cstrong\u003e树莓派 4B\u003c/strong\u003e, 四核八 G 内存 配置,系统为 Ubuntu 22.04.1 LTS\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ uname -a\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLinux ubuntu 5.15.0-1049-raspi \u003cspan style=\"color:#75715e\"\u003e#52-Ubuntu SMP PREEMPT Thu Mar 14 08:39:42 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ cat /etc/issue\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eUbuntu 22.04.1 LTS \u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e\\l\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"环境检查\"\u003e环境检查\u003c/h2\u003e\n\u003cp\u003e由于 k8s 会使用 8080 和 6443 这两个端口,因此要保证端口可用,然后禁用 swap。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo swapoff -a\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e最后对安装环境初始化,参考 \u003ca href=\"https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/\"\u003ehttps://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"安装-docker\"\u003e安装 Docker\u003c/h2\u003e\n\u003cp\u003e参考 \u003ca href=\"https://docs.docker.com/engine/install/ubuntu/\"\u003ehttps://docs.docker.com/engine/install/ubuntu/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e安装成功后,修改 \u003ccode\u003ecgroupdriver\u003c/code\u003e 为 \u003ccode\u003esystemd\u003c/code\u003e, …\u003c/p\u003e"
January 12, 2024
使用kubectl create service 命令无法为pod创建service问题
"\u003cp\u003e在做一个试验时,无意中发现使用 \u003ccode\u003ekubectl create service\u003c/code\u003e 命令无法为一个通过 \u003ccode\u003edeployment\u003c/code\u003e 创建出来的pod创建对应的 \u003ccode\u003eservice\u003c/code\u003e, 感觉有点奇怪,经过分析才明白怎么回事,这里将过程记录一下。\u003c/p\u003e\n\u003cp\u003e这里需要说明一下,本文操作全部是通过 \u003ccode\u003ekubectl create\u003c/code\u003e 命令来完成的,并没有使用 \u003ccode\u003ekubectl apply -f pod.yaml\u003c/code\u003e 这种方式。\u003c/p\u003e\n\u003cp\u003e这里先创建一个实验命名空间 \u003ccode\u003elab\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl create ns lab\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e首先创建一个\u003ccode\u003edeployment\u003c/code\u003e 对象\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl create deployment test --image\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003enginx:1.23-alpine --replicas\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e --port\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e80\u003c/span\u003e -n lab\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e确认创建成功\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl get deploy,pod -n lab\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNAME READY UP-TO-DATE AVAILABLE AGE\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edeployment.apps/test 2/2 \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2 …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 2, 2023
pod sandbox 创建netns源码分析
"\u003cp\u003e在上一篇《\u003ca href=\"https://blog.haohtml.com/archives/33163/\"\u003e创建Pod源码解析\u003c/a\u003e》文中,我们大概介绍了Pod的整体创建过程。其中有一步很重要,就是在创建三类容器之前必须先创建一个 \u003ccode\u003e sandbox\u003c/code\u003e (\u003ca href=\"https://github.com/kubernetes/kubernetes/blob/v1.27.3/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L1079\"\u003e源码\u003c/a\u003e),本篇就来分析一下sandbox这一块的 \u003ccode\u003enetns\u003c/code\u003e 实现过程。\u003c/p\u003e\n\u003cp\u003e对 \u003ccode\u003esandbox\u003c/code\u003e 的创建由 \u003ccode\u003ekubelet\u003c/code\u003e 组件通过调用 \u003ca href=\"https://kubernetes.io/zh-cn/docs/concepts/architecture/cri/\"\u003eCRI\u003c/a\u003e 容器运行时服务来实现的,对于容器运行的实现目前市面上有多个,如 \u003ca href=\"https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#docker\"\u003eDocker Engine\u003c/a\u003e(不推荐)、 \u003ca href=\"https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#containerd\"\u003econtainerd\u003c/a\u003e、\u003ca href=\"https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/#cri-o\"\u003eCRI-O\u003c/a\u003e 等,由于目前生产环境中选择 containerd 的占大多数,所以这里我们以 \u003ccode\u003econtainerd\u003c/code\u003e 为例来看一下其实现过程。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/containerd/containerd/blob/32bf805e5703bc91387d047fa76625e915ac2b80/pkg/cri/server/sandbox_run.go\"\u003ehttps://github.com/containerd/containerd/blob/32bf805e5703bc91387d047fa76625e915ac2b80/pkg/cri/server/sandbox_run.go\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e对 sandbox 的创建是由 cri 服务调用 \u003ccode\u003eRunPodSandbox()\u003c/code\u003e方法来实现的。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// RunPodSandbox creates and starts a pod-level sandbox. …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
November 28, 2023
Rust中与闭包相关的三个trait
"\u003cp\u003e在 Rust 中,闭包就是一种能捕获 \u003ccode\u003e上下文环境变量\u003c/code\u003e 的函数。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e range \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e..\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e get_range_count \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e||\u003c/span\u003e range.count(); \n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e代码里的这个 \u003ccode\u003eget_range_count\u003c/code\u003e 就是闭包,range 是被这个闭包捕获的环境变量。\u003c/p\u003e\n\u003cp\u003e虽然说它是一种函数,但是不通过 \u003ccode\u003efn\u003c/code\u003e 进行定义。\u003cstrong\u003e在 Rust 中,并不把这个闭包的类型处理成 fn 这种函数指针类型,而是有单独的类型定义。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e切记这里是将闭包处理成是 \u003ccode\u003e单独的类型定义\u003c/code\u003e,这一点区别与其它开发语言。\u003c/p\u003e\n\u003cp\u003e至于按哪一种类型来处理,这个没有办法得知,因为只有在Rust编译器在编译的时候才可以确定其类型,并且在确定类型时,还需要根据这个闭包捕获上下文环境变量时的行为来确定。\u003c/p\u003e\n\u003ch1 id=\"闭包trait分类\"\u003e闭包trait分类\u003c/h1\u003e\n\u003cp\u003e根据闭包行为划分为三类trait( 主因是受到所有权影响):\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003eFnOnce\u003c/code\u003e 适用于只能被调用一次的闭包,\u003ccode\u003e所有闭包\u003c/code\u003e都至少实现了这个 trait,因为所有闭包都必须能够被调用。一个会将捕获的值移出闭包体的闭包只实现 \u003ccode\u003eFnOnce\u003c/code\u003e trait,这是因为它只能被调用一次。其获取了上下文环境变量的所有权。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eFnMut\u003c/code\u003e 适用 …\u003c/li\u003e\u003c/ol\u003e"
November 16, 2023
Rust中的迭代器iter
"\u003cp\u003e迭代器模式允许你对一个序列的项进行某些处理。\u003cstrong\u003e迭代器\u003c/strong\u003e(\u003cem\u003eiterator\u003c/em\u003e)负责遍历序列中的每一项和决定序列何时结束的逻辑。当使用迭代器时,我们无需重新实现这些逻辑。\u003c/p\u003e\n\u003cp\u003e在 Rust 中,迭代器是 \u003cstrong\u003e惰性的\u003c/strong\u003e(\u003cem\u003elazy\u003c/em\u003e),这意味着在调用方法使用迭代器之前它都不会有效果。例如,示例中的代码通过调用定义于 \u003ccode\u003eVec\u003c/code\u003e 上的 \u003ccode\u003eiter\u003c/code\u003e 方法在一个 vector \u003ccode\u003ev1\u003c/code\u003e 上创建了一个迭代器。这段代码本身没有任何用处:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e v1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evec!\u003c/span\u003e[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003elet\u003c/span\u003e v1_iter \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e v1.iter();\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e迭代器被储存在 \u003ccode\u003ev1_iter\u003c/code\u003e 变量中。一旦创建迭代器之后,可以选择用多种方式利用它。\u003c/p\u003e\n\u003ch1 id=\"迭代器分类\"\u003e迭代器分类\u003c/h1\u003e\n\u003cp\u003eRust 中迭代器根据 \u003ccode\u003e所有权\u003c/code\u003e 可分为 \u003ccode\u003eiter()\u003c/code\u003e、\u003ccode\u003eiter_mut()\u003c/code\u003e、\u003ccode\u003einto_iter()\u003c/code\u003e 三种迭代器,使用场景:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e获取集合元素不可变引用的迭代器,对应方法为 \u003ccode\u003eiter()\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获取集合元素可变引用的迭代器,对应方法为 \u003ccode\u003eiter_mut()\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获取集合元素所有权的迭代器,对应方法为 \u003ccode\u003einto_iter()\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e也就是说当你在 Rust 中看到调用了 \u003ccode\u003eiter()\u003c/code\u003e 方法,则表示这里使用了不可 …\u003c/p\u003e"
November 7, 2023
Rust 中的 Result 与 Option
"\u003cp\u003e在 Rust 中有两个常用的 \u003ccode\u003eenum\u003c/code\u003e 枚举类型,分别为 \u003ccode\u003eResult\u003c/code\u003e 和 \u003ccode\u003eOption\u003c/code\u003e,本节介绍它们两者各自的使用场景和用法。\u003c/p\u003e\n\u003cp\u003e这里我们先给出结论\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e结果 \u003ccode\u003eResult\u003c/code\u003e 表示 \u003ccode\u003e成功\u003c/code\u003e 或 \u003ccode\u003e失败\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e选项 \u003ccode\u003eOption\u003c/code\u003e 表示 \u003ccode\u003e有\u003c/code\u003e 或者 \u003ccode\u003e无\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e当从本地读取一个文件时,这时候可能读取成功,也有可能由于文件不存在或权限不足导致读取时候,这种场景一般就需要使用 \u003ccode\u003eResult\u003c/code\u003e;而当从一组数据集中查询指定元素是否存在时,这时有可能存在,也有可能不存在(用None 表示),这时情况就应该选择Option。\u003c/p\u003e\n\u003cp\u003e由此看到,这两个枚举类型的区别理解起来还是挺简单的,下面我们单独对每一种类型做一下详细的介绍。\u003c/p\u003e\n\u003ch1 id=\"结果-result\"\u003e结果 Result\u003c/h1\u003e\n\u003cp\u003e定义\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-rust\" data-lang=\"rust\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e Result\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003eT, E\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Ok(T),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e Err(E),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003eResult\u0026lt;T, E\u0026gt;\u003c/code\u003e 类型拥有两个取值:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eOk(value)\u003c/code\u003e 表示操作成功,并包装操作返回的 \u003ccode\u003evalue\u003c/code\u003e(\u003ccode\u003evalue\u003c/code\u003e 拥有 \u003ccode\u003eT\u003c/code\u003e 泛类型)。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eErr(why)\u003c/code\u003e,表示操作失败,并包装 \u003ccode\u003ewhy\u003c/code\u003e,它(但愿)能够解释失败的原因(\u003ccode\u003ewhy\u003c/code\u003e 拥有 \u003ccode\u003eE\u003c/code\u003e 类型)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e举个例子,这里打开 …\u003c/p\u003e"
October 2, 2023
kubectr 一款快速查看Pod容器的kubectl插件
"\u003cp\u003e以前工作中经常需要查看Pod里容器相关信息,特别是容器镜像信息,以前一直是通过 \u003ccode\u003ekubectl describe\u003c/code\u003e命令查看的\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sh\" data-lang=\"sh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl describe my-pod\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e但由于输出的内容特别多,查看容器关键信息特别麻烦。印象最深的莫过于在部署 \u003ccode\u003eistio\u003c/code\u003e时,由于国内网络环境不稳定,经常性的遇到镜像下载失败的情况,当时极其的头疼。\u003c/p\u003e\n\u003cp\u003e于是最近花了一点时间,开发了一款快速查看 Pod 容器信息的插件 \u003ca href=\"https://github.com/cfanbo/kubectr\"\u003ekubectr\u003c/a\u003e 。\u003c/p\u003e\n\u003ch1 id=\"安装\"\u003e安装\u003c/h1\u003e\n\u003cp\u003e安装方法主要有三种\u003c/p\u003e\n\u003ch2 id=\"krew-安装推荐\"\u003ekrew 安装(推荐)\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sh\" data-lang=\"sh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectl krew install ctr\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e目前已提交到 \u003ca href=\"https://github.com/kubernetes-sigs/krew\"\u003ekrew\u003c/a\u003e ,但由于官方审核速度较慢,此安装方法不敢保证可用\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"二进制安装\"\u003e二进制安装\u003c/h2\u003e\n\u003cp\u003e从 \u003ca href=\"https://github.com/cfanbo/kubectr/releases\"\u003ehttps://github.com/cfanbo/kubectr/releases\u003c/a\u003e 下载对应的平台版本,并解压到对应的 PATH 环境变量目录即可。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sh\" data-lang=\"sh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ tar zxvf kubectr_linux_amd64.tar.gz\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ sudo mv kubectr /usr/local/bin/\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ kubectr -h\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"源码安装\"\u003e源码安装\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-sh\" data-lang=\"sh\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git clone …\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
September 22, 2023
envoy中 lua filter 与 wasm filter使用教程
"\u003cp\u003e在 Envoy 中当我们需要对 \u003ca href=\"https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-msg-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager\"\u003ehttp_connection_manager\u003c/a\u003e 中的请求进行修改时,如添加或删除一个请求header,一般通过 \u003ccode\u003eHTTP Filter\u003c/code\u003e 过滤器来实现。\u003c/p\u003e\n\u003cp\u003e而在Envoy 包含的几十个Filter中,通常会选择 \u003ccode\u003eLua Filter \u003c/code\u003e(\u003ca href=\"https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/lua/v3/lua.proto#extensions-filters-http-lua-v3-lua\"\u003eextensions.filters.http.lua.v3.Lua\u003c/a\u003e) 或 \u003ccode\u003eWasm Filter\u003c/code\u003e (\u003ca href=\"https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/wasm/v3/wasm.proto#extensions-filters-http-wasm-v3-wasm\"\u003eextensions.filters.http.wasm.v3.Wasm\u003c/a\u003e)这两类过滤器。\u003c/p\u003e\n\u003ch1 id=\"lua-filter-与-wasm-filter\"\u003eLua Filter 与 Wasm Filter\u003c/h1\u003e\n\u003cp\u003e下表是 \u003ccode\u003eLua Filter\u003c/code\u003e 与 \u003ccode\u003eHTTP Filter\u003c/code\u003e 的对比\u003c/p\u003e\n\u003ctable\u003e\n \u003cthead\u003e\n \u003ctr\u003e\n \u003cth\u003e\u003c/th\u003e\n \u003cth\u003eLua Filter\u003c/th\u003e\n \u003cth\u003eWasm Filter\u003c/th\u003e\n \u003c/tr\u003e\n \u003c/thead\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd\u003e编程语言\u003c/td\u003e\n \u003ctd\u003eLua,解释型脚本语言\u003c/td\u003e\n \u003ctd\u003eWebAssembly,编译型语言\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd\u003e运行环境\u003c/td\u003e\n \u003ctd\u003eEnvoy 内置的 Lua …\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e"
September 17, 2023
WebAssembly开发入门教程
"\u003ch1 id=\"wasm简介\"\u003ewasm简介\u003c/h1\u003e\n\u003cp\u003eWebAssembly(Wasm)是一种通用字节码技术,它可以将其他编程语言(如 Go、Rust、C/C++ 等)的程序代码编译为可在浏览器或服务端环境直接执行的字节码程序。\u003c/p\u003e\n\u003ch1 id=\"使用场景\"\u003e使用场景\u003c/h1\u003e\n\u003cp\u003e主要有两个使用场景,分别为 浏览器 和 服务端。\u003c/p\u003e\n\u003ch2 id=\"浏览器\"\u003e浏览器\u003c/h2\u003e\n\u003cp\u003ewasm最早的出现是为了解决浏览器端的性能问题,让web应用可以达到与本地原生应用类似的性能。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/09/640.png\" alt=\"Image\"\u003e\u003c/p\u003e\n\u003cp\u003e对于浏览器chrome 采用了v8 javascript引擎,其内置了一个 Wasm Runtime,因此可以实现对 wasm 的支持,这也正是浏览器可以运动wasm的原因。\u003c/p\u003e\n\u003ch2 id=\"服务端\"\u003e服务端\u003c/h2\u003e\n\u003cp\u003e2019 年 3 月,Mozilla 推出了 WebAssembly 系统接口(Wasi),以标准化 WebAssembly 应用程序与系统资源之间的交互抽象,例如文件系统访问、内存管理和网络连接,该接口类似于 POSIX 等标准 API。\u003cstrong\u003eWasi 规范的出现极大地扩展了 WebAssembly 的应用场景,使得 Wasm 不仅限于在浏览器中运行,而且可以在服务器端得到应用\u003c/strong\u003e。同时,平台开发者可以针对特定的操作系统和运行环境提供 Wasi 接口的不同实现,允 …\u003c/p\u003e"
September 5, 2023
istio 中 sidecar 注入实现原理
"\u003cp\u003e在 istio 中为了对流量进行有效的管理,一般通过\u003ccode\u003e注入\u003c/code\u003e的方式将代理 \u003ccode\u003eistio-proxy\u003c/code\u003e 与应用程序一起位于同一个Pod,然后通过 \u003ccode\u003eistio-init \u003c/code\u003e initContainer修改 iptables 实现 \u003ccode\u003eingress\u003c/code\u003e 或 \u003ccode\u003eegress\u003c/code\u003e,那么在 istio 中这个注入是如何实现的呢,本节对其实现原理进行一些分析。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://istio.io/latest/docs/concepts/security/arch-sec.svg\" alt=\"https://istio.io/latest/docs/concepts/security/arch-sec.svg\"\u003e\u003c/p\u003e\n\u003ch1 id=\"实现原理\"\u003e实现原理\u003c/h1\u003e\n\u003cp\u003e在上一节\u003ca href=\"https://blog.haohtml.com/archives/34883/\"\u003e《apiserver 中的webhook开发教程》\u003c/a\u003e 我们介绍过\u003ccode\u003eadmission controller\u003c/code\u003e 基本实现原理,由此得知当创建一个资源对象的时候,可以通过定义 \u003ccode\u003eValidatingWebhookConfiguration\u003c/code\u003e 或 \u003ccode\u003eMutatingWebhookConfiguration\u003c/code\u003e 实现在创建的进程中对这些 webhook 进行调用。而 \u003ccode\u003eMutatingWebhookConfiguration\u003c/code\u003e 则可以对请求的资源进行修改。在istio中的 \u003ccode\u003einjection\u003c/code\u003e 正是基于此原理实现的。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/08/6ca5dd6b207691069de1cf4df59cc6ad.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003ch1 id=\"webhook配置\"\u003ewebhook配置\u003c/h1\u003e\n\u003cp\u003e当我们在k8s集群中安装 istio 后,会创建一些资源,如 \u003ccode\u003edeployment\u003c/code\u003e、\u003ccode\u003eservice\u003c/code\u003e、\u003ccode\u003ecrd\u003c/code\u003e 等\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ istioctl …\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
August 31, 2023
terraform 中的 provider
"\u003cp\u003e本文主要对 \u003ca href=\"https://www.terraform.io/\"\u003eterraform\u003c/a\u003e 中的 \u003ccode\u003eProviders\u003c/code\u003e 进行介绍,让刚刚接触 \u003ccode\u003eterraform\u003c/code\u003e 的用户对其有一个大概的了解,以下内容翻译自:https://developer.hashicorp.com/terraform/language/providers\u003c/p\u003e\n\u003ch1 id=\"什么是-providers\"\u003e什么是 Providers\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e实践:\u003c/strong\u003e Try the \u003ca href=\"https://developer.hashicorp.com/terraform/tutorials/configuration-language/provider-use?utm_source=WEBSITE\u0026amp;utm_medium=WEB_IO\u0026amp;utm_offer=ARTICLE_PAGE\u0026amp;utm_content=DOCS\"\u003ePerform CRUD Operations with Providers\u003c/a\u003e tutorial.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eTerraform 依赖于称为提供商的插件来与\u003ccode\u003e云提供商\u003c/code\u003e、\u003ccode\u003eSaaS 提供商\u003c/code\u003e和 \u003ccode\u003e其他 API\u003c/code\u003e 进行交互。 Terraform 配置必须声明它们需要哪些 \u003ccode\u003eproviders\u003c/code\u003e,以便 \u003ccode\u003eTerraform\u003c/code\u003e 可以 \u003cstrong\u003e安装\u003c/strong\u003e 和 \u003cstrong\u003e使用\u003c/strong\u003e 它们。此外,某些提供商在使用之前需要进行配置(例如 \u003ccode\u003e端点 URL\u003c/code\u003e 或 \u003ccode\u003e云区域\u003c/code\u003e)。\u003c/p\u003e\n\u003ch1 id=\"providers-能做什么\"\u003eProviders 能做什么\u003c/h1\u003e\n\u003cp\u003e每一个 Providers 都会有一组 Terraform 可以管理的 \u003ca href=\"https://developer.hashicorp.com/terraform/language/resources\"\u003eresource types\u003c/a\u003e 和或 \u003ca href=\"https://developer.hashicorp.com/terraform/language/data-sources\"\u003edata sources\u003c/a\u003e。如我们经常使用的 \u003ca href=\"https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs\"\u003edocker provider\u003c/a\u003e, 它提供了一些 \u003ccode\u003eResources\u003c/code\u003e 和 \u003ccode\u003eData sources\u003c/code\u003e,使用 …\u003c/p\u003e"
August 19, 2023
k8s 中 CRD controller 开发教程
"\u003cp\u003e本文主要介绍 \u003ccode\u003ecrd controller\u003c/code\u003e 的基本开发过程,让每一个刚接触k8s开发的同学都可以轻松开发自己的控制器。\u003c/p\u003e\n\u003ch1 id=\"kubebuilder-简介\"\u003ekubebuilder 简介\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003ekubebuilder\u003c/code\u003e 是一个帮助开发者快速开发 \u003ccode\u003ekubernetes API\u003c/code\u003e 的脚手架命令行工具,其依赖 \u003ccode\u003econtroller-tools\u003c/code\u003e 和 \u003ccode\u003econtroller-runtime\u003c/code\u003e 两个库。其中 \u003ccode\u003econtroller-runtime\u003c/code\u003e 简化 \u003ccode\u003ekubernetes controller\u003c/code\u003e 的开发,并且对 \u003ccode\u003ekubernetes\u003c/code\u003e 的几个常用库进行了二次封装, 以简化开发工程。而 \u003ccode\u003econtroller-tool\u003c/code\u003e 主要功能是代码生成。\u003c/p\u003e\n\u003cp\u003e下图是使用 \u003ccode\u003ekubebuilder\u003c/code\u003e 的工作流程图:\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/08/76264fc22f097ec97349461e383ed996.webp\" alt=\"format%2Cpng\"\u003e\u003c/p\u003e\n\u003ch1 id=\"安装-kubebuilder\"\u003e安装 kubebuilder\u003c/h1\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e# download kubebuilder and install locally.\n➜ curl -L -o kubebuilder \u0026#34;https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)\u0026#34;\n➜ chmod +x kubebuilder …\u003c/code\u003e\u003c/pre\u003e"
August 3, 2023
apiserver 中的webhook开发教程
"\u003cp\u003ek8s: v1.27.3\u003c/p\u003e\n\u003ch2 id=\"what-are-they.wp-block-heading\"\u003e什么是准入控制插件?\u003ca href=\"https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/#what-are-they\"\u003e\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e准入控制器\u003c/strong\u003e 是一段代码,它会在请求通过\u003cstrong\u003e认证\u003c/strong\u003e和\u003cstrong\u003e鉴权\u003c/strong\u003e之后、对象被持久化之前拦截到达 API 服务器的请求。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/08/6ca5dd6b207691069de1cf4df59cc6ad.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e准入控制器可以执行 \u003cstrong\u003e变更(Mutating)\u003c/strong\u003e 和或 \u003cstrong\u003e验证(Validating)\u003c/strong\u003e 操作。 变更(mutating)控制器可以根据被其接受的请求更改相关对象;验证(validating)控制器则不行。\u003c/p\u003e\n\u003cp\u003e准入控制器限制创建、删除、修改对象的请求。 准入控制器也可以阻止自定义动作,例如通过 API 服务器代理连接到 Pod 的请求。 准入控制器\u003cstrong\u003e不会\u003c/strong\u003e (也不能)阻止读取(\u003cstrong\u003eget\u003c/strong\u003e、\u003cstrong\u003ewatch\u003c/strong\u003e 或 \u003cstrong\u003elist\u003c/strong\u003e)对象的请求。\u003c/p\u003e\n\u003cp\u003e某些控制器既是变更准入控制器又是验证准入控制器。如果两个阶段之一的任何一个控制器拒绝了某请求,则整个请求将立即被拒绝,并向最终用户返回错误。\u003c/p\u003e\n\u003cp\u003eKubernetes 1.27 中的准入控制器由下面的\u003ca href=\"https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do\"\u003e列表\u003c/a\u003e组成, 并编译进 \u003ccode\u003ekube-apiserver\u003c/code\u003e 可执行文件,并且只能由集群管理员配置。 在该列表中,有两个特殊的控制器:\u003ccode\u003eMutatingAdmissionWebhook\u003c/code\u003e 和 \u003ccode\u003eValidatingAdmissionWebhook\u003c/code\u003e。 它们 …\u003c/p\u003e"
August 1, 2023
k8s之kube-controller-manager 源码分析
"\u003cp\u003eKubernetes 控制器管理器(\u003ccode\u003ekube-controller-manager\u003c/code\u003e)是一个守护进程,内嵌随 Kubernetes 一起发布的核心控制回路。 在机器人和自动化的应用中,控制回路是一个永不休止的循环,用于调节系统状态。 在 Kubernetes 中,每个控制器是一个控制回路,通过 API 服务器监视集群的共享状态, 并尝试进行更改以将当前状态转为期望状态。 目前,Kubernetes 自带的控制器例子包括副本控制器、节点控制器、命名空间控制器和服务账号控制器等。\u003c/p\u003e\n\u003cp\u003e本文不对 \u003ccode\u003ekube-controller-manager\u003c/code\u003e 管理的每个控制器的执行原理做介绍,只是从全局观看一下kube-controller-manager 启动每个控制器的整体实现过程。\u003c/p\u003e\n\u003cp\u003ek8s: v1.27.3\u003c/p\u003e\n\u003cp\u003e文件: \u003ca href=\"https://github.com/kubernetes/kubernetes/blob/v1.27.3/cmd/kube-controller-manager/app/controllermanager.go\"\u003ecmd/kube-controller-manager/app/controllermanager.go\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"控制器选项初始化\"\u003e控制器选项初始化\u003c/h1\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// cmd/kube-controller-manager/app/controllermanager.go#L104\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
July 31, 2023
k8s调度器插件开发教程
"\u003cp\u003e上一篇 \u003ca href=\"https://blog.haohtml.com/archives/33138\"\u003e《k8s调度器 kube-scheduler 源码解析》\u003c/a\u003e 大概介绍一调度器的内容,提到扩展点的插件这个概念,下面我们看看如何开发一个自定义调度器。\u003c/p\u003e\n\u003cp\u003e本文源码托管在 \u003ca href=\"https://github.com/cfanbo/sample-scheduler\"\u003ehttps://github.com/cfanbo/sample-scheduler\u003c/a\u003e。\u003c/p\u003e\n\u003ch1 id=\"插件机制\"\u003e插件机制\u003c/h1\u003e\n\u003cp\u003e在Kubernetes调度器中,共有两种插件机制,分别为 \u003ccode\u003ein-tree\u003c/code\u003e 和 \u003ccode\u003eout-of-tree\u003c/code\u003e。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIn-tree插件(内建插件):这些插件是作为Kubernetes核心组件的一部分直接编译和交付的。它们与Kubernetes的源代码一起维护,并与Kubernetes版本保持同步。这些插件以静态库形式打包到kube-scheduler二进制文件中,因此在使用时不需要单独安装和配置。一些常见的in-tree插件包括默认的调度算法、Packed Scheduling等。\u003c/li\u003e\n\u003cli\u003eOut-of-tree插件(外部插件):这些插件是作为独立项目开发和维护的,它们与Kubernetes核心代码分开,并且可以单独部署和更新。本质上,out-of-tree插件是基于Kubernetes的调度器扩展点进行开发的。这些插件以独立的二进制文件 …\u003c/li\u003e\u003c/ol\u003e"
July 28, 2023
k8s调试之 kube-apiserver 组件
"\u003cp\u003e上一节\u003ca href=\"https://blog.haohtml.com/archives/34402\"\u003e《GoLand+dlv进行远程调试》\u003c/a\u003e我们介绍了如何使用 \u003ccode\u003eGoLand\u003c/code\u003e 进行远程调试,本节我们就以 \u003ccode\u003ekube-apiserver\u003c/code\u003e 为例演示一下调试方法。\u003c/p\u003e\n\u003ch1 id=\"服务器环境\"\u003e服务器环境\u003c/h1\u003e\n\u003cp\u003e作为开发调试服务器,需要安装以下环境\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e安装 \u003ccode\u003eGolang\u003c/code\u003e 环境,国内最好设置 \u003ccode\u003eGOPROXY\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e安装 \u003ccode\u003edlv\u003c/code\u003e 调试工具\u003c/li\u003e\n\u003cli\u003e安装 \u003ccode\u003eDocker\u003c/code\u003e 环境, 同时安装 \u003ccode\u003econtainerd\u003c/code\u003e 服务(对应官方教程中的 \u003ccode\u003econtainerd.io\u003c/code\u003e 安装包)并设置代理\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"同步代码本地\"\u003e同步代码(本地)\u003c/h1\u003e\n\u003cp\u003e以下为我们本机环境设置。\u003c/p\u003e\n\u003cp\u003e本机下载 \u003ca href=\"https://github.com/kubernetes/kubernetes\"\u003ekubernetes\u003c/a\u003e 仓库\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit clone --filter\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eblob:none https://github.com/kubernetes/kubernetes.git\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e这里指定 –filter=bold:none 可以实现最小化下载\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这里 k8s 项目目录为 \u003ccode\u003e/Users/sxf/workspace/kubernetes\u003c/code\u003e, 对应远程服务器目录为 \u003ccode\u003e/home/sxf/workspace/kubernetes\u003c/code\u003e,如图所示\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/07/d2b5ca33bd970f64a6301fa75ae2eb22-6.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e映射关系配置\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/07/d2b5ca33bd970f64a6301fa75ae2eb22-7.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e同时选择自动上传 \u003ccode\u003eAutomatic upload (Always)\u003c/code\u003e 菜单,这 …\u003c/p\u003e"
July 27, 2023
Goland+dlv远程调试
"\u003cp\u003e环境\u003c/p\u003e\n\u003cp\u003e远程服务器(Linux):192.168.245.137\u003c/p\u003e\n\u003cp\u003e本地(macOS):GoLand\u003c/p\u003e\n\u003ch1 id=\"目的\"\u003e目的\u003c/h1\u003e\n\u003cp\u003e远程调试就是使用使用本地 IDE 来调试远程服务器上的服务。本地打断点,调用远程服务的接口。本地就会停在断点。\u003c/p\u003e\n\u003cp\u003e为什么需要远程调试呢?主要有以下几点原因:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e运行环境:有时候本机不具备调试环境,如开发的程序依赖太多组件,而这些组件在当前机器并不被支持\u003c/li\u003e\n\u003cli\u003e性能:一般远程服务器的配置都比较高,编译速度也比较快。而开发机器的配置相对要低一些,每次修改程序都要重新编译,非常的消耗时间。\u003c/li\u003e\n\u003cli\u003e硬盘空间:编译时产生大量的中间临时文件,多达10个G左右,如果本机硬盘空间不足的话,则根本就没有办法进行本地调试\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e我这里用的系统是macOS,硬盘只有128G大小,硬盘空间非常的紧张,vmware虚拟机占用了30个G, 在虚拟机里编译时发现期间产生的临时文件达到6个G,硬盘空间已经不远远不够,所以选择使用远程调试这种方式。\u003c/p\u003e\n\u003cp\u003e这些调试方式对于k8s 开发者来讲应该比较常见,如 \u003ca href=\"https://blog.haohtml.com/archives/34454\"\u003e调试 \u003ccode\u003ekube-apiserver\u003c/code\u003e 组件\u003c/a\u003e。\u003c/p\u003e\n\u003ch1 id=\"安装-dlv远程\"\u003e安装 dlv(远程)\u003c/h1\u003e\n\u003cp\u003e首先我们在远程服务器安装 \u003ca href=\"https://go.dev\"\u003eGolang\u003c/a\u003e 环境 和 \u003ca href=\"https://github.com/go-delve/delve\"\u003edlv\u003c/a\u003e 命令。 …\u003c/p\u003e"
July 18, 2023
kubelet 源码之 Plugin注册机制
"\u003cp\u003e上一篇\u003ca href=\"https://blog.haohtml.com/archives/33188\"\u003e《Kubelet 服务引导流程》\u003c/a\u003e我们讲了kubelet的大概引导流程, 本节我们看一下 \u003ccode\u003ePlugins\u003c/code\u003e 这一块的实现源码。\u003c/p\u003e\n\u003cp\u003eversion: v1.27.3\u003c/p\u003e\n\u003ch1 id=\"插件模块入口\"\u003e插件模块入口\u003c/h1\u003e\n\u003cp\u003e入口文件 \u003ccode\u003e/pkg/kubelet/kubelet.go\u003c/code\u003e中的 \u003ccode\u003eNewMainKubelet()\u003c/code\u003e 函数,\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eNewMainKubelet\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003ekubeCfg\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003ekubeletconfiginternal\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eKubeletConfiguration\u003c/span\u003e,\u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e) (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eKubelet\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003eerror\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e// 插件管理器 /pkg/kubelet/kubelet.go#L811-L814\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003eklet\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003epluginManager\u003c/span\u003e = \u003cspan style=\"color:#a6e22e\"\u003epluginmanager\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eNewPluginManager\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003eklet\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003egetPluginsRegistrationDir\u003c/span\u003e(), \u003cspan style=\"color:#75715e\"\u003e/* sockDir */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003ekubeDeps\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eRecorder\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#f92672\"\u003e...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里第一个参数 \u003ccode\u003eklet.getPluginsRegistrationDir() …\u003c/code\u003e\u003c/p\u003e"
July 7, 2023
kube-proxy 源码解析
"\u003cp\u003ek8s版本:v1.17.3\u003c/p\u003e\n\u003ch1 id=\"组件简介\"\u003e组件简介\u003c/h1\u003e\n\u003cp\u003ekube-proxy是Kubernetes中的一个核心组件之一,它提供了一个网络代理和负载均衡服务,用于将用户请求路由到集群中的正确服务。\u003c/p\u003e\n\u003cp\u003ekube-proxy的主要功能包括以下几个方面:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e服务代理:kube-proxy会监听Kubernetes API服务器上的服务和端口,并将请求转发到相应的后端Pod。它通过在节点上创建iptables规则或使用IPVS(IP Virtual Server)进行负载均衡,以保证请求的正确路由。\u003c/li\u003e\n\u003cli\u003e负载均衡:当多个Pod实例对外提供相同的服务时,kube-proxy可以根据负载均衡算法将请求分发到这些实例之间,以达到负载均衡的目的。它可以基于轮询、随机、源IP哈希等算法进行负载均衡。\u003c/li\u003e\n\u003cli\u003e故障转移:如果某个Pod实例不可用,kube-proxy会检测到并将其自动从负载均衡轮询中移除,从而保证用户请求不会被转发到不可用的实例上。\u003c/li\u003e\n\u003cli\u003e会话保持(Session Affinity):kube-proxy可以通过设置会话粘性(Session Affinity)来将同一客户端的请求转发到同一Pod实例,从而保持会话状态的一致性。\u003c/li\u003e\n\u003cli\u003e …\u003c/li\u003e\u003c/ol\u003e"
June 21, 2023
Kubelet 服务引导流程
"\u003cp\u003e版本:v1.17.3\u003c/p\u003e\n\u003cp\u003e入口文件: \u003ca href=\"https://github.com/kubernetes/kubernetes/blob/v1.27.3/cmd/kubelet/kubelet.go\"\u003e/cmd/kubelet/kubelet.go\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e本文主要是为了通过阅读kubelet启动流程源码,实现对整个kubelet 组件及其服务有所了解,因此许多相关组件服务的运行机制并没有详细介绍,如果有时间的话,可以针对每个组件服务进行详细介绍。\u003c/p\u003e\n\u003cp\u003e在k8s中 \u003ccode\u003ekubelet\u003c/code\u003e 是一个极其重要的组件之一,也是 Kubernetes 里面第二个不可被替代的组件(第一个不可被替代的组件当然是 \u003ccode\u003ekube-apiserver\u003c/code\u003e)。也就是说,无论如何,都不太建议你对 kubelet 的代码进行大量的改动。保持 kubelet 跟上游基本一致的重要性,就跟保持 kube-apiserver 跟上游一致是一个道理。\u003c/p\u003e\n\u003cp\u003ekubelet 本身,也是按照“控制器”模式来工作的。它实际的工作原理,可以用如下所示的一幅示意图来表示清楚。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/07/d2b5ca33bd970f64a6301fa75ae2eb22-2.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e可以看到,kubelet 的工作核心,就是一个控制循环,即:SyncLoop(图中的大圆圈)。而驱动这个控制循环运行的事件,包括四种:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePod 更新事件;\u003c/li\u003e\n\u003cli\u003ePod 生命周期变化;\u003c/li\u003e\n\u003cli\u003ekubelet 本身设置的执行周期;\u003c/li\u003e\n\u003cli\u003e定时的清理事件。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e所以,跟其他控 …\u003c/p\u003e"
June 11, 2023
创建Pod源码解析
"\u003cp\u003e在上一篇\u003ca href=\"https://blog.haohtml.com/archives/33188\"\u003e《Kubelet 服务引导流程》\u003c/a\u003e中我们介绍了 \u003ccode\u003ekubelet\u003c/code\u003e 服务启动的大致流程,其中提到过对 Pod 的管理,这一节将详细介绍一下对Pod的相关操作,如创建、修改、删除等操作。建议先了解一下上节介绍的内容。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003ekubelet\u003c/code\u003e 启动的时候,会通过三种 pod source 方式来获取 pod 信息:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003efile: 这种方式只要针对 staticPod 来处理,定时观察配置文件是否发生变更情况来写入 pod\u003c/li\u003e\n\u003cli\u003ehttp方式: 就是通过一个http请求一个 URL 地址,用来获取 \u003ccode\u003esimple Pod\u003c/code\u003e 信息\u003c/li\u003e\n\u003cli\u003eclientSet: 这种方式直接与 APIServer 通讯,对 pod 进行watch\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e上面这三种 \u003ccode\u003epod source\u003c/code\u003e ,一旦有pod 的变更信息,将直接写入一个 \u003ccode\u003ekubetypes.PodUpdate\u003c/code\u003e 这个 \u003ccode\u003echannel\u003c/code\u003e(参考: \u003ca href=\"https://github.com/kubernetes/kubernetes/blob/v1.27.3/pkg/kubelet/kubelet.go#L278-L313\"\u003ehttps://github.com/kubernetes/kubernetes/blob/v1.27.3/pkg/kubelet/kubelet.go#L278-L313\u003c/a\u003e),然后由下面我们要讲的内容进行读取消费。\u003c/p\u003e\n\u003cp\u003e对于pod 的操作除了这 …\u003c/p\u003e"
June 11, 2023
k8s调度器 kube-scheduler 源码解析
"\u003cp\u003e版本号:v1.27.2\u003c/p\u003e\n\u003cp\u003eKubernetes 调度程序作为一个进程与其他主组件(例如 API 服务器)一起运行。它与 API 服务器的接口是监视具有空 \u003ccode\u003ePodSpec.NodeName\u003c/code\u003e 的 Pod,并且对于每个 Pod,它都会发布一个 \u003ccode\u003eBinding\u003c/code\u003e,指示应将 Pod 调度到哪里。\u003c/p\u003e\n\u003ch1 id=\"调度过程\"\u003e调度过程\u003c/h1\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e +-------+\n +---------------+ node 1|\n | +-------+\n |\n +----\u0026gt; | Apply pred. filters\n | |\n | | +-------+\n | +----+----------\u0026gt;+node 2 |\n | | +--+----+\n | watch | |\n | | | …\u003c/code\u003e\u003c/pre\u003e"
April 25, 2023
istio之pilot-agent 源码分析
"\u003cp\u003e源码版本:istio-v1.11.3\u003c/p\u003e\n\u003cp\u003e为了方便理解,本文会介绍到 \u003ccode\u003evm\u003c/code\u003e 和 \u003ccode\u003e容器\u003c/code\u003e 两种部署形式的情况,一般会在讲解时提到,因此需要注意当前的部署方式,不过他们的架构是完全一样的。\u003c/p\u003e\n\u003ch1 id=\"架构\"\u003e架构\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003epilot\u003c/code\u003e 共分两个主要模块,一个是 \u003ccode\u003epilot-agent\u003c/code\u003e 用来提供 pod 中的服务发现 \u003ccode\u003e客户端\u003c/code\u003e,另一个是 \u003ccode\u003epolot-discovery\u003c/code\u003e 提供服务发现 \u003ccode\u003e服务端\u003c/code\u003e。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2023/04/d2b5ca33bd970f64a6301fa75ae2eb22-4.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e其中 \u003ccode\u003eenvoy\u003c/code\u003e 和 \u003ccode\u003eIstio Agent\u003c/code\u003e 就是我们上面所讲的 \u003ccode\u003epilot-agent\u003c/code\u003e 模块,其为 \u003ccode\u003e数据面\u003c/code\u003e 组件,而 \u003ccode\u003eIstiod\u003c/code\u003e 则为 \u003ccode\u003e控制面\u003c/code\u003e,模块对应源码见\u003c/p\u003e\n\u003ch1 id=\"pilot-agent\"\u003epilot-agent\u003c/h1\u003e\n\u003cp\u003e对于 \u003ccode\u003epolot-agent\u003c/code\u003e 它运行在每个pod中 ,并以 \u003ccode\u003esidecar\u003c/code\u003e 方式与应用容器运行在同一个pod。如果你使用的是 \u003ccode\u003evm\u003c/code\u003e 的话,则可以在当前主机通过 \u003ccode\u003epstree\u003c/code\u003e 命令看到进程视图\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e# pstree -pu 24530\nsu(24530)───pilot-agent(24611,istio-proxy)─┬─envoy(24619)─┬─{envoy}(24620) …\u003c/code\u003e\u003c/pre\u003e"
February 15, 2023
kubernetes 之 client-go 之 informer 工作原理源码解析
"\u003cp\u003e本文主要介绍有关 \u003ccode\u003eclient go\u003c/code\u003e 架构实现原理,在整个client-go架构中有一个很重要的组件就是 \u003ccode\u003einformer\u003c/code\u003e,本节我们重点对其进行一些介绍。\u003c/p\u003e\n\u003ch1 id=\"informer-机制\"\u003eInformer 机制\u003c/h1\u003e\n\u003cp\u003e采用 k8s HTTP API 可以查询集群中所有的资源对象并 Watch 其变化,但大量的 HTTP 调用会对 API Server 造成较大的负荷,而且网络调用可能存在较大的延迟。除此之外,开发者还需要在程序中处理资源的缓存,HTTP 链接出问题后的重连等。为了解决这些问题并简化 Controller 的开发工作,K8s 在 client go 中提供了一个 \u003ccode\u003einformer\u003c/code\u003e 客户端库,可以视其为一个组件。\u003c/p\u003e\n\u003cp\u003e在 Kubernetes 中,\u003ccode\u003eInformer\u003c/code\u003e 可以用于监视 Kubernetes API 服务器中的资源并将它们的当前状态缓存到本地(\u003ccode\u003eindex -\u0026gt; store)\u003c/code\u003e ,这样就避免了客户端不断地向 API 服务器发送请求,直接从本地即可。\u003c/p\u003e\n\u003cp\u003e相比直接采用 HTTP Watch,使用 Kubernetes Informer 有以下优势:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e减少 API 服务器的负载:通过在本地缓存资源信 …\u003c/li\u003e\u003c/ul\u003e"
January 16, 2023
Golang 中网络请求使用指定网卡
"\u003cp\u003e当用户发起一个网络请求时,流量会通过默认的网卡接口流出与流入,但有时需要将流量通过指定的网卡进行流出流入,这时我们可能需要进行一些额外的开发工作,对其实现主要用到了 \u003ccode\u003eDialer.Control\u003c/code\u003e 配置项。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etype Dialer struct {\n\n // If Control is not nil, it is called after creating the network\n // connection but before actually dialing.\n //\n // Network and address parameters passed to Control method are not\n // necessarily the ones passed to Dial. For example, passing \u0026#34;tcp\u0026#34; to Dial\n // will cause the Control function to be called with \u0026#34;tcp4\u0026#34; or \u0026#34;tcp6\u0026#34;. …\u003c/code\u003e\u003c/pre\u003e"
October 30, 2022
Linux下两种 DNAT 用法的差异
"\u003cp\u003e前段时间使用 \u003ccode\u003eiptables\u003c/code\u003e 的 \u003ccode\u003eDNAT\u003c/code\u003e 实现一个业务需求的时候,遇到了一些问题这里将其整个过程记录下来。\u003c/p\u003e\n\u003ch2 id=\"需求\"\u003e需求\u003c/h2\u003e\n\u003cp\u003e这里假设开发机地址为 \u003ccode\u003e192.168.3.80\u003c/code\u003e,要实现的需求是当用户在开发机访问一个IP地址 \u003ccode\u003e192.168.3.196\u003c/code\u003e时,将请求转发到另一台机器 \u003ccode\u003e192.168.3.58\u003c/code\u003e,很明显直接使用 \u003ccode\u003eDNAT\u003c/code\u003e 来实现即可。\u003c/p\u003e\n\u003ch2 id=\"问题现象\"\u003e问题现象\u003c/h2\u003e\n\u003cp\u003eiptables 命令如下\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo iptables -t nat -F\nsudo iptables -t nat -A PREROUTING -d 192.168.3.196 -p tcp --dport 8080 -j DNAT --to-destination 192.168.3.58:8080\nsudo iptables -t nat -A POSTROUTING -d 192.168.3.58 -p tcp --dport 8080 -j SNAT --to-source 192.168.3.196:8080\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这时在开发机器访问\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecurl http://192.168.3.196:8080\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e发现提示错误\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecurl: (7) Failed …\u003c/code\u003e\u003c/pre\u003e"
June 10, 2022
https 是如何建立连接的
"\u003ch2 id=\"一什么是httpstlsssl\"\u003e\u003cstrong\u003e一、什么是HTTPS、TLS、SSL\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eHTTPS,也称作HTTP over TLS。TLS的前身是SSL,TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。下图描述了在TCP/IP协议栈中TLS(各子协议)和HTTP的关系。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/06/7584c4e760a0c0191e913baf0a49fc9b.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003ch2 id=\"二http和https协议的区别\"\u003e\u003cstrong\u003e二、HTTP和HTTPS协议的区别\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e1、HTTPS协议需要到证书颁发机构(Certificate Authority,简称CA)申请证书,一般免费证书很少,需要交费。\u003c/p\u003e\n\u003cp\u003e2、HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL加密传输协议。\u003c/p\u003e\n\u003cp\u003e3、HTTP和HTTPS使用的是完全不同的连接方式,使用的端口也不一样,前者是80,后者是443。\u003c/p\u003e\n\u003cp\u003e4、HTTP的连接很简单,是无状态的。\u003c/p\u003e\n\u003cp\u003e5、HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比HTTP协议安全。\u003c/p\u003e\n\u003cp\u003e从上面可看出,HTTPS和HTTP协议相比提供了\u003c/p\u003e\n\u003cp\u003e· 数据完整性:内容传输经过完整性校验\u003c/p\u003e\n\u003cp\u003e· 数据隐私性:内容经过对称加密,每个连接生成一个唯一的加密密钥\u003c/p\u003e\n\u003cp\u003e· 身份认证:第三方无法伪造服务端(客户端)身份\u003c/p\u003e\n\u003cp\u003e其 …\u003c/p\u003e"
June 10, 2022
实现 Linux 终端录屏转gif动画
"\u003cp\u003e在一些开源其中,有些文档使用git动画来介绍的话效果会好很多,所以这里把在Linux终端下如何生成git动画效果整理出来,供大家参考。\u003cimg src=\"https://s3.eu-central-1.amazonaws.com/sickill/github/asciicast2gif/demo-2.gif\" alt=\"\"\u003e\u003c/p\u003e\n\u003ch2 id=\"安装录屏软件-asciinema\"\u003e安装录屏软件 asciinema\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eMac\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e brew install asciinema\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eUbuntu\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e sudo apt-add-repository ppa:zanchey/asciinema\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eDebian\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e sudo apt-get install asciinema\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003ePip安装\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e sudo pip3 install asciinema\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e目前此软件不支持 Windows。更多安装教程参考:\u003c/p\u003e\n\u003ch2 id=\"用法介绍\"\u003e用法介绍\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e ❯ asciinema -h\n usage: asciinema [-h] [--version] {rec,play,cat,upload,auth} ...\n \n Record and share your terminal sessions, the right way.\n \n positional arguments:\n {rec,play,cat,upload,auth}\n rec …\u003c/code\u003e\u003c/pre\u003e"
May 24, 2022
Linux 中的 Tun/Tap 介绍
"\u003ch1 id=\"tuntap-设备\"\u003eTUN/TAP 设备\u003c/h1\u003e\n\u003cp\u003e在计算机中TUN与TAP是操作系统内核中的虚拟网络设备。不同于硬件设备这些虚拟的网络设备全部用软件实现,但提供了与硬件设备完全相同的功能。\u003c/p\u003e\n\u003cp\u003e我们先了解一下物理设备的工作原理\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/07/57e54aad529225723698841910e61c46.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e所有主机物理网卡收到的数据包时,会先将其交给内核的 Network Stack 处理,然后通过 Socket API 通知给用户态的用户程序。\u003c/p\u003e\n\u003cp\u003eLinux 中 \u003ccode\u003eTun/Tap\u003c/code\u003e 驱动程序为应用程序提供了两种交互方式:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e虚拟网络接口和字符设备 \u003ccode\u003e/dev/net/tun\u003c/code\u003e。写入字符设备 \u003ccode\u003e/dev/net/tun\u003c/code\u003e 的数据会发送到虚拟网络接口中;\u003c/li\u003e\n\u003cli\u003e发送到虚拟网络接口中的数据也会出现在该字符设备上;\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我们再看下 tun 设备的工作原理\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/07/ece6896a211da4167687ea55edc4f2c9.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e用户态应用往字符设备 \u003ccode\u003e/dev/tunX\u003c/code\u003e 写数据时,写入的数据都会出现在TUN虚拟设备上,当内核发送一个包给 TUN 虚拟设备时,通过读这个字符设备 \u003ccode\u003e/dev/tunX\u003c/code\u003e 同样可以拿到包的内容。\u003c/p\u003e\n\u003cp\u003e用户态应用程序写数据到 \u003ccode\u003etun/tap\u003c/code\u003e 设备后进入内核态,内核态通过TCP协议复制到用户态,最后数据再次复制到内核态并通过物理网卡转发出去,期间共经历了三次用户态与内核态的复制 …\u003c/p\u003e"
March 31, 2022
用 Goalng 开发 OPA 策略
"\u003cp\u003e\u003ccode\u003eOpen Policy Agent\u003c/code\u003e 简称\u003ccode\u003eOPA\u003c/code\u003e是一个开源的通用策略引擎,可在整个堆栈中实现统一的、上下文感知的策略实施。OPA 已经成为了云原生计算基金会 ( \u003ca href=\"https://www.cncf.io/\"\u003eCNCF\u003c/a\u003e) 领域的毕业项目,已经在 \u003ca href=\"https://www.openpolicyagent.org/docs/kubernetes-admission-control.html\"\u003eKubernetes\u003c/a\u003e / \u003ca href=\"https://istio.io\"\u003eIstio\u003c/a\u003e 等多个知名项目里使用 。\u003c/p\u003e\n\u003cp\u003eOPA的核心思想就是策略即代码。\u003c/p\u003e\n\u003cp\u003e它使用\u003ccode\u003eRego\u003c/code\u003e语言开发,Rego 的灵感来自 \u003ca href=\"https://en.wikipedia.org/wiki/Datalog\"\u003eDatalog\u003c/a\u003e,它是一种易于理解、已有数十年的历史的查询语言。Rego 扩展了 Datalog 以支持 JSON 等文档模型。对于它的详细介绍请参考官方文档 ,这里不再介绍,本方主要介绍如何使用Golang 来开发一个opa策略。\u003c/p\u003e\n\u003ch1 id=\"概述\"\u003e概述\u003c/h1\u003e\n\u003cp\u003eOPA 将 \u003ccode\u003e策略决策\u003c/code\u003e 与 \u003ccode\u003e策略执行\u003c/code\u003e 分离,当您的软件需要做出策略决策时,它会查询 OPA 并提供结构化数据(例如 JSON)作为输入。 OPA 接受任意结构化数据作为输入。\u003cimg src=\"https://d33wubrfki0l68.cloudfront.net/b394f524e15a67457b85fdfeed02ff3f2764eb9e/6ac2b/docs/latest/images/opa-service.svg\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e对于它的输入一般称为 \u003ccode\u003einput\u003c/code\u003e, 可以为任意类型,输出也一样可以为任意类型,即可以输出布尔值 \u003ccode\u003etrue\u003c/code\u003e 或 \u003ccode\u003efalse\u003c/code\u003e,也可以输出一个 \u003ccode\u003eJSON\u003c/code\u003e 字符串对象。\u003c/p\u003e\n\u003ch1 id=\"示例\"\u003e示例\u003c/h1\u003e\n\u003cp\u003e我们先从官方提供的一个 playground 开始,它是一个官方提供的在线执行 …\u003c/p\u003e"
February 25, 2022
一文看懂Golang 定时器源码
"\u003cp\u003e计时器分 Timer 和 Ticker 两种,它们底层基本是一样的,两差的区别请参考 , 这里我们的介绍对象是 Timer 。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/03/fcabf1624c9030edb67ec1e8bf7ad4d9.png\" alt=\"\"\u003egolang timer\u003c/p\u003e\n\u003ch1 id=\"计时器结构体.wp-block-heading\"\u003e计时器结构体\u003c/h1\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e // NewTimer creates a new Timer that will send\n // the current time on its channel after at least duration d.\n func NewTimer(d Duration) *Timer {\n c := make(chan Time, 1)\n t := \u0026amp;Timer{\n C: c,\n r: runtimeTimer{\n when: when(d),\n f: sendTime,\n arg: c,\n },\n }\n startTimer(\u0026amp;t.r)\n return t\n }\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e通过调用 \u003ccode\u003eNewTimer()\u003c/code\u003e 函数创建一个 \u003ccode\u003eTimer\u003c/code\u003e,首先创建一个长度 …\u003c/p\u003e"
November 25, 2021
Golang常见编译参数
"\u003cp\u003e在执行 go build 命令的时候,经常需要添加一些参数,或许是为了调试,也或许是为了生成最终部署二进制文件。\u003c/p\u003e\n\u003cp\u003e在编译特定包时需要传递参数,格式应遵守“包名=参数列表”,如\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ego build -gcflags -gcflags=\u0026#39;log=-N -l\u0026#39; main.go\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"-gcflags\"\u003e-gcflags\u003c/h2\u003e\n\u003cp\u003ego build 可以用 \u003cem\u003e-gcflags\u003c/em\u003e 给_go_编译器传入参数,也就是传给 go tool compile 的参数,因此可以用 go tool compile –help 查看所有可用的参数。\u003c/p\u003e\n\u003cp\u003e其中 -m 可以检查代码的编译优化情况,包括逃逸情况和函数是否内联。\u003c/p\u003e\n\u003ch2 id=\"-ldflags\"\u003e-ldflags\u003c/h2\u003e\n\u003cp\u003ego build用 -ldflags 给go链接器传入参数,实际是给go tool link的参数,可以用go tool link –help查看可用的参数。\u003c/p\u003e\n\u003cp\u003e常用-X来指定版本号等编译时才决定的参数值。例如代码中定义var buildVer string,然后在编译时用go build -ldflags “-X main.buildVer=1.0” … 来赋值。注意-X只能给string类型变量赋值。\u003c/p\u003e"
November 25, 2021
Golang中的 CGO_ENABLED 环境变量
"\u003cp\u003eGolang中的编译参数\u003c/p\u003e\n\u003cp\u003e开发中经常使用 \u003ccode\u003ego build\u003c/code\u003e 命令来编译我们的程序源码,然后将生成二进制文件直接部署,极其方便。\u003c/p\u003e\n\u003cp\u003e对于 \u003ccode\u003ego build\u003c/code\u003e 有一些参数,对于针对程序源码进行一些编译优化,下面我们对经常使用的一些参数来介绍一下。\u003c/p\u003e\n\u003ch1 id=\"环境变量\"\u003e环境变量\u003c/h1\u003e\n\u003cp\u003e环境变量需要在go命令前面设置,如果多个变量的话,中间需要用“空格”分隔。下面我们介绍一个非常常见到的一些环境变量\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -o myserver main.go\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e除了这里给出的这几个变量外,还有一些其它变量,如 GODEBUG、GOFLAGS、GOPROXY 等,所有支持环境变量都可以在 里找到,有兴趣的话可以看看他们的作用。\u003c/p\u003e\n\u003cp\u003e这里重点介绍一下 \u003ccode\u003eCGO_ENABLED\u003c/code\u003e 环境变量对我们程序的影响。 \u003ccode\u003eCGO_ENABLED\u003c/code\u003e是用来控制golang 编译期间是否支持调用 cgo 命令的开关,其值为1或0,默认情况下值为1,可以用 \u003ccode\u003ego env\u003c/code\u003e 查看默认值。\u003c/p\u003e\n\u003cp\u003e如果你的程序里调用了cgo 命令,此参数必须设置为1,否则将编译时出错。这里直接用文档 中的一个例 …\u003c/p\u003e"
November 23, 2021
理解 firewalld/ufw 与iptables、netfilter 的关系
"\u003cp\u003eiptables 作为 Linux/Unix 下一款优秀的防火墙软件,在安全方面发挥着极其重要的作用,作为系统管理员来讲一点也不陌生。不过对于一些新手来说,复杂性是一个门槛,Linux厂商为了解决这个问题,于是推出了新的管理工具,如 Centos 下的 Firewalld 和 Ubuntu 下的ufw, 他们对新手十分友好,只需要几个很简单的命令即可实现想要的功能,再不也必为记不住iptables中的四表五键而烦恼了。\n那么,是不是有了 firewalld 和 ufw就不需要iptables了呢?并不是的。\u003c/p\u003e\n\u003cp\u003e首先我们要清楚firewalld、ufw 与iptables的关系,可以理解为两者只是对iptables其进行了一层封装,它们在用户交互方面做了非常多的改进,使其对用户更加友好,不需要再记住原来那么多命令了。\u003c/p\u003e\n\u003cp\u003e而目前对于一些系统管理员来讲,大概率还是会直接使用 iptables,主要原因是灵活性,当然也有一定的历史原因。对比前面两个管理工具,他们也存在一定的问题,如只能对单条规则进行管理,详细参考相关文档。\u003c/p\u003e\n\u003cp\u003e另外对于 firewalld 还有图形界面。 …\u003c/p\u003e"
August 16, 2021
k8s安装负载均衡器:Metallb
"\u003cp\u003e在使用kubenetes的过程中,如何将服务开放到集群外部访问是一个重要的问题。当使用云平台(阿里云、腾讯云、AWS等)的容器服务时,我们可以通过配置 service 为 \u003cstrong\u003eLoadBalancer\u003c/strong\u003e 模式来绑定云平台的负载均衡器,从而实现外网的访问。但是,如果对于自建的 kubernetes裸机集群,这个问题则要麻烦的多。\u003c/p\u003e\n\u003cp\u003e祼机集群不支持负载均衡的方式,可用的不外乎NodePort、HostNetwork、ExternalIPs等方式来实现外部访问。但这些方式并不完美,他们或多或少都存在的一些缺点,这使得裸机集群成为Kubernetes生态系统中的二等公民。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/metallb/metallb\"\u003eMetalLB\u003c/a\u003e 旨在通过提供与标准网络设备集成的Network LB实施来解决这个痛点,从而使裸机群集上的外部服务也尽可能“正常运行”,减少运维上的管理成本。它是一种纯软件的解决方案,参考 \u003ca href=\"https://kubernetes.github.io/ingress-nginx/deploy/baremetal/\"\u003ehttps://kubernetes.github.io/ingress-nginx/deploy/baremetal/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e从 v0.13.0 版本开始,官方对解决方案进行了部分调整,操作步骤简洁一些,建议使用最新版本, …\u003c/p\u003e"
May 23, 2021
Golang中的runtime.LockOSThread 和 runtime.UnlockOSThread
"\u003cp\u003e在runtime中有 \u003ccode\u003e[runtime.LockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4248-L4278)\u003c/code\u003e 和 \u003ccode\u003e[runtime.UnlockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4302-L4323)\u003c/code\u003e 两个函数,这两个函数有什么作用呢?我们看一下标准库中对它们的解释。\u003c/p\u003e\n\u003ch2 id=\"runtimelockosthread\"\u003eruntime.LockOSThread\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// LockOSThread wires the calling goroutine to its current operating system thread.\n// The calling goroutine will always execute in that thread,\n// and no other goroutine will execute in it,\n// until the calling goroutine has made …\u003c/code\u003e\u003c/pre\u003e"
May 21, 2021
认识无锁队列
"\u003cp\u003e\u003ccode\u003e无锁队列\u003c/code\u003e是 \u003ccode\u003elock-free\u003c/code\u003e 中最基本的数据结构,一般应用在需要一款高性能队列的场景下。\u003c/p\u003e\n\u003cp\u003e对于多线程用户来说,无锁队列的入队和出队操作是线程安全的,不用再加锁控制\u003c/p\u003e\n\u003ch1 id=\"什么是无锁队列\"\u003e什么是无锁队列\u003c/h1\u003e\n\u003cp\u003e队列每个开发者都知道,那么什么又是无锁队列呢?字面理解起来就是一个无锁状态的队列,\u003ccode\u003e多个线程(消费者)\u003c/code\u003e同时操作数据的时候不需要加锁,因为加/解锁都是一个很消耗资源的动作。\u003c/p\u003e\n\u003ch1 id=\"实现原理\"\u003e实现原理\u003c/h1\u003e\n\u003cp\u003e我们先看一下无锁队列的底层实现数据结构。\u003c/p\u003e\n\u003ch2 id=\"数据结构\"\u003e数据结构\u003c/h2\u003e\n\u003cp\u003e无锁队列底层的数据结构实现方式主要有两种:\u003ccode\u003e数组\u003c/code\u003e 和 \u003ccode\u003e链接\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"数组\"\u003e数组\u003c/h3\u003e\n\u003cp\u003e在首次初始化时,需要申请\u003ccode\u003e一块连接\u003c/code\u003e的\u003ccode\u003e大\u003c/code\u003e的内存。读写数据直接从数据的指定位置操作即可,时间复杂度为O(1)。\u003c/p\u003e\n\u003cp\u003e缺点:数组长度有限,一旦数组索引位置写满,则无法继续写入,即队列有上限。\u003c/p\u003e\n\u003ch3 id=\"链表\"\u003e链表\u003c/h3\u003e\n\u003cp\u003e不用像数组一样,刚开始就申请一块连接的大的内存空间。只有在每次写时数据的时候,申请这个数据节点大小的内存即可,这样就可以实现无限的写入,没有长度限制问题。\u003c/p\u003e\n\u003cp\u003e缺点:每次写数据都要申请内存,在写的场景,最差的情况是多少个数据就申请多少次内存,而每次申请都是一个消耗资源的动作。\u003c/p\u003e\n\u003cp\u003e可以看到无锁底层的实现的不同各有优势。多数据情况下,我们都采 …\u003c/p\u003e"
May 10, 2021
Runtime: goroutine的暂停和恢复源码剖析
"\u003cp\u003e上一节《 \u003ca href=\"https://blog.haohtml.com/archives/27003\"\u003eGC 对根对象扫描实现的源码分析\u003c/a\u003e》中,我们提到过在GC的时候,在对一些goroutine 栈进行扫描时,会在其扫描前触发 G 的暂停(\u003ccode\u003e[suspendG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L76-L254)\u003c/code\u003e)和恢复(\u003ccode\u003e[resumeG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L256-L280)\u003c/code\u003e)。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// markroot scans the i\u0026#39;th root.\n//\n// Preemption must be disabled (because this uses a gcWork).\n//\n// nowritebarrier is only advisory here.\n//\n//go:nowritebarrier\nfunc markroot(gcw *gcWork, i uint32) {\n\tbaseFlushCache := uint32(fixedRootCount) …\u003c/code\u003e\u003c/pre\u003e"
May 7, 2021
goroutine栈的申请与释放
"\u003cp\u003e对于提高对 stack 的使用效率,避免重复从heap中分配与释放,对其使用了 \u003ccode\u003epool\u003c/code\u003e 的概念,\u003ccode\u003eruntime\u003c/code\u003e 里为共提供了两个pool, 分别为 \u003ccode\u003estackpool\u003c/code\u003e ,另一个为 \u003ccode\u003estackLarge\u003c/code\u003e。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2022/05/b33bde90901d27dd591e65c12e007fa2.png\" alt=\"\"\u003estack pool\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003estackpool\u003c/code\u003e: 16b~32k 对应通用的大小的stack。获取时通过调用 \u003ccode\u003estackpoolalloc()\u003c/code\u003e, 释放时调用 \u003ccode\u003estackpoolfree()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003estackLarge\u003c/code\u003e:对应 \u0026gt; 32K 的 stack\u003c/p\u003e\n\u003cp\u003e在程序全局调度器 \u003ca href=\"https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L634\"\u003e初始化\u003c/a\u003e 时会通过调用 \u003ccode\u003estackinit()\u003c/code\u003e 实现对 \u003ccode\u003estack\u003c/code\u003e 初始化。\u003c/p\u003e\n\u003cp\u003e当我们执行一个 \u003ccode\u003ego func()\u003c/code\u003e 语句的时候,\u003ccode\u003eruntime\u003c/code\u003e 会通过调用 \u003ccode\u003enewproc()\u003c/code\u003e 函数来创建G。而内部真正创建G的函数为 \u003ccode\u003e[newproc1()](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L3990-L4098)\u003c/code\u003e,在没有G可以复用的情况下,会通过 \u003ccode\u003enewg = malg(_StackMin)\u003c/code\u003e 语句创建一个\u003cstrong\u003e包含stack\u003c/strong\u003e的G。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// Allocate a …\u003c/code\u003e\u003c/pre\u003e"
May 7, 2021
Golang的GPM 模型在网络编程中存在的问题
"\u003ch2 id=\"现状\"\u003e现状\u003c/h2\u003e\n\u003cp\u003e目前在网络编程中,golang采用的是一种 \u003ccode\u003egoroutine-per-connection\u003c/code\u003e 的模式,即为每一个连接都分配一个goroutine,一个连接就是一个goroutine,多个连接之间没有关系。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;io/ioutil\u0026#34;\n\t\u0026#34;net\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\n//模拟server端\nfunc main() {\n\ttcpServer, _ := net.ResolveTCPAddr(\u0026#34;tcp4\u0026#34;, \u0026#34;:8080\u0026#34;)\n\tlistener, _ := net.ListenTCP(\u0026#34;tcp\u0026#34;, tcpServer)\n\n\tfor {\n\t\t//当有新客户端请求时拿到与客户端的连接\n\t\tconn, err := listener.Accept()\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// …\u003c/code\u003e\u003c/pre\u003e"
May 1, 2021
Linux 内核select、poll 和 eventpoll 的实现
"\u003cp\u003eLinux 内核仓库 \u003ca href=\"https://github.com/torvalds/linux\"\u003ehttps://github.com/torvalds/linux\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eLinux 内核文档: \u003ca href=\"https://www.kernel.org/doc/html/latest/index.html\"\u003ehttps://www.kernel.org/doc/html/latest/index.html\u003c/a\u003e( \u003ca href=\"https://www.kernel.org/doc/html/latest/translations/zh_CN/index.html\"\u003e中文\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e开发工具参考: \u003ca href=\"https://www.kernel.org/doc/html/latest/dev-tools/index.html\"\u003ehttps://www.kernel.org/doc/html/latest/dev-tools/index.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e也可以使用 VSCode + 插件C/C++ GNU Global\u003c/p\u003e\n\u003cp\u003e通过前面三个博客可以得知 \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104097648\"\u003e\u003cstrong\u003eselect\u003c/strong\u003e\u003c/a\u003e,** \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104099183\"\u003epoll\u003c/a\u003e\u003cstrong\u003e,\u003c/strong\u003e \u003ca href=\"https://blog.csdn.net/weixin_38537730/article/details/104093556\"\u003eeventpoll\u003c/a\u003e** 的详细实现,现在来总结对比下它们之间的不同:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eselect 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/cf1f47a3a2058cac1ffe1376a5825bb8.jpg\" alt=\"93c50bd46eded3432584b819b8c1e7cd\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003epoll 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/05795514077440f88ef0622e88fc6eb1.jpg\" alt=\"118c7aba5835cf06e006a1834dbe9f40\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eeventpoll 流程图\u003c/strong\u003e\n\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/05/f859094931597fe7298edb417c48c96b.png\" alt=\"2a937b08de0c8ed6c32b45ae19399a01\"\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e优缺点总结\u003c/strong\u003e\n\u0026lt;1\u0026gt; \u003cstrong\u003e监控文件最大数不同\u003c/strong\u003e:select和poll都是以数组形式传入药监控的文件句柄,而这个数组是有大小限制的1024个左右(不是很清楚).而epoll则是每add一个文件句柄会new一个新epi出来,挂载在ep的红黑树中,监控的文件个数没有明确限制(可能会受限于系统最大打开文件句柄数)从这点上看,epoll是优于select和poll. …\u003c/li\u003e\u003c/ol\u003e"
April 30, 2021
缓存池 bytebufferpool 库实现原理
"\u003cp\u003e上一节 \u003ca href=\"https://blog.haohtml.com/archives/24697\"\u003e《Runtime: Golang 之 sync.Pool 源码分析》\u003c/a\u003e 我们介绍了sync.Pool 的源码分析,本节介绍一个 \u003ca href=\"https://github.com/valyala/fasthttp\"\u003e\u003ccode\u003efasthttp\u003c/code\u003e\u003c/a\u003e 中引用的一缓存池库 \u003ccode\u003e[bytebufferpool](https://github.com/valyala/bytebufferpool)\u003c/code\u003e,这两个库是同一个开发者。对于这个缓存池库与同类型的几个库的对比,可以参考 \u003ca href=\"https://omgnull.github.io/go-benchmark/buffer/\"\u003ehttps://omgnull.github.io/go-benchmark/buffer/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e建议大家了解一下\u003ccode\u003e[fasthttp](https://github.com/valyala/fasthttp)\u003c/code\u003e 这个库,性能要比直接使用内置的 \u003ccode\u003enet/http\u003c/code\u003e 高出很多,其主要原因是大量的用到了缓存池 \u003ccode\u003esync.Pool\u003c/code\u003e 进行性能提升。\u003c/p\u003e\n\u003ch2 id=\"用法\"\u003e用法\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// https://github.com/valyala/bytebufferpool/blob/18533face0/bytebuffer_example_test.go\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epackage\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ebytebufferpool_test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fmt\u0026#34; …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
April 26, 2021
docker如何利用cgroup对容器资源进行限制
"\u003cp\u003e在容器里有两个非常重要的概念,一个是 \u003ccode\u003enamespace\u003c/code\u003e 用来实现对容器里所有进程进行隔离;另一个就是 \u003ccode\u003ecgroup\u003c/code\u003e,用来对容器进程内使用资源进行限制。那 \u003ccode\u003ecgroup\u003c/code\u003e 又是如何实现对资源进行限制的呢,今天我们来了解一下它的实现原理。\u003c/p\u003e\n\u003ch2 id=\"什么是cgroup\"\u003e什么是cgroup\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003ecgroup\u003c/code\u003e 是 \u003ccode\u003eControl Groups\u003c/code\u003e 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离 进程组 所使用的物理资源(如 cpu、memory、磁盘IO等等) 的机制,被 \u003ccode\u003eLXC\u003c/code\u003e、\u003ccode\u003edocker\u003c/code\u003e 等很多项目用于实现进程资源控制。cgroup 是将任意进程进行分组化管理的 Linux 内核功能。\n\u003ccode\u003ecgroup\u003c/code\u003e 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。 一定要切记,这里的限制单元为 \u003ccode\u003e进程组\u003c/code\u003e,而不是进程。\u003c/p\u003e\n\u003ch2 id=\"子系统\"\u003e子系统\u003c/h2\u003e\n\u003cp\u003e上面提到的具体的资源管理功能统称为 cgroup \u003ccode\u003e子系统\u003c/code\u003e,所有子系统列表可以通过 \u003ccode\u003ecat /proc/cgroups\u003c/code\u003e 命令查看,主要有以下几大子系统:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e# cat /proc/cgroups\n#subsys_name\thierarchy …\u003c/code\u003e\u003c/pre\u003e"
April 12, 2021
Golang 内存组件之mspan、mcache、mcentral 和 mheap 数据结构
"\u003cp\u003eGolang中的内存组件关系如下图所示\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/04/5a666325bb7cfea6f5182e0ee7c528cf.jpg\" alt=\"components of memory allocation\"\u003egolang 内存分配组件\u003c/p\u003e\n\u003cp\u003e在学习golang 内存时,经常会涉及几个重要的数据结构,如果不熟悉它们的情况下,理解起来就显得格外的吃力,所以本篇主要对相关的几个内存组件做下数据结构的介绍。\u003c/p\u003e\n\u003cp\u003e在 Golang 中,\u003ccode\u003emcache\u003c/code\u003e、\u003ccode\u003emspan\u003c/code\u003e、\u003ccode\u003emcentral\u003c/code\u003e 和 \u003ccode\u003emheap\u003c/code\u003e 是内存管理的四大组件,\u003ccode\u003emcache\u003c/code\u003e 管理线程在本地缓存的 \u003ccode\u003emspan\u003c/code\u003e,而 \u003ccode\u003emcentral\u003c/code\u003e 管理着全局的 \u003ccode\u003emspan\u003c/code\u003e 为所有 \u003ccode\u003emcache\u003c/code\u003e 提供所有线程。\u003c/p\u003e\n\u003cp\u003e根据分配对象的大小,内部会使用不同的内存分配机制,详细参考函数 \u003ca href=\"https://github.com/golang/go/blob/go1.16.2/src/runtime/malloc.go#L902-L1171\"\u003emallocgo()\u003c/a\u003e ,所于内存分配与回收,参考文件介绍 \u003ca href=\"https://github.com/golang/go/blob/go1.16.2/src/runtime/malloc.go#L5\"\u003emalloc.go\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e\u0026lt;16KB\u003c/code\u003e 会使用微小对象内存分配器从 \u003ccode\u003eP\u003c/code\u003e 中的 \u003ccode\u003emcache\u003c/code\u003e 分配,主要使用 \u003ccode\u003emcache.tinyXXX\u003c/code\u003e 这类的字段\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e16-32KB\u003c/code\u003e 从 \u003ccode\u003eP\u003c/code\u003e 中的 \u003ccode\u003emcache\u003c/code\u003e 中分配\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026gt;32KB\u003c/code\u003e 直接从 \u003ccode\u003emheap\u003c/code\u003e 中分配\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对于golang中的内存申请流程,大家应该都非常熟悉了,这里不再进行详细描述。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/04/1bb7fe2168b7ac2e24afadf698dc6ee6.png\" alt=\"\"\u003eGolang 内存组件关系\u003c/p\u003e\n\u003ch1 id=\"mcache\"\u003emcache\u003c/h1\u003e\n\u003cp\u003e在GPM关系中,会在每个 \u003ccode\u003eP …\u003c/code\u003e\u003c/p\u003e"
April 9, 2021
GC 对根对象扫描实现的源码分析
"\u003ch1 id=\"工作池gcwork\"\u003e工作池gcWork\u003c/h1\u003e\n\u003cp\u003e工作缓存池(\u003ccode\u003ework pool\u003c/code\u003e)实现了生产者和消费者模型,用于指向灰色对象。一个灰色对象在工作队列中被扫描标记,一个黑色对象表示已被标记不在队列中。\u003c/p\u003e\n\u003cp\u003e写屏障、根发现、栈扫描和对象扫描都会生成一个指向灰色对象的指针。扫描消费时会指向这个灰色对象,从而将先其变为黑色,再扫描它们,此时可能会产生一个新的指针指向灰色对象。这个就是三色标记法的基本知识点,应该很好理解。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003egcWork\u003c/code\u003e 是为垃圾回收器提供的一个生产和消费工作接口。\u003c/p\u003e\n\u003cp\u003e它可以用在stack上,如\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e(preemption must be disabled)\ngcw := \u0026amp;getg().m.p.ptr().gcw\n.. call gcw.put() to produce and gcw.tryGet() to consume ..\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在标记阶段使用gcWork可以防止垃圾收集器转换到标记终止,这一点很重要,因为gcWork可能在本地持有GC工作缓冲区。可以通过禁用抢占(\u003ccode\u003esystemstack\u003c/code\u003e 或 \u003ccode\u003eacquirem\u003c/code\u003e)来实现。\u003c/p\u003e\n\u003cp\u003e数据结构\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etype gcWork struct {\n\twbuf1, wbuf2 …\u003c/code\u003e\u003c/pre\u003e"
April 7, 2021
Runtime: Golang GC源码分析
"\u003cp\u003e在阅读此文前,需要先了解一下三色标记法以及混合写屏障这些概念。\u003c/p\u003e\n\u003cp\u003e源文件 \u003ccode\u003e[src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16/src/runtime/mgc.go)\u003c/code\u003e 版本 1.16.2。\u003c/p\u003e\n\u003ch1 id=\"基本知识\"\u003e基本知识\u003c/h1\u003e\n\u003cp\u003e在介绍GC之前,我们需要认识有些与GC相关的基本信息,如GC的状态、模式、统计信息等。\u003c/p\u003e\n\u003ch2 id=\"三种状态\"\u003e三种状态\u003c/h2\u003e\n\u003cp\u003e共有三种状态\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003econst (\n\t_GCoff = iota // GC not running; sweeping in background, write barrier disabled\n\t_GCmark // GC marking roots and workbufs: allocate black, write barrier ENABLED\n\t_GCmarktermination // GC mark termination: allocate black, P\u0026#39;s help GC, write barrier ENABLED\n) …\u003c/code\u003e\u003c/pre\u003e"
April 6, 2021
Golang中的切片与GC
"\u003cp\u003e今天再看 \u003ccode\u003etimer\u003c/code\u003e 源码的时候,在函数 \u003ccode\u003e[clearDeletedTimers()](https://github.com/golang/go/blob/go1.16.2/src/runtime/time.go#L904-L992)\u003c/code\u003e 里看到一段对切片的处理代码,实现目的就是对一个切片内容进行缩容。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// src/runtime/time.go\n\n// The caller must have locked the timers for pp.\nfunc clearDeletedTimers(pp *p) {\n\ttimers := pp.timers\n\t......\n\t// 对无用的切片元素赋值 nil\n\tfor i := to; i \u0026lt; len(timers); i++ {\n\t\ttimers[i] = nil\n\t}\n\n\tatomic.Xadd(\u0026amp;pp.deletedTimers, -cdel)\n\tatomic.Xadd(\u0026amp;pp.numTimers, -cdel)\n\tatomic.Xadd(\u0026amp;pp.adjustTimers, -cearlier) …\u003c/code\u003e\u003c/pre\u003e"
March 29, 2021
Runtime: Golang 定时器实现原理及源码解析
"\u003cp\u003e定时器作为开发经常使用的一种数据类型,是每个开发者需要掌握的,对于一个高级开发很有必要了解它的实现原理,今天我们runtime源码来学习一下它的底层实现。\u003c/p\u003e\n\u003cp\u003e定时器分两种,分别为 Timer 和 Ticker,两者差不多,这里重点以Timer为例。\u003c/p\u003e\n\u003cp\u003e源文件位于 \u003ccode\u003e[src/time/sleep.go](https://github.com/golang/go/blob/go1.16.2/src/time/sleep.go)\u003c/code\u003e 和 \u003ccode\u003e[src/time/tick.go](https://github.com/golang/go/blob/go1.16.2/src/time/tick.go)\u003c/code\u003e 。 go version 1.16.2\u003c/p\u003e\n\u003ch1 id=\"数据结构\"\u003e数据结构\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003eTimer\u003c/code\u003e 数据结构\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// src/runtime/sleep.go\n\n// The Timer type represents a single event.\n// When the Timer expires, the current time will be sent on C,\n// unless the Timer was created by …\u003c/code\u003e\u003c/pre\u003e"
March 28, 2021
Golang中的CAS原子操作 和 锁
"\u003cp\u003e在高并发编程中,经常会出现对同一个资源并发访问修改的情况,为了保证最终结果的正确性,一般会使用 \u003ccode\u003e锁\u003c/code\u003e 和 \u003ccode\u003eCAS原子操作\u003c/code\u003e 来实现。\u003c/p\u003e\n\u003cp\u003e如要对一个变量进行计数统计,两种实现方式分别为\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;sync\u0026#34;\n)\n\n// 锁实现方式\nfunc main() {\n\tvar count int64\n\tvar wg sync.WaitGroup\n\tvar mu sync.Mutex\n\n\tfor i := 0; i \u0026lt; 10000; i++ {\n\t\twg.Add(1)\n\t\tgo func(wg *sync.WaitGroup) {\n\t\t\tdefer wg.Done()\n\t\t\tmu.Lock()\n\t\t\tcount = count + 1\n\t\t\tmu.Unlock()\n\t\t}(\u0026amp;wg)\n\t}\n\twg.Wait()\n\n\t// count = 10000\n\tfmt.Println(\u0026#34;count = \u0026#34;, count)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e与\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport ( …\u003c/code\u003e\u003c/pre\u003e"
March 23, 2021
Golang并发同步原语之-信号量Semaphore
"\u003cp\u003e信号量是并发编程中比较常见的一种同步机制,它会保持资源计数器一直在\u003ccode\u003e0-N\u003c/code\u003e(\u003ccode\u003eN\u003c/code\u003e表示权重值大小,在用户初始化时指定)之间。当用户获取的时候会减少一点,使用完毕后再恢复过来。当遇到请求时资源不够的情况下,将会进入休眠状态以等待其它进程释放资源。\u003c/p\u003e\n\u003cp\u003e在 Golang 官方扩展库中为我们提供了一个基于权重的信号量 \u003ccode\u003e[semaphore](https://github.com/golang/sync/blob/master/semaphore/semaphore.go)\u003c/code\u003e 并发原语。\u003c/p\u003e\n\u003cp\u003e你可以将下面的参数 \u003ccode\u003en\u003c/code\u003e 理解为资源权重总和,表示每次获取时的权重;也可以理解为资源数量,表示每次获取时必须一次性获取的资源数量。为了理解方便,这里直接将其理解为资源数量。\u003c/p\u003e\n\u003ch2 id=\"数据结构\"\u003e数据结构\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003e[semaphoreWeighted](https://github.com/golang/sync/blob/master/semaphore/semaphore.go#L19-L33)\u003c/code\u003e 结构体\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etype waiter struct {\n\tn int64\n\tready chan\u0026lt;- struct{} // Closed …\u003c/code\u003e\u003c/pre\u003e"
March 22, 2021
学习Golang GC 必知的几个知识点
"\u003cp\u003e对于gc的介绍主要位于 \u003ccode\u003e[src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16.2/src/runtime/mgc.go)\u003c/code\u003e,以下内容是对注释的翻译。\u003c/p\u003e\n\u003ch2 id=\"gc-四个阶段\"\u003eGC 四个阶段\u003c/h2\u003e\n\u003cp\u003e通过源文件注释得知GC共分四个阶段:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eGC 清理终止 (\u003ccode\u003eGC performs sweep termination\u003c/code\u003e)\na. \u003ccode\u003eStop the world\u003c/code\u003e, 每个P 进入GC \u003ccode\u003esafepoint\u003c/code\u003e(安全点),从此刻开始,万物静止。\nb. 清理未被清理的span,如果GC被强制执行时才会出现这些未清理的span\u003c/li\u003e\n\u003cli\u003eGC 标记阶段(\u003ccode\u003eGC performs the mark phase\u003c/code\u003e)\na. 将gc标记从 \u003ccode\u003e_GCoff\u003c/code\u003e 修改为 \u003ccode\u003e_GCmark\u003c/code\u003e,开启写屏障(\u003ccode\u003ewrite barries\u003c/code\u003e)和 协助助手(\u003ccode\u003emutator assists\u003c/code\u003e),将根对象放入队列。 在STW期间,在所有P都启用写屏障之前不会有什么对象被扫描。\nb. \u003ccode\u003eStart the world\u003c/code\u003e(恢复STW)。标记工作线程和协助助手并发的执行。对于任何指针的写操作和指针值,都会被写屏障覆盖,使新分配的对象标记为黑 …\u003c/li\u003e\u003c/ol\u003e"
March 20, 2021
Runtime: Golang 之 sync.Pool 源码分析
"\u003cp\u003ePool 指一组可以单独保存和恢复的 \u003ccode\u003e临时对象\u003c/code\u003e。Pool 中的对象随时都有可能在没有收到任何通知的情况下被GC自动销毁移除。\u003c/p\u003e\n\u003cp\u003e多个goroutine同时操作Pool是\u003ccode\u003e并发安全\u003c/code\u003e的。\u003c/p\u003e\n\u003cp\u003e源文件为 \u003ccode\u003e[src/sync/pool.go](https://github.com/golang/go/blob/master/src/sync/pool.go)\u003c/code\u003e go version: 1.16.2\u003c/p\u003e\n\u003ch1 id=\"为什么使用pool\"\u003e为什么使用Pool\u003c/h1\u003e\n\u003cp\u003e在开发高性能应用时,经常会有一些完全相同的对象需要频繁的创建和销毁,每次创建都需要在堆中分配对象,等使用完毕后,这些对象需要等待GC回收。我们知道在Golang中使用三色标记法进行垃圾回收的,在回收期间会有一个短暂\u003ccode\u003eSTW\u003c/code\u003e(stop the world)的时间段,这样就会导致程序性能下降。\u003c/p\u003e\n\u003cp\u003e那么能否实现类似数据库连接池这种效果,用来避免对象的频繁创建和销毁,达到尽可能的资源复用呢?为了实现这种需求,标准库中有了\u003ccode\u003esync.Pool\u003c/code\u003e 这个数据结构。看名字很知道它是一个池。但是它和我们想象中的数据库连接池还是有些差别的。对于数据库连接池这种资源只要不手动释放就可以一直利用, …\u003c/p\u003e"
March 19, 2021
Runtime: Golang同步原语Mutex源码分析
"\u003cp\u003e在 \u003ccode\u003esync\u003c/code\u003e 包里提供了最基本的同步原语,如互斥锁 \u003ccode\u003eMutex\u003c/code\u003e。除 \u003ccode\u003eOnce\u003c/code\u003e 和 \u003ccode\u003eWaitGroup\u003c/code\u003e 类型外,大部分是由低级库提供的,更高级别的同步最好是通过 \u003ccode\u003echannel\u003c/code\u003e 通讯来实现。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eMutex\u003c/code\u003e 类型的变量默认值是未加锁状态,在第一次使用后,此值将\u003ccode\u003e不得\u003c/code\u003e复制,这点切记!!!\u003c/p\u003e\n\u003cp\u003e本文基于go version: 1.16.2\u003c/p\u003e\n\u003cp\u003eMutex 锁实现了 \u003ccode\u003eLocker\u003c/code\u003e 接口。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// A Locker represents an object that can be locked and unlocked.\ntype Locker interface {\n\tLock()\n\tUnlock()\n}\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"锁的模式\"\u003e锁的模式\u003c/h2\u003e\n\u003cp\u003e为了互斥公平性,Mutex 分为 \u003ccode\u003e正常模式\u003c/code\u003e 和 \u003ccode\u003e饥饿模式\u003c/code\u003e 两种。\u003c/p\u003e\n\u003ch3 id=\"正常模式\"\u003e正常模式\u003c/h3\u003e\n\u003cp\u003e在正常模式下,等待者 \u003ccode\u003ewaiter\u003c/code\u003e 会进入到一个\u003ccode\u003eFIFO\u003c/code\u003e队列,在获取锁时\u003ccode\u003ewaiter\u003c/code\u003e会按照先进先出的顺序获取。当唤醒一个\u003ccode\u003ewaiter\u003c/code\u003e 时它被并不会立即获取锁,而是要与\u003ccode\u003e新来的goroutine\u003c/code\u003e竞争,这种情况下新来的goroutine比较有优势,主要是因为它已经运行在CPU,可能它的数量还不少,所以\u003ccode\u003ewaiter\u003c/code\u003e大概率下获取不到 …\u003c/p\u003e"
March 5, 2021
Golang什么时候会触发GC
"\u003cp\u003eGolang采用了三色标记法来进行垃圾回收,那么在什么场景下会触发这个GC动作呢?\u003c/p\u003e\n\u003cp\u003e源码主要位于文件 \u003ccode\u003e[src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16/src/runtime/mgc.go)\u003c/code\u003e go version 1.16\u003c/p\u003e\n\u003cp\u003e触发条件从大方面来说,分为 \u003ccode\u003e手动触发\u003c/code\u003e 和 \u003ccode\u003e系统触发\u003c/code\u003e 两种方式。手动触发一般很少用,主要通过开发者调用 \u003ccode\u003eruntime.GC()\u003c/code\u003e 函数来实现,而对于系统自动触发是 \u003ccode\u003e运行时\u003c/code\u003e 根据一些条件自行维护的,这也正是本文要介绍的内容。\u003c/p\u003e\n\u003cp\u003e不管哪种触发方式,底层回收机制是一样的,所以我们先看一下手动触发,看看能否根据它来找GC触发所需的条件。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// src/runtime/mgc.go\n\n// GC runs a garbage collection and blocks the caller until the\n// garbage collection is complete. It may also block the entire\n// program.\nfunc GC() {\n\tn := …\u003c/code\u003e\u003c/pre\u003e"
March 4, 2021
Golang 基于信号的异步抢占与处理
"\u003cp\u003e在Go1.14版本开始实现了 \u003ccode\u003e基于信号的协程抢占调度\u003c/code\u003e 模式,在此版本以前执行以下代码是永远也无法执行最后一条println语句。\u003c/p\u003e\n\u003cp\u003e本文基于go version 1.16\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;runtime\u0026#34;\n \u0026#34;time\u0026#34;\n)\n\nfunc main() {\n runtime.GOMAXPROCS(1)\n go func() {\n for {\n }\n }()\n\n time.Sleep(time.Millisecond)\n println(\u0026#34;OK\u0026#34;)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e原因很简单:在main函数里只有一个CPU,从上到下执行到 \u003ccode\u003etime.Sleep()\u003c/code\u003e 函数的时候,会将 \u003ccode\u003emain goroutine\u003c/code\u003e 放入运行队列,出让了P,开始执行匿名函数,但匿名函数是一个for循环,没有任何 \u003ccode\u003eIO\u003c/code\u003e 语句,也就无法引起对 \u003ccode\u003eG\u003c/code\u003e 的调度,所以当前仅有的一个 \u003ccode\u003eP\u003c/code\u003e 永远被其占用,导致无法打印OK。\u003c/p\u003e\n\u003cp\u003e这个问题在1.14版本开始有所改变,主要是因为引入了\u003ccode\u003e基于信号的抢占模式\u003c/code\u003e。在程序启动 …\u003c/p\u003e"
March 1, 2021
Golang 的调度策略之G的窃取
"\u003cp\u003e我们上篇文章( \u003ca href=\"https://blog.haohtml.com/archives/21411\"\u003eGolang 的底层引导流程/启动顺序\u003c/a\u003e)介绍了一个golang程序的启动流程,在文章的最后对于最重要的一点“\u003ccode\u003e调度\u003c/code\u003e“ (函数 \u003ccode\u003e[schedule()](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L2607-L2723)\u003c/code\u003e) 并没有展开来讲,今天我们继续从源码来分析一下它的调度机制。\u003c/p\u003e\n\u003cp\u003e在此之前我们要明白golang中的调度主要指的是什么?在 \u003ccode\u003esrc/runtime/proc.go\u003c/code\u003e 文件里有一段注释这样写到\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e// Goroutine scheduler\u003c/p\u003e\n\u003cp\u003e// The scheduler’s job is to distribute ready-to-run goroutines over worker threads.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这里指如何找一个已准备好运行的 G 关联到PM 让其执行。对于G 的调度可以围绕三个方面来理解:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e时机:什么时候关联(调度)。对于调度时机一般是指有空闲P的时候都会去找G执行\u003c/li\u003e\n\u003cli\u003e对象:选择哪个G进行调度。这是我们本篇要讲的内容\u003c/li\u003e\n\u003cli\u003e机制:如何调度。\u003ccode\u003eexecute()\u003c/code\u003e 函数\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e理解 …\u003c/p\u003e"
February 27, 2021
Runtime: Golang是如何处理系统调用阻塞的?
"\u003cp\u003e我们知道在Golang中,当一个Goroutine由于执行 \u003ccode\u003e系统调用\u003c/code\u003e 而阻塞时,会将M从GPM中分离出去,然后P再找一个G和M重新执行,避免浪费CPU资源,那么在内部又是如何实现的呢?今天我们还是通过学习Runtime源码的形式来看下他的内部实现细节有哪些?\u003c/p\u003e\n\u003cp\u003ego version 1.15.6\u003c/p\u003e\n\u003cp\u003e我们知道一个P有四种运行状态,而当执行系统调用函数阻塞时,会从 \u003ccode\u003e_Prunning\u003c/code\u003e 状态切换到 \u003ccode\u003e_Psyscall\u003c/code\u003e,等系统调用函数执行完毕后再切换回来。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/01/0d20dfce0e3dd6968aebe84535b853c6.png\" alt=\"P的状态切换\"\u003eP的状态切换\u003c/p\u003e\n\u003cp\u003e从上图我们可以看出 \u003ccode\u003eP\u003c/code\u003e 执行系统调用时会执行 \u003ccode\u003e[entersyscall()](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L3134-L3142)\u003c/code\u003e 函数(另还有一个类似的阻塞函数 \u003ca href=\"https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L3171-L3212\"\u003e\u003ccode\u003eentersyscallblock()\u003c/code\u003e\u003c/a\u003e ,注意两者的区别)。当系统调用执行完毕切换回去会执行 \u003ca href=\"https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L3222-L3305\"\u003e\u003ccode\u003eexitsyscall()\u003c/code\u003e\u003c/a\u003e 函数,下面我们看一下这两个函数的实现。\u003c/p\u003e\n\u003ch1 id=\"进入系统调用\"\u003e进入系统调用\u003c/h1\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// Standard syscall entry used by the go syscall …\u003c/code\u003e\u003c/pre\u003e"
February 26, 2021
Runtime: 当一个goroutine 运行结束后会发生什么
"\u003cp\u003e上一篇我们介绍了 \u003ca href=\"https://blog.haohtml.com/archives/23168\"\u003e创建一个goroutine 会经历些什么\u003c/a\u003e,今天我们再看下当一个\u003ccode\u003egoroutine\u003c/code\u003e 运行结束的时候,又会发生什么?\u003c/p\u003e\n\u003cp\u003ego version 1.15.6。\u003c/p\u003e\n\u003cp\u003e主要源文件为 \u003ccode\u003e[src/runtime/proc.go](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go)\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e当一个\u003ccode\u003egoroutine\u003c/code\u003e 运行结束的时候,默认会执行一个 \u003ccode\u003e[goexit1()](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L2941-L2950)\u003c/code\u003e 的函数,这是一个只有八行代码的函数,其中最后以通过 \u003ccode\u003e[mcall()](https://github.com/golang/go/blob/go1.15.6/src/runtime/stubs.go#L34)\u003c/code\u003e 调用 \u003ccode\u003e[goexit0](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L2952-L3011)\u003c/code\u003e 函数结束。因此我们主 …\u003c/p\u003e"
February 17, 2021
Runtime: 创建一个goroutine都经历了什么?
"\u003cp\u003e我们都知道goroutine的在golang中发挥了很大的作用,那么当我们创建一个新的goroutine时,它是怎么一步一步创建的呢?都经历了哪些操作呢?今天我们通过源码来剖析一下创建goroutine都经历了些什么?go version 1.15.6\u003c/p\u003e\n\u003cp\u003e对goroutine最关键的两个函数是 \u003ccode\u003e[newproc()](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L3535-L3564)\u003c/code\u003e 和 \u003ccode\u003e[newproc1()](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L3566-L3674)\u003c/code\u003e,而 \u003ccode\u003enewproc1()\u003c/code\u003e 函数是我们最需要关注的。\u003c/p\u003e\n\u003ch2 id=\"函数-newproc\"\u003e函数 newproc()\u003c/h2\u003e\n\u003cp\u003e我们先看一个简单的创建goroutine的例子,找出来创建它的函数。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nfunc start(a, b, c int64) {\n\t_ = a + b + c\n}\n\nfunc main() {\n\tgo start(7, 2, 5)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e输出结果: …\u003c/p\u003e"
February 15, 2021
Runtime: 理解Golang中接口interface的底层实现
"\u003cp\u003e接口类型是Golang中是一种非常非常常见的\u003ccode\u003e数据类型\u003c/code\u003e,每个开发人员都很有必要知道它到底是如何使用的,如果了解了它的底层实现就对开发就更有帮助了。\u003c/p\u003e\n\u003ch1 id=\"接口的定义\"\u003e接口的定义\u003c/h1\u003e\n\u003cp\u003e在Golang中 \u003ccode\u003einterface\u003c/code\u003e 通常是指实现了一 组抽象方法的集合,它提供了一种无侵入式的方式。当你实现了一个接口中指定的所有方法的时候,那么就实现了这个接口,在Golang中对它的实现并不需要 \u003ccode\u003eimplements\u003c/code\u003e 关键字。\u003c/p\u003e\n\u003cp\u003e有时候我们称这种模型叫做鸭子模型(Duck typing),维基百科对鸭子模型的定义是\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e”If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.“\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e翻译过来就是 ”如果它看起来像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那他就可以认为是鸭子“。\u003c/p\u003e\n\u003cp\u003eGo 不同版本之间interface的结构可能不太一样,但整体都差不多,这里使用的Go版本为 1.15.6。\u003c/p\u003e\n\u003ch1 id=\"数据结构\"\u003e数据结构\u003c/h1\u003e\n\u003cp\u003eGo 中 \u003ccode\u003einterface\u003c/code\u003e 在运行时可分 \u003ccode\u003eeface\u003c/code\u003e 和 \u003ccode\u003eiface\u003c/code\u003e 两种数据结构,我们先看一下对它们的 …\u003c/p\u003e"
February 13, 2021
认识Golang中的sysmon监控线程
"\u003cp\u003eGo Runtime 在启动程序的时候,会创建一个独立的 \u003ccode\u003eM\u003c/code\u003e 作为监控线程,称为 \u003ccode\u003esysmon\u003c/code\u003e,它是一个系统级的 \u003ccode\u003edaemon\u003c/code\u003e 线程。这个\u003ccode\u003esysmon\u003c/code\u003e 独立于 GPM 之外,也就是说不需要P就可以运行,因此官方工具 \u003ccode\u003ego tool trace\u003c/code\u003e 是无法追踪分析到此线程( \u003ca href=\"https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L4639-L4760\"\u003e源码\u003c/a\u003e)。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/02/6ad0cfb3df2281110cf60630fcfb0e96.png\" alt=\"\"\u003esysmon\u003c/p\u003e\n\u003cp\u003e在程序执行期间 \u003ccode\u003esysmon\u003c/code\u003e 每隔 \u003ccode\u003e20us~10ms\u003c/code\u003e 轮询执行一次( \u003ca href=\"https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L4652-L4659\"\u003e源码\u003c/a\u003e),监控那些长时间运行的 G 任务, 然后设置其可以被强占的标识符,这样别的 \u003ccode\u003eGoroutine\u003c/code\u003e 就可以抢先进来执行。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// src/runtime/proc.go\n\n// forcegcperiod is the maximum time in nanoseconds between garbage\n// collections. If we go this long without a garbage collection, one\n// is forced to run.\n//\n// This is a variable for testing purposes. It normally doesn\u0026#39;t …\u003c/code\u003e\u003c/pre\u003e"
February 11, 2021
g0 特殊的goroutine
"\u003cp\u003e在上篇 \u003ca href=\"https://blog.haohtml.com/archives/21010\"\u003e《golang中G、P、M 和 sched 三者的数据结构》\u003c/a\u003e文章中,我们介绍了\u003ccode\u003eG\u003c/code\u003e、\u003ccode\u003eM\u003c/code\u003e 和 \u003ccode\u003eP\u003c/code\u003e 的数据结构,其中M结构体中第一个字段是 \u003ccode\u003eg0\u003c/code\u003e,这个字段也是一个 \u003ccode\u003egoroutine\u003c/code\u003e,但和普通的 \u003ccode\u003egoroutine\u003c/code\u003e 有一些区别,它主要用来实现对 goroutine 进行调度,下面我们将介绍它是如何实现调度goroutine的。\u003c/p\u003e\n\u003cp\u003e另外还有一个 \u003ccode\u003em0\u003c/code\u003e , 它是一个全局变量,与 \u003ccode\u003eg0\u003c/code\u003e 的区别如下\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/03/8e229b7806870bf4f17da207665b8a43.jpg\" alt=\"\"\u003eM0 与 g0的区别\u003c/p\u003e\n\u003cp\u003e本文主要翻译自 \u003ca href=\"https://medium.com/a-journey-with-go/go-g0-special-goroutine-8c778c6704d8\"\u003eGo: g0, Special Goroutine\u003c/a\u003e 一文,有兴趣的可以查阅原文,作者有一系列高质量的文章推荐大家都阅读一遍。ℹ️ 本文基于 Go 1.13。\u003c/p\u003e\n\u003cp\u003e我们知道在Golang中所有的\u003ccode\u003egoroutine\u003c/code\u003e的运行都是由\u003ccode\u003e调度器\u003c/code\u003e来负责管理的,go调度器尝试为所有的\u003ccode\u003egoroutine\u003c/code\u003e来分配运行时间,当有\u003ccode\u003egoroutine\u003c/code\u003e被阻塞或终止时,调度器会通过对\u003ccode\u003egoroutine\u003c/code\u003e 进行调度以此来保证所有CPU都处于忙碌状态,避免有CPU空闲状态浪费时间。\u003c/p\u003e\n\u003ch2 id=\"goroutine-切换规则\"\u003egoroutine 切换规则\u003c/h2\u003e\n\u003cp\u003e在此之前我们需要记住一些goroutine切换规则。runtime源码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// …\u003c/code\u003e\u003c/pre\u003e"
January 26, 2021
Golang环境变量之GODEBUG
"\u003cp\u003e\u003ccode\u003eGODEBUG\u003c/code\u003e 是 golang中一个控制runtime调度变量的变量,其值为一个用逗号隔开的 name=val对列表,常见有以下几个命名变量。\u003c/p\u003e\n\u003ch2 id=\"allocfreetrace\"\u003eallocfreetrace\u003c/h2\u003e\n\u003cp\u003e设置\u003ccode\u003eallocfreetrace = 1\u003c/code\u003e会导致对每个分配进行概要分析,并在每个对象的分配上打印堆栈跟踪并释放它们。\u003c/p\u003e\n\u003ch2 id=\"clobberfree\"\u003eclobberfree\u003c/h2\u003e\n\u003cp\u003e设置 \u003ccode\u003eclobberfree=1\u003c/code\u003e会使垃圾回收器在释放对象的时候,对象里的内存内容可能是错误的。\u003c/p\u003e\n\u003ch2 id=\"cgocheck\"\u003ecgocheck\u003c/h2\u003e\n\u003cp\u003ecgo相关。\u003c/p\u003e\n\u003cp\u003e设置 \u003ccode\u003ecgocheck=0\u003c/code\u003e 将禁用当包使用cgo非法传递给go指针到非go代码的检查。如果值为1(默认值)会启用检测,但可能会丢失有一些错误。如果设置为2的话,则不会丢失错误。但会使程序变慢。\u003c/p\u003e\n\u003ch2 id=\"efence\"\u003eefence\u003c/h2\u003e\n\u003cp\u003e设置 \u003ccode\u003eefence=1\u003c/code\u003e会使回收器运行在一个模式。每个对象都在一个唯一的页和地址,且永远也不会被回收。\u003c/p\u003e\n\u003ch2 id=\"gccheckmark\"\u003egccheckmark\u003c/h2\u003e\n\u003cp\u003eGC相关。\u003c/p\u003e\n\u003cp\u003e设置 \u003ccode\u003egccheckmark=1\u003c/code\u003e 启用验证垃圾回收器的并发标记,通过在STW时第二个标记阶段来实现,如果在第二阶段的时候,找到一个可达对象,但未找到并发标记,则GC会发生Panic。\u003c/p\u003e\n\u003ch2 id=\"gcpacertrace\"\u003egcpacertrace …\u003c/h2\u003e"
January 26, 2021
Golang中MemStats的介绍
"\u003cp\u003e平时在开发中,有时间需要通过查看内存使用情况来分析程序的性能问题,经常会使用到 MemStats 这个结构体。但平时用到的都是一些最基本的方法,今天我们全面认识一下MemStas。\u003c/p\u003e\n\u003cp\u003e相关文件为 \u003ccode\u003esrc/runtime/mstats.go\u003c/code\u003e ,本文章里主要是与内存统计相关。\u003c/p\u003e\n\u003ch2 id=\"memstats-结构体\"\u003eMemStats 结构体\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// MemStats记录有关内存分配器的统计信息\ntype MemStats struct {\n\t// General statistics.\n\tAlloc uint64\n\tTotalAlloc uint64\n\tSys uint64\n\tLookups uint64\n\tMallocs uint64\n\tFrees uint64\n\n\t// Heap memory statistics.\n\tHeapAlloc uint64\n\tHeapSys uint64\n\tHeapIdle uint64\n\tHeapInuse uint64\n\tHeapReleased uint64\n\tHeapObjects uint64\n\n\t// Stack memory statistics.\n\tStackInuse uint64 …\u003c/code\u003e\u003c/pre\u003e"
January 25, 2021
Golang中Stack的管理
"\u003ch1 id=\"栈的演变\"\u003e栈的演变\u003c/h1\u003e\n\u003cp\u003e在 Go1.13之前的版本,Golang 栈管理是使用的\u003ccode\u003e分段栈(Segment Stacks)\u003c/code\u003e机制来实现的,由于sgement stack 存在 \u003ccode\u003e热分裂(hot split\u003c/code\u003e)的问题,后面版本改为采用\u003ccode\u003e连续栈( [Contiguous stacks](https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub))\u003c/code\u003e机制( \u003ca href=\"https://golang.org/doc/go1.3#stacks\"\u003e说明\u003c/a\u003e)。\u003c/p\u003e\n\u003ch2 id=\"分段栈segment-stack\"\u003e分段栈(Segment Stack)\u003c/h2\u003e\n\u003cp\u003e分段栈是指开始时只有一个stack,当需要更多的 stack 时,就再去申请一个,然后将多个stack 之间用双向链接连接在一起。当使用完成后,再将无用的 \u003ccode\u003estack\u003c/code\u003e 从链接中删除释放内存。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/01/d2b5ca33bd970f64a6301fa75ae2eb22-3.png\" alt=\"\"\u003esegment stack\u003c/p\u003e\n\u003cp\u003e可以看到这样确实实现了stack 按需增长和收缩,在增加新stack时不需要拷贝原来的数据,系统使用率挺高的。但在一定特别的情况下会存在 \u003ccode\u003e热分裂(hot split)\u003c/code\u003e 的问题。\u003c/p\u003e\n\u003cp\u003e当一个 stack 即将用完的时候,任意一个函数都会导致堆栈的扩容,当函数执行完返回后,又要触发堆栈的收缩。如果这个操作 …\u003c/p\u003e"
January 22, 2021
Golang 的底层引导流程/启动顺序
"\u003cp\u003e在Golang中,程序的执行入口为 \u003ccode\u003emain()\u003c/code\u003e 函数,那么底层又是如何工作的呢? 这个问题的答案我们可以在runtime源码找到。对它的解释主要在 \u003ccode\u003e[src/runtime/proc.go](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go)\u003c/code\u003e 文件,下面我们看一下它是如何一步一步开始执行的。go version 1.15.6\u003c/p\u003e\n\u003cp\u003e在文件头部有一段对 \u003ccode\u003e[Goroutine scheduler](https://github.com/golang/go/blob/go1.15.6/src/runtime/proc.go#L19)\u003c/code\u003e 的介绍,我们先了解一下。\u003c/p\u003e\n\u003cp\u003e调度器的工作是分发\u003ccode\u003egoroutines\u003c/code\u003e到工作线程让其运行。一句话指明了调度器的存在意义,就是指挥协调GPM干活。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e主要包含三部分\u003c/strong\u003e\n\u003ccode\u003eG\u003c/code\u003e 指的是 goroutine\n\u003ccode\u003eM\u003c/code\u003e 工作线程,也叫\u003ccode\u003emachine\u003c/code\u003e\n\u003ccode\u003eP\u003c/code\u003e 处理器(逻辑CPU),执行 \u003ccode\u003eGo code\u003c/code\u003e 的一种资源。这里的Go code 其实就是 goroutine里的代码。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eM\u003c/code\u003e必须被指派给\u003ccode\u003eP\u003c/code\u003e去执行 \u003ccode\u003eGo code\u003c/code\u003e, 但可以被 …\u003c/p\u003e"
January 21, 2021
golang中G、P、M 和 sched 三者的数据结构
"\u003cp\u003eG、P、M 三者是golang实现高并发能的最为重要的概念,\u003ccode\u003eruntime\u003c/code\u003e 通过 \u003ccode\u003e调度器\u003c/code\u003e 来实现三者的相互调度执行,通过 \u003ccode\u003ep\u003c/code\u003e 将用户态的 \u003ccode\u003eg\u003c/code\u003e 与内核态资源 \u003ccode\u003em\u003c/code\u003e 的动态绑定来执行,以减少以前通过频繁创建内核态线程而产生的一系列的性能问题,充分发挥服务器最大有限资源。\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/01/7c68d000148bf601267b43631c795bfd.png\" alt=\"\"\u003eGPM 协作\u003c/p\u003e\n\u003cp\u003e调度器的工作是将一个 G(需要执行的代码)、一个 M(代码执行的地方)和一个 P(代码执行所需要的权限和资源)结合起来。\u003c/p\u003e\n\u003cp\u003e所有的 g、m 和 p 对象都是分配在\u003ccode\u003e堆\u003c/code\u003e上且永不释放的,所以它们的内存使用是很稳定的。得益于此,runtime 可以在调度器实现中避免写屏障。当一个G执行完成后,可以放入pool中被再次使用,避免重复申请资源。\u003c/p\u003e\n\u003cp\u003e本节主要通过阅读runtime源码来认识这三个组件到底长的是什么样子,以此加深对 GPM 的理解。go version go1.15.6\u003c/p\u003e\n\u003cp\u003e理解下文前建议先阅读一下 \u003ccode\u003esrc/runtime/HACKING.md\u003c/code\u003e 文件,中文可阅读 \u003ca href=\"https://www.purewhite.io/2019/11/28/runtime-hacking-translate/\"\u003e这里\u003c/a\u003e,这个文件内容是面向开发者理解\u003ccode\u003eruntime\u003c/code\u003e的很值得看一看。\u003c/p\u003e\n\u003cp\u003e本文若没有指定源码文件路径,则默认为 \u003ccode\u003esrc/runtime/runtime2.go\u003c/code\u003e。\u003c/p\u003e\n\u003ch1 id=\"g\"\u003eG\u003c/h1\u003e\n\u003cp\u003eG …\u003c/p\u003e"
January 18, 2021
Runtime: Golang中channel实现原理源码分析
"\u003cp\u003echannel是golang中特有的一种数据结构,通常与goroutine一起使用,下面我们就介绍一下这种数据结构。\u003c/p\u003e\n\u003ch2 id=\"channel数据结构\"\u003echannel数据结构\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003echannel\u003c/code\u003e 是Golang 中最重要的一个数据结构,源码里对应的结构体是\u003ccode\u003ehchan\u003c/code\u003e,当我们创建一个\u003ccode\u003echannel\u003c/code\u003e 的时候,实际上是创建了一个\u003ccode\u003ehchan\u003c/code\u003e结构体。\u003c/p\u003e\n\u003ch3 id=\"hchan结构体\"\u003ehchan结构体\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// src/runtime/chan.go\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etype\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehchan\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003eqcount\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// total data in the queue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003edataqsiz\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// size of the circular queue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003ebuf\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eunsafe\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePointer\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// points to an array of dataqsiz elements\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003eelemsize\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint16\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003eclosed\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint32\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003eelemtype\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e_type\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// element type\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003esendx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// send index\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003erecvx\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euint\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
January 11, 2021
Runtime:源码解析Golang 的map实现原理
"\u003cp\u003ego version 1.15.6\u003c/p\u003e\n\u003cp\u003emap作为一种常见的 \u003ccode\u003ekey-value\u003c/code\u003e 数据结构,不同语言的实现原理基本差不多。首先在系统里分配一段连接的内存地址作为数组,然后通过对map键进行\u003ccode\u003ehash算法\u003c/code\u003e(最终将键转换成了一个整型数字)定位到不同的桶bucket(数组的索引位置),然后将值存储到对应的bucket里\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/01/7614fd6c619c3d1b07a787a82b19cad0.png\" alt=\"map hash算法\"\u003e\u003c/p\u003e\n\u003cp\u003e理想的情况下是一个\u003ccode\u003ebucket\u003c/code\u003e存储一个值,即数组的形式,时间复杂度为O(1)。\u003c/p\u003e\n\u003cp\u003e如果存在键值碰撞的话,可以通过 \u003ccode\u003e链表法\u003c/code\u003e 或者 \u003ccode\u003e开放寻址法\u003c/code\u003e 来解决。\u003c/p\u003e\n\u003cp\u003e链表法\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2021/01/57c223fe323d13755f7b47d3ad427fe1-1.png\" alt=\"d2b5ca33bd970f64a6301fa75ae2eb22-1\"\u003e\u003c/p\u003e\n\u003cp\u003e开放寻址法\u003c/p\u003e\n\u003cp\u003e对于开放寻址法有多种算法,常见的有线性探测法,线性补偿探测法,随机探测法等,这里不再介绍。\u003c/p\u003e\n\u003ch2 id=\"map基本数据结构\"\u003emap基本数据结构\u003c/h2\u003e\n\u003ch3 id=\"hmap结构体\"\u003ehmap结构体\u003c/h3\u003e\n\u003cp\u003emap的核心数据结构定义在 \u003ccode\u003e/runtime/map.go\u003c/code\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// A header for a Go map.\ntype hmap struct {\n\t// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.\n\t// Make sure this stays in sync …\u003c/code\u003e\u003c/pre\u003e"
December 26, 2020
Golang并发模式之扇入FAN-IN和扇出FAN-OUT
"\u003cp\u003e在现实世界中,经常有一些工作是属于流水线类型的,它们的每一个步骤都是紧密关联的,第一步先做什么,再做什么,最后做什么。特别是制造业这个行业,基本全是流水线生产车间。在我们开发中也经常遇到这类的业务场景。\u003c/p\u003e\n\u003cp\u003e假如我们有个流水线共分三个步骤,分别是 job1、job2和job3。代码: \u003ca href=\"https://play.golang.org/p/e7ZlP9ofXB3\"\u003ehttps://play.golang.org/p/e7ZlP9ofXB3\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epackage\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fmt\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;time\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ejob1\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003ecount\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003e\u0026lt;-\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003echan\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#a6e22e\"\u003eoutCh\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e make(\u003cspan style=\"color:#66d9ef\"\u003echan\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ego\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#66d9ef\"\u003edefer\u003c/span\u003e close(\u003cspan style=\"color:#a6e22e\"\u003eoutCh\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; \u003cspan style=\"color:#a6e22e\"\u003ei\u003c/span\u003e \u0026lt; \u003cspan style=\"color:#a6e22e\"\u003ecount\u003c/span\u003e; \u003cspan style=\"color:#a6e22e\"\u003ei\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#a6e22e\"\u003etime\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eSleep\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003etime\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eSecond\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#a6e22e\"\u003efmt\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePrintln\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;job1 finish:\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\t\u003cspan style=\"color:#a6e22e\"\u003eoutCh\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eoutCh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ejob2\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003einCh …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
December 24, 2020
重新认识Golang中的空结构体
"\u003col\u003e\n\u003cli\u003e认识空结构体\u003c/li\u003e\n\u003cli\u003e低层实现原理\u003c/li\u003e\n\u003cli\u003e空结构体之内存对齐\u003c/li\u003e\n\u003cli\u003e应用场景\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e在golang中,如果我们想实现一个set集合的话,一般会使用map来实现,其中将set的值作为map的键,对于map的值一般使用一个空结构体来实现,当然对map值也可以使用一个bool类型或者数字类型等,只要符合一个键值对应关系即可。但我们一般推荐使用struct{}来实现,为什么呢?\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\tm := make(map[int]struct{})\n\tm[1] = struct{}{}\n\tm[2] = struct{}{}\n\n\tif _, ok := m[1]; ok {\n\t\tfmt.Println(\u0026#34;exists\u0026#34;)\n\t}\n\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面这段代码是一个很简单的使用map实现的set功能,这里是采用空结构体struct{}来实现。\u003c/p\u003e\n\u003cp\u003e在分析为什么使用struct{}以前,我看先认识一个struct。\u003c/p\u003e\n\u003ch2 id=\"认识空结构体-struct\"\u003e认识空结构体 struct\u003c/h2\u003e\n\u003cp\u003e我们先看一个这段代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport ( …\u003c/code\u003e\u003c/pre\u003e"
December 17, 2020
Golang中的内存重排(Memory Reordering)
"\u003ch2 id=\"什么是内存重排\"\u003e什么是内存重排\u003c/h2\u003e\n\u003cp\u003e内存重排指的是内存的读/写指令重排。\u003c/p\u003e\n\u003ch2 id=\"为什么要内存重排\"\u003e为什么要内存重排\u003c/h2\u003e\n\u003cp\u003e为了提升程序执行效率,减少一些IO操作,一些硬件或者编译器会对程序进行一些指令优化,优化后的结果可能会导致程序编码时的顺序与代码编译后的先后顺序不一致。\u003c/p\u003e\n\u003cp\u003e就拿做饭场景来说吧,是先蒸米还是先炒菜,这两者是没有冲突的,编译器在编译时有可能与你要求的顺序不一样。\u003c/p\u003e\n\u003ch2 id=\"编译器重排\"\u003e编译器重排\u003c/h2\u003e\n\u003cp\u003e如下面这段代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eX = 0\nfor i in range(100):\n X = 1\n print X\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e要实现打印100次1,很显示在for里面每次都执行X=1语句有些浪费资源,如果将初始变量值修改为1,是不是要快的多。编译器也分析到了这一点,于是在编译时对代码做了以下优化\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eX = 1\nfor i in range(100):\n print X\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e最终输出结果是一样的,两段代码功能也一样。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e但是\u003c/strong\u003e如果此时有另一个线程里执行了一个 X=0 的赋值语句的话(两个线程同时运行),那么输出结果就可能与我们想要的不一样了。\u003c/p\u003e\n\u003cp\u003e优化前情况:第一个线程执行到了第3次print X 后,第二个线程执行了X=0,把X 的值进行了修改,结果就有可能是1110 …\u003c/p\u003e"
November 19, 2020
Golang中的并发原语 Singleflight
"\u003cp\u003e在Golang中有一个并发原语是 \u003ca href=\"https://pkg.go.dev/golang.org/x/sync/singleflight\"\u003eSingleflight\u003c/a\u003e,好像知道的开发者并不多。其中著名的 \u003ca href=\"https://github.com/golang/groupcache\"\u003ehttps://github.com/golang/groupcache\u003c/a\u003e 就用到了这个并发原语。\u003c/p\u003e\n\u003ch2 id=\"golang版本\"\u003eGolang版本\u003c/h2\u003e\n\u003cp\u003ego1.15.5\u003c/p\u003e\n\u003ch2 id=\"相关知识点\"\u003e相关知识点\u003c/h2\u003e\n\u003cp\u003emap、Mutex、channel、\u003c/p\u003e\n\u003ch2 id=\"使用场景\"\u003e使用场景\u003c/h2\u003e\n\u003cp\u003e一般用在对指定资源频繁操作的情况下,如高并发下的“缓存击穿”问题。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e缓存击穿:一个存在的key,在缓存过期的瞬间,同时有大量的请求过来,造成所有请求都去DB读取数据,这些请求都会击穿缓存到DB,造成瞬时DB请求量大、压力瞬间骤增,导致数据库负载过高,影响整个系统正常运行。(缓存击穿不同于 缓存雪崩 和 缓存穿透)\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e怎么理解这个原语呢,简单的讲就是将对同一个资源的多个请求合并为一个请求。\u003c/p\u003e\n\u003cp\u003e举例说明,假如当有10万个请求来获取同一个key的值的时候,正常情况下会执行10万次get操作。而使用singleflight并发语后,只需要首次的地个请求执行一次get操作就可以了,其它请求再过来时,只需要只需要等待即可。待执行结果返回后,再把结果分别返回给等待中的请求,每个请求再返回给客户端,由此看看,在一定的高 …\u003c/p\u003e"
September 27, 2020
Protobuf协议实现原理
"\u003cp\u003e\u003ccode\u003eprotobuf\u003c/code\u003e是Google开源的一款支持跨平台、语言中立的结构化数据描述和高性能序列化协议,此协议完全基于二进制,所以性能要远远高于JSON/XML。由于出色的传输性能因此常见于微服务之间的通讯,其中最为著名的是Google开源的 \u003ca href=\"https://grpc.io/\"\u003egRPC\u003c/a\u003e 框架。\u003c/p\u003e\n\u003cp\u003e那么protobuf是如何实现高性能的,又是如何实现数据的编码和解码的呢?\u003c/p\u003e\n\u003ch2 id=\"protobuf协议原理\"\u003eprotobuf协议原理\u003c/h2\u003e\n\u003cp\u003e基于128bits的数据存储方式(Base 128 Varints)\u003c/p\u003e\n\u003cp\u003eVarint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。\u003c/p\u003e\n\u003cp\u003e比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息\u003c/p\u003e\n\u003cp\u003eVarint 中的每个 byte 的最 …\u003c/p\u003e"
September 19, 2020
Golang开发中中使用GitHub私有仓库
"\u003cp\u003e私有仓库地址为\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egithub.com/cfanbo/websocket\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"一设置私有环境变量-goprivate\"\u003e一、设置私有环境变量 GOPRIVATE\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ go env -w GOPRIVATE=github.com/cfanbo/websocket\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e对于为什么需要设置 GOPRIMARY 变量,可以参考 \u003ca href=\"https://gocn.vip/topics/9904\"\u003e这里\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e对于GOPRIVATE值级别分为仓库级别和账号级别。\u003c/p\u003e\n\u003cp\u003e如果只有一个仓库,直接设置为仓库地址即可。如果有多个私有仓库的话,使用”,”分开,都在这个账号下,也可以将值设置为账号级别,这样账号下的所有私有仓库都可以正常访问。如 \u003ca href=\"http://github.com/cfanbo\"\u003ehttp://github.com/cfanbo\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如果不想每次都重新设置,我们也可以利用通配符,例如:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ go env -w GOPRIVATE=\u0026#34;*.example.com\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样子设置的话,所有模块路径为 example.com 的子域名(例如:git.example.com)都将不经过 Go module proxy 和 Go checksum database,需要注意的是不包括 example.com 本身。\u003c/p\u003e\n\u003cp\u003e国内用户访问仓库建议设置 GORPOXY …\u003c/p\u003e"
June 6, 2020
利用jenkins+github实现应用的自动部署及回滚
"\u003cp\u003e对于jenkins的介绍这里不再详细写了,此教程只是为了让大家对部署和回滚原理有所了解。\u003c/p\u003e\n\u003ch2 id=\"一创建项目\"\u003e一、创建项目\u003c/h2\u003e\n\u003cp\u003e点击左侧的“New Item”,输入项目名称,如 rollback-demo。\u003c/p\u003e\n\u003cp\u003e选中 ” 丢弃旧的构建(Discard old builds)”项,在“策略(Strategy” 选择”\u003cem\u003eLog Rotation\u003c/em\u003e“, 并输入保留的最大构建个数。\u003c/p\u003e\n\u003ch2 id=\"二常规配置-05a2833329fee18776c5682a1068d288\"\u003e二、常规配置 \u003cimg src=\"https://blogstatic.haohtml.com/uploads/2020/06/16e3bc0afb4cf3f179f02fc598c220cd.png\" alt=\"05a2833329fee18776c5682a1068d288\"\u003e\u003c/h2\u003e\n\u003cp\u003e设置参数,点击”\u003cem\u003eAdd Parameter\u003c/em\u003e“,依次选择 “\u003cem\u003eChoice Parameter\u003c/em\u003e” 和 “\u003cem\u003eString Parameter\u003c/em\u003e“这两,填写如下\u003cimg src=\"https://blogstatic.haohtml.com/uploads/2020/06/3193669cca6c1da1bdde929ec1666ff2.png\" alt=\"ac7d45c20f8b6777ab153ce75439dafb\"\u003e\u003c/p\u003e\n\u003cp\u003e这里的Name 项为参数名称,用户在操作的时候,会在deploy 和 rollback 两个值中选择一项。\u003c/p\u003e\n\u003ch2 id=\"三源码管理\"\u003e三、源码管理\u003c/h2\u003e\n\u003cp\u003e我们这里选择Git.并填写github.com上的项目地址,记得设置认证 Credentials。构建分支直接使用默认的 */master 即可以了。查看代码浏览器选择 githubweb,并填写项目的github地址。\u003c/p\u003e\n\u003ch2 id=\"四构建触发事件\"\u003e四、构建触发事件\u003c/h2\u003e\n\u003cp\u003e选择 “GitHub hook trigger for GITScm polling”,表示使用github webhook来 …\u003c/p\u003e"
May 27, 2020
golang中几种对goroutine的控制方法
"\u003cp\u003e我们先看一段代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc listen() {\n\tticker := time.NewTicker(time.Second)\n\tfor {\n\t\tselect {\n\t\tcase \u0026lt;-ticker.C:\n\t\t\tfmt.Println(time.Now())\n\t\t}\n\t}\n}\nfunc main() {\n\tgo listen()\n\ttime.Sleep(time.Second * 5)\n\tfmt.Println(\u0026#34;main exit\u0026#34;)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e非常简单的一个goroutine用法,想必每个gopher都看过的。\u003c/p\u003e\n\u003cp\u003e不过在实际生产中,我们几乎看不到这种用法的的身影,原因很简单,我们无法实现对goroutine的控制,而一般业务中我们需要根据不同情况对goroutine进行各种操作。\u003c/p\u003e\n\u003cp\u003e要实现对goroutine的控制,一般有以下两种。\u003c/p\u003e\n\u003ch2 id=\"一手动发送goroutine控制信号\"\u003e一、手动发送goroutine控制信号\u003c/h2\u003e\n\u003cp\u003e这里我们发送一个退出goroutine的信号。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// listen 利用只读chan控制goroutine的退出\nfunc listen(ch \u0026lt;-chan bool) {\n\tticker := …\u003c/code\u003e\u003c/pre\u003e"
May 3, 2020
Golang遍历切片删除元素引起恐慌问题
"\u003cp\u003e删除一个切片的部分元素, 告知切片操作:\u003ca href=\"http://cn.voidcc.com/question/p-mkbvfagj-hy.html\"\u003eGolang遍历切片恐慌时删除元素\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"问题描述\"\u003e问题描述\u003c/h2\u003e\n\u003cp\u003e代码( \u003ca href=\"https://go.dev/play/p/Kyvo7YQuw1m\"\u003e演示代码\u003c/a\u003e):\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\tslice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}\n\tfor i, value := range slice {\n\t\tif value%3 == 0 { // remove 3, 6, 9\n\t\t\tslice = append(slice[:i], slice[i+1:]...)\n\t\t}\n\t}\n\tfmt.Printf(\u0026#34;%v\u0026#34;, slice)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行结果\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epanic: runtime error: slice bounds out of range [8:6]\n\ngoroutine 1 [running]:\nmain.main()\n\t/tmp/sandbox2635969259/prog.go:11 +0x212\n\nProgram exited.\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"解决办法\"\u003e\u003cstrong\u003e解决办法:\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e以下是网友想到的几种办法\u003c/p\u003e\n\u003cp\u003e1、使用\u003ccode\u003egoto\u003c/code\u003e和标签\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc …\u003c/code\u003e\u003c/pre\u003e"
April 30, 2020
Golang中select用法导致CPU占用100%的问题分析
"\u003cp\u003e上一节( \u003ca href=\"https://blog.haohtml.com/archives/19670\"\u003egolang中有关select的几个知识点\u003c/a\u003e)中介绍了一些对于select{}的一些用法,今天介绍一下有关select在 \u003ccode\u003efor语句\u003c/code\u003e 中由于使用不当引起的CPU占用100% 的案例。\u003c/p\u003e\n\u003cp\u003e先看代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\nfunc main() {\n\tch := make(chan int, 10)\n\t// 读取chan\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase i := \u0026lt;-ch:\n\t\t\t\t// 只读取15次chan\n\t\t\t\tfmt.Println(i)\n\t\t\tdefault:\n\t\t\t\t// 读取15次chan以后的操作一直在这个空语句无任何IO操作的default条件里死循环,无法出让P,以保证一个GPM关系。\n\t\t\t\t// 而如果无default条件的话,则系统当读取完15次chan后,当前goroutine会发生 chan IO 阻塞, Go调度器根据GPM的调度关系,会将当前执行关系中的G切换出去,再从LRQ队列中取一个新的G,重新组成一 …\u003c/code\u003e\u003c/pre\u003e"
April 21, 2020
基于 GitHub Actions 实现 Golang 项目的自动构建部署
"\u003cp\u003e前几天 GitHub官网宣布 GitHub 的所有核心功能对所有人都免费开放,不得不说自从微软收购了GitHub后,确实带来了一些很大的改变。\u003c/p\u003e\n\u003cp\u003e以前有些项目考虑到协作关系的原因,虽然放在github上面,但对于一些项目的持续构建和部署一般是通过自行抢建Travis CI、jenkins等系统来实现。虽然去年推出了Actions用来代替它类三方系统,但感觉着还是不方便,必须有些核心功能无法使用,此消息的发布很有可能将这种格局打破。\u003c/p\u003e\n\u003cp\u003e本篇教程将介绍使用github的系列产品来实现项目的发布,构建,测试和部署,当然这仅仅是一个非常小的示例,有些地方后期可能会有更好的瞿恩方案。\u003c/p\u003e\n\u003cp\u003eGitHub Actions 是一款持续集成工具,包括clone代码,代码构建,程序测试和项目发布等一系列操作。更多内容参考:\u003c/p\u003e\n\u003cp\u003e如果你对CI/CD不了解的话,建议先找些文档看看。\u003c/p\u003e\n\u003cp\u003e项目源文件见\u003c/p\u003e\n\u003ch2 id=\"github-actions-术语\"\u003eGitHub Actions 术语\u003c/h2\u003e\n\u003cp\u003eGitHub Actions 相关的术语。\u003c/p\u003e\n\u003cp\u003e(1)workflow (工作流程):持续集成一次运行的过程,就是一个 workflow。\u003c/p\u003e\n\u003cp\u003e(2)job (任务):一个 workflow 由一个或 …\u003c/p\u003e"
March 27, 2020
Golang中的限速器 time/rate
"\u003cp\u003e在高并发的系统中,限流已作为必不可少的功能,而常见的限流算法有:计数器、滑动窗口、令牌桶、漏斗(漏桶)。其中滑动窗口算法、令牌桶和漏斗算法应用最为广泛。\u003c/p\u003e\n\u003ch2 id=\"常见限流算法\"\u003e常见限流算法\u003c/h2\u003e\n\u003cp\u003e这里不再对 \u003ccode\u003e计数器算法\u003c/code\u003e 和 \u003ccode\u003e滑动窗口\u003c/code\u003e 算法一一介绍,有兴趣的同学可以参考其它相关文章。\u003c/p\u003e\n\u003ch3 id=\"漏斗算法\"\u003e漏斗算法\u003c/h3\u003e\n\u003cp\u003e漏斗算法很容易理解,它就像有一个漏斗容器一样,漏斗上面一直往容器里倒水(请求),漏斗下方以\u003cstrong\u003e固定速率\u003c/strong\u003e一直流出(消费)。如果漏斗容器满的情况下,再倒入的水就会溢出,此时表示新的请求将被丢弃。可以看到这种算法在应对大的突发流量时,会造成部分请求弃用丢失。\u003c/p\u003e\n\u003cp\u003e可以看出漏斗算法能强行限制数据的传输速率。\u003cimg src=\"https://blog.haohtml.com/wp-content/uploads/2020/03/rate-limit.png\" alt=\"\"\u003e漏斗算法\u003c/p\u003e\n\u003ch3 id=\"令牌桶算法\"\u003e令牌桶算法\u003c/h3\u003e\n\u003cp\u003e从某种意义上来说,令牌算法是对漏斗算法的一种改进。对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发情况。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。\u003c/p\u003e\n\u003cp\u003e令牌桶算法是指一个固定大小的桶,可以存放的令牌的最大个数也是固定的。此算法以一种\u003cstrong\u003e固定速率\u003c/strong\u003e不断的往桶中存放令牌,而每次请求调用前必须先从桶中获取令牌才可以。否则进行拒绝或等待,直到获取到有效令牌为止。如果桶内的令牌数量已达到桶的最 …\u003c/p\u003e"
March 19, 2020
Golang中的两个定时器 ticker 和 timer
"\u003cp\u003eGolang中time包有两个定时器,分别为 \u003ccode\u003eticker\u003c/code\u003e 和 \u003ccode\u003etimer\u003c/code\u003e。两者都可以实现定时功能,但各自都有自己的使用场景。\u003c/p\u003e\n\u003ch2 id=\"ticker定时器\"\u003eTicker定时器\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;time\u0026#34;\n)\n\nfunc main() {\n // Ticker 包含一个通道字段C,每隔时间段 d 就向该通道发送当时系统时间。\n // 它会调整时间间隔或者丢弃 tick 信息以适应反应慢的接收者。\n // 如果d \u0026lt;= 0会触发panic。关闭该 Ticker 可以释放相关资源。\n\n\tticker1 := time.NewTicker(5 * time.Second)\n\t// 一定要调用Stop(),回收资源\n\tdefer ticker1.Stop()\n\tgo func(t *time.Ticker) {\n\t\tfor {\n\t\t\t// 每5秒中从chan t.C 中读取一次\n\t\t\t\u0026lt;-t.C\n\t\t\tfmt.Println(\u0026#34;Ticker:\u0026#34;, …\u003c/code\u003e\u003c/pre\u003e"
March 4, 2020
认识虚拟内存
"\u003ch2 id=\"什么是虚拟内存\"\u003e什么是虚拟内存\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98/101812\"\u003e虚拟内存\u003c/a\u003e是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。\u003c/p\u003e\n\u003ch2 id=\"为什么需要虚拟内存\"\u003e为什么需要虚拟内存\u003c/h2\u003e\n\u003cp\u003e我们知道程序执行指令的时候,程序计数器是顺序地一条一条指令执行下去,这一条条指令就需要连续地存储在一起,所以就需要这块内存是连续的。物理内存是有限的,如果多个程序同时运行的话,访问同一个物理地址的话,就有可能内存地址冲突,怎么办呢?\u003c/p\u003e\n\u003cp\u003e这时就需要虚拟内存发挥的作用了,程序里有指令和各种内存地址,系统从物理内存申请一段地址,与这个程序指令里用到的内存地址建立映射关系,这样实际程序指令执行的时候,会通过虚拟内存地址,找到对应的物理内存地址执行。对于任何一个程序来说,它看到的都是同样的内存地址。我们只需要维护一个虚拟内存到物理内存的映射表即可。\u003c/p\u003e\n\u003cp\u003e这种从物理内存申请一段地址建立映射的方法,我们称其为\u003cstrong\u003e内存分段\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e看似解决了上面的问题,但这里又引起了新的问 …\u003c/p\u003e"
January 18, 2020
Golang中的变量逃逸问题 变量去哪了?
"\u003cp\u003e参考阅读 \u003ca href=\"https://mp.weixin.qq.com/s/ashgWyb-w4fT47xX60yNFA\"\u003ehttps://mp.weixin.qq.com/s/ashgWyb-w4fT47xX60yNFA\u003c/a\u003e\u003c/p\u003e"
January 18, 2020
Golang中关于defer语句理解的一道题
"\u003ch2 id=\"示例\"\u003e示例\u003c/h2\u003e\n\u003cp\u003e我们先看一下源代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc f(n int) (r int) {\n\tdefer func() {\n\t\tr += n\n\t\trecover()\n\t}()\n\n\tvar fc func()\n\tdefer fc()\n\tfc = func() {\n\t\tr += 2\n\t}\n\n\treturn n + 1\n}\n\nfunc main() {\n\tfmt.Println(f(3))\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e大家感觉着打印的值是多少呢?5、9还是7?执行完以后发现是7。好像与多数理解的有些出入,为什么是7,而不是9呢。下面我们来分析一下。\u003c/p\u003e\n\u003ch2 id=\"问题分析\"\u003e问题分析\u003c/h2\u003e\n\u003cp\u003e对于defer执行的顺序是FIFO这一点都很清楚,我们只需要看搞懂f()函数的执行顺序就行了。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e执行顺序为:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e注册第1个defer 函数, 这里为匿名函数,函数体为 “func() { r += n recover() }()”,内部对应一个函数指针。这里延时函数所有相关的操作一步完成。\u003c/li\u003e\n\u003cli\u003e注册第2个defer函数,函数名为fc(),无函数体, 函数指针为\u003cstrong\u003enil\u003c/strong\u003e(也有可能指针不会空,但指针指向的内容非函数体 …\u003c/li\u003e\u003c/ol\u003e"
January 15, 2020
开发者必知redis知识点
"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e剖析Redis常用数据类型对应的数据结构 \u003ca href=\"https://time.geekbang.org/column/article/79159\"\u003ehttps://time.geekbang.org/column/article/79159\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis中的COW(Copy-On-Write) \u003ca href=\"https://www.jianshu.com/p/b2fb2ee5e3a0\"\u003ehttps://www.jianshu.com/p/b2fb2ee5e3a0\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis常用有哪些数据类型及每种数据类型的使用场景有哪些 \u003ca href=\"https://www.cnblogs.com/tqlin/p/10478459.html\"\u003ehttps://www.cnblogs.com/tqlin/p/10478459.html\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果存储一个JSON数据时,选择hash还是string 存储数据? \u003ca href=\"https://segmentfault.com/a/1190000019552836\"\u003ehttps://segmentfault.com/a/1190000019552836\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis与memcache的区别 \u003ca href=\"https://www.cnblogs.com/JavaBlackHole/p/7726195.html\"\u003ehttps://www.cnblogs.com/JavaBlackHole/p/7726195.html\u003c/a\u003e \u003ca href=\"https://blog.csdn.net/qq_34126805/article/details/81748107\"\u003ehttps://blog.csdn.net/qq_34126805/article/details/81748107\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eredis支持多CPU吗?如何发挥多cpu? …\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"
January 14, 2020
golang中有关select的几个知识点
"\u003cp\u003egolang中的select语句格式如下\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eselect {\n case \u0026lt;-ch1:\n // 如果从 ch1 信道成功接收数据,则执行该分支代码\n case ch2 \u0026lt;- 1:\n // 如果成功向 ch2 信道成功发送数据,则执行该分支代码\n default:\n // 如果上面都没有成功,则进入 default 分支处理流程\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e可以看到select的语法结构有点类似于switch,但又有些不同。\u003c/p\u003e\n\u003cp\u003eselect里的case后面并不带判断条件,而是一个信道的操作,不同于switch里的case,对于从其它语言转过来的开发者来说有些需要特别注意的地方。\u003c/p\u003e\n\u003cp\u003egolang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注:Go 语言的 \u003ccode\u003eselect\u003c/code\u003e 语句借鉴自 Unix 的 \u003ccode\u003eselect()\u003c/code\u003e 函数,在 Unix 中,可以通过调用 \u003ccode\u003eselect()\u003c/code\u003e 函数来监控一系列的文件句柄, …\u003c/p\u003e\u003c/blockquote\u003e"
January 11, 2020
golang性能调优工具
"\u003cp\u003e\u003ca href=\"https://cloud.tencent.com/developer/article/1478198\"\u003eGODEBUG\u003c/a\u003e, 输出结果以gc 开头的表示进行了gc垃圾回收操作,后面的数字表示gc 的次数\u003cimg src=\"https://blog.haohtml.com/wp-content/uploads/2020/01/golang_gc.jpg\" alt=\"\"\u003e \u003ca href=\"https://www.jianshu.com/p/ba9f07a346d5\"\u003epprof\u003c/a\u003e\u003c/p\u003e"
January 11, 2020
golang中的sync.Pool对象缓存
"\u003ch2 id=\"参考文章\"\u003e参考文章\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://juejin.im/post/5b7678f451882533110e8948\"\u003eGolang 的 协程调度机制 与 GOMAXPROCS 性能调优\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.cnblogs.com/sunsky303/p/9706210.html\"\u003e深入Golang之sync.Pool详解\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.jianshu.com/p/494cda4db297\"\u003egolang sync.Pool 分析\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://juejin.im/post/5d006254e51d45776031afe3\"\u003e[译] Go: 理解 Sync.Pool 的设计\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e视频 \u003ca href=\"https://time.geekbang.org/course/detail/160-87731\"\u003esync.pool对象缓存\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"知识点\"\u003e知识点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003ePool只是一个缓存,一个缓存,一个缓存。由于生命周期受GC的影响,一定不要用于数据库连接池这类的应用场景,它只是一个缓存。\u003c/li\u003e\n\u003cli\u003egolang1.13版本对 \u003ca href=\"https://golang.org/pkg/sync/#Pool\"\u003ePool\u003c/a\u003e 进行了优化,结构体添加了两个字段 victim 和 victimSize。\u003c/li\u003e\n\u003cli\u003e适应于通过复用,降低复杂对象的创建和GC代价的场景\u003c/li\u003e\n\u003cli\u003e因为init()的时候会注册一个PoolCleanup函数,他会在gc时清除掉sync.Pool中的所有的缓存的对象。所以每个sync.Pool的生命周期为两次GC中间时段才有效,可以手动进行gc操作 \u003cstrong\u003eruntime.GC()\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e由于要保证协程安全,所以会有锁的开销\u003c/li\u003e\n\u003cli\u003e每个Pool都有一个私有池(协程安全)和共享池(\u003cstrong\u003e协程不安全\u003c/strong\u003e),其中私有池只有存放一个值。\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e每次Get()时会先从当前P的私有池private中获取( \u003ca href=\"https://studygolang.com/articles/11825\"\u003e类似MPG模型中的G\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e如果获 …\u003c/li\u003e\u003c/ol\u003e"
January 11, 2020
golang 的编程模式之“功能选项”
"\u003cp\u003e最近在用go重构iot中的一个服务时,发现库 \u003ca href=\"https://github.com/apache/rocketmq-client-go/releases/tag/v2.0.0-rc1\"\u003erocketmq-client-go@v2.0.0-rc1\u003c/a\u003e 在初始化消费客户端实现时,实现的极其优雅,代码见 \u003ca href=\"https://github.com/apache/rocketmq-client-go/blob/v2.0.0-rc1/examples/consumer/simple/main.go#L32\"\u003ehttps://github.com/apache/rocketmq-client-go/blob/v2.0.0-rc1/examples/consumer/simple/main.go#L32\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ec, _ := rocketmq.NewPushConsumer(\n consumer.WithGroupName(\u0026#34;testGroup\u0026#34;),\n consumer.WithNameServer([]string{\u0026#34;127.0.0.1:9876\u0026#34;}),\n)\nerr := c.Subscribe(\u0026#34;test\u0026#34;, consumer.MessageSelector{}, func(ctx context.Context,\n msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {\n for i := …\u003c/code\u003e\u003c/pre\u003e"
December 31, 2019
使用Dockerfile 多阶段构建Golang 应用
"\u003cp\u003edocker在开发和运维中使用的场景越来越多,作为开发人员非常有必要了解一些docker的基本知识,而离我们工作中最近的也就是对应用的docker部署编排了,小到一个dockerfile, docker-compse文件的编写,大到k8s的管理。这里我们以 golang应用为例讲解一些Dockerfile的基本用法,在ci/cd中经常用到这些知识。\u003c/p\u003e\n\u003ch1 id=\"前提\"\u003e前提\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003e项目清单:\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003edrwxr-xr-x 9 sxf staff 288 12 31 16:13 .\ndrwx------@ 17 sxf staff 544 12 31 14:59 ..\n-rw-r--r-- 1 sxf staff 14 12 31 16:09 .dockerignore\ndrwxr-xr-x 14 sxf staff 448 12 31 16:21 .git\n-rw-r--r-- 1 sxf staff 467 12 31 16:08 Dockerfile\n-rw-r--r-- 1 sxf staff 11 12 31 15:01 README.md …\u003c/code\u003e\u003c/pre\u003e"
November 8, 2019
Golang中的goroutine泄漏问题
"\u003cp\u003egoroutine作为Go中开发语言中的一大利器,在高并发中发挥着无法忽略的作用。但东西虽好,真正做到用好还是有一些要注意的地方,特别是对于刚刚接触这门开发语言的新手来说,稍有不慎,就极有可能导致goroutine 泄漏。\u003c/p\u003e\n\u003ch2 id=\"什么是goroutine-leak\"\u003e什么是goroutine Leak\u003c/h2\u003e\n\u003cp\u003egoroutine leak 的意思是go协程泄漏,那么什么又是协程泄漏呢?我们知道每次使用go关键字开启一个gorountine任务,经过一段时间的运行,最终是会结束,从而进行系统资源的释放回收。而如果由于操作不当导致一些goroutine一直处于阻塞状态或者永远运行中,永远也不会结束,这就必定会一直占用系统资源。最球的情况下是随着系统运行,一直在创建此类goroutine,那么最终结果就是程序崩溃或者系统崩溃。这种情况我们一般称为goroutine leak。\u003c/p\u003e\n\u003ch2 id=\"出现的问题\"\u003e出现的问题\u003c/h2\u003e\n\u003cp\u003e先看一段代码:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n \u0026#34;math/rand\u0026#34;\n \u0026#34;runtime\u0026#34;\n \u0026#34;time\u0026#34;\n)\n\nfunc query() …\u003c/code\u003e\u003c/pre\u003e"
August 12, 2019
一列说明数组与Hash效率的区别到底多大
"\u003cp\u003e在数组中添加 10000 个元素,然后分别对这 10000 个元素进行检索,最后统计检索的时间。\u003c/p\u003e\n\u003cp\u003e数组Array\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eimport time\n# 插入数据,数组\nresult = []\nfor i in range(10000):\n result.append(i)\n# 检索数据\ntime_start=time.time()\nfor i in range(10000):\n temp = result.index(i)\ntime_end=time.time()\nprint(\u0026#39;检索时间\u0026#39;, time_end-time_start)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行结果:\u003c/p\u003e\n\u003cp\u003e检索时间为 \u003cstrong\u003e1.2436728477478027\u003c/strong\u003e 秒。\u003c/p\u003e\n\u003cp\u003eHash哈希\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eimport time\n# 插入数据\nresult = {}\nfor i in range(1000000):\n result[i] = i\n# 检索数据\ntime_start=time.time()\nfor i in range(10000):\n temp = result[i]\ntime_end=time.time() …\u003c/code\u003e\u003c/pre\u003e"
July 11, 2019
golang内存对齐(进阶必看)
"\u003cp\u003e先看一个结构体\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// 写法一\ntype T1 struct {\n\ta int8\n\tb int64\n\tc int16\n}\n\n// 写法二\ntype T2 struct {\n\ta int8\n\tc int16\n\tb int64\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e对于这两个结构体,都有a、b、c三个定义完全一样的字段,只是在定义结构体的时候字段顺序不一样而已,那么两种写法有什么影响吗?\u003c/p\u003e\n\u003cp\u003e对于新手来说,感觉着没有什么区别的,只是一个书写顺序不同而已,但对于go编译器来说,则有着很大的区别,特别是在不同架构上(32位/64位)的编译器,在一定程度上对内存的使用大小和执行效率有着一定的不同。这里的主要知识点就是golang语言中的内存对齐概念(alignment guarantee),\u003c/p\u003e\n\u003ch2 id=\"类型的尺寸和结构体字节填充structure-padding\"\u003e类型的尺寸和结构体字节填充(structure padding)\u003c/h2\u003e\n\u003cp\u003eGo白皮书只对以下种类的类型的尺寸进行了\u003ca href=\"https://golang.google.cn/ref/spec#Size_and_alignment_guarantees\"\u003e明确规定\u003c/a\u003e。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e类型种类 尺寸(字节数)\n------ ------\nbyte, uint8, int8 1\nuint16, int16 2 …\u003c/code\u003e\u003c/pre\u003e"
March 23, 2019
goroutine和线程区别
"\u003cp\u003e从调度上看,goroutine的调度开销远远小于线程调度开销。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eOS的线程由OS内核调度,每隔几毫秒,一个硬件时钟中断发到CPU,CPU调用一个调度器内核函数\u003c/strong\u003e。这个函数暂停当前正在运行的线程,把他的寄存器信息保存到内存中(暂时保存线程状态),查看线程列表并决定接下来运行哪一个线程,再从内存中恢复线程的注册表信息,最后继续执行选中的线程。这种线程切换需要一个完整的上下文切换:即保存一个线程的状态到内存,再恢复另外一个线程的状态,最后更新调度器的数据结构。某种意义上,这种操作还是很慢的。\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/go_scheduler.png\" alt=\"\"\u003eOS 线程调度器\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGo运行的时候包涵一个自己的调度器\u003c/strong\u003e,这个调度器使用一个称为一个M:N调度技术,m个goroutine到n个os线程(可以用GOMAXPROCS来控制n的数量),\u003cstrong\u003eGo的调度器不是由硬件时钟来定期触发的,而是由特定的go语言结构来触发的\u003c/strong\u003e,他不需要切换到内核语境,所以调度一个goroutine比调度一个线程的成本低很多。\u003c/p\u003e\n\u003cp\u003e从栈空间上,goroutine的栈空间更加动态灵活。\u003c/p\u003e\n\u003cp\u003e每个OS的线程都有一个固定大小的栈内存,通常是2MB,栈内存用于保存在其他函数调用期间哪些正在执行或者临时暂停的函数的局部 …\u003c/p\u003e"
November 29, 2018
mac下安装python web框架django
"\u003cp\u003e\u003cstrong\u003e前提\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e由于mac自带的python2.7(路径 /usr/bin/python)\n后来手动又安装了python3.7(/usr/local/bin/python3)\u003c/p\u003e\n\u003cp\u003e两个版本共存。为了方便,直接在.zshrc文件里做了别名映射\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ealias python=\u0026#34;/usr/local/bin/python3.7\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e所以直接使用命令python实际上用的是3.7版本。\u003c/p\u003e\n\u003cp\u003e按照官方教程 \u003ca href=\"https://docs.djangoproject.com/zh-hans/2.1/intro/install/\"\u003ehttps://docs.djangoproject.com/zh-hans/2.1/intro/install/\u003c/a\u003e 安装django。发现在使用命令 pip install django 安装后发现检测不到django,很奇怪,后来发现了问题所在。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e➜ ~ python\nPython 3.7.1 (default, Nov 6 2018, 18:46:03)\n[Clang 10.0.0 (clang-1000.11.45.5)] on darwin\nType \u0026#34;help\u0026#34;, \u0026#34;copyright\u0026#34;, \u0026#34;credits\u0026#34; or …\u003c/code\u003e\u003c/pre\u003e"
November 27, 2018
Python中的装饰器decorator
"\u003cp\u003ePython中装饰器有些类似于java中的面向切片编程AOP的概念,就是对一些请求方法进行一些拦截,然后加入一些其实的逻辑。可以参与 \u003ca href=\"https://blog.csdn.net/caimouse/article/details/78078189\"\u003ehttps://blog.csdn.net/caimouse/article/details/78078189\u003c/a\u003e 这篇举的例子,很好理解。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://wiki.jikexueyuan.com/project/the-python-study-notes-second-edition/decorator.html\"\u003ehttp://wiki.jikexueyuan.com/project/the-python-study-notes-second-edition/decorator.html\u003c/a\u003e\u003c/p\u003e"
October 20, 2018
Golang中struct结构体的的值方法和指针方法
"\u003cp\u003e推荐:\u003ca href=\"https://mp.weixin.qq.com/s/msXzSfrDAHNPFjMtJ_i0cw\"\u003eGo的方法集详解(360云计算)\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e平时我们在写struct的时候,经常会用到一些方法,有些方法是我们熟悉的普通方法,在golang中我们称之为值方法,而另一种则是指针方法。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etype Person struct {\n Firstname string\n Lastname string\n Age uint8\n}\n// 值方法\nfunc (p Person) show() {\n fmt.Println(p.Firstname)\n}\n// 指针方法\nfunc (p *Person) show2() {\n fmt.Println(p.Firstname)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e可以看到所谓的值方法与指针方法在编写的时候,只是有无*****号的区别,这个*就是指针的意思。\u003c/p\u003e\n\u003cp\u003e那么用法又有何不同呢?\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// 值方法\nfunc (p Person) setFirstName(name string) {\n p.Firstname = name\n}\n// 指针方法\nfunc (p *Person) setFirstName2(name string) { …\u003c/code\u003e\u003c/pre\u003e"
October 19, 2018
Golang中的unsafe.Sizeof()简述
"\u003cp\u003e测试环境:\n系统 win7 64位\ngo version: go1.10 windows/amd64\u003c/p\u003e\n\u003cp\u003e我们先看一下代码的输出\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;unsafe\u0026#34;\n\nfunc main() {\n\t// string\n\tstr1 := \u0026#34;abc\u0026#34;\n\tprintln(\u0026#34;string1:\u0026#34;, unsafe.Sizeof(str1)) // 16\n\tstr2 := \u0026#34;abcdef\u0026#34;\n\tprintln(\u0026#34;string2:\u0026#34;, unsafe.Sizeof(str2)) // 16\n\n\t// 数组\n\tarr1 := [...]int{1, 2, 3, 4}\n\tprintln(\u0026#34;array1:\u0026#34;, unsafe.Sizeof(arr1)) // 32 = 8 * 4\n\n\tarr2 := [...]int{1, 2, 3, 4, 5}\n\tprintln(\u0026#34;array2:\u0026#34;, unsafe.Sizeof(arr2)) // 40 = 8 * 5\n\n\t// slice 好多人 …\u003c/code\u003e\u003c/pre\u003e"
October 19, 2018
数据结构与算法
"\u003cp\u003e平时开发中,一般很少用到手动来写算法的情况,但实际上我们一直在接触一些数据结构与算法,如JAVA中的ArrayList 就用到了数据结构与算法,从名字可以看到了用到了Array这种数组结构和链表结构。下面根据目前学习的情况做一个总结。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e数据结构\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我们常见的数组结构一般有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eArray数组、\u003c/li\u003e\n\u003cli\u003eStack栈、\u003c/li\u003e\n\u003cli\u003eHeap堆、\u003c/li\u003e\n\u003cli\u003eQueue队列\u003c/li\u003e\n\u003cli\u003eHash 哈希类型\u003c/li\u003e\n\u003cli\u003eLinkedList 链表,其中又分为单向链表、双向链表、还有最少用的环形链表\u003c/li\u003e\n\u003cli\u003eTree 这个Tree分的太多了,如B-Tree、 B+Tree(mysql使用)、Binary Search Tree二叉搜索树 、AVL高度平衡树、Red Black Tree红黑树 等\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/data-struct.png\" alt=\"数据结构\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.bigocheatsheet.com/\"\u003ehttp://www.bigocheatsheet.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e算法\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一般开发中用到的基本上排序算法居多,而算法大体上又分为比较排序和非比较排序。我们常用的比较排序算法有(参考: \u003ca href=\"http://www.cnblogs.com/eniac12/p/5329396.html\"\u003ehttp://www.cnblogs.com/eniac12/p/5329396.html\u003c/a\u003e):\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e快速排序 (Quick Sort)\u003c/li\u003e\n\u003cli\u003e冒泡排序 (Bubble Sort) …\u003c/li\u003e\u003c/ul\u003e"
October 17, 2018
常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)
"\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/alsf/p/6606287.html\"\u003ehttps://www.cnblogs.com/alsf/p/6606287.html\u003c/a\u003e\n\u003ca href=\"https://blog.csdn.net/wang_hufeng/article/details/80774761\"\u003ehttps://blog.csdn.net/wang_hufeng/article/details/80774761\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e推荐”极客时间”的两个算法专栏,其中有个专栏是视频形式的,两个专栏讲的都是特别的通俗易懂的。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://time.geekbang.org/column/126\"\u003ehttps://time.geekbang.org/column/126\u003c/a\u003e \u003ca href=\"https://time.geekbang.org/course/intro/130\"\u003ehttps://time.geekbang.org/course/intro/130\u003c/a\u003e\u003c/p\u003e"
October 13, 2018
Heap And Stack 堆与栈的区别
"\u003cp\u003e\u003cstrong\u003e堆与栈的区别\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e推荐: \u003ca href=\"https://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/\"\u003ehttps://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e栈是上下顺序存储的,且“先进后出LIFO”规则,只能删除顶部的元素,而堆是没有特定的顺序的存储,您可以删除任意元素。堆分配需要维护分配的内存和未分配的内存的完整记录,以及一些开销维护以减少碎片,找到足够大以适应请求大小的连续内存段,等等。内存可以随时释放,留出自由空间。有时,内存分配器将执行维护任务,比如通过将分配的内存到处移动来对内存进行碎片整理,或者在运行时进行垃圾收集——当内存不再处于作用域中时对其进行标识并释放它。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e栈用在线程中,程序执行时由线程创建有限数量的栈空间,当线程结束的时候会自动回收,属于系统级。\n堆一般是由应用程序在启动时创建,由应用程序回收,属于应用级。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe stack is attached to a thread, so when the thread exits the stack is reclaimed. The heap is …\u003c/p\u003e\u003c/blockquote\u003e"
October 9, 2018
Golang中的调度器
"\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/go-mpg-1.jpg\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003egolang实现的协程调度器,其实就是在维护一个G、P、M三者间关系的队列。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e介绍(Introduction)\u003c/strong\u003e\n———————\nGo 1.1最大的特色之一就是这个新的调度器,由Dmitry Vyukov贡献。新调度器让并行的Go程序获得了一个动态的性能增长,针对它我不能再做点更好的工作了,我觉得我还是为它写点什么吧。\u003c/p\u003e\n\u003cp\u003e这篇博客里面大多数东西都已经被包含在了[原始设计文档]( \u003ca href=\"https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw\"\u003ehttps://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw\u003c/a\u003e)中了,这个文档的内容相当广泛,但是过于技术化了。\u003c/p\u003e\n\u003cp\u003e关于新调度器,你所需要知道的都在那个设计文档中,但是我这篇博客有图片,所以更加清晰易懂。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e带调度器的Go runtime需要什么?(What does the Go runtime need with a scheduler?)\u003c/strong\u003e\n——————————————————————————-\n但是在我们开始看新调度器之前,我们需要理解为什么需要调度器。为什么既然操作系统能为我们调度线程了,我们又创造了一个\u003cstrong\u003e用户空间调 …\u003c/strong\u003e\u003c/p\u003e"
September 24, 2018
Git中的git reset的三种参数的区别
"\u003cp\u003e我们平时在使用git的时候,经常会遇到需要撤销上次操作的需求,这时候需要用到git reset的这个命令,他的使用就是 “git-reset – Reset current HEAD to the specified state”, 注意这里主要操作的就是这个 \u003cstrong\u003eHEAD\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e为了方便我们先了解一下 Git 的工作流程\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/git_flow.jpg\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e相信大家对这个图已经很熟悉了,其中index也叫stage暂存区或者暂存索引区。git reset 共有三个互斥参数分别为”–soft”、”–mixed(默认参数)” 和 “–hard”,每种参数表示一种恢复模式,下面我们将分别看一下这git reset 三个参数的用法区别。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e前提条件\u003c/strong\u003e\n我们仓库中的Git 提交顺序为 “A(a.txt) -\u0026gt; B(b.txt) -\u0026gt; C(c.txt)“,当前分支为master。\n当前 HEAD 指向C,即 a47072e9f97eac4ac02c0abac82b26a9719663fc (HEAD -\u0026gt; master),我们以恢复到B(aad0c91e7b1d3577)点为准。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etest1 git:(master) …\u003c/code\u003e\u003c/pre\u003e"
September 4, 2018
IO多路复用机制详解(转)
"\u003cp\u003e服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种:\u003c/p\u003e\n\u003cp\u003e(1)\u003cstrong\u003e同步阻塞IO\u003c/strong\u003e(Blocking IO):即传统的IO模型。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182909126.png\" alt=\"image-20230904182909126\"\u003e\u003c/p\u003e\n\u003cp\u003e(2)\u003cstrong\u003e同步非阻塞IO\u003c/strong\u003e(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182842534.png\" alt=\"image-20230904182842534\"\u003e\u003c/p\u003e\n\u003cp\u003e(3)\u003cstrong\u003eIO多路复用\u003c/strong\u003e(IO Multiplexing):即经典的 \u003ca href=\"https://blog.csdn.net/linxcool/article/details/7771952\"\u003e反应器Reactor设计模式\u003c/a\u003e,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。高性能并发服务程序使用IO多路复用模型+多线程任务处理的架构。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182800068.png\" alt=\"image-20230904182800068\"\u003e\u003c/p\u003e\n\u003cp\u003e(4)\u003cstrong\u003e异步IO\u003c/strong\u003e(Asynchronous IO):即经典的 \u003ca href=\"https://blog.csdn.net/xiongping_/article/details/45152333\"\u003eProactor设计模式\u003c/a\u003e,也称为异步非阻塞IO。不经常用。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182813616.png\" alt=\"image-20230904182813616\"\u003e\u003c/p\u003e\n\u003cp\u003e高性能I/O设计模式Reactor和Proactor: \u003ca href=\"https://blog.csdn.net/xiongping_/article/details/45152333\"\u003ehttps://blog.csdn.net/xiongping_/article/details/45152333\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/aspirant/p/9166944.html\"\u003eselect、poll、epoll之间的区别(搜狗面试)\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e转自: …\u003c/p\u003e"
August 31, 2018
Go的内存模型
"\u003cp\u003e\u003ca href=\"https://segmentfault.com/a/1190000008230146\"\u003ehttps://segmentfault.com/a/1190000008230146\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e原文: \u003ca href=\"https://golang.org/ref/mem\"\u003ehttps://golang.org/ref/mem\u003c/a\u003e\u003c/p\u003e"
August 30, 2018
如何优雅地关闭Go channel
"\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/d24dfbb33781\"\u003ehttps://www.jianshu.com/p/d24dfbb33781\u003c/a\u003e\u003c/p\u003e"
August 30, 2018
理解Go语言的nil
"\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/dd80f6be7969\"\u003ehttps://www.jianshu.com/p/dd80f6be7969\u003c/a\u003e\u003c/p\u003e"
August 28, 2018
[译]Go里面的unsafe包详解
"\u003cp\u003eunsafe包位置: \u003ccode\u003esrc/unsafe/unsafe.go\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e指针类型:\u003c/strong\u003e\n***类型:**普通指针,用于传递对象地址,不能进行指针运算。\n**unsafe.Pointer:**通用指针,用于转换不同类型的指针,不能进行指针运算。\n**uintptr:**用于指针运算,GC 不把 uintptr 当指针,uintptr 无法持有对象。uintptr 类型的目标会被 GC 回收。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eunsafe.Pointer 可以和 普通指针 进行相互转换。\nunsafe.Pointer 可以和 uintptr 进行相互转换。\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e也就是说 unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一般使用流程:\u003c/strong\u003e\n第一步:将结构体 -\u0026gt; 通用指针unsafe.Pointer(struct) -\u0026gt; uintptr(通用指针)获取内存段的起始位置start_pos,并记录下来,第二步使用。\n第二步:使用start_pos + unsafe.Offsetof(s.b) -\u0026gt; 将地址转为能用指 …\u003c/p\u003e"
August 28, 2018
golang中slice切片理解总结
"\u003cp\u003e首先我们对切片有一个大概的理解,先看一下slice的内部结构,共分三部分,一个是指向底层数组的时候,一个是长度len,另一个就是slice的容量cap了。如cap不足以放在新值的时候,会产生新的内存地址申请。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182516517.png\" alt=\"image-20230904182516517\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/image-20230904182527333.png\" alt=\"image-20230904182527333\"\u003e\u003c/p\u003e\n\u003cp\u003e先看代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\n // 创建一个切片,长度为9,容量为10\n fmt.Println(\u0026#34;----- 1.测试切片变量append的影响(未申请新的内存空间)-----\u0026#34;)\n a := make([]int, 9,10)\n fmt.Printf( \u0026#34;%p len=%d cap=%d %vn\u0026#34; , a, len(a), cap(a), a)\n\n // 切片进行append操作,由于原来len(a)长度为9,而cap(a)容量为10,未达到扩展内存的要求,此时新创建的切片变量还指向原来的底层数组,只是数组的后面添加一个新值\n // 此时一共两个切片变量,一个是a,另一个是s4。但共指向的一个内存地址\n s4 := …\u003c/code\u003e\u003c/pre\u003e"
July 2, 2018
Go中复制文件的3种方式
"\u003cp\u003e\u003ca href=\"https://opensource.com/article/18/6/copying-files-go\"\u003ehttps://opensource.com/article/18/6/copying-files-go\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e更多: \u003ca href=\"https://opensource.com/tags/go\"\u003ehttps://opensource.com/tags/go\u003c/a\u003e\u003c/p\u003e"
June 14, 2018
时间复杂度:O(1)、O(n)、O(n²)、O(nlogn)等
"\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_27093465/article/details/70690749\"\u003ehttps://blog.csdn.net/qq_27093465/article/details/70690749\u003c/a\u003e\u003c/p\u003e"
June 11, 2018
Linux下对进程通信管理的信号机制概述
"\u003cp\u003e今天看到了篇使用golang实现的系统无感重启的文章, \u003ca href=\"https://gravitational.com/blog/golang-ssh-bastion-graceful-restarts/\"\u003ehttps://gravitational.com/blog/golang-ssh-bastion-graceful-restarts/\u003c/a\u003e,一般用来平滑处理一些系统服务,避免先停止再启用导致的服务不可用的情况。其中用到了信号机制,这里找了一些文章主要有来介绍这方面的文章,以便加深理解。 \u003ca href=\"https://blog.csdn.net/junyucsdn/article/details/50519248\"\u003ehttps://blog.csdn.net/junyucsdn/article/details/50519248\u003c/a\u003e \u003ca href=\"https://blog.csdn.net/tiany524/article/details/17048069\"\u003ehttps://blog.csdn.net/tiany524/article/details/17048069\u003c/a\u003e \u003ca href=\"https://my.oschina.net/chenliang165/blog/125825\"\u003ehttps://my.oschina.net/chenliang165/blog/125825\u003c/a\u003e\u003c/p\u003e"
March 8, 2018
Go中slice作为参数传递的一些“坑”
"\u003cp\u003e看明白了这篇文章,下面的例子基本也就明白了\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n\ta := []int{1,2,3}\n\tabc(a)\n\tfmt.Println(a)\n}\nfunc abc(a []int) {\n\ta[0] = 2 //修改后还是原来的a\n\ta = append(a, 4) // 此a非原a,使用append导致了重新分配内存地址(存储空间不足,系统自动分配一块新的足够大的内存地址,此时a的物理内存地址已经发行了变化,并将原来a的值copy一份到新的内存地址,所以这里修改的只是新内存地址的值,原来内存地址的值并没有改变),试着删除这行运行一次再看结果\n\tfmt.Println(a)\n\n\ta[0] = 7 // 新a,因为上面执行了append\n\tfmt.Println(a)\n\n\tfmt.Printf(\u0026#34;\\n===\\n\u0026#34;)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e解释:\n[\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/golang_slice_append.png\" alt=\"\"\u003e][1]\u003c/p\u003e"
March 3, 2018
golang中string rune byte 三者的关系
"\u003cp\u003e\u003ccode\u003eGo\u003c/code\u003e 语言中 \u003ccode\u003ebyte\u003c/code\u003e 和 \u003ccode\u003erune\u003c/code\u003e 实质上就是 \u003ccode\u003euint8\u003c/code\u003e 和 \u003ccode\u003eint32\u003c/code\u003e 类型。 \u003ccode\u003ebyte\u003c/code\u003e 用来强调数据是 \u003ccode\u003eraw data\u003c/code\u003e,而不是数字;而 \u003ccode\u003erune\u003c/code\u003e 用来表示 \u003ccode\u003eUnicode\u003c/code\u003e 的 \u003ccode\u003ecode point\u003c/code\u003e。参考 \u003ca href=\"https://golang.org/ref/spec#Numeric_types\"\u003e规范.\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在Golang中 string 底层是用byte字节数组存储的,并且是不可以修改的。\u003c/p\u003e\n\u003ch1 class=\"postTitle.wp-block-heading\" id=\"go语言中的byte和rune区别对比\"\u003eGo语言中的byte和rune区别、对比\u003c/h1\u003e\n\u003cp\u003e例如\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003es:=\u0026#34;Go编程\u0026#34;\nfmt.Println(len(s)) //输出结果应该是8因为中文字符是用3个字节存的(2+3*2=8)。\nfmt.Printf(\u0026#34;%d\u0026#34;, len(string(rune(\u0026#39;编\u0026#39;)))) //经测试一个汉字确实占用3个字节,所以结果是3\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果想要获得字符个数的话,需要先转换为rune切片再使用内置的len函数\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efmt.Println(len([]rune(s))) // 结果就是4了。\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e所以用string存储unicode的话,如果有中文,按下标是访问不到的,因为你只能得到一个byte。 要想访问中文的话,还是要用rune切片,这样就能按下表访问。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e总结:\u003c/strong\u003e\n\u003ccode\u003erune …\u003c/code\u003e\u003c/p\u003e"
February 21, 2018
解决mac下brew link python3出错brew Error: Permission denied @ dir_s_mkdir – /usr/local/Frameworks
"\u003cp\u003emac上默认的python版本为2.7.10版本,需要升级到python3 版本,通过brew升级\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$brew install python3\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e提示错误\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$ brew install python3 Warning: python3 3.6.3is already installed, it‘s just not linked. You can use \u003ccode\u003ebrew link python3\u003c/code\u003e to link this version. $ brew link python3 Linking /usr/local/Cellar/python3/3.6.3… Error: Permission denied @ dir_s_mkdir\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e发现\u003ccode\u003e/usr/local/\u003c/code\u003e下没有路径\u003ccode\u003e/usr/local/Frameworks\u003c/code\u003e\n需要新建该路径,并修改权限\u003c/p\u003e\n\u003cp\u003e解决:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ sudo mkdir /usr/local/Frameworks\n$ sudo chown $(whoami):admin /usr/local/Frameworks\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e成功:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew link python3\nLinking …\u003c/code\u003e\u003c/pre\u003e"
January 26, 2018
利用“码云gitee”的钩子实现git仓库自动更新
"\u003cp\u003e使用git时,传统发布方式是手动将新代码 上传到远程仓库,然后在登录服务器执行git pull命令拉取最新的代码,这种操作如果频繁更新的话,我们可以利用git的钩子来实现自动 部署 功能。\u003c/p\u003e\n\u003cp\u003e前提:\nlinux\nphp (gitpull.php)\nnginx 运行用户为 www\u003c/p\u003e\n\u003cp\u003e注意网站 gitpull.php 文件权限问题,还有是否有shell_exec 命令的执行权限\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、先创建自动部署用户的密钥\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo - www\nssh-keygen -t rsa -C \u0026#34;syadmin@gmail.com\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e二、将用户www生成的公钥添加到码云后台\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecat ~/.ssh/id_rsa.pub\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e三、将码云域名gitee.com 添加到授权白名单\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003essh-keyscan -t rsa gitee.com \u0026gt;\u0026gt; ~/.ssh/known_hosts\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e或者以www用户执行一次gitpull命令\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo - www\ncd /data/wwwroot/www\ngit pull\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e根据提示,输入 yes 即可。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e四、在码云的部署钩子里进行url设置\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eurl …\u003c/p\u003e"
October 17, 2017
php的Pdo扩展实现类似mysql_ping的方法
"\u003cp\u003e在php里Pdo是没有mysql_ping和mysqli_ping函数的,可以使用以下方法来代替它\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eclass NPDO {\n private $pdo;\n private $params;\n\n public function __construct() {\n $this-\u0026gt;params = func_get_args();\n $this-\u0026gt;init();\n }\n\n public function __call($name, array $args) {\n return call_user_func_array(array($this-\u0026gt;pdo, $name), $args);\n }\n\n // The ping() will try to reconnect once if connection lost.\n public function ping() {\n try {\n $this-\u0026gt;pdo-\u0026gt;query(\u0026#39;SELECT …\u003c/code\u003e\u003c/pre\u003e"
June 23, 2017
swoole模块及使用场景
"\u003cp\u003e一、多任务及多进程: 用来大量采集数据时使用,再利用多进程提高效率\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/koastal/article/details/52871316\"\u003ehttp://blog.csdn.net/koastal/article/details/52871316\u003c/a\u003e \u003ca href=\"http://www.tuicool.com/articles/ZFNFvqm\"\u003ehttp://www.tuicool.com/articles/ZFNFvqm\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e二、定时任务\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/LinkedDestiny/swoole-doc/blob/master/src/03/swoole_timer_server.php\"\u003ehttps://github.com/LinkedDestiny/swoole-doc/blob/master/src/03/swoole_timer_server.php\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eswoole新版本已经废除掉了 timer 指令,请使用 swoole_timer_tick 代替。参考:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://wiki.swoole.com/wiki/page/480.html\"\u003ehttps://wiki.swoole.com/wiki/page/480.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e或\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://wiki.swoole.com/wiki/page/414.html\"\u003ehttps://wiki.swoole.com/wiki/page/414.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e三、执行异步任务(耗时任务处理)\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://wiki.swoole.com/wiki/page/162.html\"\u003ehttps://wiki.swoole.com/wiki/page/162.html\u003c/a\u003e \u003ca href=\"https://wiki.swoole.com/wiki/page/481.html\"\u003ehttps://wiki.swoole.com/wiki/page/481.html …\u003c/a\u003e\u003c/p\u003e"
March 29, 2017
git无法pull仓库refusing to merge unrelated histories的解决办法
"\u003cp\u003e在本地有一个很久的项目,需要上传到远程git仓库中,先在远程创建了一个仓库,在本地配置好后,发现上传的时候,提示先git pull 一下,但git pull的时候提示这个错误,主要是因为目前两个git仓库信息不一致问题,我们要将两个项目合并在一起,需要添加一个 –allow-unrelated-histories 参数即可。\u003c/p\u003e\n\u003cp\u003e先进入cli命令行模式,执行\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit pull origin master --allow-unrelated-histories\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e然后再执行git pull origin master 即可。\u003c/p\u003e\n\u003cp\u003e参考: \u003ca href=\"http://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories\"\u003ehttp://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories\u003c/a\u003e\u003c/p\u003e"
November 25, 2016
Laravel中的异常处理
"\u003cp\u003eEloquent try/catch on duplicate key Exception and delete?\u003c/p\u003e\n\u003cp\u003eI’ve a form for a new vendor where the controller listens for its POST.\nFrom there on I’m creating a new endor and the equivalential login for this vendor.\u003c/p\u003e\n\u003cp\u003eController :\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$vendor = Vendor::create( $request-\u0026gt;all() );\n$login = Vendor::createLogin($vendor-\u0026gt;vendor_id);\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ethe \u003cem\u003ecreateLogin\u003c/em\u003e function :\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epublic static function createLogin($lid){\n $name = self::find($lid)-\u0026gt;vendor_name;\n $name = explode(\u0026#39; \u0026#39;, $name); …\u003c/code\u003e\u003c/pre\u003e"
November 18, 2016
Laravel框架数据库CURD操作、连贯操作使用方法
"\u003cp\u003eLaravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、Selects\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e检索表中的所有行\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$users = DB::table(\u0026#39;users\u0026#39;)-\u0026gt;get();\nforeach ($users as $user)\n{\nvar_dump($user-\u0026gt;name);\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e从表检索单个行\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$user = DB::table(\u0026#39;users\u0026#39;)-\u0026gt;where(\u0026#39;name\u0026#39;, \u0026#39;John\u0026#39;)-\u0026gt;first();\nvar_dump($user-\u0026gt;name);\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e检索单个列的行\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$name = DB::table(\u0026#39;users\u0026#39;)-\u0026gt;where(\u0026#39;name\u0026#39;, \u0026#39;John\u0026#39;)-\u0026gt;pluck(\u0026#39;name\u0026#39;);\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e检索一个列值列表\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$roles = …\u003c/code\u003e\u003c/pre\u003e"
November 13, 2016
PHP中的max_input_vars指令
"\u003cp\u003e今天接到客服部工作人员反馈的一个问题,客户使用产品系统是允许用户添加产品属性的,而每个属性是由多个表单域组成 ,这样当每添加一个属性就等于添加了n个表单域,这个客户添加的非常的多,发现在提交保存的时候总是失败,提示其中一个表单元素的索引值不存在,经测试是发现服务端接收的一些表单域丢失了一部分。起初分析的是服务器接收的数据超出了php设置的max_post_size(其实当时已经设置了8M,足够使用了),修改了测试发现此问题仍然存在。后来将用户原来的一些添加的表单元素进行删除,再重新添加同样数据库表单域可以成功,但一旦超出一定数量的表单域就会发生丢失的情况,这个时候首先怀疑的是apache是否有类似限制接收隐藏域的指令,找了没有找到,紧接着在php中批到一个max_input_vars这个指令,意思就是说php中允许接收的最大表单域数据,到目前为止基本上是确定这个原因引起的了,奖其修改为2000,重启Apache,发现一切正常。\u003c/p\u003e\n\u003cp\u003e总结:提起php中的max_input_vars 估计很少人知道这个这个指令,因为他的使用场景实在是太少了,在php.ini中这个指令的定义是指服务端最大可以接 …\u003c/p\u003e"
November 9, 2016
使用supervisord监控php脚本
"\u003cp\u003e官网: \u003ca href=\"http://www.supervisord.org\"\u003ehttp://www.supervisord.org\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e一、安装supervisord\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$brew install supervisord\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在mac下安装要比linux下安装方便的多。\u003c/p\u003e\n\u003cp\u003e二、配置\u003c/p\u003e\n\u003cp\u003e修改/usr/local/etc/supervisord.ini文件,取消以下几行注释\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e[inet_http_server] ; inet (TCP) server disabled by default\nport=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)\nusername=user ; (default is no username (open server))\npassword=123 ; (default is no password (open server))\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样就可以通过浏览器对进行管理了。\u003c/p\u003e\n\u003cp\u003e三、添加一个新应用\u003c/p\u003e\n\u003cp\u003e创建一个a.php文件,内容如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ewhile(true){\necho \u0026#39;a\u0026#39; . time() . \u0026#34;\\r\\n\u0026#34;;\nsleep(1);\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e …\u003c/p\u003e"
November 1, 2016
按位与、或、异或等运算方法
"\u003cp\u003e\u003cstrong\u003e常见位运算\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e异或^:相同为0,不同为1。如:0^0=0; 0^1=1; 1^0=1; 1^1=0\n按位与\u0026amp;: 都为1则为1,否则为0。如:1\u0026amp;1=1; 1\u0026amp;0=0; 0\u0026amp;1=0; 0\u0026amp;0=0\n按位或|:有1则为1,否则为0。如:1|1=1; 1|0=1; 0|1=1; 0|0=0\n按位非(按位取反)~:取反操作。如:1-\u0026gt;0; 0-\u0026gt;1\u003c/p\u003e\n\u003cp\u003e——–\u003c/p\u003e\n\u003ch3\u003e\u003c/h3\u003e\n\u003ch3 id=\"按位与运算符参加运算的两个数据按二进制位进行与运算运算规则000-010-100-111即两位同时为1结果才为1否则为0例如35-即-0000-0011--0000-0101--0000-0001-因此35的值得1另负数按补码形式参加按位与运算与运算的特殊用途1清零如果想将一个单元清零即使其全部二进制位为0只要与一个各位都为零的数值相与结果为零2取一个数中指定位方法找一个数对应x要取的位该数的对应位为1其余位为零此数与x进行与运算可以得到x中的指定位例设x10101110-取x的低4位用-x--0000-1111--0000-1110即可得到-还可用来取x的246位\"\u003e**按位与运算符(\u0026amp;)**参加运算的两个数据,按二进制位进行“与”运算。运算规则:0\u0026amp;0=0; 0\u0026amp;1=0; 1\u0026amp;0=0; 1\u0026amp;1=1;即:两位同时为“1”,结果才为“1”,否则为0例如:3\u0026amp;5 即 0000 0011 \u0026amp; 0000 0101 = 0000 0001 因此,3\u0026amp;5的值得1。另,负数按补码形式参加按位与运算。“与运算”的特殊用途:(1)清零。如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。(2)取一个数中指定位方法:找一个数,对应X要取的位,该数的对应位为1,其余位 …\u003c/h3\u003e"
October 31, 2016
解决git clone时报错:The requested URL returned error: 401 Unauthorized while accessing的问题
"\u003cp\u003e版本问题,最直接的解决办法就是重新编辑安装git吧:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e下载:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ewget -O git.zip https://github.com/git/git/archive/master.zip\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e解压:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eunzip git.zip\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e进入git目录:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecd git-master\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"4\"\u003e\n\u003cli\u003e编译安装:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eautoconf\n./configure --prefix=/usr/local\nmake \u0026amp;\u0026amp; make install\n\u003c/code\u003e\u003c/pre\u003e\u003col start=\"5\"\u003e\n\u003cli\u003e最后别忘了删掉旧的git,并把新版本的git建立软链接到/usr/bin/git\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003erm /usr/bin/git\nln -s /usr/local/bin/git /usr/bin/git\n\u003c/code\u003e\u003c/pre\u003e"
October 25, 2016
git提示“Pull is not possible because you have unmerged files.”的解决办法(转)
"\u003cp\u003e在git pull的过程中,如果有冲突,那么除了冲突的文件之外,其它的文件都会做为staged区的文件保存起来。\u003c/p\u003e\n\u003cp\u003e重现:\u003c/p\u003e\n\u003cp\u003e$ git pull\u003c/p\u003e\n\u003cp\u003eA Applications/Commerce/BookingAnalysis.java\nA Applications/Commerce/ClickSummaryFormatter.java\nM Applications/CommerceForecasting/forecast/Forecast.java\nA Applications/CommerceForecasting/forecast/ForecastCurveProviderCategory.java\nM Applications/CommerceForecasting/forecast/ForecastProvider.java\nM Applications/CommerceForecasting/forecast/InputPropertyItem.java\n……\u003c/p\u003e\n\u003cp\u003eA …\u003c/p\u003e"
September 11, 2016
Visual Studio Code之常备快捷键
"\u003cp\u003e推荐:\u003ca href=\"http://www.cnblogs.com/summit7ca/p/5225494.html\"\u003eVisual Studio Code 添加设置代码段(snippet)\u003c/a\u003e{#cb_post_title_url.postTitle2}\u003c/p\u003e\n\u003cp\u003e官方快捷键大全: \u003ca href=\"https://code.visualstudio.com/docs/customization/keybindings\"\u003ehttps://code.visualstudio.com/docs/customization/keybindings\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eVisual Studio Code是个牛逼的编辑器,启动非常快,完全可以用来代替其他文本文件编辑工具。又可以用来做开发,支持各种语言,相比其他IDE,轻量级完全可配置还集成Git感觉非常的适合前端开发。 所以我仔细研究了一下文档未来可能会作为主力工具使用。\u003c/p\u003e\n\u003ch1 id=\"主命令框_Command_Palette\"\u003e主命令框\u003c/h1\u003e\n\u003cp\u003e最重要的功能就是\u003ccode\u003eF1\u003c/code\u003e或\u003ccode\u003eCtrl+Shift+P\u003c/code\u003e打开的命令面板了,在这个命令框里可以执行VSCode的任何一条命令,甚至关闭这个编辑器。\n按一下\u003ccode\u003eBackspace\u003c/code\u003e会进入到\u003ccode\u003eCtrl+P\u003c/code\u003e模式里\n在\u003ccode\u003eCtrl+P\u003c/code\u003e下输入\u003ccode\u003e\u0026gt;\u003c/code\u003e又可以回到\u003ccode\u003eCtrl+Shift+P\u003c/code\u003e模式。\n在\u003ccode\u003eCtrl+P\u003c/code\u003e窗口下还可以\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e直接输入文件名,跳转到文件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e?\u003c/code\u003e 列出当前可执行的动作\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e!\u003c/code\u003e 显示Errors或Warnings,也可以`Ctrl+Shift+M\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e:\u003c/code\u003e 跳转到行数,也可以\u003ccode\u003eCtrl+G\u003c/code\u003e …\u003c/li\u003e\u003c/ul\u003e"
August 13, 2016
windows下备份mysql数据库dos脚本
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e@echo off \u0026amp; setlocal ENABLEEXTENSIONS\n:: ---------- 配置项 ----------\n:: 备份放置的路径,加\nset BACKUP_PATH=D:\\Backup\n:: 要备份的数据库名称,多个用空格分隔\nset DATABASES=1688 abc ceshi\n:: MySQL 用户名\nset USERNAME=root\n:: MySQL 密码\nset PASSWORD=root\n:: MySQL Bin 目录,加\n:: 如果可以直接使用 dump(安装时添加 MySQL Bin 目录到了环境变量),此处留空即可\nset MYSQL=D:\\Progra~1\\phpStudy\\MySQL\\bin\\\n:: WinRAR 自带命令行工具的可执行文件路径,长文件名注意用 Dos 长文件名书写方式\nset WINRAR=D:\\Progra~1\\WinRAR\\Rar.exe\n:: ---------- 以下请勿修改 ----------\nset YEAR=%date:~0,4%\nset MONTH=%date:~5,2%\nset …\u003c/code\u003e\u003c/pre\u003e"
May 28, 2016
利用tcpdump抓取MySQL执行的SQL
"\u003cp\u003e\u003ca href=\"http://ourmysql.com/archives/1358\"\u003ehttp://ourmysql.com/archives/1358\u003c/a\u003e\n编写脚本文件dumpsql.sh,内容如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#!/bin/bash\n#this script used montor mysql network traffic.echo sql\ntcpdump -i eth0 -s 0 -l -w - dst port 3306 | strings | perl -e \u0026#39;\nwhile(\u0026lt;\u0026gt;) { chomp; next if /^[^ ]+[ ]*$/;\n if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL)/i)\n {\n if (defined $q) { print \u0026#34;$q\\n\u0026#34;; }\n $q=$_;\n } else {\n $_ =~ s/^[ \\t]+//; $q.=\u0026#34; $_\u0026#34;;\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行并抓去sql的执行。\u003c/p\u003e\n\u003cp\u003e抓取后在当前目录出现out.log文件,执 …\u003c/p\u003e"
May 21, 2016
理解OAuth 2.0
"\u003ch2 id=\"客户端的授权模式\"\u003e客户端的授权模式\u003c/h2\u003e\n\u003cp\u003e客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e授权码模式(authorization code)最完整、流程最严密的授权模式,如GitHub、微信等网站第三方登录方式\u003c/li\u003e\n\u003cli\u003e简化模式(implicit)\u003c/li\u003e\n\u003cli\u003e密码模式(resource owner password credentials)如目前手机APP中使用此模式\u003c/li\u003e\n\u003cli\u003e客户端模式(client credentials)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html\"\u003ehttp://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html\u003c/a\u003e\u003c/p\u003e"
May 16, 2016
Git 工具 – submodule 子模块
"\u003cp\u003e\u003ca href=\"https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97\"\u003ehttps://git-scm.com/book/zh/v2/Git 工具-子模块\u003c/a\u003e\u003c/p\u003e"
April 18, 2016
Mac上使用Brew 进行PHP多版本管理
"\u003cp\u003e\u003ca href=\"http://yansu.org/2014/09/26/use-old-version-of-brew-php.html\"\u003ehttp://yansu.org/2014/09/26/use-old-version-of-brew-php.html\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"section\"\u003e版本切换方式\u003c/h2\u003e\n\u003cp\u003e通过brew安装的php可以通过 \u003ccode\u003ebrew link\u003c/code\u003e 和 \u003ccode\u003ebrew unlink\u003c/code\u003e 来切换不同版本。\u003c/p\u003e\n\u003cp\u003e例如\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew list\nbrew unlink php56\nbrew link php55\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e大版本可以用 \u003ccode\u003ebrew list\u003c/code\u003e 来查,如果是小版本的话只能去 \u003ccode\u003e/usr/local/Cellar/php55\u003c/code\u003e 看了。这个时候使用 \u003ccode\u003ephp-version\u003c/code\u003e 可以更方便一点。\u003c/p\u003e\n\u003cp\u003e我测试的此方法不行,只能使用php-verson 进行切换。\u003c/p\u003e\n\u003ch2 id=\"php-version\"\u003e安装 \u003ccode\u003ephp-version\u003c/code\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/wilmoore/php-version\"\u003ephp-version\u003c/a\u003e 是一个帮助管理从brew安装的php版本切换的工具。\u003c/p\u003e\n\u003cp\u003e安装非常简单\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew install php-version\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e然后执行\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;span class=\u0026#34;nb\u0026#34;\u0026gt;source\u0026lt;/span\u0026gt; \u0026lt;span class=\u0026#34;k\u0026#34;\u0026gt;$(\u0026lt;/span\u0026gt;brew --prefix …\u003c/code\u003e\u003c/pre\u003e"
April 13, 2016
JWT介绍
"\u003cp\u003e\u003cstrong\u003eJWT是什么\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eJWT全称是JSON Web Tokens,是RFC 7519标准,用于安全校验两方可信性的安全措施。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eJWT解决了哪些问题?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eJWT本身设计是用于解决Session机制不能够很好的在SPA/API类型(restful)应用中处理身份认证问题。通常API的调用是无状态(stateless)的,使用Session等形式会有上下文要求。如当用户登录完成后,可以通过下发JWT的形式进行无状态的API调用。在此之前通常是使用的方式包括不限于如Basic Auth、Oauth2或Token形式进行。\u003c/p\u003e\n\u003cp\u003eJWT相比是额外添加了签名校验方式,本质上来说对抗如暴力碰撞等形式有一些作用。但是由于本身长度的限制,存储的信息量有限。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eJWT处理方式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eJWT内容主要分为三段,分别对应头部信息,存储数据和签名信息三部分,中间使用『.』符号连接,三段信息均进行Base64编码。\u003c/p\u003e\n\u003cp\u003e具体实现方式可参考如下伪代码实现:\u003c/p\u003e\n\u003cp\u003eencodeBase64(header) + ‘.’ + encodeBase64(payload) + ‘.’ + Sign(key + encodeBase64(header) + …\u003c/p\u003e"
April 3, 2016
[翻译]理解 GO 语言的内存使用
"\u003cp\u003e许多人在刚开始接触 Go 语言时,经常会有的疑惑就是“为什么一个 Hello world 会占用如此之多的内存?”。 \u003ca href=\"https://deferpanic.com/blog/understanding-golang-memory-usage/\" title=\"Understanding Go Lang Memory Usage\"\u003eUnderstanding Go Lang Memory Usage\u003c/a\u003e 很好的解释了这个问题。不过“简介”就是“简介”,更加深入的内容恐怕要读者自己去探索了。另外,文章写到最后,作者飘了,估计引起了一些公愤,于是又自己给自己补刀,左一刀,右一刀……\u003c/p\u003e\n\u003cp\u003e————翻译分隔线————\u003c/p\u003e\n\u003ch1 id=\"理解-go-语言的内存使用\"\u003e理解 Go 语言的内存使用\u003c/h1\u003e\n\u003cp\u003e\u003cem\u003e2014年12月22日,星期一\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e温馨提示\u003c/strong\u003e:这仅是关于 Go 语言内存的简介,俗话说不入虎穴、焉得虎子,读者可以进行更加深入的探索。\u003c/p\u003e\n\u003cp\u003e大多数 Go 开发者都会尝试像这样简单的 hello world 程序:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\u0026#34;fmt\u0026#34;\n\u0026#34;time\u0026#34;\n)\n\nfunc main() {\nfmt.Println(\u0026#34;hi\u0026#34;)\n\ntime.Sleep(30 * time.Second)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e然后他们就完全崩溃了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2016/04/high_mem-300x38.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2016/04/high_mem-300x38.png\" alt=\"high_mem-300x38\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这个笔记本也只有 16 G 内存!\u003c/p\u003e\n\u003ch2 id=\"虚拟内存-vs-常驻内存\"\u003e虚拟内存 vs 常驻内存\u003c/h2\u003e\n\u003cp\u003eGo 管理内存的方式可能与你以 …\u003c/p\u003e"
March 25, 2016
Profiling Go Programs
"\u003cp\u003e转自: \u003ca href=\"http://blog.golang.org/profiling-go-programs\"\u003ehttp://blog.golang.org/profiling-go-programs\u003c/a\u003e (需翻墙)\u003c/p\u003e\n\u003ch1 id=\"the-go-blog\"\u003e\u003ca href=\"http://blog.golang.org/\"\u003eThe Go Blog\u003c/a\u003e\u003c/h1\u003e\n\u003ch3 class=\"title\" id=\"profiling-go-programs\"\u003e\u003ca href=\"http://blog.golang.org/profiling-go-programs\"\u003eProfiling Go Programs\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e24 June 2011\u003c/p\u003e\n\u003cp\u003eAt Scala Days 2011, Robert Hundt presented a paper titled \u003ca href=\"http://research.google.com/pubs/pub37122.html\"\u003eLoop Recognition in C++/Java/Go/Scala.\u003c/a\u003e The paper implemented a specific loop finding algorithm, such as you might use in a flow analysis pass of a compiler, in C++, Go, Java, Scala, and then used those programs to draw conclusions about typical performance concerns in these languages. The Go program presented in that paper runs quite …\u003c/p\u003e"
March 24, 2016
golang中并发实例
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n\t//\u0026#34;runtime\u0026#34;\n\t\u0026#34;os\u0026#34;\n\t\u0026#34;runtime/pprof\u0026#34; // 引用pprof package\n\t\u0026#34;time\u0026#34;\n)\n\nfunc main() {\n\tf, _ := os.Create(\u0026#34;profile_file\u0026#34;)\n\tpprof.StartCPUProfile(f) // 开始cpu profile,结果写到文件f中\n\tdefer pprof.StopCPUProfile() // 结束profile\n\n\tstartTime := time.Now().Second()\n\t//runtime.GOMAXPROCS(runtime.NumCPU())\n\n\t// 注意这里的缓存大小\n\tch := make(chan int, 100)\n\tquit := make(chan bool)\n\n\t// 注意这里把读取chan操作放在了写入chan之前了(为了安全建议对chan的goroutines读取放在前面,写入放在后 …\u003c/code\u003e\u003c/pre\u003e"
March 24, 2016
在Golang中使用json
"\u003cblockquote\u003e\n\u003cp\u003e由于要开发一个小型的web应用,而web应用大部分都会使用json作为数据传输的格式,所以有了这篇文章。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch4 id=\"包引用\"\u003e包引用\u003c/h4\u003e\n\u003cp\u003eimport (\n\u0026ldquo;encoding/json\u0026rdquo;\n\u0026ldquo;github.com/bitly/go-simplejson\u0026rdquo; // for json get\n)\u003c/p\u003e\n\u003ch4 id=\"用于存放数据的结构体\"\u003e用于存放数据的结构体\u003c/h4\u003e\n\u003cp\u003etype MyData struct {\nName string \u003ccode\u003ejson:\u0026quot;item\u0026quot;\u003c/code\u003e\nOther float32 \u003ccode\u003ejson:\u0026quot;amount\u0026quot;\u003c/code\u003e\n}\u003c/p\u003e\n\u003cp\u003e这里需要注意的就是后面单引号中的内容。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ejson:\u0026quot;item\u0026quot;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e这个的作用,就是Name字段在从结构体实例编码到JSON数据格式的时候,使用item作为名字。算是一种重命名的方式吧。\u003c/p\u003e\n\u003ch4 id=\"编码json\"\u003e编码JSON\u003c/h4\u003e\n\u003cp\u003evar detail MyData\u003c/p\u003e\n\u003cp\u003edetail.Name = \u0026ldquo;1\u0026rdquo;\ndetail.Other = \u0026ldquo;2\u0026rdquo;\u003c/p\u003e\n\u003cp\u003ebody, err := json.Marshal(detail)\nif err != nil …\u003c/p\u003e"
March 24, 2016
golang的json操作
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;encoding/json\u0026#34;\n \u0026#34;fmt\u0026#34;\n \u0026#34;os\u0026#34;\n)\n\ntype ConfigStruct struct {\n Host string `json:\u0026#34;host\u0026#34;`\n Port int `json:\u0026#34;port\u0026#34;`\n AnalyticsFile string `json:\u0026#34;analytics_file\u0026#34;`\n StaticFileVersion int `json:\u0026#34;static_file_version\u0026#34;`\n StaticDir string `json:\u0026#34;static_dir\u0026#34;`\n TemplatesDir string `json:\u0026#34;templates_dir\u0026#34;`\n SerTcpSocketHost …\u003c/code\u003e\u003c/pre\u003e"
March 23, 2016
golang中的md5的用法
"\u003cp\u003e代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;crypto/md5\u0026#34;\n\t\u0026#34;encoding/hex\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\t// md5 加密的第一种方法\n\tsrcData := []byte(\u0026#34;iyannik0215\u0026#34;)\n\tcipherText1 := md5.Sum(srcData)\n\tfmt.Printf(\u0026#34;md5 encrypto is \u0026#34;iyannik0215\u0026#34;: %x n\u0026#34;, cipherText1)\n\n\t// md5 加密的第二种方法\n\thash := md5.New()\n\thash.Write(srcData)\n\tcipherText2 := hash.Sum(nil)\n\thexText := make([]byte, 32)\n\thex.Encode(hexText, cipherText2)\n\tfmt.Println(\u0026#34;md5 encrypto is \u0026#34;iyannik0215\u0026#34;:\u0026#34;, …\u003c/code\u003e\u003c/pre\u003e"
March 21, 2016
如何优雅的在 koa 中处理错误
"\u003cp\u003e\u003ca href=\"http://taobaofed.org/blog/2016/03/18/error-handling-in-koa/\"\u003ehttp://taobaofed.org/blog/2016/03/18/error-handling-in-koa/\u003c/a\u003e\u003c/p\u003e"
March 21, 2016
koa中生成器函数generator执行顺序详解
"\u003cp\u003e\u003cstrong\u003eES6的generator\u003c/strong\u003e \u003ca href=\"http://book.apebook.org/minghe/koa-action/co/start.html\"\u003ehttp://book.apebook.org/minghe/koa-action/co/start.html\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\nfunction* gen() {\n var a = yield \u0026#39;start\u0026#39;;\n console.log(a);\n var b = yield \u0026#39;end\u0026#39;;\n console.log(b);\n return \u0026#39;over\u0026#39;;\n}\nvar it = gen();\nconsole.log(it.next()); // {value: \u0026#39;start\u0026#39;, done: false}\nconsole.log(it.next(22)); // 22 {value: \u0026#39;end\u0026#39;, done: false}\nconsole.log(it.next(333)); // 333 {value: \u0026#39;over\u0026#39;, done: true}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e带有 \u003ccode\u003e*\u003c/code\u003e 的函数声明表示是一个 generator 函数,当执行 \u003ccode\u003egen()\u003c/code\u003e 时,函数体内的代码并没有执行, …\u003c/p\u003e"
March 12, 2016
node出现“dyld: bad external relocation length”的解决办法
"\u003cp\u003emac下有时候在执行 npm的过程中,我们强制中止了操作或者一些命令出现问题会提示“dyld: bad external relocation length”这个错误,这个时候只要将未下载完的文件删除即可,我这里使用 n 4.4.3下载的时候,网络出现异常,提示这个错误,只要删除 /usr/local/n/versions/node/4.4.3 这个目录即可。\u003c/p\u003e\n\u003cp\u003e如果还是不行的话,可以试着执行一下\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew doctor\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e命令,根据提示操作就可以了。\u003c/p\u003e\n\u003cp\u003e我遇到的情况是使用node版本控制n安装新版本号的时候,好像安装包下载的不完整,但提示安装成功了,在最后提示这个错误。试了好多方法卸载重装也不行,最后根据 brew doctor 的提示,执行了\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew link --overwrite node\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e彻底解决了。\u003c/p\u003e"
March 12, 2016
nodejs中package.json文件说明
"\u003cp\u003e推荐: \u003ca href=\"http://jingpin.jikexueyuan.com/article/34254.html\"\u003ehttp://jingpin.jikexueyuan.com/article/34254.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003epackage.json 中包含各种所需模块以及项目的配置信息(名称、版本、许可证等)meta 信息。\u003c/p\u003e\n\u003cp\u003epackage.json文件可以通过npm init 来创建\u003c/p\u003e\n\u003ch4 id=\"包含可配置项\"\u003e包含可配置项\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003ename 名称\u003c/li\u003e\n\u003cli\u003e应用描述 description\u003c/li\u003e\n\u003cli\u003e版本号 version\u003c/li\u003e\n\u003cli\u003e应用的配置项 config\u003c/li\u003e\n\u003cli\u003e作者 author\u003c/li\u003e\n\u003cli\u003e资源仓库地址 respository\u003c/li\u003e\n\u003cli\u003e授权方式 licenses\u003c/li\u003e\n\u003cli\u003e目录 directories\u003c/li\u003e\n\u003cli\u003e应用入口文件 main\u003c/li\u003e\n\u003cli\u003e命令行文件 bin\u003c/li\u003e\n\u003cli\u003e项目应用运行依赖模块 dependencies\u003c/li\u003e\n\u003cli\u003e项目应用开发环境依赖 devDependencies\u003c/li\u003e\n\u003cli\u003e运行引擎 engines\u003c/li\u003e\n\u003cli\u003e脚本 script\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e简单模式\u003c/p\u003e\n\u003cp\u003e==========================\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e{\n\n name: \u0026#34;myApp\u0026#34;,\n\n version :\u0026#34;0.0.1\u0026#34;\n\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e完整模式\u003c/p\u003e\n\u003cp\u003e===========================\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e{\n\n \u0026#34;name\u0026#34;: …\u003c/code\u003e\u003c/pre\u003e"
March 12, 2016
PHP底层工作原理
"\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2016/03/51de416caaddc.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2016/03/51de416caaddc.png\" alt=\"51de416caaddc\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e从图上可以看出,php从下到上是一个4层体系\u003c/p\u003e\n\u003cp\u003e①Zend引擎\u003c/p\u003e\n\u003cp\u003eZend整体用纯c实现,是php的内核部分,它将php代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、 实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕zend 实现。\u003c/p\u003e\n\u003cp\u003e②Extensions\u003c/p\u003e\n\u003cp\u003e围绕着zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array系列)、标准库等都是通过 extension来实现,用户也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的(如贴吧正在使用的php中间层、富文本解析 就是extension的典型应用)。\u003c/p\u003e\n\u003cp\u003e③Sapi\u003c/p\u003e\n\u003cp\u003eSapi全称是Server Application Programming Interface,也就是服务端应用编程接口,sapi通过一系列钩子函数,使得php可以和外围交互数据,这是php非常优雅和成功的一个设计,通过 sapi成功的将php本身和上层应用解耦隔离,php可以不 …\u003c/p\u003e"
March 10, 2016
NPM 命令介绍(转)
"\u003cp\u003eNPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e允许用户从NPM服务器下载别人编写的第三方包到本地使用。\u003c/li\u003e\n\u003cli\u003e允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。\u003c/li\u003e\n\u003cli\u003e允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 **“npm -v” **来测试是否成功安装。命令如下,出现版本提示表示安装成功:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ npm -v\n2.3.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果你安装的是旧版本的 npm,可以很容易得通过 npm 命令来升级,命令如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ sudo npm install npm -g\n/usr/local/bin/npm -\u0026gt; /usr/local/lib/node_modules/npm/bin/npm-cli.js\nnpm@2.14.2 /usr/local/lib/node_modules/npm\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果是 Window 系统使用以下命令即可:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003enpm install npm -g\n\u003c/code\u003e\u003c/pre\u003e\u003chr\u003e\n\u003ch2 id=\"使用-npm-命令安装模块\"\u003e使用 npm 命令安装模块\u003c/h2\u003e\n\u003cp\u003enpm …\u003c/p\u003e"
March 10, 2016
nodejs学习资料
"\u003cp\u003e修改npm包管理器的registry( \u003ca href=\"http://registry.npmjs.org/\"\u003eregistry.npmjs.org\u003c/a\u003e)为淘宝镜像( \u003ca href=\"http://npm.taobao.org\"\u003enpm.taobao.org\u003c/a\u003e),参考nam config -h 相关命令\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003enpm config set registry “https://registry.npm.taobao.org“\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ca href=\"http://npm.taobao.org\"\u003ehttp://npm.taobao.org\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e七天学会NodeJS \u003ca href=\"http://nqdeng.github.io/7-days-nodejs/\"\u003ehttp://nqdeng.github.io/7-days-nodejs/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eNode.js Style Guide \u003ca href=\"https://github.com/dead-horse/node-style-guide\"\u003ehttps://github.com/dead-horse/node-style-guide\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e深入Node.js的模块机制 \u003ca href=\"http://www.infoq.com/cn/articles/nodejs-module-mechanism/\"\u003ehttp://www.infoq.com/cn/articles/nodejs-module-mechanism/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e学习ES6生成器(Generator) \u003ca href=\"http://www.toobug.net/article/learning_es6_generator.html\"\u003ehttp://www.toobug.net/article/learning_es6_generator.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003erequire() 源码解读 \u003ca href=\"http://www.ruanyifeng.com/blog/2015/05/require.html\"\u003ehttp://www.ruanyifeng.com/blog/2015/05/require.html …\u003c/a\u003e\u003c/p\u003e"
March 10, 2016
nodejs中exports与module.exports的区别
"\u003cp\u003e对于两者的理解只要记住一句话:“\u003cstrong\u003eexports就是module.exports****的引用\u003c/strong\u003e”即可。\u003c/p\u003e\n\u003cp\u003e推荐易理解的文档: \u003ca href=\"http://cnodejs.org/topic/5231a630101e574521e45ef8\"\u003ehttp://cnodejs.org/topic/5231a630101e574521e45ef8\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e原文:\u003c/p\u003e\n\u003cp\u003e你肯定非常熟悉nodejs模块中的\u003cstrong\u003eexports\u003c/strong\u003e对象,你可以用它创建你的模块。例如:(假设这是rocker.js文件)\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eexports.name = function() {\n console.log(\u0026#39;My name is Lemmy Kilmister\u0026#39;);\n};\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在另一个文件中你这样引用\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003evar rocker = require(\u0026#39;./rocker.js\u0026#39;);\nrocker.name(); // \u0026#39;My name is Lemmy Kilmister\u0026#39;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e那到底\u003cstrong\u003eModule.exports\u003c/strong\u003e是什么呢?它是否合法呢?\u003c/p\u003e\n\u003cp\u003e其实,\u003cstrong\u003e\u003ccode\u003eModule.exports\u003c/code\u003e\u003cstrong\u003e才是真正的接口,\u003cstrong\u003eexports\u003c/strong\u003e只不过是它的一个辅助工具。 最终返回给调用的是\u003c/strong\u003e\u003ccode\u003eModule.exports\u003c/code\u003e\u003cstrong\u003e而不是\u003c/strong\u003eexports。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e所有的\u003cstrong\u003eexports\u003c/strong\u003e收集到的属 …\u003c/p\u003e"
March 7, 2016
Node.js框架比较: Express vs. Koa vs. Hapi
"\u003cp\u003e\u003ca href=\"http://www.nodejs.net/a/20141223/191626.html\"\u003ehttp://www.nodejs.net/a/20141223/191626.html\u003c/a\u003e \u003ca href=\"http://www.zhihu.com/question/25388201\"\u003ehttp://www.zhihu.com/question/25388201\u003c/a\u003e \u003ca href=\"https://cnodejs.org/topic/56936889c2289f51658f0926\"\u003ehttps://cnodejs.org/topic/56936889c2289f51658f0926\u003c/a\u003e\u003c/p\u003e"
February 23, 2016
Git-svn命令对比表,svn用户必看
"\u003cp\u003e提供给从svn转git的开发人员参考\u003c/p\u003e\n\u003cp\u003eGit与Subversion的命令对比表\u003c/p\u003e\n\u003ctable\u003e\n \u003cthead\u003e\n \u003ctr\u003e\n \u003cth style=\"text-align: left\"\u003e\u003cstrong\u003e操作\u003c/strong\u003e\u003c/th\u003e\n \u003cth style=\"text-align: left\"\u003e\u003cstrong\u003eGIT\u003c/strong\u003e\u003c/th\u003e\n \u003cth style=\"text-align: left\"\u003e\u003cstrong\u003eSUBVERSION\u003c/strong\u003e\u003c/th\u003e\n \u003c/tr\u003e\n \u003c/thead\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e复制数据仓库\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit clone\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003esvn checkout\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e提交\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit commit\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003esvn commit\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e查看提交的详细记录\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit show\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003esvn cat\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e确认状态\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit status\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003esvn status\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e确认差异\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit diff\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003esvn diff\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003ctd style=\"text-align: left\"\u003e确认记录\u003c/td\u003e\n \u003ctd style=\"text-align: left\"\u003egit …\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e"
February 15, 2016
深入解析php中的foreach问题
"\u003cp\u003e篇文章是对php中的foreach问题进行了详细的分析介绍,需要的朋友参考下\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e前言:\u003c/strong\u003e php4中引入了foreach结构,这是一种遍历数组的简单方式。相比传统的for循环,foreach能够更加便捷的获取键值对。在php5之前,foreach仅能用于数组;php5之后,利用foreach还能遍历对象(详见:遍历对象)。本文中仅讨论遍历数组的情况。foreach虽然简单,不过它可能会出现一些意外的行为,特别是代码涉及引用的情况下。\u003c/p\u003e\n\u003cp\u003e下面列举了几种case,有助于我们进一步认清foreach的本质。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e问题1:\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$arr = array(1,2,3);\nforeach($arr as $k =\u0026gt; \u0026amp;$v) {\n$v = $v * 2;\n}\n// now $arr is array(2, 4, 6)\nforeach($arr as $k =\u0026gt; $v) {\necho \u0026#34;$k\u0026#34;, \u0026#34; =\u0026gt; \u0026#34;, \u0026#34;$v\u0026#34;;\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e先从简单的开始,如果我们尝试运行上述代码,就会发现最后输出为0=\u0026gt;2 1=\u0026gt;4 2=\u0026gt;4 。 …\u003c/p\u003e"
December 22, 2015
使用 Git Hook 实现网站的自动部署
"\u003cp\u003e自动化能解放人类的双手,而且更重要的是,因为按照规定的流程来走,也减少了很多误操作的产生。不知道大家平时都是怎么样更新自己生产环境的代码的,FTP 覆盖旧文件、服务器定时任务去 build 最新的源码,还是有更高级的做法?\u003c/p\u003e\n\u003cp\u003e目前我在使用 Git Hook 来部署自己的项目。Git Hook 是 Git 提供的一个钩子,能被特定的事件触发后调用。其实,更通俗的讲,当你设置了 Git Hook 后,只要你的远程仓库收到一次 push 之后,Git Hook 就能帮你执行一次 bash 脚本。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGit的挂钩(Hook)主要包含:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eapplypatch-msg\u003c/li\u003e\n\u003cli\u003epost-update\u003c/li\u003e\n\u003cli\u003epre-rebase\u003c/li\u003e\n\u003cli\u003ecommit-msg\u003c/li\u003e\n\u003cli\u003epre-applypatch\u003c/li\u003e\n\u003cli\u003eupdate\u003c/li\u003e\n\u003cli\u003epost-commit\u003c/li\u003e\n\u003cli\u003epre-commit\u003c/li\u003e\n\u003cli\u003epost-receive\u003c/li\u003e\n\u003cli\u003eprepare-commit-msg\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里我们只需要使用 post-receive 这个 Hook:在接收 post(push)请求之后执行。\u003c/p\u003e\n\u003cp\u003e下面是我使用 Git Hook 进行简单的自动化部署,可能还有更高级的做法,大家自己去挖掘。\u003c/p\u003e\n\u003cp\u003e服务器上需要配 …\u003c/p\u003e"
December 22, 2015
Git中的hooks钩子
"\u003cp\u003eGit可以定制一些钩子,这些钩子可以在特定的情况下被执行,分为Client端的钩子和Server端的钩子。\nClient 端钩子被operation触发,比如commit,merge等Server 端钩子被网络动作触发,比如pushed commits。\u003c/p\u003e\n\u003cp\u003e那么钩子是放在哪的呢?\u003c/p\u003e\n\u003cp\u003e在.git/hooks/文件夹下。当你init一个仓库的时候,下边会有一些钩子的例子,以.sample结尾。\u003c/p\u003e\n\u003cp\u003e那么钩子什么时候被执行,Git预定义了触发时机:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eClientSide hooks:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1 pre-commit,当执行commit动作时先执行此hook,可以用此hook做一些检查,比如代码风格检查,或者先跑测试。\u003c/p\u003e\n\u003cp\u003e2 prepare-commit-msg, 当commit时需要输入message前会触发此hook,可以用此hook来定制自己的default message信息。\u003c/p\u003e\n\u003cp\u003e3 commit-msg,当用户输入commit的message后被触发,可以用此hook校验message的信息,比如是否符合规定,有没有cr等。\u003c/p\u003e\n\u003cp\u003e4 post-commit, 当commit完成后被触发,可以用此hook发 …\u003c/p\u003e"
December 13, 2015
brew tap介绍
"\u003cp\u003e官方介绍: \u003ca href=\"https://github.com/Homebrew/homebrew/wiki/brew-tap\"\u003ehttps://github.com/Homebrew/homebrew/wiki/brew-tap\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003ebrew 有个默认的仓库,brew tap 你可以看成是第三方的仓库。\n这个相信很多人都已经用到过了,安装他人扩展的 brew 服务。由于 brew 和包含的包源都是通过 github 来管理,人为的维护管理,除了自己的源还允许别人的源添加进来。类似与 Ubuntu 的 ppa。好处在于只有我安装规定的方式把包丢到 github 上面就可以用了!\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew tap \u0026lt;gihhub_user/repo\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这个命令并没有包含任何的帮助说明,其实它只接受上面的这个参数。\u003c/p\u003e\n\u003cp\u003e举例说明一下,Mac OS 比较歧视 PHP ,所以每次系统更新都会把常用的开发包(Ruby、Python 等)也顺带着更新到最新版本。(吐槽:Java 都已经被抛弃不再默认安装了),而 brew 居然也不包含 PHP 的包,那怎么办呢?\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew tap josegonzalez/php\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e命令完成之后,执行(当前最新是 php 5.5 版本,请根据需要替换)\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ brew install …\u003c/code\u003e\u003c/pre\u003e"
December 9, 2015
mac下安装PHP提示configure: error: Cannot find OpenSSL’s 的解决办法
"\u003cp\u003e在mac 10.11.2 下安装PHP7的时候,在./configure的时候,提示\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003echecking for strftime… (cached) yes\nchecking whether to enable LIBXML support… yes\nchecking libxml2 install dir… /usr\nchecking for xml2-config path… /usr/bin/xml2-config\nchecking whether libxml build works… yes\nchecking for OpenSSL support… yes\nchecking for Kerberos support… no\nchecking whether to use system default cipher list instead of hardcoded value… no\nchecking for RAND_egd… no\nchecking for pkg-config… no\nconfigure: error: Cannot find OpenSSL’s\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e错 …\u003c/p\u003e"
December 9, 2015
常用 Git 命令清单(推荐)
"\u003cp\u003e作者: \u003ca href=\"http://www.ruanyifeng.com\"\u003e阮一峰\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e日期: \u003ca href=\"http://www.ruanyifeng.com/blog/2015/12/\"\u003e2015年12月 9日\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e我每天使用 Git ,但是很多命令记不住。\u003c/p\u003e\n\u003cp\u003e一般来说,日常使用只要记住下图6个命令,就可以了。但是熟练使用,恐怕要记住60~100个命令。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015120901.png\" alt=\"\"\u003e\u003c/p\u003e\n\u003cp\u003e下面是我整理的常用 Git 命令清单。几个专用名词的译名如下。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eWorkspace:工作区\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eIndex / Stage:暂存区\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRepository:仓库区(或本地仓库)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRemote:远程仓库\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"一新建代码库\"\u003e一、新建代码库\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 在当前目录新建一个Git代码库\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git init\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 新建一个目录,将其初始化为Git代码库\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git init \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eproject-name\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 下载一个项目和它的整个代码历史\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git clone \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003eurl\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"二配置\"\u003e二、配置\u003c/h2\u003e\n\u003cp\u003eGit的设置文件为\u003ccode\u003e.gitconfig\u003c/code\u003e,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 显示当前的Git配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git config --list\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 编辑Git配置文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git config -e \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e--global\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 设置提交代码时的用户信息\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e$ git config \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003e--global …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/blockquote\u003e"
December 5, 2015
win7下wamp安装PHP7,提示错误模块名称: php7ts.dll的解决办法
"\u003cp\u003e2015年12月3号,PHP7正式发布,目前一直在用PHP5.5版本的,PHP7的性能提高非常大,于是想在本机做一些测试,顺便为后期程序升级PHP7版本做准备。\u003c/p\u003e\n\u003cp\u003e目前开发环境为WIN7 64位。当前软件情况为64位 \u003ca href=\"http://www.wampserver.com/#wampserver-64-bits-php-5-5\"\u003eWampServer2.5\u003c/a\u003e(php5.5.12/apache2.4.9/mysql5.6.17),目前WAMP已经是多PHP版本同时存在,可以很方便的切换到各个PHP版本。\u003c/p\u003e\n\u003cp\u003e按照以前的方法( \u003ca href=\"http://blog.haohtml.com/archives/16180\"\u003ehttp://blog.haohtml.com/archives/16180\u003c/a\u003e),直接从官方下载 \u003ca href=\"http://windows.php.net/download#php-7.0\"\u003ePHP7.0.0\u003c/a\u003e,解压放在 D:/wamp/bin/php/ 这个目录里,并设置phpForApache.ini文件(复制PHP.ini),停止WAMP所有服务并退出,然后再重启WAMP。此时在WAMP的PHP的版本选择里应该会出现PHP7.0.0这个版本选择,我们选择此版本,wamp重启。到此所有步骤已经完成。\u003c/p\u003e\n\u003cp\u003e由于我们需要用到一些PHP的扩展,如GD2,MYSQL,发现启用扩展后,WAMP重启失败,通过WIN7的系统日志发现以下信息:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e错误应用程序名称: httpd.exe,版本: …\u003c/p\u003e\u003c/blockquote\u003e"
December 4, 2015
wamp下配置支持多版本php
"\u003cp\u003e\u003cstrong\u003e\u003ca href=\"http://www.wampserver.com/en\"\u003eWAMPServer\u003c/a\u003e\u003c/strong\u003e 可以让开发者在Windows系统下快速搭建WAMP环境,它支持多版本的Apache、MySQL、PHP之间的相互切换,互不影响,对于PHPer开发者来讲极为方便快速。\u003c/p\u003e\n\u003cp\u003e以下是在WAMPServer下同时支持PHP5.3、PHP5.4、PHP5.5、PHP5.6的步骤:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1、安装WAMPServer\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e根据自己的操作系统选择相应的WAMP版本,我这里选择WAMPSERVER-32 BITS \u0026amp; PHP 5.5-2.5,双击安装,选择安装目录即可,超级简单。\u003c/p\u003e\n\u003cp\u003e根据我安装的版本,这里已经默认安装了PHP5.5.12,如下图,可以发现多了两个特别文件: \u003cstrong\u003ephpForApache.ini\u003c/strong\u003e、 \u003cstrong\u003ewampserver.conf\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2015/12/wamp_1.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2015/12/wamp_1.png\" alt=\"wamp_1\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2、下载PHP二进制包\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003ePHP目前提供PHP5.3、PHP5.4、PHP5.5、PHP5.6版本,因为我安装的是WAMPSERVER-32 BITS,所以对应的PHP版本只能是32位,到 \u003cstrong\u003e\u003ca href=\"http://windows.php.net/download/\"\u003eWindows PHP\u003c/a\u003e\u003c/strong\u003e 下载TS版本( \u003cstrong\u003eThread-Safe-VC9-X86\u003c/strong\u003e)对应的PHP二进制 \u003cstrong\u003eZIP\u003c/strong\u003e 包,并解压缩二进制包到WAMP安装目录, …\u003c/p\u003e"
December 2, 2015
React开发中的常见问题
"\u003cp\u003e当你在写react的时候报了类似于这样子的错:\u003cstrong\u003eEach child in an array or iterator should have a unique “key” prop.Check the render method of \u003ccode\u003exxxx\u003c/code\u003e. See \u003ca href=\"https://fb.me/react-warning-keys\"\u003ehttps://fb.me/react-warning-keys\u003c/a\u003e for more information.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e原因是这样子的:\u003cstrong\u003eReact can’t know that your array is static, so you get the warning. The most practical thing to do here is to write something like.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e解决办法只要在循环的每个子项添加一个key就行了,代码如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003evar names = [\u0026#39;Alice\u0026#39;, \u0026#39;Emily\u0026#39;, \u0026#39;Kate\u0026#39;];\n\nReactDOM.render(\n \u0026lt;div\u0026gt;\n {\n names.map(function (name, …\u003c/code\u003e\u003c/pre\u003e"
November 30, 2015
webpack使用教程
"\u003cp\u003e官方中文:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.css88.com/doc/webpack/concepts\"\u003ehttp://www.css88.com/doc/webpack/concepts/\u003c/a\u003e \u003ca href=\"https://webpack.js.org/guides/getting-started/\"\u003ehttps://www.webpackjs.com/guides/getting-started\u003c/a\u003e\n中文: \u003ca href=\"https://doc.webpack-china.org/guides/getting-started\"\u003ehttps://doc.webpack-china.org/guides/getting-started\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e经典入门(推荐): \u003ca href=\"https://github.com/ruanyf/webpack-demos\"\u003ehttps://github.com/ruanyf/webpack-demos\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e官方入门教程: \u003ca href=\"https://webpack.js.org/guides/getting-started/\"\u003ehttps://webpack.js.org/guides/getting-started/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eReact+Babal+WebPack: \u003ca href=\"https://github.com/ruanyf/react-babel-webpack-boilerplate\"\u003ehttps://github.com/ruanyf/react-babel-webpack-boilerplate\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eGitbook 英文原版: \u003ca href=\"http://christianalfoni.github.io/react-webpack-cookbook/\"\u003ehttp://christianalfoni.github.io/react-webpack-cookbook/\u003c/a\u003e\n中文版: \u003ca href=\"https://fakefish.github.io/react-webpack-cookbook/\"\u003ehttps://fakefish.github.io/react-webpack-cookbook/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e如何使用webpack …\u003c/strong\u003e\u003c/p\u003e"
November 5, 2015
基于SourceTree 下的 Git Flow 模型
"\u003cp\u003egitflow 开发流程参考: \u003ca href=\"http://blog.haohtml.com/archives/15317\"\u003ehttp://blog.haohtml.com/archives/15317\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e[\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/git_flow.png\" alt=\"git_flow\"\u003e][1]\n\u003cstrong\u003e基于SourceTree 下的 Git Flow 模型\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003esourceTree 是一个开源的git 图形管理工具,可下载mac版本,windows版本\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGit Flow 是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e基本的操作流程\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e先用sourceTree 创建本地git 项目,xxxProject,\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在项目里面先提交一次 commit 一下,默认提交在了 master分支;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后在 sourceTree工具 右上角,点击 GitFlow,开启git Flow 规范模型的开发\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e[\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/git-flow_1.png\" alt=\"git-flow_1\"\u003e][2]\u003c/p\u003e\n\u003cp\u003e如上图,在开启gitFlow 之后;\u003c/p\u003e\n\u003cp\u003e生产环境分支使用:master\u003c/p\u003e\n\u003cp\u003e开发分支使用:develop\u003c/p\u003e\n\u003cp\u003e当需要新增加功能,发布版本时,创建补丁修复bug时,分别有对应的 feature,release,hotfix前缀这样的分支\u003c/p\u003e\n\u003cp\u003e这样在项目的开发过程之中,管理项目分支就变得非常的规范了;\u003c/p\u003e\n\u003cp\u003e4:开启之后,我们的项目就回到 …\u003c/p\u003e"
November 4, 2015
Git忽略文件权限
"\u003cp\u003e默认git会记录文件的权限信息,如果文件的权限信息被修改,那么git也作为一个差异保存。但是我们有时候是不需要这方面的差异的(例如在Windows下使用Cygwin),这时需要关闭文件权限的检查。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/20230904181521.png\" alt=\"img\"\u003e\u003c/p\u003e\n\u003cp\u003egit中可以加入忽略文件权限的配置,具体如下:\u003c/p\u003e\n\u003cp\u003e$ git config core.filemode false\n$ git config \u0026ndash;list\u003c/p\u003e\n\u003cp\u003e也可以使用以下命令查看是否生效。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecat .git/config\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/20230904181513.png\" alt=\"img\"\u003e\u003c/p\u003e\n\u003cp\u003e还有一个小问题,在设置这个属性之前权限就混乱的话,是无法自动修复的。这时候,如果仅仅是权限混乱的话,直接\u003ccode\u003egit reset --hard\u003c/code\u003e恢复吧,git会将项目完全恢复到最近一次提交,包括权限。 \u003c/p\u003e"
November 1, 2015
git diff命令详解
"\u003cp\u003ediff里面a表示前面那个变量,b表示第二个变量\u003c/p\u003e\n\u003cp\u003eHEAD commit版本\nIndex staged版本\u003c/p\u003e\n\u003cp\u003ea、查看尚未暂存的文件更新了哪些部分,不加参数直接输入\ngit diff\n此命令比较的是工作目录(Working tree)和暂存区域快照(index)之间的差异\n也就是修改之后还没有暂存起来的变化内容。\u003c/p\u003e\n\u003cp\u003eb、查看已经暂存起来的文件(staged)和上次提交时的快照之间(HEAD)的差异\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit diff –cached\ngit diff –staged\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e显示的是下一次commit时会提交到HEAD的内容(不带-a情况下)\u003c/p\u003e\n\u003cp\u003ec、显示工作版本(Working tree)和HEAD的差别\ngit diff HEAD\u003c/p\u003e\n\u003cp\u003ed、直接将两个分支上最新的提交做diff\ngit diff topic master 或 git diff topic..master\u003c/p\u003e\n\u003cp\u003ee、输出自topic和master分别开发以来,master分支上的changed。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003egit diff topic…master\nChanges that occurred on the master branch …\u003c/code\u003e\u003c/pre\u003e"
October 26, 2015
使用brew cask来安装Mac应用
"\u003ch2 id=\"简介\"\u003e简介\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/phinze/homebrew-cask\"\u003e\u003ccode\u003ebrew cask\u003c/code\u003e\u003c/a\u003e 是一个用命令行管理 Mac 下应用的工具,它是基于 \u003ca href=\"http://brew.sh/\"\u003e\u003ccode\u003ehomebrew\u003c/code\u003e\u003c/a\u003e 的一个增强工具。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehomebrew\u003c/code\u003e 可以管理 Mac 下的命令行工具,例如 \u003ccode\u003eimagemagick\u003c/code\u003e, \u003ccode\u003enodejs\u003c/code\u003e,如下所示:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew cask install qq\nbrew cask install google-chrome\nbrew cask install evernote\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e而使用上 \u003ccode\u003ebrew cask\u003c/code\u003e 之后,你还可以用它来管理 Mac 下的 Gui 程序,例如 \u003ccode\u003eqq\u003c/code\u003e, \u003ccode\u003echrome\u003c/code\u003e, \u003ccode\u003eevernote\u003c/code\u003e 等,如下所示:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ebrew cask install qq\nbrew cask install google-chrome\nbrew cask install evernote\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003ch3 id=\"安装-homebrew\"\u003e安装 homebrew\u003c/h3\u003e\n\u003cp\u003e用以下一行命令即可安装 homebrew\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eruby -e \u0026#34;$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e之后执行 \u003ccode\u003ebrew doctor\u003c/code\u003e 命令可以看看 \u003ccode\u003ehomebrew\u003c/code\u003e 的 …\u003c/p\u003e"
October 19, 2015
写好 Git Commit 信息的 7 个建议
"\u003cp\u003e这里推荐: \u003ca href=\"http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html\"\u003ehttp://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html\u003c/a\u003e\n\u003cstrong\u003e介绍: 为什么好的提交信息如此重要\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当你随意浏览任一 git 仓库的日志,你很可能会发现其中的提交信息或多或少有点乱。举个例子,瞧一瞧我早先提交到 Spring 上的这些宝贝:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$ git log –oneline -5 –author cbeams –before “Fri Mar 26 2009”\u003c/p\u003e\n\u003cp\u003ee5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle …\u003c/p\u003e\u003c/blockquote\u003e"
September 19, 2015
Xcode7 使用NSURLSession发送HTTP请求出错
"\u003cp\u003e控制台打印:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eApplication Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在iOS9 中,苹果将原http协议改成了https协议,使用 TLS1.2 SSL加密请求数据。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决方法:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在info.plist中添加\nNSAppTransportSecurityNSAllowsArbitraryLoads\n\u003ctrue/\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2015/09/20150629175005991.png\"\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/20150629175005991.png\" alt=\"20150629175005991\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e官方文档:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-DontLinkElementID_13\"\u003ehttps://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-DontLinkElementID_13\u003c/a\u003e\u003c/p\u003e"
September 19, 2015
xcode7下安装Alamofire第三方网络基础库
"\u003cp\u003e1.安装类库管理工具\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://code4app.com/article/cocoapods-install-usage\"\u003eCocoaPods安装和使用教程\u003c/a\u003e \u003ca href=\"https://github.com/Carthage/Carthage\"\u003e去中心化的依赖管理器Carthage\u003c/a\u003e (这里没有使用这个库)\u003c/p\u003e\n\u003cp\u003e2.安装Alamofire\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Alamofire/Alamofire\"\u003ehttps://github.com/Alamofire/Alamofire\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以下为在使用Cocopods管理Alamofire类库的前后项目结构图,项目名称为CocoaPodsDemo\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2015/09/cocoapods_1.png\"\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/cocoapods_1.png\" alt=\"cocoapods_1\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2015/09/cocoapods_2.png\"\u003e\u003cimg src=\"https://blog--static.oss-cn-shanghai.aliyuncs.com//uploads/2023/09/cocoapods_2.png\" alt=\"cocoapods_2\"\u003e\u003c/a\u003e\u003c/p\u003e"
September 10, 2015
git中 gitignore 文件的正确用法
"\u003cp\u003e使用 git 做代码管理工具时,设置 gitignore 是必不可少的流程,一些系统或者 IDE 会在目录下生成与项目不相关的文件,而这些文件我们不期望被提交到仓库之中。理解 gitignore 的 pattern 规则十分重要。\u003c/p\u003e\n\u003ch3 id=\"Pattern_规则\"\u003e\u003cstrong\u003ePattern 规则\u003c/strong\u003e\u003c/h3\u003e\n\u003cp\u003e关于 Pattern 规则,可以查看 git 的相关文档: \u003ca href=\"http://git-scm.com/docs/gitignore\"\u003ehttp://git-scm.com/docs/gitignore\u003c/a\u003e,大致有以下几点:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e空行不匹配任何内容,所以可以作为块分隔符;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e#\u003c/code\u003e 开头表示注释,如果相匹配 \u003ccode\u003e#\u003c/code\u003e,可以在前面加一个反斜杠,即 \u003ccode\u003e\\#\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003e除非加了反斜杠,否则一连串的空格会被忽略;\u003c/li\u003e\n\u003cli\u003e如果在匹配的内容前面加上 \u003ccode\u003e!\u003c/code\u003e,则这些匹配过的部分将被移出,如果要匹配以 \u003ccode\u003e!\u003c/code\u003e 开头的内容,需要加上反斜杠,如 \u003ccode\u003e\\!important.txt\u003c/code\u003e;\u003c/li\u003e\n\u003cli\u003e如果一个匹配 pattern 后面有一个斜杠,如 \u003ccode\u003efoo/\u003c/code\u003e,则默认会匹配所有(包含父子文件夹)中的 foo 文件夹内容,并且它不会匹配单个的文件;\u003c/li\u003e\n\u003cli\u003e如果一个匹配 pattern 不包含斜杠,如 \u003ccode\u003efoo\u003c/code\u003e,Git 会将其作为一个 shell 的查找命令匹配内容。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e需要注意的\u003ccode\u003e**\u003c/code\u003e: …\u003c/p\u003e"
July 24, 2015
安装apache+php(fastcgi)
"\u003cp\u003e最近有下二次开发的程序,由于源程序使用了zend压缩,提示需要安装 Zend Guard Loader 扩展。而安装zend guard 7后,发现在phpinfo()里检测不到,后来才发现原来zend guard只能使用nfs非安全线程的php,没有办法,重新下载NFS版本的php版本。以下为安装要点:\u003c/p\u003e\n\u003cp\u003e我用的是WampServer集成环境,于是就想到了把 Apache 换成 FastCGI 模式来跑 PHP5.3 nts 版,这样就可以使用Zend Guard Loader 扩展了。\u003c/p\u003e\n\u003cp\u003e1、下载 \u003ca href=\"http://windows.php.net/downloads/releases/php-5.3.28-nts-Win32-VC9-x86.zip\"\u003ePHP5.3.28\u003c/a\u003e ,解压到 F:/php5.3.28nts ,配置好 php.ini,也顺便把 Zend Guard Loader 扩展配置好。\u003c/p\u003e\n\u003cp\u003e2、下载 \u003ca href=\"http://archive.apache.org/dist/httpd/binaries/win32/\"\u003emod_fcgid-2.3.6-win32-x86.zip\u003c/a\u003e 或 \u003ca href=\"http://www.apachelounge.com/download/\"\u003ehttp://www.apachelounge.com/download/\u003c/a\u003e 解压 manual、modules 目录中的文件到 f:\\wamp\\bin\\apache\\apache2.2.22 对应目录里去。\u003c/p\u003e\n\u003cp\u003e3、打开 Apache …\u003c/p\u003e"
June 17, 2015
git commit 与 git commit -a 的区别
"\u003cp\u003e软件版本:\n操作系统:ubuntu10.04\n内核版本:Linux version 2.6.32-36-generic\ngit 版本:git version 1.7.0.4\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e目录:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e文件状态\u003c/li\u003e\n\u003cli\u003e提交\n2.1 git commit 与 git commit -a\n2.2 添加提交信息\u003c/li\u003e\n\u003cli\u003e修改/取消\u003c/li\u003e\n\u003cli\u003e参考资料\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e1. 文件状态\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e一般仓库中的文件可能存在于这三种状态:\u003c/p\u003e\n\u003cp\u003e1)Untracked files → 文件未被跟踪;\n2)Changes to be committed → 文件已暂存,这是下次提交的内容;\n3) Changes bu not updated → 文件被修改,但并没有添加到暂存区。如果 commit 时没有带 -a 选项,这个状态下的文件不会被提交。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$git status\n# On branch master\n# Changes to be committed:\n# (use \u0026#34;git reset HEAD \u0026lt;file\u0026gt;...\u0026#34; to unstage)\n#\n# new file: file2\n#\n# Changed but …\u003c/code\u003e\u003c/pre\u003e"
June 15, 2015
golang中chan实例
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport \u0026#34;fmt\u0026#34;\n\nfunc main() {\n data := make(chan int) // 数据交换队列\n exit := make(chan bool) // 退出通知\n\ngo func() {\n for d := range data { // 从队列迭代接收数据,直到 close 。\n fmt.Println(d)\n }\n\n fmt.Println(\u0026#34;recv over.\u0026#34;)\n exit \u0026lt;- true // 发出退出通知。\n}()\n\ndata \u0026lt;- 1 // 发送数据。\ndata \u0026lt;- 2\ndata \u0026lt;- 3\n\nclose(data) // 关闭队列。\n\nfmt.Println(\u0026#34;send over.\u0026#34;)\n\n\u0026lt;-exit // 等待退出通知。\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e输出结果:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e1\n2\n3\nsend over.\nrecv over.\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e而如果将上面与 exit chan有关的三行删除掉,则结果为:\u003c/p\u003e"
June 13, 2015
golang中chan的理解与使用教程
"\u003cp\u003e对于 chan 介绍见: \u003ca href=\"https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.7.md\"\u003ehttps://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.7.md\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这里我们主要通过实例来介绍对chan的理解及用法.\u003c/p\u003e\n\u003ch1 id=\"无buffer的channels\"\u003e无Buffer的Channels\u003c/h1\u003e\n\u003cp\u003e实例1:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc main() {\nci := make(chan int)\n\nci \u0026lt;- 4\n\nvalue := \u0026lt;-ci\nfmt.Println(value)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行结果错误为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003efatal error: all goroutines are asleep - deadlock!\ngoroutine 1 [chan send]:\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e从上面“fatal error: all goroutines are asleep - deadlock!” 这句我们可以看出是groutings 阻塞了,这里为写阻塞,从“goroutine 1 [chan send]”可以看出来。\u003c/p\u003e\n\u003cp\u003e这一点文档里已经说明阻塞的原因了:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使 …\u003c/p\u003e\u003c/blockquote\u003e"
June 13, 2015
Dev with Vagrant and Docker
"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e为了在团队里搭建统一的本地开发环境,最近花了点时间用了下vagrant和docker,在此做个记录, 这也算一个DevOps的实践。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"vagrant介绍\"\u003eVagrant介绍\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"http://vagrantup.com/\"\u003eVagrant\u003c/a\u003e 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史。\u003c/p\u003e\n\u003cp\u003e我们可以通过 Vagrant 封装一个 Linux 的开发环境,分发给团队成员。成员可以在自己喜欢的桌面系统(Mac/Windows/Linux)上开发程序,代码却能统一在封装好的环境里运行,非常霸气。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e以上介绍直接抄自\u003ca href=\"http://blog.segmentfault.com/fenbox/1190000000264347\"\u003e网络\u003c/a\u003e,我觉得介绍的很到位。\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e「注意点:」\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003evagrant up命令执行后,如果看到下面的错误信息,则需要安装另外一个工具:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[default] The guest additions on this VM do not match the installed version of\nVirtualBox! In most cases this is fine, but in rare cases it can\nprevent …\u003c/p\u003e\u003c/blockquote\u003e"
June 9, 2015
golang中flag包的用法
"\u003cp\u003egolang中flag包主要用来CLI下,获取命令参数,示例如下mysql.go:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\u0026#34;flag\u0026#34;\n\u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n host := flag.String(\u0026#34;h\u0026#34;, \u0026#34;localhost\u0026#34;, \u0026#34;请指定一个主机\u0026#34;)\n user := flag.String(\u0026#34;u\u0026#34;, \u0026#34;root\u0026#34;, \u0026#34;请指定数据库用户\u0026#34;)\n port := flag.Int(\u0026#34;P\u0026#34;, 3306, \u0026#34;Port number to use for commection or 0 for default to, in port 3306\u0026#34;)\n\n //var name string\n //flag.StringVar(\u0026amp;name, \u0026#34;u\u0026#34;, \u0026#34;root\u0026#34;, \u0026#34;请指定用户名\u0026#34;)\n\n flag.Parse() // …\u003c/code\u003e\u003c/pre\u003e"
May 1, 2015
ios8中action segue
"\u003cp\u003eos8 action segue 有几种方法,一般选择哪一个,每种方法都有什么用,在什么环境下使用?\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2015/05/57_400607_5f360e47ff35d47.jpg\"\u003e\u003cimg src=\"http://blogx.haohtml.com/wp-content/uploads/2015/05/57_400607_5f360e47ff35d47.jpg\" alt=\"57_400607_5f360e47ff35d47\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eApple的解释在这里: \u003ca href=\"https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardSegue.html\"\u003ehttps://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/chapters/StoryboardSegue.html\u003c/a\u003e\n我的翻译:\n\u003cstrong\u003eShow\u003c/strong\u003e: 在master或detail区域展现内容(典型的如iPad的设置界面,左侧是master,右侧是detail),究竟是在哪个区要取决于屏幕上的内容,如果不分master/detail,就单纯的把新的内容push到当前view controller stack的顶部\n\u003cstrong\u003eShow Detail\u003c/strong\u003e: 大致同Show,在detail区域展现内容,如果不分master/detail,新的内容取代当前view controller stack的顶部\n\u003cstrong\u003ePresent Modally\u003c/strong\u003e:模态展示内容\n\u003cstrong\u003ePresent as Popover\u003c/strong\u003e:在当前的view上出现一个小窗口来展示内容,无处不在的“选中文字后出现 复制/翻译 按钮就是这个\n\u003cstrong\u003eCustom\u003c/strong\u003e:自定义 …\u003c/p\u003e"
April 8, 2015
golang中的sync.WaitGroup
"\u003cp\u003eGolang的sync的包有一个并发原语WaitGroup,在日常开发中比较的有用。\u003c/p\u003e\n\u003cp\u003eWaitGroup的用途:它能够一直等到所有的goroutine执行完成,在其期间会会阻塞主线程的执行,直到所有的goroutine执行完成。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e这里要注意一下,在其中的多个goroutine 的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eWaitGroup总共有三个方法:\u003ccode\u003eAdd(delta int),\u003c/code\u003e \u003ccode\u003eDone()\u003c/code\u003e 和 \u003ccode\u003eWait()\u003c/code\u003e。简单的说一下这三个方法的作用。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAdd: 添加或者减少等待goroutine的数量\u003c/p\u003e\n\u003cp\u003eDone: 相当于Add(-1)\u003c/p\u003e\n\u003cp\u003eWait: 执行阻塞,直到所有的WaitGroup数量变成0\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e举个例子\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n \u0026#34;sync\u0026#34;\n \u0026#34;time\u0026#34;\n)\n\nfunc main() {\n var wg sync.WaitGroup\n\n for i := 0; i \u0026lt; 5; i++ { …\u003c/code\u003e\u003c/pre\u003e"
April 8, 2015
Golang语言的GOPATH与工作目录详解
"\u003cp\u003e这篇文章主要介绍了Go语言的GOPATH与工作目录详解,本文详细讲解了GOPATH设置、应用目录结构、编译应用等内容,需要的朋友可以参考下\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGOPATH设置\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003ego 命令依赖一个重要的环境变量:$GOPATH\u003c/p\u003e\n\u003cp\u003e(注:这个不是Go安装目录( \u003cstrong\u003eGOROOT\u003c/strong\u003e)。下面以笔者的工作目录为说明,请替换自己机器上的工作目录。)\u003c/p\u003e\n\u003cp\u003e在类似 Unix 环境大概这样设置:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eexport GOPATH=/home/apple/mygo\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e为了方便,应该把新建以上文件夹,并且把以上一行加入到 .bashrc 或者 .zshrc 或者自己的 sh 的配置文件中。\u003c/p\u003e\n\u003cp\u003eWindows 设置如下,新建一个环境变量名称叫做GOPATH:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eGOPATH=c:mygo\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eGOPATH允许多个目录,当有多个目录时,请注意分隔符,多个目录的时候Windows是分号,Linux系统是冒号,当有多个GOPATH时,默认会将go get的内容放在第一个目录下\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e以上 $GOPATH 目录约定有三个子目录:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1.src 存放源代码(比如:.go .c .h .s等)\u003c/p\u003e\n\u003cp\u003e2.pkg 编译后生成的文件(比如:.a)\u003c/p\u003e\n\u003cp\u003e3.bin 编译后生成的可执行文件( …\u003c/p\u003e"
March 6, 2015
关于Pull Request的十个建议(转)
"\u003cp\u003ePull Request是Bitbucket、GitHub等源代码托管系统为了方便开发者之间协作而提供的一个功能,它提供了一个用户友好的Web界面来帮助审查人员进行代码审查。开发人员可以通过GitHub发出Pull Requests要求请求他人将程序拉下来进行代码审查。一个好的Pull Request不仅仅只是代码的事情,还牵涉到代码审查者对代码的审查,所以开发者不仅要写出好的代码,还必须迎合审查者的审查工作,才能给使得自己贡献的代码顺利通过审查并合并到master分支。现对丹麦的程序员、软件架构师、独立顾问Mark Seemann在自己博客中发布的一篇题为《关于Pull Request的十个建议》的文章进行一个全面的整理,以供读者阅读和参考。具体内容如下:\u003c/p\u003e\n\u003ch2 id=\"1-进行较小的pull-request\"\u003e\u003cstrong\u003e1. 进行较小的Pull Request\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e一个小且集中的Pull Request会使得提交的代码更加容易通过审核。据Mark Seemann根据自己的经验透漏,对提交代码进行审查所花费的时间是随着代码大小呈指数增长,而非线性增长;Pull Request多大才合适与Pull Request做了什么相关,最好少于12个文件的改变。如 …\u003c/p\u003e"
September 14, 2014
使用git-flow来帮助管理git代码
"\u003cp\u003e对git不熟悉的我,经常把git提交搞得很乱,导致在master上有许多无用的commit,最终决定好好地看一下git的使用教程,却不小心发现了还有一个git-flow的工具可以帮助我管理好git项目的代码。\u003c/p\u003e\n\u003cp\u003egit-flow在ubuntu上使用比较简单。首先安装,可以通过apt-get来获取。命令如下:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003esudo apt-get install git-flow\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e如果是在windows下,可以参考这篇文章进行安装: \u003ca href=\"http://my.eoe.cn/sunxun/archive/158.html\"\u003ehttp://my.eoe.cn/sunxun/archive/158.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e如果你的git已经装好,则方便多了,下载下面两个地址的文件,并解压出getopt.exe和libintl3.dll放到git的安装目录的bin目录下。 \u003ca href=\"http://sourceforge.net/projects/gnuwin32/files/util-linux/2.14.1/util-linux-ng-2.14.1-bin.zip/download\"\u003ehttp://sourceforge.net/projects/gnuwin32/files/util-linux/2.14.1/util-linux-ng-2.14.1-bin.zip/download …\u003c/a\u003e\u003c/p\u003e"
June 20, 2014
golint—golang代码质量检测
"\u003cp\u003egithub: \u003ca href=\"https://github.com/golang/lint\"\u003ehttps://github.com/golang/lint\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003egolint是类似javascript中的jslint的工具,主要功能就是检测代码中不规范的地方。golint用于检测go代码。\u003c/p\u003e\n\u003ch2 id=\"使用\"\u003e使用\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ go get github.com/golang/lint\n$ go install github.com/golang/lint\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003egolint 文件名或者目录\u003c/code\u003e\n检测对应的代码。\u003c/p\u003e\n\u003cp\u003egolint会输出一些代码存在的问题:\n比如:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003erecorder.go:55:5: exported var RecordBind should have comment or be unexported\nrecorder.go:158:1: exported function Record_ErrorRecord should have comment or be unexported\nrecorder.go:173:6: don\u0026#39;t use underscores in Go names; type Data_MemStats should be DataMemStats …\u003c/code\u003e\u003c/pre\u003e"
June 19, 2014
Swift中的标准函数
"\u003cp\u003eSwift中共有74个内建函数,但是在Swift官方文档(“ \u003ca href=\"https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097\"\u003eThe Swift Programming Language\u003c/a\u003e”)中只记录了7中。剩下的67个都没有记录。\u003c/p\u003e\n\u003cp\u003e本文将列举Swift所有的内建函数。本文中提到的所谓的内建函数是指那些在Swift中不需要导入任何模块(如Foundation等)或者引用任何类就可以使用的函数。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eabs(signedNumber)\u003c/strong\u003e: 返回给定的有符号数字的绝对值。很简单,但是没有在文档中记录。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eabs(-1) == 1\u003c/li\u003e\n\u003cli\u003eabs(-42) == 42\u003c/li\u003e\n\u003cli\u003eabs(42) == 42\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003econtains(sequence, element)\u003c/strong\u003e: 如果给定的序列(如数组)包含特定的元素,则返回true。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003evar languages = [“Swift”, “Objective-C”]\u003c/li\u003e\n\u003cli\u003econtains(languages, “Swift”) == true\u003c/li\u003e\n\u003cli\u003econtains(languages, “Java”) == false\u003c/li\u003e\n\u003cli\u003econtains([29, 85, 42, 96, 75], 42) == true\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003edropFirst(sequence)\u003c/strong\u003e: 返 …\u003c/p\u003e"
June 16, 2014
iOS的主要框架介绍(转)
"\u003cp\u003e框架是一个目录,这个目录包含了共享库,访问共享库里代码的头文件,和其它的图片和声音的资源文件。一个共享库定义的方法或函数可以被应用程序调用。\u003c/p\u003e\n\u003cp\u003eIOS提供了很多你可以在应用程序里调用的框架。要使用一个框架,需要将它添加到你的项目中,你的项目才可以使用它。许多应用程序都使用了如Foundation、UIKit、和Core Graphics这些框架。根据你为应用程序选择的模版,相关的框架就已经被自动引入了。如果默认加入的框架不能满足你的应用程序的需求,你也可以加入需要的框架。\u003c/p\u003e\n\u003cp\u003e看看HelloWorld.xcodeproj项目里都包含了哪些框架(注:HelloWorld.xcodeproj是《\u003cem\u003eYour First iOS App\u003c/em\u003e tutorial 》这篇教程里的一个项目)\u003c/p\u003e\n\u003cp\u003e1.在XCode里打开HelloWorld.xcodeproj项目(如果还没有打开)\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e在project navigator窗口里点击,点击Frameworks目录前面的三角形图标。你会看到:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eUIKit.framework,Foundation.framework, 和CoreGraphics.framework\u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e点击 …\u003c/li\u003e\u003c/ol\u003e"
June 12, 2014
Swift中的结构体与类的区别(有坑存在)
"\u003ch2 id=\"-\"\u003e结构体和枚举是值类型\u003c/h2\u003e\n\u003cp\u003e在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Booleans)、字符串(string)、数组(array)和字典(dictionaries),都是值类型,并且都是以结构体的形式在后台所实现。\u003c/p\u003e\n\u003cp\u003e在 Swift 中,所有的结构体和枚举都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。\u003c/p\u003e\n\u003ch2 id=\"-\"\u003e类是引用类型\u003c/h2\u003e\n\u003cp\u003e与值类型不同,引用类型在被赋予到一个变量,常量或者被传递到一个函数时,操作的并不是其拷贝。因此,引用的是已存在的实例本身而不是其拷贝。\u003c/p\u003e\n\u003ch1 id=\"恒等运算符\"\u003e恒等运算符\u003c/h1\u003e\n\u003cp\u003e因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作值类型,在被赋予到常量,变量或者传递到函数时,总是会被拷贝。)\u003c/p\u003e\n\u003cp\u003e如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e等价于 ( === )\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不等价于 ( !== )\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e以下是运用这两个运算符检测两个常量或者变量是否引用同一个实例:\u003c/p\u003e\n\u003cp\u003eif …\u003c/p\u003e"
June 12, 2014
Swift中的函数
"\u003cp\u003e对于Swift语言中的函数还是有许多与其它语言不同的地方的。如下:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. 对于指定函数黑夜参数值的函数,在调用函数的时候,如果需要指定参数值的话,需要以“参数名:值”这种格式调用\u003c/strong\u003e\nfunc join(s1:String, s2: String, joinstr: String = “-“) -\u0026gt; String {\nreturn s1 + joinstr + s2\n}\u003c/p\u003e\n\u003cp\u003elet result = join(“hello”, “world”, joinstr:”===”) //或者直接写前两个值\nprintln(result)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. 常量参数和变量参数(Constant and Variable Parameters)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e数参数默认是常量。试图在函数体中更改参数值将会导致编译错误。这意味着你不能错误地更改参数值。\u003c/p\u003e\n\u003cp\u003e但是,有时候,如果函数中有传入参数的变量值副本将是很有用的。你可以通过指定一个或多个参数为变量参数,从而避免自己在函数中定义新的变量。变量参数不是常量,你可以在函数中把它当做新的可修改副本来使用。\u003c/p\u003e\n\u003cp\u003e通过在参数名前加关键字 \u003ccode\u003evar\u003c/code\u003e 来定义变量参数:\u003c/p\u003e\n\u003cp\u003efunc …\u003c/p\u003e"
June 11, 2014
Swift编程语言中的optional(可选)
"\u003ch2 id=\"-\"\u003e可选\u003c/h2\u003e\n\u003cp\u003e使用可选来处理值可能缺失的情况。可选表示:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e有值,等于 x\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e或者\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e没有值\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意:C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回 \u003ccode\u003enil\u003c/code\u003e, \u003ccode\u003enil\u003c/code\u003e 表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如 \u003ccode\u003eNSNotFound\u003c/code\u003e)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选可以让你暗示任意类型的值缺失,并不需要一个特殊值。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e来看一个例子。Swift 的 \u003ccode\u003eString\u003c/code\u003e 类型有一个叫做 \u003ccode\u003etoInt\u003c/code\u003e 的方法,作用是将一个 \u003ccode\u003eString\u003c/code\u003e 值转换成一个 \u003ccode\u003eInt\u003c/code\u003e 值。然而,并不是所有的字符串都可以转换成一个整数。字符串 \u003ccode\u003e\u0026quot;123\u0026quot;\u003c/code\u003e 可以被转换成数字 \u003ccode\u003e123\u003c/code\u003e,但是字符串 \u003ccode\u003e\u0026quot;hello, world\u0026quot;\u003c/code\u003e 不行。\u003c/p\u003e\n\u003cp\u003e下面的例子使用 \u003ccode\u003etoInt\u003c/code\u003e 方法来尝试将一个 \u003ccode\u003eString\u003c/code\u003e 转换成 \u003ccode\u003eInt\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003elet …\u003c/p\u003e"
June 10, 2014
Swift中的字典
"\u003cp\u003e//1.创建字典\u003c/p\u003e\n\u003cp\u003evar dict:Dictionary\u0026lt;Int, String\u0026gt; = [:“美国“,1:“中国“, 2:“英国“]\u003c/p\u003e\n\u003cp\u003evar country = [\u003c/p\u003e\n\u003cp\u003e“china”: “中国“,\u003c/p\u003e\n\u003cp\u003e“en”:“英国“,\u003c/p\u003e\n\u003cp\u003e“usa”:“美国“\u003c/p\u003e\n\u003cp\u003e]\u003c/p\u003e\n\u003cp\u003e//创建一个空的字典\u003c/p\u003e\n\u003cp\u003evar emptyDictionary = Dictionary\u0026lt;String, Float\u0026gt;()\u003c/p\u003e\n\u003cp\u003evar emptyDictionary2 = [:]\u003c/p\u003e\n\u003cp\u003efor (key,value) incountry {\u003c/p\u003e\n\u003cp\u003evar result = key + value\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e//2.获取字典中的所有键名和键值及字典元素个数\u003c/p\u003e\n\u003cp\u003evar keys = Array(country.keys)\u003c/p\u003e\n\u003cp\u003evar values = Array(country.values)\u003c/p\u003e\n\u003cp\u003evar cnum = country.count\u003c/p\u003e\n\u003cp\u003e//3.访问字典\u003c/p\u003e\n\u003cp\u003evar value = dict[]\u003c/p\u003e\n\u003cp\u003evar value2 = country[“china”]\u003c/p\u003e\n\u003cp\u003e//4.修改字典,修改后,字典中的位置会发生改变\u003c/p\u003e\n\u003cp\u003ecountry[“china”] = “中华人民 …\u003c/p\u003e"
June 10, 2014
swift中的数组操作
"\u003cp\u003evar shopCart: String[] = [“苹果“, “桔子“, “荔枝“]\u003c/p\u003e\n\u003cp\u003evar shoppingList = [“catfilsh”, “water”, “tulips”]\u003c/p\u003e\n\u003cp\u003e//创建一个空数组\u003c/p\u003e\n\u003cp\u003evar emptyArray = String\u003ca href=\"\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e//数组遍历\u003c/p\u003e\n\u003cp\u003efor str inshopCart {\u003c/p\u003e\n\u003cp\u003e println(str)\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e//带索引值的遍历\u003c/p\u003e\n\u003cp\u003efor (index, value) inenumerate(shopCart) {\n println(“(index+1):(value)“)\n}\u003c/p\u003e\n\u003cp\u003e//判断数组是否为空及数组元素个数\u003c/p\u003e\n\u003cp\u003eifshopCart.isEmpty {\u003c/p\u003e\n\u003cp\u003eprintln(“购物车中无任何商品,请购买”)\u003c/p\u003e\n\u003cp\u003e} else {\u003c/p\u003e\n\u003cp\u003eprintln(“您当前购物车中共 (shopCart.count) 有件商品”)\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003eprintln(“=================”)\u003c/p\u003e\n\u003cp\u003e//数组元素添加,{苹果 桔子 荔枝 芒果}\u003c/p\u003e\n\u003cp\u003eshopCart.append(“芒果“)\u003c/p\u003e\n\u003cp\u003efor str inshopCart {\u003c/p\u003e\n\u003cp\u003eprintln(str)\u003c/p\u003e\n\u003cp\u003e} …\u003c/p\u003e"
May 28, 2014
Linux中让crontab以秒为单位执行任务
"\u003cp\u003eLinux下实现秒级定时任务的两种方案(Crontab 每秒运行):\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e第一种方案,当然是写一个后台运行的脚本一直循环,然后每次循环sleep一段时间。\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#!/bin/bash\nwhile true ;do\n\ncommand\n\nsleep XX //间隔秒数\n\ndone\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e或者使用for语句\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#!/bin/bash\n\nfor((i=1;i\u0026lt;=20;i++));do\n/home/somedir/scripts.sh \u0026gt; /dev/null 2\u0026gt;\u0026amp;1\nsleep 3\ndone\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e第二种方案,使用crontab。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我们都知道crontab的粒度最小是到分钟,但是我们还是可以通过变通的方法做到隔多少秒运行一次。\u003c/p\u003e\n\u003cp\u003e以下方法将每20秒执行一次\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ecrontab -e\n* * * * * /bin/date\n* * * * * sleep 20; /bin/date.sh\n* * * * * sleep 40; /bin/date.sh\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e说明:需要将/bin/date.sh更换成你的命令即可\u003c/p\u003e\n\u003cp\u003e这种做法去处理隔几十秒的定时任务还好,要是每1秒运行一次就得添加60条记录。。。如果每秒运 …\u003c/p\u003e"
March 8, 2014
golang中for循环方法的差异
"\u003cp\u003e用for循环遍历字符串时,也有 byte 和 rune 两种方式.第一种试为byte,第二种rune。\u003c/p\u003e\n\u003cp\u003egolang中string rune byte 三者的关系 \u003ca href=\"https://blog.haohtml.com/archives/17646\"\u003ehttps://blog.haohtml.com/archives/17646\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n s := \u0026#34;abc汉字\u0026#34;\n\n for i := 0; i \u0026lt; len(s); i++ {\n fmt.Printf(\u0026#34;%c,\u0026#34;, s[i])\n }\n\n fmt.Println()\n\n for _, r := range s {\n fmt.Printf(\u0026#34;%cn\u0026#34;, r)\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e输出结果:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ea,b,c,æ,±,,å,,,\na\nb\nc\n汉\n字\n\u003c/code\u003e\u003c/pre\u003e"
December 23, 2013
git stash和git stash pop的用法
"\u003cp\u003e推荐阅读: \u003ca href=\"http://www.cppblog.com/deercoder/archive/2011/11/13/160007.html\"\u003ehttp://www.cppblog.com/deercoder/archive/2011/11/13/160007.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e原文: \u003ca href=\"http://gitbook.liuhui998.com/4_5.html\"\u003ehttp://gitbook.liuhui998.com/4_5.html\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、基本操作\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当你正在做一项复杂的工作时, 发现了一个和当前工作不相关但是又很讨厌的bug. 你这时想先修复bug再做手头的工作, 那么就可以用 git stash 来保存当前的工作状态, 等你修复完bug后,执行’反储藏\u0026rsquo;(unstash)操作就可以回到之前的工作里.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git stash save \u0026#34;work in progress for foo feature\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面这条命令会保存你的本地修改到储藏(stash)中, 然后将你的工作目录和索引里的内容全部重置, 回到你当前所在分支的上次提交时的状态.\u003c/p\u003e\n\u003cp\u003e好了, 你现在就可以开始你的修复工作了.\u003c/p\u003e\n\u003cp\u003e… edit and test …\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git commit -a -m \u0026#34;blorpl: typofix\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e当你修复完bug后, 你可以用git stash apply来回 …\u003c/p\u003e"
November 22, 2013
redmine与git组合配置
"\u003cp\u003e参考:\u003ca href=\"http://www.redmine.org/projects/redmine/wiki/HowTo_Easily_integrate_a_(SSH_secured)_GIT_repository_into_redmine\"\u003ehttp://www.redmine.org/projects/redmine/wiki/HowTo_Easily_integrate_a_(SSH_secured)_GIT_repository_into_redmine\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在redmine 的”配置”选项里,填写git仓库位置的时候,一定要在写完整的.git路径,如 \u003cstrong\u003e/data/www/redmine/repos/agent/.git\u003c/strong\u003e ,否则redmine会无法发现git仓库.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://http://blog.haohtml.com/wp-content/uploads/2013/11/redmine-git-repo.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/redmine-git-repo.png\" alt=\"redmine-git-repo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e相关文章:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/benkaoya/article/details/8762935\"\u003ehttp://blog.csdn.net/benkaoya/article/details/8762935\u003c/a\u003e\u003c/p\u003e"
November 11, 2013
使用 Vagrant 打造跨平台开发环境
"\u003cp\u003e\u003ca href=\"http://vagrantup.com/\"\u003eVagrant\u003c/a\u003e 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史。\u003c/p\u003e\n\u003cp\u003e我们可以通过 Vagrant 封装一个 Linux 的开发环境,分发给团队成员。成员可以在自己喜欢的桌面系统(Mac/Windows/Linux)上开发程序,代码却能统一在封装好的环境里运行,非常霸气。\u003c/p\u003e\n\u003ch2 id=\"安装步骤\"\u003e安装步骤\u003c/h2\u003e\n\u003ch3 id=\"1-安装-virtualbox\"\u003e1. 安装 VirtualBox\u003c/h3\u003e\n\u003cp\u003e虚拟机还是得依靠 VirtualBox 来搭建,免费小巧。\n下载地址: \u003ca href=\"https://www.virtualbox.org/wiki/Downloads\"\u003ehttps://www.virtualbox.org/wiki/Downloads\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e* 虽然 Vagrant 也支持 VMware,不过 VMware 是收费的,对应的 Vagrant 版本也是收费的\u003c/em\u003e\u003c/p\u003e\n\u003ch3 id=\"2-安装-vagrant\"\u003e2. 安装 Vagrant\u003c/h3\u003e\n\u003cp\u003e下载地址: \u003ca href=\"http://downloads.vagrantup.com/\"\u003ehttp://downloads.vagrantup.com/\u003c/a\u003e 根据提示一步步安装。\u003c/p\u003e\n\u003cp\u003e此外,还得下载官方封装好的基础镜像:\nUbuntu precise 32 VirtualBox …\u003c/p\u003e"
November 4, 2013
PHP 多台服务器 session 用Memcached存储Session
"\u003cp\u003e\u003cstrong\u003ephp实现多服务器共享session的方法:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e多服务器共享session的方法:\u003c/p\u003e\n\u003cp\u003e1.通过NFS文件共享的方式,多台WEB服务器共享保存session文件的磁盘\n2.保存在数据库中,这种方式的扩展性很强,可以随意增加WEB而不受影响\n3.可以将session数据保存在memcached中,memcached是基于内存存储数据的,性能很高,用户并发量很大的时候尤其合适,参考PHP实现多服务器session共享之memcache共享\n4.文件方式保存session时,可以采用php的扩展eaccelerator来存储sesion\u003c/p\u003e\n\u003cp\u003ephp中的Session默认是用文件的方式存储的,如果用多台WEB服务器,Session共享可能就会成为一个大的问题,可以用NFS共享的方式来存储,但是对于并发请求更多的站点来说,用NFS也会出现问题,下面就说说用Memcached来保存Session的问题。\u003c/p\u003e\n\u003cp\u003evi memcached_session.php,输入如下的代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ip = \u0026#39;192.168.1.111\u0026#39;;\n$port = 11211; …\u003c/code\u003e\u003c/pre\u003e"
October 31, 2013
Golang import使用说明
"\u003cp\u003e我们在写Go代码的时候经常用到import这个命令用来导入包文件,而我们经常看到的方式参考如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\nimport(\n\u0026#34;fmt\u0026#34;\n)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e然后我们代码里面可以通过如下的方式调用\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efmt.Println(\u0026#34;hello world\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面这个fmt是Go语言的标准库,他其实是去goroot下去加载该模块,当然Go的import还支持如下两种方式来加载自己写的模块:\u003c/p\u003e\n\u003cp\u003e1.相对路径\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eimport “./model” //当前文件同一目录的model目录,但是不建议这种方式来import\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e2.绝对路径\u003c/p\u003e\n\u003cp\u003eimport “shorturl/model” //加载gopath/src/shorturl/model模块\u003c/p\u003e\n\u003cp\u003e上面展示了一些import常用的几种方式,但是还有一些特殊的import,让很多新手很费解,下面我们来一一讲解一下到底是怎么一回事\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.点操作\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我们有时候会看到如下的方式导入包\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eimport(\n. \u0026#34;fmt\u0026#34;\n)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用 …\u003c/p\u003e"
October 22, 2013
golang实现验证电子信箱和手机格式合法性(正则表达式)
"\u003cp\u003e邮箱验证\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc checkEmail(email string) (b bool) {\n if m, _ := regexp.MatchString(\u0026#34;^([a-zA-Z0-9\\_-])+@([a-zA-Z0-9\\_-])+(.[a-zA-Z0-9_-])+\u0026#34;, email); !m {\n \treturn false\n }\n return true\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e手机验证\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\nimport (\n\u0026#34;regexp\u0026#34;\n)\n\nconst (\n\tregular = \u0026#34;^(13[0-9]|14[57]|15[0-35-9]|18[07-9])\\\\d{8}$\u0026#34;\n)\n\nfunc validate(mobileNum string) bool {\n reg := regexp.MustCompile(regular)\n return reg.MatchString(mobileNum)\n}\n\nfunc main() {\n if validate(\u0026#34;13888888888\u0026#34;) { …\u003c/code\u003e\u003c/pre\u003e"
October 22, 2013
[必读]golang语言报错信息fatal error: all goroutines are asleep – deadlock!
"\u003cp\u003e出错信息\u003cstrong\u003efatal error: all goroutines are asleep – deadlock!\u003c/strong\u003e\n\u003cstrong\u003e出错信息的意思是:\u003c/strong\u003e\n在main goroutine线,期望从管道中获得一个数据,\u003cstrong\u003e而这个数据必须是其他goroutine线放入管道的\u003c/strong\u003e\n但是其他goroutine线都已经执行完了(all goroutines are asleep),那么就永远不会有数据放入管道。\n所以,main goroutine线在等一个永远不会来的数据,那整个程序就永远等下去了。\n这显然是没有结果的,所以这个程序就说“算了吧,不坚持了,我自己自杀掉,报一个错给代码作者,我被deadlock了”\n例子:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nfunc main() {\n c := make(chan bool)\n go func() {\n c \u0026lt;- true\n }()\n \u0026lt;-c //这里从c管道,取到一个true\n \u0026lt;-c //这行导致deadlock,因为这时的c管道,永远都取不到数据(注释掉这行就不报错)\n}\n\u003c/code\u003e\u003c/pre\u003e"
October 22, 2013
golang日志模块测试
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n \u0026#34;log\u0026#34;\n \u0026#34;os\u0026#34;\n)\n\nfunc main(){\n logfile,err := os.OpenFile(\u0026#34;d:/workspace/golang/test.log\u0026#34;,os.O\\_RDWR|os.O\\_CREATE|os.O_APPEND,0);\n if err!=nil {\n fmt.Printf(\u0026#34;%s\\r\\n\u0026#34;,err.Error());\n os.Exit(-1);\n }\n defer logfile.Close();\n \n logger := log.New(logfile,\u0026#34;\\r\\n\u0026#34;,log.Ldate|log.Ltime|log.Llongfile);\n logger.Println(\u0026#34;hello\u0026#34;);\n logger.Println(\u0026#34;oh….\u0026#34;);\n logger.Fatal(\u0026#34;test\u0026#34;); …\u003c/code\u003e\u003c/pre\u003e"
October 7, 2013
php框架–php框架的连贯查询实现原理
"\u003cp\u003e如果你是一名使用过多种框架的php程序员,你一定见过这样的查询语句:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$result = $mysqlDb-\u0026gt;limit(’0,10′)-\u0026gt;order(‘id desc’)-\u0026gt;findall();\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面的查询语句,连续使用-\u0026gt;操作符进行操作,并最终返回一个查询结果,那么这是如何实现的呢。\u003c/p\u003e\n\u003cp\u003e我们来简单分析一下:\u003c/p\u003e\n\u003cp\u003e-\u0026gt;操作符用来访问对象,上面的语句一共使用了3次-\u0026gt;操作符,而最后一次返回的是查询结果,这说明,前2次-\u0026gt;访问后,返回的应该是一个对象,因为在php中,如果你对一个非对象使用-\u0026gt;操作符是不可能的。这告诉我们,$mysql实例中的limit和order方法都返回一个对其所在类自身的引用即 return $this,了解了这一点,那么我们就可以实现连贯查询了。请看站长写的示例代码:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e/*\n *类功能:实现数据库的连贯查询操作\n */\n class mysql_query{\n var $tbl=’user’;//要操作的表名\n var $limit=”;//存储limit语句的变量\n var $order=”;//存储order …\u003c/code\u003e\u003c/pre\u003e"
October 7, 2013
[翻译]绝妙的 channel
"\u003cp\u003e在编写 golang 程序的过程中,channel 会经常使用。本文对 channel 的使用的确很特别,同时也非常实用。\u003c/p\u003e\n\u003cp\u003e原文在此: \u003ca href=\"http://dave.cheney.net/2013/04/30/curious-channels\" title=\"Curious channels\"\u003ehttp://dave.cheney.net/2013/04/30/curious-channels\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在编写 golang 程序的过程中,channel 会经常使用。本文对 channel 的使用的确很特别,同时也非常实用。\u003c/p\u003e\n\u003cp\u003e原文在此:http://dave.cheney.net/2013/04/30/curious-channels\u003c/p\u003e\n\u003cp\u003e翻译:\u003ca href=\"http://mikespook.com/2013/05/%E7%BF%BB%E8%AF%91%E7%BB%9D%E5%A6%99%E7%9A%84-channel/#more-1635\"\u003ehttp://mikespook.com/2013/05/%E7%BF%BB%E8%AF%91%E7%BB%9D%E5%A6%99%E7%9A%84-channel/#more-1635\u003c/a\u003e\u003c/p\u003e"
October 4, 2013
VIM编辑器下go语法高亮显示
"\u003ch1 id=\"go-in-vim\"\u003eGo in Vim\u003c/h1\u003e\n\u003cp\u003eThe standard Go distribution includes a Go syntax file for Vim in \u003ccode\u003ego/misc/vim/\u003c/code\u003e.\u003c/p\u003e\n\u003ch2 id=\"installation-instructions\"\u003eInstallation Instructions\u003c/h2\u003e\n\u003cp\u003ePlace \u003ccode\u003e$GOROOT/misc/vim/syntax/go.vim\u003c/code\u003e in \u003ccode\u003e~/.vim/syntax/\u003c/code\u003e and put the following in \u003ccode\u003e~/.vim/ftdetect/go.vim\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003e在go的安装目录里有/misc/vim/syntax 他 /misc/vim/ftdetect 两个目录,将里面的文件复制到~/.vim/相应的目录里即可。\u003c/p\u003e\n\u003cp\u003eau BufRead,BufNewFile *.go set filetype=go\u003c/p\u003e\n\u003ch2 id=\"extras-and-alternative-files\"\u003eExtras and Alternative Files\u003c/h2\u003e\n\u003cp\u003eAn alternative indent file for Vim by Alecs King can be found \u003ca href=\"http://go-lang.cat-v.org/text-editors/vim/go-indent.vim\"\u003ehere\u003c/a\u003e.\u003c/p\u003e\n\u003ch2 id=\"autocompletion\"\u003eAutocompletion\u003c/h2\u003e\n\u003cp\u003eThe \u003ca href=\"http://github.com/nsf/gocode\"\u003egocode\u003c/a\u003e daemon by nsf includes a vim script …\u003c/p\u003e"
October 3, 2013
ZeroMQ的模式-Publish-Subscribe[转]
"\u003cp\u003e\u003cstrong\u003ePublish-subscribe Pattern\u003c/strong\u003e:发布订阅模式。\u003c/p\u003e\n\u003cp\u003e现实中,并不是所有请求都期待答复,而不期待答复,自然就没有了状态。所以相对于REQ-REP,PUB-SUB模式容易理解也简单得多。广播听过吧?收音机用过吧?就这个意思。\u003c/p\u003e\n\u003cp\u003e相应地,该模式下的socket也就两种:ZMQ_PUB \u0026amp; ZMQ_SUB。 分别对应电台和收音机。\u003c/p\u003e\n\u003ch1 id=\"toc9\"\u003eZMQ_PUB\u003c/h1\u003e\n\u003cp\u003eZMQ_PUB主要用来让消息发布者用来散发消息的。所有连接上的peer都能收到由它散发的消息。 \u003ca href=\"http://api.zeromq.org/2-1:zmq_recv\"\u003ezmq_recv(3)\u003c/a\u003e 这个API是不能用在这个socket上的,原因显而易见。而zmq_send作用在该socket上时是永远不会阻塞的,如果订阅者异常,发出的消息则会被丢弃。\u003c/p\u003e\n\u003cp\u003eSummary of ZMQ_PUB characteristics\u003c/p\u003e\n\u003cp\u003eCompatible peer sockets\n\u003cem\u003eZMQ_SUB\u003c/em\u003e\nDirection\u003c/p\u003e\n\u003cp\u003eUnidirectional\u003c/p\u003e\n\u003cp\u003eSend/receive pattern\u003c/p\u003e\n\u003cp\u003eSend only\u003c/p\u003e\n\u003cp\u003eIncoming routing strategy\u003c/p\u003e\n\u003cp\u003eN/A\u003c/p\u003e\n\u003cp\u003eOutgoing routing strategy …\u003c/p\u003e"
October 3, 2013
ZeroMQ的模式-综述
"\u003cp\u003e通过对 \u003ca href=\"http://zguide.zeromq.org/page:all\"\u003eGuide\u003c/a\u003e 的阅读,可以发现ZeroMQ对这个世界中消息传输的模式进行了很好的抽象。为了描述模式,0mq定义了不同的socket。 0mq socket是0mq世界的东西,跟传统世界的socket是不一样的。\u003c/p\u003e\n\u003cp\u003e我们知道,传统的socket其实就是访问下面两种(TCP \u0026amp; UDP)对象的\u003cstrong\u003e同步\u003c/strong\u003e的接口:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e面向连接的可靠字节流(SOCK_STREAM)\u003c/li\u003e\n\u003cli\u003e无连接的不可靠的数据报文(SOCK_DGRAM)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e所以你可以说传统socket传输的是字节流或者独立的报文。\u003c/p\u003e\n\u003cp\u003e而0mq的socket传输的是消息(Message)。它是对\u003cstrong\u003e异步_消息_\u003c/strong\u003e\u003cem\u003e队列\u003c/em\u003e(MQ)的一种抽象。官方的原话是:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eØMQ sockets present an abstraction of an asynchronous \u003cem\u003emessage queue\u003c/em\u003e, with the exact queueing semantics depending on the socket type in use.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e异步\u003c/strong\u003e的意思在这里指的是物理连接的创建、销毁、重连、传输对于用户来说都是透明的,这些东西都由0mq组织好了。它传输的是独立的**\u003cem\u003e消 …\u003c/em\u003e\u003c/p\u003e"
October 3, 2013
ZeroMQ的模式-Requset-Reply[转]
"\u003cp\u003e我们先来看看第一种模式:\u003cstrong\u003eRequest-Reply Pattern\u003c/strong\u003e。 请求应答模式。\u003c/p\u003e\n\u003cp\u003eRequest-Reply这个名字很直白,口语点说就是\u003cstrong\u003e一问一答\u003c/strong\u003e。可以使同步的遵循请求序的一问一答,也可以是异步的不按请求序的一问一答;其中也可以包含各种不同的路由策略——让谁来回答。zeromq定义的为这个模式服务的socket有:ZMQ_REQ, ZMQ_REP, ZMQ_ROUTER以及ZMQ_DEALER. 用他们进行合理的组合,就可以实现现实世界中各种不同的请求应答模式。\u003c/p\u003e\n\u003cp\u003e分别来看:\u003c/p\u003e\n\u003ch1 id=\"zmq_req\"\u003eZMQ_REQ\u003c/h1\u003e\n\u003cp\u003eZMQ_REQ做的事情就是\u003cstrong\u003e发问\u003c/strong\u003e,然后\u003cstrong\u003e收答\u003c/strong\u003e。发、收必须是严格按序进行。请求时对对端进行Round Robin,遇到异常则阻塞。官方对这个socket的总结如下:\u003c/p\u003e\n\u003cp\u003eSummary of ZMQ_REQ characteristics\u003c/p\u003e\n\u003cp\u003eCompatible peer sockets\n\u003cem\u003eZMQ_REP\u003c/em\u003e\nDirection\u003c/p\u003e\n\u003cp\u003eBidirectional\u003c/p\u003e\n\u003cp\u003eSend/receive pattern\u003c/p\u003e\n\u003cp\u003eSend, Receive, Send, Receive, …\u003c/p\u003e\n\u003cp\u003eOutgoing routing strategy …\u003c/p\u003e"
October 3, 2013
ZeroMQ的模式-Pipeline[转]
"\u003cp\u003e\u003cstrong\u003ePipeline pattern\u003c/strong\u003e 管道模式。\u003c/p\u003e\n\u003cp\u003e这种模式描述的场景是数据被散布到以管道方式组织的各个节点上。管道的每一步都连接一个或多个节点,连接多个节点时数据以RR方式往下流。\u003c/p\u003e\n\u003cp\u003e注意是\u003cstrong\u003e流\u003c/strong\u003e,意味着数据跟发布模式一样是单向的。这个模式对应的socket是ZMQ_PUSH和ZMQ_PULL.\u003c/p\u003e\n\u003ch1 id=\"zmq_push\"\u003eZMQ_PUSH\u003c/h1\u003e\n\u003cp\u003e用来向下游节点发消息。下游多个节点时采取RoundRobin分发,_zmq_recv()_对于这个socket也是无效的。\u003c/p\u003e\n\u003cp\u003e与Pub不同的是,当下游节点达到高水位(HWM)或者根本没有下游节点时,_zmq_send()_就阻塞了,消息并不丢失。\u003c/p\u003e\n\u003cp\u003eSummary of ZMQ_PUSH characteristics\u003c/p\u003e\n\u003cp\u003eCompatible peer sockets\n\u003cem\u003eZMQ_PULL\u003c/em\u003e\nDirection\u003c/p\u003e\n\u003cp\u003eUnidirectional\u003c/p\u003e\n\u003cp\u003eSend/receive pattern\u003c/p\u003e\n\u003cp\u003eSend only\u003c/p\u003e\n\u003cp\u003eIncoming routing strategy\u003c/p\u003e\n\u003cp\u003eN/A\u003c/p\u003e\n\u003cp\u003eOutgoing routing strategy\u003c/p\u003e\n\u003cp\u003eRound-robin\u003c/p\u003e\n\u003cp\u003eZMQ_HWM option action\u003c/p\u003e\n\u003cp\u003eBlock …\u003c/p\u003e"
October 2, 2013
gozmq的安装与使用教程(zeromq分布式消息队列+golang)
"\u003cp\u003e实现功能:用go实现消息队列的写入与读取(打算用在发送邮件服务)\u003c/p\u003e\n\u003cp\u003e环境工具:\nCentos 64X 6.4\nzeromq 3.2.4: \u003ca href=\"http://www.zeromq.org\"\u003ezeromq.org\u003c/a\u003e\ngolang: \u003ca href=\"http://golang.org/\"\u003ehttp://golang.org/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一.安装golang( \u003ca href=\"http://golang.org/doc/install\"\u003ehttp://golang.org/doc/install\u003c/a\u003e)\u003c/strong\u003e\n这一步很简单,只需要从 \u003ca href=\"http://code.google.com/p/go/downloads\"\u003ehttp://code.google.com/p/go/downloads\u003c/a\u003e 下载到服务器,解压到/usr/local/go目录,再设置一下系统变量就可以了.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ewget https://go.googlecode.com/files/go1.1.2.linux-amd64.tar.gz\ntar -C /usr/local -xzf go1.1.2.linux-amd64.tar.gz\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e设置系统变量GOROOT\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eAdd \u003ccode\u003e/usr/local/go/bin\u003c/code\u003e to the \u003ccode\u003ePATH\u003c/code\u003e environment variable. You can do this by adding this line to your \u003ccode\u003e/etc/profile\u003c/code\u003e (for a system-wide …\u003c/p\u003e"
August 23, 2013
Git 常用命令详解(二)
"\u003ch3 id=\"git-community-book-中文版\"\u003e\u003ca href=\"http://gitbook.liuhui998.com/index.html\"\u003eGit Community Book 中文版\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eGit 是一个很强大的分布式版本管理工具,它不但适用于管理大型开源软件的源代码(如: \u003ca href=\"http://git.kernel.org/\"\u003elinux kernel\u003c/a\u003e),管理私人的文档和源代码也有很多优势(如: \u003ca href=\"http://code.google.com/p/wsi-lgame-pro/\"\u003ewsi-lgame-pro\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003eGit 的更多介绍,请参考我的上一篇博客: \u003ca href=\"http://blog.csdn.net/sunboy_2050/article/details/7527877\"\u003eGit 版本管理工具\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、 Git 命令初识\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在正式介绍Git命令之前,先介绍一下Git 的基本命令和操作,对Git命令有一个总体的认识\u003c/p\u003e\n\u003cp\u003e示例:从Git 版本库的初始化,通常有两种方式:\u003c/p\u003e\n\u003cp\u003e1)git clone:这是一种较为简单的初始化方式,当你已经有一个远程的Git版本库,只需要在本地克隆一份\u003c/p\u003e\n\u003cp\u003e例如:git clone git://github.com/someone/some_project.git some_project\u003c/p\u003e\n\u003cp\u003e上面的命令就是将’git://github.com/someone/some_project.git’这个URL地址的远程版本库,完全克隆到本地some_project目录下\u003c/p\u003e\n\u003cp\u003e2)git init 和 git remote:这种方式稍微复杂一些,当你本地创建了一个工作目录,你可以进 …\u003c/p\u003e"
August 12, 2013
golang中结构体的初始化方法的不同用法(new方法)
"\u003cp\u003e自定义一个结构体\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003etype Rect struct {\n x, y float64\n width, height float64\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e初始化方法:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003erect1 := new(Rect)\nrect2 := \u0026amp;Rect{}\nrect3 := \u0026amp;Rect{0, 0, 100, 200}\nrect4 := \u0026amp;Rect{width:100, height:200}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e注意这几个变量全部为指向Rect结构的指针(\u003cstrong\u003e指针变量\u003c/strong\u003e),因为使用了new()函数和\u0026amp;操作符。\u003c/p\u003e\n\u003cp\u003e而如果使用方法\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ea := Rect{}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e则表示这个是一个Rect{}\u003cstrong\u003e结构类型\u003c/strong\u003e.两者是不一样的.参考代码:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc main() {\na := Rect{}\na.x = 15\n\nrect1 := \u0026amp;Rect{0, 0, 100, 200}\nrect1.x = 10\n\nfmt.Printf(\u0026#34;%v\\n%T\\n\u0026#34;, a, a)\nfmt.Printf(\u0026#34;%v\\n%T\\n\u0026#34;, rect1, rect1)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行结果为:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e{15 0 0 0}\n main.Rect …\u003c/code\u003e\u003c/pre\u003e"
August 11, 2013
golang中的文档管理
"\u003cp\u003efoo.go\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e// CopyRight 2013 The Go Author. All Right reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE fifle.\n\n/*\nPackage foo implements a set of simple mathematical functions. These comments are for\ndemonstration purpose only. Nothing more.\n\nIf you have any questions,please don’t hesitate to add yourself to\ngolang-uns@googlegroups.com.\n\nyou can alse visit golang.org for full Go documentation.\n*/\n\npackage foo\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n)\n\n// …\u003c/code\u003e\u003c/pre\u003e"
August 11, 2013
golang中的map数据类型操作实例
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;fmt\u0026#34;\n)\n\ntype stu struct {\n\tName string\n\tAge int\n}\n\nfunc main() {\n\n\t// 声明一个map变量student,键名为string,值为stu\n\tvar student map[string]stu\n\n\t// 给map变量创建值,同时指定最多可以存储5个stu值\n\tstudent = make(map[string]stu, 5)\n\n\t// map元素赋值\n\tstudent[\u0026#34;stu1\u0026#34;] = stu{\u0026#34;zhao\u0026#34;, 25}\n\tstudent[\u0026#34;stu2\u0026#34;] = stu{\u0026#34;zhang\u0026#34;, 28}\n\tstudent[\u0026#34;stu3\u0026#34;] = stu{\u0026#34;sun\u0026#34;, 32}\n\tstudent[\u0026#34;stu4\u0026#34;] = stu{\u0026#34;li\u0026#34;, 40}\n\tstudent[\u0026#34;stu5\u0026#34;] = stu{}\n\n\t//上面方式的简写方法\n\t/* …\u003c/code\u003e\u003c/pre\u003e"
August 9, 2013
go语言单元测试
"\u003cp\u003eGo本身提供了一套轻量级的测试框架.符合规则的测试代码会在运行测试时被自动识别并执行.单元测试源文件的命名规则如平衡点:在需要测试的包下面创建以”_test”结尾的go文件,开如[^.]*_test.go\u003c/p\u003e\n\u003cp\u003eGo单元测试函数分为两在类.\u003cstrong\u003e功能测试函数\u003c/strong\u003e和\u003cstrong\u003e性能测试函数\u003c/strong\u003e,分别以Test和Benchmark为函数名前缀并以*testing.T 和 *testing.B 为单一参数的函数。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc TestAdd1(t *testing.T)\nfunc BenchmarkAdd1(t *testing.T)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e测试工具会根据函数中的实际执行动作得到不同的测试结果。\u003c/p\u003e\n\u003cp\u003e功能测试函数会根据测试代码执行过程中是否发生错误来反馈结果;\n性能测试函数仅仅打印出来测试所花费时间,用来判断程序性能;\u003c/p\u003e\n\u003ch1 id=\"准备\"\u003e准备\u003c/h1\u003e\n\u003cp\u003e新建一个文件,命名为 go_test.go\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage go_test\n\nimport \u0026#34;testing\u0026#34;\n\nfunc Add(a, b int) int {\n return a + b\n}\n\u003c/code\u003e\u003c/pre\u003e\u003ch1 id=\"功能测试\"\u003e功能测试\u003c/h1\u003e\n\u003cp\u003e在go_test.go文件里添加以下代码\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunc TestAdd1(t …\u003c/code\u003e\u003c/pre\u003e"
August 7, 2013
安装hg命令
"\u003cp\u003e在使用golang开发的时候,有些时间github.com上面的包需要执行hg命令(hg命令简介).这个时候就需要安装一下才可以.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLinux下安装Mercurial(hg):\u003c/strong\u003e\u003c/p\u003e\n\u003ch1 id=\"安装mercurial\"\u003e安装Mercurial\u003c/h1\u003e\n\u003cp\u003e在进行后面的操作之前需要安装Mercurial( \u003ca href=\"http://baike.baidu.com/view/1094619.htm\"\u003e百科\u003c/a\u003e)版本管理系统(可以输出hg名词检测是否安装)。输入以下命令安装:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo easy_install mercurial\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e对于 Ubuntu/Debian 系统,easy_install 命令可以用\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eapt-get install python-setuptools python-dev build-essential\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e安装。 如果上述命令安装失败的话,还可以尝试去官方网站 \u003ca href=\"http://mercurial.selenic.com/wiki/Download\"\u003e下载\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWindows下安装\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e国内国度网盘下载(32位): \u003ca href=\"http://pan.baidu.com/share/link?shareid=3528053518\u0026amp;uk=2365864479\"\u003ehttp://pan.baidu.com/share/link?shareid=3528053518\u0026amp;uk=2365864479\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e(64位): \u003ca href=\"http://pan.baidu.com/share/link?shareid=3560201274\u0026amp;uk=2365864479\"\u003ehttp://pan.baidu.com/share/link?shareid=3560201274\u0026amp;uk=2365864479\u003c/a\u003e\u003c/p\u003e"
July 23, 2013
exec: “pkg-config”: executable file not found in %PATH% 的解决办法
"\u003cp\u003e在windows下要用 \u003ca href=\"http://blog.haohtml.com/tag/golang\"\u003egolang\u003c/a\u003e 实现操作 \u003ca href=\"http://blog.haohtml.com/tag/zeromq\"\u003ezeromq\u003c/a\u003e 消息队列,发现在sublime下进行\u003c/p\u003e\n\u003cp\u003ego get -tags zmq_3_x github.com/alecthomas/gozmq\u003c/p\u003e\n\u003cp\u003e操作的时候,提示\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e# pkg-config –cflags libzmq libzmq libzmq libzmq\nexec: “pkg-config”: executable file not found in %PATH%\nexit status 2\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e原因是因为没有安装pkg-config.需要手动安装,并设置一下环境变量.pkg-config下载地址: \u003ca href=\"http://ftp.acc.umu.se/pub/gnome/binaries/win32/dependencies/pkg-config_0.23-3_win32.zip\"\u003ehttp://ftp.acc.umu.se/pub/gnome/binaries/win32/dependencies/pkg-config_0.23-3_win32.zip\u003c/a\u003e ( \u003ca href=\"http://ftp.acc.umu.se/pub/gnome/binaries/win64/dependencies/pkg-config_0.23-2_win64.zip\"\u003ehttp://ftp.acc.umu.se/pub/gnome/binaries/win64/dependencies/pkg-config_0.23-2_win64.zip\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003e如果无法下载,直接打开所在的目录,找到合适的软件包下载.然后将包里bin目录里 …\u003c/p\u003e"
July 23, 2013
用golang发送邮件
"\u003cp\u003e配置文件 \u003ccode\u003econf.json\u003c/code\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e{\n\u0026#34;Username\u0026#34;: \u0026#34;sunxxg@163.com\u0026#34;,\n\u0026#34;Password\u0026#34;: \u0026#34;123456\u0026#34;,\n\u0026#34;Smtphost\u0026#34;:\u0026#34;smtp.163.com:25\u0026#34;\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e主程序 sendmail.go\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\t\u0026#34;encoding/json\u0026#34;\n\t\u0026#34;fmt\u0026#34;\n\t\u0026#34;io\u0026#34;\n\t\u0026#34;log\u0026#34;\n\t\u0026#34;net/smtp\u0026#34;\n\t\u0026#34;os\u0026#34;\n\t\u0026#34;strings\u0026#34;\n)\n\ntype cfgmail struct {\n\tUsername string\n\tPassword string\n\tSmtphost string\n}\n\ntype cfg struct {\n\tName, Text string\n}\n\nfunc main() {\n\n\t// 从json文件中读取发送邮件服务器配置信息\n\tcfgjson := getConf()\n\n\tvar …\u003c/code\u003e\u003c/pre\u003e"
July 8, 2013
Linux下安装php开发框架yaf
"\u003cp\u003e\u003ca href=\"https://github.com/laruence/php-yaf\"\u003ehttps://github.com/laruence/php-yaf\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eyaf框架中文手册:\u003c/p\u003e\n\u003cp\u003eyaf手册:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.下载并安装yaf扩展\u003c/strong\u003e \u003ca href=\"http://pecl.php.net/package/yaf\"\u003ehttp://pecl.php.net/package/yaf\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#wget http://pecl.php.net/get/yaf-2.2.9.tgz\n#tar zxvf yaf-2.2.9.tgz\n#cd yaf-2.2.9\n\n[root@bogon yaf-2.2.9]# whereis phpize\nphpize: /usr/bin/phpize /usr/share/man/man1/phpize.1.gz\n/usr/bin/phpize\n\n[root@bogon yaf-2.2.9]# /usr/bin/phpize\nConfiguring for:\nPHP Api Version: 20090626\nZend Module Api No: 20090626\nZend Extension Api No: 220090626\n#whereis php-config\nphp-config: /usr/bin/php-config …\u003c/code\u003e\u003c/pre\u003e"
June 18, 2013
测试golang中的多核多线程
"\u003cp\u003e“并发 (concurrency)” 和 “并行 ( parallelism)” 是不同的。在单个 CPU 核上,线程通过时间片或者让出控制权来实现任务切换,达到 “同时” 运行多个任务的⺫的,这就是所谓的并发。但实际上任何时刻都只有一个任务被执行,其他任务通过某种算法来排队。\u003c/p\u003e\n\u003cp\u003e多核 CPU 可以让同个进程内的 “多个线程” 做到真正意义上的同时运,它们之间不需要排队 (依然会发生排队,因为线程数量可能超出 CPU 核数量,还有其他的进程等等。这里说的是一个理想状况),这才是并行。除了多核,并行计算还可能是多台机器上部署运行。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\u0026#34;fmt\u0026#34;\n\u0026#34;runtime\u0026#34;\n)\n\nfunc test(c chan bool, n int) {\n\nx := 0\nfor i := 0; i \u0026lt; 1000000000; i++ {\nx += i\n}\n\nprintln(n, x)\n\nif n == 9 {\nc \u0026lt;- true\n}\n}\n\nfunc main() {\nruntime.GOMAXPROCS(1) //设置cpu …\u003c/code\u003e\u003c/pre\u003e"
June 17, 2013
golang中的Array 、Slices 和 Maps
"\u003cp\u003e**注意\u003ccode\u003eslice\u003c/code\u003e和数组在声明时的区别:**声明数组时,方括号内写明了数组的长度或使用\u003ccode\u003e...\u003c/code\u003e自动计算长度,而声明\u003ccode\u003eslice\u003c/code\u003e时,方括号内没有任何字符。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003earr1 := [10]int{1,2,3,4} //数组,长度为10,只有4个元素指定,其它的元素值默认为0\narr2 := [...]string{\u0026#34;a\u0026#34;,\u0026#34;b\u0026#34;,\u0026#34;c\u0026#34;} //数组,长度自适应,这里长度为3\ns1 := []int{1,2,3,4} //slice,目前长度为4,可能通过append来动态添加元素个数\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e示例:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n \u0026#34;fmt\u0026#34;\n)\n\nfunc main() {\n\n//array example\n arr := [10]int{1, 2, 3} //array 指定前三个值,其它值使用默认类型值0\n fmt.Println(len(arr))\n fmt.Println(arr)\n //a1 := append(arr, 4, 5) //数组不支持append,只有slice才支持append …\u003c/code\u003e\u003c/pre\u003e"
June 4, 2013
golang中包的用法
"\u003cp\u003e将d:/gotest/ 目录加入到GOPATH中.这里会涉及到包和结构体还有一些方法的用法,可以再深入的了了解一下\u003c/p\u003e\n\u003cp\u003e注意一下一些struct和 func 名称的大小写问题.\u003c/p\u003e\n\u003cp\u003e首先要在 \u003cstrong\u003e$GOPATH/src\u003c/strong\u003e 目录里创建一个包名目录,这里包名目录为stu,与文件名一样(也可以不一样),大概流程参考:\n\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/06/GO_package.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/GO_package.png\" alt=\"GO_package\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ed:/gotest/src/main/main.go\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage main\n\nimport (\n\u0026#34;fmt\u0026#34;\n\u0026#34;stu\u0026#34;\n)\n\nfunc main() {\n\n//sxf := new(stu.Stu)\nsxf := \u0026amp;stu.Stu{}\n\nsxf.SetName(\u0026#34;zhangli\u0026#34;)\na := sxf.GetName()\n\nfmt.Println(a)\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003ed:/gotest/src/stu/stu.go\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epackage stu\n\ntype Stu struct {\n\tname string\n\t//age int\n}\n\nfunc (s *Stu) SetName(name string) {\n\ts.name = name\n} …\u003c/code\u003e\u003c/pre\u003e"
May 20, 2013
mysql 根据英文首字母来查询汉字函数
"\u003cp\u003egbk编码:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003emysql\u0026gt; SELECT *,\n -\u0026gt; ELT(INTERVAL(CONV(HEX(left(A_UserName,1)),16,10),\n -\u0026gt; 0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7,0\nxBFA6,0xC0AC,0xC2E8,0xC4C3,0xC5B6,0xC5BE,0xC6DA,0xC8BB,0xC8F6,0xCBFA,0xCDDA,0xCE\nF4,0xD1B9,0xD4D1),\n -\u0026gt; \u0026#39;A\u0026#39;,\u0026#39;B\u0026#39;,\u0026#39;C\u0026#39;,\u0026#39;D\u0026#39;,\u0026#39;E\u0026#39;,\u0026#39;F\u0026#39;,\u0026#39;G\u0026#39;,\u0026#39;H\u0026#39;,\u0026#39;J\u0026#39;,\u0026#39;K\u0026#39;,\u0026#39;L\u0026#39;,\u0026#39;M\u0026#39;,\u0026#39;N\u0026#39;,\u0026#39;O\u0026#39;,\u0026#39;P\u0026#39;,\u0026#39;Q\u0026#39;, …\u003c/code\u003e\u003c/pre\u003e"
April 23, 2013
golang中实现自定义数据类型struct
"\u003cp\u003e可以参考: \u003ca href=\"http://blog.haohtml.com/archives/13556\"\u003egolang中的函数\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003efunc.go\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epackage\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fmt\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003etype\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estu\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eName\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estring\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e//首字母大写,允许其它包直接使用,可以直接使用 stu.Name = \u0026#39;test\u0026#39; 也可以使用 setName和getName\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eage\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e//不允许外面的包使用,可以使用 setAge和getAge方法\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e new(\u003cspan style=\"color:#a6e22e\"\u003estu\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eName\u003c/span\u003e = \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;zhang\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e// age\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003esetAge\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eage\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egetAge\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003efmt\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePrintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%v\\n\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003eage\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e//name\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estring\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003esetName\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sun\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e = \u003cspan style=\"color:#a6e22e\"\u003eperl\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003egetName\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003efmt\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePrintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%i\\n\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#a6e22e\"\u003ename\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e//print struct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003efmt\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePrintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%v\\n\u0026#34;\u003c/span\u003e, …\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"
February 27, 2013
在zend stuido下使用git插件教程
"\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/archives/13679\"\u003e上一节zend stuido下安装了git软件插件\u003c/a\u003e。下面我们来讲一下git插件的使用方法.\u003c/p\u003e\n\u003cp\u003e由于我们目前已经创建好了git项目。所以这里只介绍直接从现成的git项目仓库导入.\u003c/p\u003e\n\u003cp\u003e选择菜单”文件(File)”-\u0026gt;”Import”\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-1.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio-git-guide-1.png\" alt=\"zendstudio-git-guide-1\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-2.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio-git-guide-2.png\" alt=\"zendstudio-git-guide-2\"\u003e\u003c/a\u003e \u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-3.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-3.png\" alt=\"zendstudio-git-guide-3\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e点击”Browse…”选择存放git的目录,然后点击”Search”按钮这样就可以读取一些git配置信息,并在上面显示出来项目目录下的所有文件.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-4.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio-git-guide-4.png\" alt=\"zendstudio-git-guide-4\"\u003e\u003c/a\u003e \u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-5.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-5.png\" alt=\"zendstudio-git-guide-5\"\u003e\u003c/a\u003e最后一步是选择当前项目的名字,这个随便起的。最后点击”Finish”按钮就可以了。\u003c/p\u003e\n\u003cp\u003e这时在IDE左侧会看到项目名字及项目结构信息。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio-git-guide-6.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio-git-guide-6.png\" alt=\"zendstudio-git-guide-6\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下面可以修改一个文件,然后在左侧的导航里选择修改的文件,右键点击,选择”Team” 菜单,再选择”Commit”菜单,会弹出一个对话框,在”Commit message”对话框时里输入提示备注信息。点击”Commit”按钮就可以了。\u003c/p\u003e"
February 27, 2013
zend studio 安装git插件
"\u003cp\u003e搞php的用zend studio这个ide工具的开发人员应该不在少数,而对于我们团队开发使用svn和git版本控制软件也特别多的。我们公司团队使用的是zendstuido 10与git这两个软件。但默认情况下zendstuido并不支持git这个插件的,这个时候需要我们来手动安装git插件。方法如下:\u003c/p\u003e\n\u003cp\u003ezend studio菜单:Help -\u0026gt; Install new software…\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio_install_git_plugins.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio_install_git_plugins.png\" alt=\"zendstudio_install_git_plugins\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2013/02/zendstudio_install_git_plugins_detail.png\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/zendstudio_install_git_plugins_detail.png\" alt=\"zendstudio_install_git_plugins_detail\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e下一步会提示一些是否授受协议之类的。直接选择 我同意(i agree)就可以了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/archives/13689\"\u003e下面我们来讲一下如何在zend stuido下使用git插件\u003c/a\u003e\u003c/p\u003e"
December 31, 2012
golang中的函数
"\u003cp\u003e函数是构建Go程序的基础部件;所遇有趣的事情都是在它其中发生的。函数\n的定义看起来像这样:\nListing 3.1. 函数定义\u003c/p\u003e\n\u003cp\u003etype mytype int 新的类型,参阅第 5 章\n\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2012/12/golang-func.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2012/12/golang-func.png\" alt=\"golang-func\"\u003e\u003c/a\u003e\n0 保留字func用于定义一个函数;\u003c/p\u003e\n\u003cp\u003e1 函数可以定义用于特定的类型,这类函数更加通俗的称呼是method。这\n部分称作receiver而它是可选的(可参考: \u003ca href=\"http://blog.haohtml.com/archives/13766\"\u003ehttp://blog.haohtml.com/archives/13766\u003c/a\u003e)。如下图:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2012/12/golang-struct-func.png\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2012/12/golang-struct-func.png\" alt=\"golang-struct-func\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2 funcname是你函数的名字;\n3 int类型的变量q作为输入参数。参数用pass-by-value方式传递,意味着它\n们会被复制;\n4 变量r和s是这个函数的命名返回值。在Go的函数中可以返回多个值。\n参阅第32页的“多值返回”。如果不想对返回的参数命名,只需要提供类\n型:(int,int)。如果只有一个返回值,可以省略圆括号。如果函数是一\n个子过程,并且没有任何返回值,也可以省略这些内容;\n5 这是函数体,注意return是一个语句,所以包裹参数的括号是可选的。\u003c/p\u003e\n\u003cp\u003e这里有两个例子,左边的函数没有返回值,右边的只是简单的将输入返回。 …\u003c/p\u003e"
December 27, 2012
[golang]将函数作为值
"\u003cp\u003e就像其它在Go中的几乎所有的东西,函数也同样是值而已.它们可以像下面这样赋值给变量:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-go\" data-lang=\"go\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003epackage\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fmt\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003ef\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efunc\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t \u003cspan style=\"color:#a6e22e\"\u003efmt\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003ePrintln\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;func\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#75715e\"\u003e// 下面才开始调用函数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e \u003cspan style=\"color:#a6e22e\"\u003ef\u003c/span\u003e()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e结果会打印出 func 字符串。\u003c/p\u003e\n\u003cp\u003e另一种用法是立即调用函数,但是要求匿名函数要有返回值才可以,不然会提示错误信息.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2012/12/golang_func.jpg\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/golang_func.jpg\" alt=\"golang_func\"\u003e\u003c/a\u003e\u003c/p\u003e"
December 15, 2012
windows 下搭建 GoLang 语言开发环境
"\u003cp\u003egolang官方二进制分发包包括FreeBSD, Linux, Mac OS X (Snow Leopard/Lion), and Windows等平台,包括32位、64位等版本。\u003c/p\u003e\n\u003cp\u003e我自己使用的是windows 32位分发包,MSI格式的,下载地址为: \u003ca href=\"http://code.google.com/p/go/downloads/list\"\u003ehttp://code.google.com/p/go/downloads/list\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003egolang支持交叉编译,也就是说你在32位平台的机器上开发,可以编译生成64位平台上的可执行程序。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e环境变量说明:\u003c/strong\u003e\n$GOROOT 指向golang安装之后的根目录,windows平台下默认为c:\\go,会在安装过程中由安装程序自动写入系统环境变量。\n$GOARCH 目标平台(编译后的目标平台)的处理器架构(386、amd64、arm)\n$GOOS 目标平台(编译后的目标平台)的操作系统(darwin、freebsd、linux、windows)\n$GOBIN 指向安装之后根目录下的bin目录,即$GOROOT/bin,windows平台下默认为c:\\go\\bin,会在安装过程中由安装程序自动添加到PATH变量中\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e配 …\u003c/strong\u003e\u003c/p\u003e"
December 8, 2012
PHP类中static 和self的使用区别
"\u003cp\u003e摘自: \u003ca href=\"http://php.net/manual/en/language.oop5.late-static-bindings.php\"\u003ehttp://php.net/manual/en/language.oop5.late-static-bindings.php\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"limitations-ofself\"\u003eLimitations of \u003cem\u003eself::\u003c/em\u003e\u003c/h3\u003e\n\u003cp\u003eStatic references to the current class like \u003cem\u003eself::\u003c/em\u003e or \u003cem\u003e\u003cstrong\u003eCLASS\u003c/strong\u003e\u003c/em\u003e are resolved using the class in which the function belongs, as in where it was defined:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eExample #1 \u003cem\u003eself::\u003c/em\u003e usage\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e\u0026lt;code\u0026gt;\u0026lt;?php\u0026lt;br /\u0026gt; class A {\u0026lt;br /\u0026gt; public static function who() {\u0026lt;br /\u0026gt; echo __CLASS__;\u0026lt;br /\u0026gt; }\u0026lt;br /\u0026gt; public static function test() {\u0026lt;br /\u0026gt; self::who();\u0026lt;br /\u0026gt; }\u0026lt;br /\u0026gt; }\u003c/code\u003e class B …\u003c/p\u003e"
November 19, 2012
Ajax getjson 跨域通信 php+jquery
"\u003cp\u003e\u003cstrong\u003e网站A的表单提交部分:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e网站B的输出json部分:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e$_GET[‘jsoncallback’] . ‘(‘ . json_encode($return) . ‘)‘);\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e"
November 1, 2012
windows下node.js之 express框架+jade模板搭建
"\u003cp\u003e1、node.js安装\u003c/p\u003e\n\u003cp\u003e在Windows平台部署Node.js比较容易,从0.6.1开始,Node.js在Windows平台上可直接通过.mis文件安装。\u003c/p\u003e\n\u003cp\u003e下载地址 \u003ca href=\"http://nodejs.org/#download\"\u003ehttp://nodejs.org/#download\u003c/a\u003e 目前最新版本是 node-v0.8.3-x86.msi\u003c/p\u003e\n\u003cp\u003e文件在安装过程中已经指定了默认安装路径。\u003c/p\u003e\n\u003cp\u003e验证node.js 安装是否成功\u003c/p\u003e\n\u003cp\u003e打开cmd,直接输入\u003cstrong\u003enode -v\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e2.npm安装\u003c/p\u003e\n\u003cp\u003enode安装成功后npm已经默认安装,npm可以直接安装相关扩展\u003c/p\u003e\n\u003cp\u003e验证npm是否安装成功\u003c/p\u003e\n\u003cp\u003e打开cmd,直接输入\u003cstrong\u003enpm**** -v\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e3.express安装\u003c/p\u003e\n\u003cp\u003e打开cmd,直接输入\u003cstrong\u003enpm install -g express\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e-g:在当前目录下安装express框架\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2012/11/install_express_on_windows_for_nodejs.jpg\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2012/11/install_express_on_windows_for_nodejs.jpg\" alt=\"\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e验证express是否安装成功\u003c/p\u003e\n\u003cp\u003e安装完成后,关闭cmd,在重新打开\u003c/p\u003e\n\u003cp\u003e进入cmd,直接输入\u003cstrong\u003eexpress -V\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意我这里用的大写V\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e4.用express创建项目\u003c/p\u003e\n\u003cp\u003e1).cmd进入要创建项目的目录,直接输入 express testapp(项目名称)\u003c/p\u003e\n\u003cp\u003e2)cd testapp //进入刚新建的站点目录\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3)cmd app …\u003c/strong\u003e\u003c/p\u003e"
September 12, 2012
百度地图API如何给自定义覆盖物添加事件
"\u003cp\u003e摘要:\u003c/p\u003e\n\u003cp\u003e给marker、lable、circle等Overlay添加事件很简单,直接addEventListener即可。那么,自定义覆盖物的事件应该如何添加呢?我们一起来看一看~\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、定义构造函数并继承Overlay\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e//定义自定义覆盖物的构造函数\u003c/li\u003e\n\u003cli\u003efunctionSquareOverlay(center, length, color){\u003c/li\u003e\n\u003cli\u003ethis._center = center;\u003c/li\u003e\n\u003cli\u003ethis._length = length;\u003c/li\u003e\n\u003cli\u003ethis._color = color;\u003c/li\u003e\n\u003cli\u003e}\u003c/li\u003e\n\u003cli\u003e//继承API的BMap.Overlay\u003c/li\u003e\n\u003cli\u003eSquareOverlay.prototype = newBMap.Overlay();\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003e二、初始化自定义覆盖物\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e//实现初始化方法\u003c/li\u003e\n\u003cli\u003eSquareOverlay.prototype.initialize = function(map){\u003c/li\u003e\n\u003cli\u003e//保存map对象实例\u003c/li\u003e\n\u003cli\u003ethis._map = map;\u003c/li\u003e\n\u003cli\u003e//创建div元素,作为自定义覆盖物的容器\u003c/li\u003e\n\u003cli\u003evardiv = document.createElement(“div”);\u003c/li\u003e\n\u003cli\u003ediv.style.position = …\u003c/li\u003e\u003c/ol\u003e"
September 7, 2012
数据类型和Json格式
"\u003col\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e前几天,我才知道有一种简化的数据交换格式,叫做 \u003ca href=\"http://www.yaml.org/\"\u003eyaml\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e我翻了一遍它的 \u003ca href=\"http://www.yaml.org/spec/\"\u003e文档\u003c/a\u003e,看懂的地方不多,但是有一句话令我茅塞顿开。\u003c/p\u003e\n\u003cp\u003e它说, \u003cstrong\u003e从结构上看,所有的数据(data)最终都可以分解成三种类型\u003c/strong\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e第一种类型是 \u003cstrong\u003e标量\u003c/strong\u003e(scalar),也就是一个单独的字符串(string)或数字(numbers),比如”北京”这个单独的词。\u003c/p\u003e\n\u003cp\u003e第二种类型是 \u003cstrong\u003e序列\u003c/strong\u003e(sequence),也就是若干个相关的数据按照一定顺序并列在一起,又叫做数组(array)或列表(List),比如”北京,上海”。\u003c/p\u003e\n\u003cp\u003e第三种类型是 \u003cstrong\u003e映射\u003c/strong\u003e(mapping),也就是一个名/值对(Name/value),即数据有一个名称,还有一个与之相对应的值,这又称作散列(hash)或字典(dictionary),比如”首都:北京”。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e我恍然大悟,数据构成的最小单位原来如此简单!难怪在编程语言中,只要有了数组(array)和对象(object)就能够储存一切数据了。\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e我马上想到了 \u003ca href=\"http://www.json.org/json-zh.html\"\u003ejson\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e21世纪初,Douglas Crockford寻找一种简便的数据交换格式,能够在服务器之间交换数据。当时通用的数据交换语言是XML,但 …\u003c/p\u003e"
August 14, 2012
Git中gitignore失效的问题
"\u003cp\u003e使用git来管理代码,但发现仓库中加入了.gitignore文件,但并不能解除对.gitignore文件中指定的路径及文件进行忽略。是因为加入.gitignore的之前已经进行过提交,提交中含有要忽略的文件,而这个时候.gitignore 对这些文件是失效的,为了解决这个问题,需要先删除这些中间文件,然后进行一次提交就可以解决这些问题了。\u003c/p\u003e\n\u003cp\u003e在本地仓库将.gitgnore文件里指定的相关文件及路径全部删除,再commit到本机一下。然后执行push到git Server就可以了。这样就可以将git sever上的那些临时文件删除掉。以后再使用的话,产生的文件就不会在提交到git server上去了。\u003c/p\u003e"
August 13, 2012
redmine使用nginx提供服务
"\u003cp\u003e上一节 \u003ca href=\"http://blog.haohtml.com/archives/13282\"\u003ehttp://blog.haohtml.com/archives/13282\u003c/a\u003e 我们介绍了在centos下安装redmine软件的方法,但使用时候需要使用ip:3000 的形式才可以访问,不是太方便,我们习惯使用域名的形式来处理的。这里我们直接使用域名redmine.haohtml.com 来访问. 我们使用的是web server 为 nginx 。\u003c/p\u003e\n\u003cp\u003e我们使用虚拟主机配置文件redmine.conf.内容如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eupstream mongrel{\nserver 127.0.0.1:3000;\n}\n\nserver {\n\nlisten 80;\nserver_name redmine.haohtml.com;\nroot /data/wwwroot/redmine/redmine-2.0.3/public;\nlocation / {\nindex index.php index.html index.shtml;\nproxy_pass http://mongrel;\nproxy_redirect off;\nproxy_set_header Host $host; …\u003c/code\u003e\u003c/pre\u003e"
August 12, 2012
centos安装redmine项目管理系统[教程]
"\u003cp\u003e这里操作系统为Linux Centos5,参考文档: \u003ca href=\"http://www.redmine.org/projects/redmine/wiki/HowTo_install_Redmine_on_CentOS_5\"\u003ehttp://www.redmine.org/projects/redmine/wiki/HowTo_install_Redmine_on_CentOS_5\u003c/a\u003e\u003c/p\u003e\n\u003ch3 id=\"另外网上也有一键安装的软件官方网站为\"\u003e另外网上也有一键安装的软件,官方网站为:\u003c/h3\u003e\n\u003ch3 id=\"ruby--ruby-on-rails--rack\"\u003eRuby \u0026amp; Ruby on Rails \u0026amp; Rack\u003c/h3\u003e\n\u003cp\u003eThe required Ruby and Ruby on Rails versions for a given Redmine version is:\u003c/p\u003e\n\u003cp\u003eRedmine version\u003c/p\u003e\n\u003cp\u003eSupported Ruby versions\u003c/p\u003e\n\u003cp\u003eRequired Rails version\u003c/p\u003e\n\u003cp\u003eSupported RubyGems versions\u003c/p\u003e\n\u003cp\u003ecurrent trunk\u003c/p\u003e\n\u003cp\u003eruby 1.8.7, 1.9.2, 1.9.3, jruby-1.6.7\u003c/p\u003e\n\u003cp\u003eRails 3.2.6\u003c/p\u003e\n\u003cp\u003eRubyGems \u0026lt;= 1.8\u003c/p\u003e\n\u003cp\u003e2.0.3\u003c/p\u003e\n\u003cp\u003eruby 1.8.7, 1.9.2, 1.9.3, jruby-1.6.7\u003c/p\u003e\n\u003cp\u003eRails 3.2.6\u003c/p\u003e\n\u003cp\u003eRubyGems \u0026lt;= 1.8\u003c/p\u003e\n\u003cp\u003e2.0.2\u003c/p\u003e\n\u003cp\u003eruby …\u003c/p\u003e"
August 10, 2012
Redmine局域网访问缓慢问题解决
"\u003cp\u003e笔者查阅网上意见,发现是由于Redmine自带的WebrickWeb发布的问题,需要使用Mongrel组件来替换Webrick。在此放在这里方便大家,形成一套完整的Redmine搭建方案。\u003c/p\u003e\n\u003cp\u003e1. 替换其自带的服务器webrick 为mongrel,方法:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003egem install mongrel\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e如果提示类似“\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ehttp11.c: In function ‘header_done’:\nhttp11.c:172:13: error: ‘struct RString’ has no member named ‘ptr’\nhttp11.c:172:13: error: ‘struct RString’ has no member named ‘ptr’\nhttp11.c:172:13: error: ‘struct RString’ has no member named ‘ptr’\nhttp11.c:174:89: error: ‘struct RString’ has no member named ‘ptr’\nhttp11.c:176:52: error: ‘struct …\u003c/code\u003e\u003c/pre\u003e"
August 10, 2012
Windows下安装Redmine教程
"\u003cp\u003ewindows下的一键安装有:\u003c/p\u003e\n\u003cp\u003e参考网址:\u003c/p\u003e\n\u003cp\u003eRedmine是用Ruby开发的基于web的项目管理软件,是用ROR框架开发的一套跨平台项目管理系统,据说是源于Basecamp的ror版而来,支持多种数据库,有不少自己独特的功能,例如提供wiki、新闻台等,还可以集成其他版本管理系统和BUG跟踪系统,例如SVN、CVS、TD等等。这种 Web 形式的项目管理系统通过“项目(Project)”的形式把成员、任务(问题)、文档、讨论以及各种形式的资源组织在一起,大家参与更新任务、文档等内容来推动项目的进度,同时系统利用时间线索和各种动态的报表形式来自动给成员汇报项目进度。\u003c/p\u003e\n\u003cp\u003e我们这里使用RailsInstaller,Ruby和Rails都集成集中。\u003c/p\u003e\n\u003cp\u003e网址是:下载 \u003ca href=\"http://rubyforge.org/frs/download.php/75894/railsinstaller-2.1.0.exe\"\u003ehttp://rubyforge.org/frs/download.php/75894/railsinstaller-2.1.0.exe\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e安装在e:/盘根目录下。安装成功后目录如下图所示:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2012/08/railsinstaller_folder.gif\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2012/08/railsinstaller_folder.gif\" alt=\"\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e1.\u003cstrong\u003e下载 redmine\u003c/strong\u003e(http://www.redmine.org/projects/redmine/wiki/Download) …\u003c/p\u003e"
July 16, 2012
SSH+Git Server on Windows – 在Windows下搭建Git服务器(教程)
"\u003cp\u003e推荐软件: \u003ca href=\"http://www.oschina.net/news/60555/gitstack-2-3-7\"\u003eWindows 的 Git 服务器GitStack\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e会看英文\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e软件需求:\u003c/strong\u003e\n1.windowXP, win7 都测试通过\n2.Copssh_3.1.4_Installer.exe\n3.Git-1.7.3.1-preview20101002.exe\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e搭建git服务器步骤:\u003c/strong\u003e\n1.安装copssh\n1.1 我选择安装路径c:\\ICW,其他选项都选默认.\n1.2 设置环境变量,系统的Path中添加C:\\ICW\\bin\u003c/p\u003e\n\u003cp\u003e1.3 右键 我的电脑,选择 管理,打开 系统工具-\u0026gt;本地用户和组-\u0026gt;用户, 在用户窗口点击右键,选择 新用户,用户 名输入git,密码输入git.\n1.4.选择git用户,右键 选属性, 点击 隶属于-\u0026gt;添加,使git用户被添加到administrator组,并拥有administrator权限.\n1.5 选择 开始-\u0026gt;所有程序-\u0026gt;copssh-\u0026gt;0.1 activate a user,在user name下拉列表中选择刚刚新建的git用户,点击next,输入 Type a passhrase,并记住输入的Type a …\u003c/p\u003e"
July 8, 2012
php下用iconv函数转换字符编码的问题
"\u003cp\u003e昨天在调试 WAP 网站时发现,在增加了 GB2312 到 UTF-8 转化以后,有些页面显示不正常了——有些页面只有一半的内容,另一半被截掉了。因为被截掉的部分包含了\u003c/p\u003e\n\u003cp\u003e的后半个标签\u003c/p\u003e\n\u003cp\u003e,因此整个页面都显示不出来,而报告错误。经过猜测、尝试,最后终于把问题集中在了 iconv 函数上。在经过高人指点以后,发现这个函数的第二个参数,除了可以指定要转化到的编码以外,还可以增加两个后缀://TRANSLIT 和 //IGNORE,其中 //TRANSLIT 会自动将不能直接转化的字符变成一个或多个近似的字符,//IGNORE 会忽略掉不能转化的字符,而默认效果是从第一个非法字符截断。但是我尝试了//TRANSLIT 和 //IGNORE 这两个后缀,效果还是不对。于是我想问题可能不是出在这里。\u003c/p\u003e\n\u003cp\u003e从 GB2312 到 UTF-8 转化应该不会有不能转化的字符,因为 UTF-8 的字符集完全包含了 GB2312 中的字符,所以我想大概是前面要转化的字符集指定错了,于是我尝试着把 GB2312 改成 GBK\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ary=addslashes(iconv(\u0026#34;GB2312\u0026#34;, …\u003c/code\u003e\u003c/pre\u003e"
April 21, 2012
Zend_Filters_Input来实现对密码重复验证
"\u003ch3 id=\"2254-使用-metacommands-来控制过滤器或校验器规则\"\u003e22.5.4. 使用 Metacommands 来控制过滤器或校验器规则\u003c/h3\u003e\n\u003cp\u003e除了声明从字段到过滤器或校验器的映射,你可以在数组声明中指定一些 “metacommands” ,开控制一些 Zend_Filter_Input 的可选的行为。 Metacommands 在给定的过滤器或校验器数组值里以字符串索引条目的形式出现。\u003c/p\u003e\n\u003ch4 id=\"22541the-fields-metacommand\"\u003e22.5.4.1. The \u003ccode\u003eFIELDS\u003c/code\u003e metacommand\u003c/h4\u003e\n\u003cp\u003e如果过滤器或校验器的规则名和需要应用规则的字段名不同,可以用 ‘fields’ metacommand 来指定字段名。\u003c/p\u003e\n\u003cp\u003e可以用类常量 \u003ccode\u003eZend_Filter_Input::FIELDS\u003c/code\u003e 而不是字符串来指定这个 metacommand。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\n$filters = array(\n \u0026#39;month\u0026#39; =\u0026gt; array(\n \u0026#39;Digits\u0026#39;, // filter name at integer index [0]\n \u0026#39;fields\u0026#39; =\u0026gt; \u0026#39;mo\u0026#39; // field name …\u003c/code\u003e\u003c/pre\u003e"
April 21, 2012
Zend_Filter_Input的基本用法
"\u003cp\u003e这里我们假设有一个登录入口,有三个表单元素,分别为用户名(username),密码(password)和验证码(captcha).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e要求如下:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e所有元素去掉两边的空格\u003c/li\u003e\n\u003cli\u003e用户名要为数字和字母\u003c/li\u003e\n\u003cli\u003e验证码为数字类型(这里为了验证为空的情况下,注释掉了这块功能.启用的话,如果输入的是非数字的话,会直接提示不能为空.)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003ePHP 代码如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e \u0026#39;StringTrim\u0026#39;,\n\t\t\t\u0026#39;username\u0026#39; =\u0026gt; \u0026#39;Alnum\u0026#39;,\n\t\t\t//\u0026#39;captcha\u0026#39; =\u0026gt; \u0026#39;Digits\u0026#39;\n\t);\n\n\t$validators = array(\n\t\t\t\u0026#39;username\u0026#39; =\u0026gt; array(\n\t\t\t\t\u0026#39;allowEmpty\u0026#39; =\u0026gt; false\n\t\t\t\t),\n\t\t\t\u0026#39;password\u0026#39; =\u0026gt; array(\n\t\t\t\t\t\u0026#39;allowEmpty\u0026#39; =\u0026gt; false\n\t\t\t\t),\n\t\t\t \u0026#39;captcha\u0026#39; =\u0026gt; …\u003c/code\u003e\u003c/pre\u003e"
April 19, 2012
23.6. Zend Framework 带有的标准表单元素
"\u003ch2 id=\"236zend-framework-带有的标准表单元素\"\u003e23.6. Zend Framework 带有的标准表单元素\u003c/h2\u003e\n\u003cp\u003eZend Framework 带有的具体元素类涵盖了大部分的 HTML 表单元素。其中大部分当装饰元素时,指定了特定的视图助手来用,但有一些还提供了另外的功能。下面是这些类的列表,还有它们提供的功能的描述。\u003c/p\u003e\n\u003ch3 id=\"2361zend_form_element_button\"\u003e23.6.1. Zend_Form_Element_Button\u003c/h3\u003e\n\u003cp\u003e用来生成 HTML 按钮元素, \u003ccode\u003eZend_Form_Element_Button\u003c/code\u003e 继承 Zend_Form_Element_Submit,并派生它的定制功能。它为装饰指定 ‘formButton’ 视图助手。\u003c/p\u003e\n\u003cp\u003e像提交元素一样,它使用元素的标签作为元素的值来显示,还句话说,通过设置元素的值来设置按钮上的文字。如果有翻译适配器,标签将显示翻译后的文字。\u003c/p\u003e\n\u003cp\u003e因为标签用作元素的一部分,但按钮元素只用 ViewHelper 和 DtDdWrapper 装饰器。\u003c/p\u003e\n\u003cp\u003e在组装和校验表单之后,我们可用 \u003ccode\u003eisChecked()\u003c/code\u003e 方法来检查是否给定的按钮被点击。\u003c/p\u003e\n\u003ch3 id=\"2362zend_form_element_checkbox\"\u003e23.6.2. Zend_Form_Element_Checkbox\u003c/h3\u003e\n\u003cp\u003eHTML checkboxes 让你返回一个特定的 …\u003c/p\u003e"
April 19, 2012
Zend_Form 之定制表单
"\u003ch3 id=\"23410-定制表单\"\u003e23.4.10. 定制表单\u003c/h3\u003e\n\u003cp\u003e一个使用基于配置的表单的替代方法是继承 \u003ccode\u003eZend_Form\u003c/code\u003e 类,有若干优点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e可以容易进行单元测试来确保校验和解析如愿执行。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e精细地控制每个元素。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重使用表单对象,最大化可移植性(不需要跟踪配置文件)。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e实现定制功能。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e最典型的用例是使用 \u003ccode\u003einit()\u003c/code\u003e 方法来设置指定的表单元素和配置:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\nclass My_Form_Login extends Zend_Form\n{\n public function init()\n {\n $username = new Zend_Form_Element_Text(\u0026#39;username\u0026#39;);\n $username-\u0026gt;class = \u0026#39;formtext\u0026#39;;\n $username-\u0026gt;setLabel(\u0026#39;Username:\u0026#39;)\n -\u0026gt;setDecorators(array( …\u003c/code\u003e\u003c/pre\u003e"
April 19, 2012
Zend_Form 的方法大全,按类分组
"\u003ch3 id=\"2348-方法\"\u003e23.4.8. 方法\u003c/h3\u003e\n\u003cp\u003e下面是 \u003ccode\u003eZend_Form\u003c/code\u003e 的方法大全,按类分组:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e配置和选项:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003esetOptions(array $options)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003esetConfig(Zend_Config $config)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e插件加载器和路径:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003esetPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type = null)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003egetPluginLoader($type = null)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddPrefixPath($prefix, $path, $type = null) \u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddPrefixPaths(array $spec)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddElementPrefixPath($prefix, $path, $type = null)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddElementPrefixPaths(array $spec)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddDisplayGroupPrefixPath($prefix, $path)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e元数据:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003esetAttrib($key, $value)\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eaddAttribs(array …\u003c/code\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"
April 19, 2012
zend_form 之定制表单元素
"\u003ch3 id=\"2339-定制元素\"\u003e23.3.9. 定制元素\u003c/h3\u003e\n\u003cp\u003e通过继承 \u003ccode\u003eZend_Form_Element\u003c/code\u003e 类,你可以生成自己的定制元素,这样做的原因是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e共享通用的校验器和/或过滤器的元素\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e有定制装饰器功能的元素\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有两个方法一般用来扩展元素: \u003ccode\u003einit()\u003c/code\u003e 可为元素添加定制的初始化逻辑; \u003ccode\u003eloadDefaultDecorators()\u003c/code\u003e 可用于设置一个用于元素的缺省装饰器的列表。\u003c/p\u003e\n\u003cp\u003e用例子来说明,你在一个表单里生成的所有文本元素需要用 \u003ccode\u003eStringTrim\u003c/code\u003e 来过滤、用通用的规则表达式来校验,并且你想用你生成的定制的装饰器来显示它们,’My_Decorator_TextItem’。另外,你有许多想指定的标准属性,包括 ‘size’、 ‘maxLength’ 和 ‘class’。你可以定义这样的元素如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\nclass My_Element_Text extends Zend_Form_Element\n{\n public function init()\n {\n $this-\u0026gt;addPrefixPath(\u0026#39;My_Decorator\u0026#39;, …\u003c/code\u003e\u003c/pre\u003e"
April 19, 2012
Zend_Form中的元数据和属性
"\u003cp\u003e\u003ccode\u003eZend_Form_Element\u003c/code\u003e 处理广泛的属性和元素元数据,基本属性包括:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003ename\u003c/em\u003e: 元素名,使用 \u003ccode\u003esetName()\u003c/code\u003e 和 \u003ccode\u003egetName()\u003c/code\u003e 访问器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003elabel\u003c/em\u003e: 元素标签,使用 \u003ccode\u003esetLabel()\u003c/code\u003e 和 \u003ccode\u003egetLabel()\u003c/code\u003e 访问器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003eorder\u003c/em\u003e: 在表单中出现的元素的索引,使用 \u003ccode\u003esetOrder()\u003c/code\u003e 和 \u003ccode\u003egetOrder()\u003c/code\u003e 访问器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003evalue\u003c/em\u003e: 当前元素的值,使用 \u003ccode\u003esetValue()\u003c/code\u003e 和 \u003ccode\u003egetValue()\u003c/code\u003e 访问器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003edescription\u003c/em\u003e: 元素的描述,常用于提供工具提示或 javascript 上下文提示,描述元素的意图,使用 \u003ccode\u003esetDescription()\u003c/code\u003e 和 \u003ccode\u003egetDescription()\u003c/code\u003e 访问器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003erequired\u003c/em\u003e: 当执行表单校验时,指示元素是否必需的标志,使用 \u003ccode\u003esetRequired()\u003c/code\u003e 和 \u003ccode\u003egetRequired()\u003c/code\u003e 访问器,缺省为 false。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cem\u003eallowEmpty\u003c/em\u003e: 指示可选的元素是否应该校验空值的标志,当为 true,并且要求的标志为 false,空值就不传递给校验器链,并假定为 true。 …\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"
April 19, 2012
zend_form 基础使用方法示例
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003epublic function indexAction()\n {\n\t\t$form = new Zend_Form();\n\n\t\tif ($form-\u0026gt;isValid($_POST)) {\n\t\t\t// success!\n\t\t\t$values = $form-\u0026gt;getValues();\n\n\t\t} else {\n\t\t\t// failure\n\n\t\t\t// deubg\n\t\t\t$this-\u0026gt;view-\u0026gt;form = $form;\n\t\t\treturn $this-\u0026gt;render(\u0026#39;form\u0026#39;);\n\n\t\t}\n\n\t\t$form-\u0026gt;setAction(\u0026#39;/members/index/register\u0026#39;)\n\t\t\t-\u0026gt;setMethod(\u0026#39;post\u0026#39;);\n\n\t\t$form-\u0026gt;setAttrib(\u0026#39;id\u0026#39;, \u0026#39;login\u0026#39;);\n\n\t\t// create and confirure username element\n\t\t//$username = new …\u003c/code\u003e\u003c/pre\u003e"
April 7, 2012
git中的Reversing Pushed Changes
"\u003ch3 id=\"reversing-pushed-changes\"\u003eReversing Pushed Changes\u003c/h3\u003e\n\u003cp\u003eSometimes you or somebody else might have pushed changes accidentally to the remove repository. To get rid of them, first get a log or history of the push commits:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git log\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThen, use \u003ccode\u003egit reset\u003c/code\u003e to push back to a particular come it, identified by its SHA1 sequence from the log. For example:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git reset --hard 6bb3dc30bc0c8fc36421474cf9376d658ee643aa\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eSometimes just the first few letters and numbers of the sequence, such as \u003ccode\u003e6bb3dc\u003c/code\u003e would do.\u003c/p\u003e"
April 5, 2012
Git中的fetch和pull
"\u003cp\u003eGit中从远程的分支获取最新的版本到本地有这样2个命令:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003egit fetch origin master\ngit log -p master..origin/master\ngit merge origin/master\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e以上命令的含义:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e首先从远程的origin的master主分支下载最新的版本到origin/master分支上.\n然后比较本地的master分支和origin/master分支的差别.\n最后进行合并.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e上述过程其实可以用以下更清晰的方式来进行:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003egit fetch origin master:tmp\ngit diff tmp\ngit merge tmp\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e从远程获取最新的版本到本地的test分支上\n之后再进行比较合并\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003egit pull:相当于是从远程获取最新版本并merge到本地\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003egit pull origin master\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e上述命令其实相当于git fetch 和 git merge\n在实际使用中,git fetch更安全一些\n因为在merge前,我们可以查看更新情况,然后再决定 …\u003c/p\u003e"
March 6, 2012
spring ioc aop 的原理
"\u003cp\u003e\u003cstrong\u003espring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在传统的程序设计中,当调用者需要被调用者的协助时,通常由调用者来创建被调用者的实例。但在spring里创建被调用者的工作不再由调用者来完成,因此控制反转(IoC);创建被调用者实例的工作通常由spring容器来完成,然后注入调用者,因此也被称为依赖注入(DI),依赖注入和控制反转是同一个概念。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e面向方面编程(AOP)是以另一个角度来考虑程序结构\u003c/strong\u003e,通过分析程序结构的关注点来完善面向对象编程(OOP)。OOP将应用程序分解成各个层次的对象,而AOP将程序分解成多个切面。spring AOP 只实现了方法级别的连接点,在J2EE应用中,AOP拦截到方法级别的操作就已经足够。在spring中,未来使IoC方便地使用健壮、灵活的企业服务,需要利用spring AOP实现为IoC和企业服务之间建立联系。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eIOC:控制反转也叫依赖注入。利用了工厂模式\u003c/strong\u003e\n将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。 …\u003c/p\u003e"
December 29, 2011
二维数组和指针(C语言)
"\u003cp\u003eint *p,a[5],b[3][4];\u003c/p\u003e\n\u003cp\u003e指针变量给一维数组赋值,可以写成p=a;或则p=\u0026amp;a[0];\u003c/p\u003e\n\u003cp\u003e二维数组需要写成 p=b[0];\n以下为指针与二维数组实例:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#include \u0026lt;stdio.h\u0026gt;\nmain() {\n int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};\n int (*p)[4]=a;\n\n printf(\u0026#34;%d\\n\u0026#34;,*(*(p+2) + 3));\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e输出结果为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e23\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e===========================\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e应该注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。\u003c/strong\u003e\n二维数组指针变量是单个的变量,其一般形式中”(*指针变量名)”两边的括号不可少。\u003c/p\u003e\n\u003cp\u003e而指针数组类型表示的是多个指针(一组有序指针)在一般形式中”*指针数组名”两边不能有括号。\u003c/p\u003e\n\u003cp\u003eint (*p)[3];\n表示一个指向二维数组的指针变量。该二维数组的列数为 3或分解为一维数组的长度为3。\nint *p[3]\n表示 p 是一个 …\u003c/p\u003e"
December 24, 2011
Lua中非全局函数的写法
"\u003cp\u003e这里共有三种写法,这里基本上是将函数和表组合的写法.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.表和函数放在一起\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eLib = {}\nLib.foo = function (x, y) return x + y end\nLib.goo = function (x, y) return x -y end\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e2.使用且构造函数\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eLib = {\n foo = function (x, y) return x + y end,\n goo = function (x, y) return x - y end\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e注意第一个函数后面有一个逗号”,”\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3.Lua提供的另一种语法\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eLib = {}\nfunction Lib.foo (x, y)\n return x + y\nend\nfunction Lib.goo (x, y)\n return x -y\nend\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e当我们将函数保存在一个局部变量内时,我们得到一个局部函数,也就是说局部函数像局部变量一样在一定范围内有效。这种定义在包中是非常有用的:因为 Lua把 chunk当作函数处理,在 chunk内可以声明局部函数(仅仅在 chunk 内可见),词法定界保证 …\u003c/p\u003e"
December 23, 2011
详解如何让EditPlus支持LUA教程
"\u003cp\u003e如何让\u003cstrong\u003eEditPlus\u003c/strong\u003e支持\u003cstrong\u003eLUA\u003c/strong\u003e教程是本文要介绍的内容,这次主要介绍一下学习\u003cstrong\u003eLua\u003c/strong\u003e之前的准备工作。关于在\u003cstrong\u003eEditPlus\u003c/strong\u003e中实现\u003cstrong\u003elua\u003c/strong\u003e的安装,具体内容来看本文详解。\u003c/p\u003e\n\u003cp\u003e(1) 下载Lua安装包,最新版本是lua-5.1.3. 它的体积很小,只有210K, \u003ca href=\"http://luaforge.net/frs/?group_id=377\"\u003ehttp://luaforge.net/frs/?group_id=377\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这是WINDOWS版本. 附带了编辑器,连环境变量都一次搞定了。\u003c/p\u003e\n\u003cp\u003e(2)安装\u003cstrong\u003elua\u003c/strong\u003e包\u003c/p\u003e\n\u003cp\u003e(3)安装EditPlus编辑器:\u003c/p\u003e\n\u003cp\u003e(4)让EditPlus支持lua高亮\u003c/p\u003e\n\u003cp\u003e下拉菜单”工具” — “首选项” ,选择”语法”. 点击”添加”按钮增加一个文件类型,在下面的”描述”和”扩展名”栏里都填写lua。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e下面设置语法文件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003elua.stx文件下载地址:. 注意要按一下”载入”按钮.\u003c/p\u003e\n\u003cp\u003e再设置好”自动换行”和”缩进”.\u003c/p\u003e\n\u003cp\u003e(5)让EditPlus能调用Lua5调试代码\u003c/p\u003e\n\u003cp\u003e选择左面的”用户工具”,点击右面的”添加”–“应用程序”之后,”菜单文本”填 Run_Lua5″命令”栏, 需要写明你步骤(2)安装的lua5系统的位置.在”参数”栏, 选择”文件路径”, 或者$(FilePath) …\u003c/p\u003e"
December 11, 2011
git init 和git –bare init 的具体区别?
"\u003cp\u003e一般个人使用,用git init,这时候你的工作区也在这里。你要是想建立一个固定的地址让大家一起用,就在服务器上用git –bare init。\u003c/p\u003e\n\u003cp\u003e其实你可以看到,init建立的.git目录内容和–bare建立的目录内容是差不多的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e在初始化远程仓库时最好使用 git –bare init 而不要使用:git init。这样在使用hooks的时候,会有用处。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果使用了git init初始化,则远程仓库的目录下,也包含work tree,当本地仓库向远程仓库push时, 如果远程仓库正在push的分支上(如果当时不在push的分支,就没有问题), 那么push后的结果不会反应在work tree上, 也即在远程仓库的目录下对应的文件还是之前的内容,必须得使用git reset –hard才能看到push后的内容.\u003c/p\u003e"
December 11, 2011
“remote:error:refusing to update checked out branch:refs/heads/master”的解决办法
"\u003cp\u003e在使用Git Push代码到数据仓库时,提示如下错误:\u003c/p\u003e\n\u003cp\u003e[remote rejected] master -\u0026gt; master (branch is currently checked out)\u003c/p\u003e\n\u003cp\u003e错误原型\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eremote: error: refusing to update checked out branch: refs/heads/master\u003c/p\u003e\n\u003cp\u003eremote: error: By default, updating the current branch in a non-bare repository\u003c/p\u003e\n\u003cp\u003eremote: error: is denied, because it will make the index and work tree inconsistent\u003c/p\u003e\n\u003cp\u003eremote: error: with what you pushed, and will require ‘git reset –hard’ to match\u003c/p\u003e\n\u003cp\u003eremote: error: the work tree to HEAD.\u003c/p\u003e\n\u003cp\u003eremote: error:\u003c/p\u003e"
November 17, 2011
fckeditor的Error creating folder “” (Can’t create directory)错误的解决办法
"\u003cp\u003e今天使用了fckeditor的编辑器,在下面的环境里测试着没有一点问题的,但上传到服务器上,总是提示\u003c/p\u003e\n\u003cp\u003eError creating folder “” (Can’t create directory)\u003c/p\u003e\n\u003cp\u003e这个错误.经测试发现是 \u003cstrong\u003eapache_lookup_uri\u003c/strong\u003e 函数出的问题,经测试需要获得物理路径,无奈只能修改为 $_SERVER函数\u003c/p\u003e\n\u003cp\u003e打开文件,fckeditor\\editor\\filemanager\\connectors\\php\\io.php\u003c/p\u003e\n\u003cp\u003e修改为\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eif ( function_exists( ‘apache_lookup_uri’ ) )\n{\n/*zongzong 修改\n$info = apache_lookup_uri( $path ) ;\nreturn $info-\u0026gt;filename . $info-\u0026gt;path_info ;\n*/\nreturn $_SERVER[‘DOCUMENT_ROOT’].$path;\n}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e即可.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eapache_lookup_uri\u003c/strong\u003e 函数参考: …\u003c/p\u003e"
November 10, 2011
php里函数名或者方法名前加 & 符号表示的意思
"\u003ch1 id=\"先阅读手册\"\u003e先阅读手册\u003c/h1\u003e\n\u003cp\u003e从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用操作符**\u0026amp;**\u003c/p\u003e\n\u003cp\u003e例子 17-13. 由函数返回一个引用\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\nfunction \u0026amp;returns_reference()\n{\nreturn $someref;\n}\n\n$newref =\u0026amp; returns_reference();\n?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e有关引用的更多信息, 请查看引用的解释。\u003c/p\u003e\n\u003cp\u003e在来看一段很多开源代码喜欢用的单例注册模式\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\nclass a{}\nclass b{}\nfunction \u0026amp; aa($name)\n{\n static $class = array();\n if(!$class[$name])\n {\n $class[$name] = new $name();\n }\n return $class[$name];\n}\n$a = \u0026amp; aa(\u0026#39;a\u0026#39;);\n$b = \u0026amp; aa(\u0026#39;b\u0026#39;);\n\n$a2 = \u0026amp; aa(\u0026#39;a\u0026#39;);\n$b2 = …\u003c/code\u003e\u003c/pre\u003e"
November 1, 2011
检查局域网可用ip的dos批处理脚本
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e要扫描192.168.0.x段的所有可用ip地址\n\u003c/code\u003e\u003c/pre\u003e\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efor /L %i IN(1,1,254) DO ping -w 2 -n 1 192.168.0.%\narp -a\n\u003c/code\u003e\u003c/pre\u003e"
October 30, 2011
一个自动检测服务器网络状态的脚本
"\u003cp\u003e最近服务器总是莫明奇妙的网络不通。我在上一篇文章里写了一个自动检测网卡状态的脚本: \u003ca href=\"http://blog.haohtml.com/archives/11827\"\u003ehttp://blog.haohtml.com/archives/11827\u003c/a\u003e.但发现服务器仍然出现此问题.但服务器内部运行正常.这里基本可以确认是与外网不通的原因.就写了一个脚本,用来检测网络状态,在不通的情况就重启服务器了.此解决办法相当的变态.最好不要使用.\u003c/p\u003e\n\u003cp\u003e1.创建新文件 /data/check_net_status.sh,内容如下\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#!/bin/bash\nif [ $# -ne 1 ]\nthen\necho \u0026#39;ip address not defined!\u0026#39;\nexit\nfi\n\nip=$1\nlog_file=\u0026#34;$(date +%Y%m%d).log\u0026#34;\n\nret=`ping -c 10 $ip | grep ttl | wc -l`\nif [ $ret -lt 2 ]; then\necho \u0026#34;$(date +%H:%M:%S) ===== reboot\u0026#34; \u0026gt;\u0026gt; $log_file\nshutdown -r now\nfi …\u003c/code\u003e\u003c/pre\u003e"
October 27, 2011
php客户端memcached的安装教程
"\u003cp\u003e我们在上篇文章里()介绍了LNMP的安装方法.只安装了memcache客户端.有些用户可能需要memcached这种客户端的.这里介绍一种php客户端memcached的安装方法.\u003c/p\u003e\n\u003cp\u003e之前在安装memcache时有提到memcached客户端是叫memcache,其实还有一个基于libmemcached的客户端叫memcached,据说性能更好,功能也更多。参考:\u003c/p\u003e\n\u003cp\u003ememcache的官方主页: \u003ca href=\"http://pecl.php.net/package/memcache\"\u003ehttp://pecl.php.net/package/memcache\u003c/a\u003e\nmemcached的官方主页: \u003ca href=\"http://pecl.php.net/package/memcached\"\u003ehttp://pecl.php.net/package/memcached\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以下是我安装Memcached版本的PHP模块的过程记录:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#wget http://download.tangent.org/libmemcached-0.9.tar.gz\n#tar zxf libmemcached-0.9.tar.gz\n#cd libmemcached-0.9\n#./configure --prefix=/usr/local/libmemcached --with-memcached\n#make …\u003c/code\u003e\u003c/pre\u003e"
October 22, 2011
FreeBSD下自动检查网卡状态并自动启用网卡
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#/bin/bash\n\nlog_file=`date +%Y%m%d`\nlog_file=$log_file\u0026#34;.log\u0026#34;\ncheck_date=`date +%H:%M:%S`\n#status=`ifconfig bge0 | grep status | awk \u0026#39;{print $2}\u0026#39;`\nstatus=`ifconfig bge0 | awk \u0026#39;/status/{print $2}\u0026#39;`\n\nif [ $status != \u0026#39;active\u0026#39; ]; then\n status=\u0026#39;down\u0026#39;\n ifconfig bge0 up\nelse\n echo \u0026#39;ok\u0026#39;\nfi\n\ncheck_date=${check_date}\u0026#34; =========== \u0026#34;${status}\necho $check_date \u0026gt;\u0026gt; $log_file\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e另一处写法,其实一样的:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#!/bin/bash\nlog_file=\u0026#34;$(date …\u003c/code\u003e\u003c/pre\u003e"
September 15, 2011
[git] Git 高级:Git Reset, Checkout, Diff, Stash
"\u003ch4 id=\"git-reset\"\u003e\u003cstrong\u003eGit Reset\u003c/strong\u003e\u003c/h4\u003e\n\u003cp\u003e有时候,你可能想要撤销 Git 操作。通常,git reset 就是你需要的命令。但是,使用 git reset 可能会非常复杂,取决于你的撤销操作。如果本文没有提到你需要的,查看 \u003ca href=\"http://www.kernel.org/pub/software/scm/git/docs/git-reset.html\"\u003egit reset 官方文档\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e假设,你正在进行一个项目,想要取消所有的改变,返回到最近一次的提交,命令如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git reset --hard HEAD\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e–hard flag 将指定提交(上例中,HEAD)中的任意内容放入工作目录和缓存区内。因为 HEAD 是最近一次提交,所以我们没有做任何改变。运行 git status,会看到提示没有需要提交的。\u003c/p\u003e\n\u003cp\u003e还有其它一些 git reset 使用的 flag。假设你想要回滚你的项目到多个提交之前,但是想要保存没有提交的改变,尝试下面的:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ git reset --soft 3ce072c72d948abfa\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e当然,替换为你自己需要的 hash。–soft flag 将保存你的改变在工作目录和缓存区。换句话来说,最新的提交将会是你选择的提交。\u003c/p\u003e\n\u003cp\u003e还有很多情况,你可以使用 git reset。如果你认为需要这个名利概念的功能,查看\u003ca href=\"http://www.kernel.org/pub/software/scm/git/docs/git-reset.html\"\u003e文档\u003c/a\u003e。 …\u003c/p\u003e"
August 30, 2011
Call to undefined function curl_init()错误解决
"\u003cp\u003e提示不支持这个函数,于是在php.ini文件里启用了扩展,把前面的;去掉,重启apache,竟然不起作用.后来查找了一下,原来还需要两个dll(libeay32.dll、ssleay32.dll)文件支持,将dll复制到c:/windows/system32目录里.然后重启apache即可.\u003c/p\u003e\n\u003cp\u003e特在此记录一下.\u003c/p\u003e"
August 5, 2011
C语言中用const改善程序的健壮性
"\u003cp\u003e关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,现将本人的一些体会总结如下,期望对大家有所帮助:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一 const基础\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:\u003c/p\u003e\n\u003cp\u003eint b = 500;\nconst int* a = \u0026amp;b; [1]\nint const \u003cem\u003ea = \u0026amp;b; [2]\nint\u003c/em\u003e const a = \u0026amp;b; [3]\nconst int* const a = \u0026amp;b; [4]\u003c/p\u003e\n\u003cp\u003e如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常 …\u003c/p\u003e"
August 5, 2011
const修饰指针和引用释疑(转载)
"\u003cp\u003econst修饰指针和引用的用法,对于初学C++的人直是讳莫如深,不知所云.一旦你了解了其用法,一切便不值一哂了.下面我为读者一一释疑:\n大致说来其可分为三种情况: const修饰指针,const修饰引用,const修饰指针的引用.\n\u003cstrong\u003e1.const修饰指针\u003c/strong\u003e\nconst修饰指针又可分为三种情况:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003econst修饰指针本身\u003c/li\u003e\n\u003cli\u003econst修饰指针所指的变量(或对象)\u003c/li\u003e\n\u003cli\u003econst修饰指针本身和指针所指的变量(或对象)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e(1).const修饰指针本身\u003c/strong\u003e\n这种情形下,指针本身为常量,不可改变,任何修改指针本身的行为都是非法的.例如:\nconst int a = 1;\nconst int b = 2;\u003c/p\u003e\n\u003cp\u003eint i = 3;\nint j = 4;\nint* const pi = \u0026amp;i; //ok, pi的类型为int* const , \u0026amp;i的类型为int* const\nint* const pi = \u0026amp;a; //error, pi的类型为int* const, \u0026amp;a的类型为const int* const\npi = \u0026amp;j; //error, 指针是常量, …\u003c/p\u003e"
August 5, 2011
C语言中 static 和 const
"\u003cp\u003estatic 的两大作用:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、控制存储方式:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003estatic被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间。\u003c/p\u003e\n\u003cp\u003e1、引出原因:函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现?\n最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。\u003c/p\u003e\n\u003cp\u003e2、 解决方案:因此c++ 中引入了static,用它来修饰变量,它能够指示编译器将此变量在程序的静态存储区分配空间保存,这样即实现了目的,又使得此变量的存取范围不变。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、控制可见性与连接类型 :\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003estatic还有一个作用,它会把变量的可见范围限制在编译单元中,使它成为一个内部连接,这时,它的反义词为”extern”.\u003c/p\u003e\n\u003cp\u003estatic作用分析总结:static总是使得变量或对象的存储形式变成静态存储,连接方式变成内部连接,对于局部变量(已经是内部连接了),它仅改变其存储方式;对于全局变量( …\u003c/p\u003e"
August 5, 2011
程序基础C语言常量(const)参数
"\u003cp\u003e\u003cstrong\u003e函数 – 常量(const)参数\u003c/strong\u003e 非指针参数(也就是传值参数)不会被修改原始值, const 对它是没有意义的。 const 只用于指针。\u003c/p\u003e\n\u003cp\u003e*\u003cem\u003e1. 第一种用法: const 类型 \u003cem\u003e变量:\u003c/em\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e 这种用法将限制修改指针指向的值。#include\u003c/p\u003e\n\u003cp\u003eint fun(const int *p) {\u003c/p\u003e\n\u003cp\u003e\u003cem\u003ep += 1; /\u003c/em\u003e 只有去掉 const 这句才可以执行 */\u003c/p\u003e\n\u003cp\u003ereturn *p;\u003c/p\u003e\n\u003cp\u003e}int main(void)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eint num = 3;\u003c/p\u003e\n\u003cp\u003eprintf(“%dn”, fun(\u0026amp;num));\u003c/p\u003e\n\u003cp\u003egetchar();\u003c/p\u003e\n\u003cp\u003ereturn 0;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e不过也有办法绕过这个限制:\u003c/p\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003eint fun(const int *p) {\u003c/p\u003e\n\u003cp\u003eint \u003cem\u003ep2 = p; /\u003c/em\u003e 来个重名指针会绕过 const 的限制 */\u003c/p\u003e\n\u003cp\u003e*p2 += 1;\u003c/p\u003e\n\u003cp\u003ereturn *p;\u003c/p\u003e\n\u003cp\u003e}int main(void)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eint num = 3;\u003c/p\u003e\n\u003cp\u003eprintf(“%dn”, fun(\u0026amp;num)); /* 4 */getchar();\u003c/p\u003e"
July 1, 2011
关于C语言中的extern
"\u003cp\u003ec语言有三种链接,外部链接,内部链接和无链接。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e外部链接:对构成程序的所有文件可用,如函数和全局变量具有外部链接。\n内部链接:仅在声明他们的文件中是已知的。如声明为static的文件域具有内部链接。\n无连接:仅在自己的块中已知,其它地方没有办法访问,如局部变量。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eextern主要作用是:声明在程序的其它地方使用外部链接声明的对象。\n声明:表述对象的名称和类型。\n定义:为对象分配存储空间。\u003c/p\u003e\n\u003cp\u003e例如:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eint main(void)\n{\nextern int a, b;\nprintf(“%d %d”, a, b);\ngetch();\nreturn 0;\n}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e/* 全局变量定义到了main之后 */\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eint a = 10, b = 20;\n程序输出10 20。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e通过extern声明变量a和b,可以在a和b定义之前使用,编译器不会提示错误。\u003c/p\u003e\n\u003cp\u003eextern最重要的用途是多文件程序,c允许程序分散在多个文件中,分别编译,链接到一起。\n我们在devc++中新建立一个c工程,然后在添新建一个单元保存名称为cunclx3.c\u003c/p\u003e\n\u003cp\u003emain.c的程序代码:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include\n#include\nint …\u003c/p\u003e\u003c/blockquote\u003e"
June 29, 2011
git常用命令总结[原创]
"\u003cp\u003e\u003cstrong\u003etxt笔记一篇: \u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2011/06/git.txt\"\u003egit常用命令点击查看\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e深入理解学习Git工作流(git-workflow-tutorial) \u003ca href=\"http://segmentfault.com/a/1190000002918123\"\u003ehttp://segmentfault.com/a/1190000002918123\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以下教程主要参考" \u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2011/04/git-tut.pdf\"\u003eGit-tutor(Git使用指南):\u003c/a\u003e 和 \u003ca href=\"http://blog.haohtml.com/archives/9066\"\u003ehttp://blog.haohtml.com/archives/9066\u003c/a\u003e"实用指南而整理,第3章几乎直接在复制过来的.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关教程:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e在 CentOS 装 Git: \u003ca href=\"http://blog.haohtml.com/archives/10093\"\u003ehttp://blog.haohtml.com/archives/10093\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e在FreeBSD下安装Git: \u003ca href=\"http://blog.haohtml.com/archives/10065\"\u003ehttp://blog.haohtml.com/archives/10065\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003esvn git 的windows客户端: \u003ca href=\"http://blog.haohtml.com/archives/10069\"\u003ehttp://blog.haohtml.com/archives/10069\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e第一章 Git的基本操作方法\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一.初始化仓库\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003egit init\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e此时会在当前目录*假如为($WORK)生成一个.git的目录文件.这个.git目录就是Git仓库.其中存放的是我们所提交的文档索引内容,Git 可基于文档索引内容对其所管理的文档进行内容追踪, …\u003c/p\u003e"
June 28, 2011
node.js在linux下的安装教程
"\u003cp\u003e\u003cstrong\u003e一.安装node.js\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ewet \u003ca href=\"http://nodejs.org/dist/node-v0.4.8.tar.gz\"\u003ehttp://nodejs.org/dist/node-v0.4.8.tar.gz\u003c/a\u003e\ntar zxvf node-v0.4.8.tar.gz\ncd node-v0.4.8\n./configure –prefix=/usr/local/node\nmake\nmake install\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e二.测试\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e创建test.js文件,内容如下:\nvar http = require(‘http’);\nhttp.createServer(function (req, res) {\nres.writeHead(200, {‘Content-Type’: ‘text/plain’});\nres.end(‘Hello World\\n’);\n}).listen(1337, “127.0.0.1”);\nconsole.log(‘Server running at http://127.0.0.1:1337/’);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e执行:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003enode test.js\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在浏览器里输入 http://127.0.0.1:1337/,可以看到 “Hello World“字样,即表示安装成功!注意后面不能加文件 …\u003c/p\u003e"
June 27, 2011
svn git 的windows客户端
"\u003cp\u003e根据自己使用的操作系统是32位的还是64位的不同,需要选择软件的相应版本。\u003c/p\u003e\n\u003cp\u003e先安装msysgit:\n\u003ca href=\"https://git-scm.com/downloads\"\u003ehttps://git-scm.com/downloads\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e再安装git windows客户端tortoisegit :\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://download.tortoisegit.org/\"\u003ehttp://download.tortoisegit.org/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在安装tortoisegit的时候,选择第一个 Use(Tortoise)Plink即可。\u003c/p\u003e\n\u003cp\u003e===================\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eTortoiseGit日常使用指南\u003c/strong\u003e: \u003ca href=\"/wp-content/uploads/2011/01/TortoiseGit_Guide.pdf\"\u003e/wp-content/uploads/2011/01/TortoiseGit_Guide.pdf\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e相关教程:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eGit使用教程视频:\nGit使用学习教程:\n在 CentOS 装 Git:\n在FreeBSD下安装:\u003c/p\u003e\n\u003cp\u003e============================================================\u003c/p\u003e\n\u003cp\u003esvn windows客户端:\n\u003ca href=\"http://tortoisesvn.tigris.org/\"\u003ehttp://tortoisesvn.tigris.org/\u003c/a\u003e\u003c/p\u003e"
June 25, 2011
Failed to initialize storage module解决方法
"\u003cp\u003e今天更新了一下自己的cms,然后后台就提示登陆不了,报错如下:Failed to initialize storage module。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决方法有两种如下:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1。在报错的文件里的session start();之前加入如下代码:ini_set(‘session.save_handler’, ‘files’); 。这种方法适合租用空间的用户使用。\u003c/p\u003e\n\u003cp\u003e2。在php.ini文件里,显式指定session的save_path(比如 c:/temp)然后重启web服务。如果服务器的管理权限属于你,那还是这样改比较方便。\u003c/p\u003e\n\u003cp\u003e原因分析:php5一个安全模式的bug,默认session的save_path是系统的临时目录,这样会要校验权限。\u003c/p\u003e\n\u003cp\u003ePHP中使用SESSION后出现Failed to initialize storage module错误的解决方法:\n在session start之前加入以下这句话\nini_set(‘session.save_handler’, ‘files’);\u003c/p\u003e"
June 16, 2011
c语言socket编程常用函数2
"\u003cp\u003e\u003cstrong\u003esocket()函数\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e#include\n#include int socket(int domain, int type, int protocol);\ndomain应该设置为”AF_INET”,和上面数据结构 struct sockaddr_in 中一样,或者其它的type 告诉内容是SOCK_STREAM还是SOCK_DGRAM 类型,或者其它的.\nprotocol 设置为0.\u003c/p\u003e\n\u003cp\u003esocket()只是返回以后在系统调用中可能用到的socket描述符,或者错误的时候返回-1.全局变量errno中将存储返回的错误值.\u003c/p\u003e\n\u003cp\u003e=====================\n\u003cstrong\u003ebind() 函数\u003c/strong\u003e\n一旦你有一个套接字,你可能要将套接字和机器上的一定的端口关联起来。 ( 如果你想用 listen() 来侦听一定端口的数据,这是必要一步 –MUD 告 诉你说用命令 “telnet x.y.z 6969” 。 ) 如果你只想用 connect() ,那么这个步骤没有必 要 。\n但是无论如何,请继续读下去。\u003c/p\u003e\n\u003cp\u003e这里是系统调用 bind() 的大概:\u003c/p\u003e\n\u003cp\u003e#include\n#include int bind(int …\u003c/p\u003e"
June 16, 2011
c语言socket编程笔记1
"\u003cblockquote\u003e\n\u003cp\u003estruct sockaddr {\nunsigned short sa_family; // 地址家族,Af_XXX\nchar sa_data[14]; // 14字节协议地址\n};\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003esa_family 能够是各种各样的类型,但是在这篇文章中都是”AF_INET” 。 sa_data 包含套接字中的目标地址和端口信息。\n这好像有点不明智。\u003c/p\u003e\n\u003cp\u003e=====================================\u003c/p\u003e\n\u003cp\u003e为了处理 struct sockaddr,程序员创造了一个并列的结构:\nstruct sockaddr_in (“in” 代表 “Internet”)\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003estruct sockaddr_in {\nshort int sin_family; //通讯类型(同struct sockadd中的sa_family一样可设置为 AF_INET )\nstruct in_addr sin_addr; //Internet 地址(结构体见下,网络字节顺序,储存 4 字节的 IP 地址)\nunsigned short int sin_port; //端口(网络字节顺序)\nunsigned …\u003c/p\u003e\u003c/blockquote\u003e"
June 9, 2011
利用PHP操作Linux消息队列完成进程间通信
"\u003cp\u003e当我们开发的系统需要使用多进程方式运行时,进程间通信便成了至关重要的环节。消息队列(message queue)是Linux系统进程间通信的一种方式。\u003c/p\u003e\n\u003cp\u003e关于Linux系统进程通信的概念及实现可查看: \u003ca href=\"http://www.ibm.com/developerworks/cn/linux/l-ipc/\"\u003ehttp://www.ibm.com/developerworks/cn/linux/l-ipc/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e关于Linux系统消息队列的概念及实现可查看: \u003ca href=\"http://www.ibm.com/developerworks/cn/linux/l-ipc/\"\u003ehttp://www.ibm.com/developerworks/cn/linux/l-ipc/part4/\u003c/a\u003e\nPHP的sysvmsg模块是对Linux系统支持的System V IPC中的System V消息队列函数族的封装。我们需要利用sysvmsg模块提供的函数来进进程间通信。先来看一段示例代码_1:\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e01``\u0026lt;?php\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e02\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e03``$message_queue_key\u003c/code\u003e \u003ccode\u003e= \u003c/code\u003e \u003ccode\u003eftok\u003c/code\u003e \u003ccode\u003e(\u003c/code\u003e \u003ccode\u003e__FILE__\u003c/code\u003e \u003ccode\u003e, \u003c/code\u003e \u003ccode\u003e'a'\u003c/code\u003e \u003ccode\u003e);\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e04\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e05``$message_queue\u003c/code\u003e \u003ccode\u003e= msg_get_queue(\u003c/code\u003e \u003ccode\u003e$message_queue_key\u003c/code\u003e \u003ccode\u003e, 0666);\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e06``var_dump(\u003c/code\u003e \u003ccode\u003e$message_queue\u003c/code\u003e \u003ccode\u003e);\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e07 …\u003c/code\u003e\u003c/p\u003e"
June 6, 2011
配置PHP.INI监测服务器的脚本耗时
"\u003cp\u003e配置php.ini中的\nauto_prepend_file\nauto_append_file\n加入自动解析页面来获取执行时间\u003c/p\u003e\n\u003cp\u003e; Automatically add files before or after any PHP document.\nauto_prepend_file = monitor_prog.php\nauto_append_file = monitor_prog.php\u003c/p\u003e\n\u003cp\u003e把monitor_prog.php放到包含目录下。\u003c/p\u003e\n\u003cp\u003emonitor_prog.php\u003c/p\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e// print_r($_SERVER);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eif ( ! function_exists ( ‘ getmicrotime_t ‘ ) ) {\u003c/p\u003e\n\u003cp\u003efunction getmicrotime_t(){\u003c/p\u003e\n\u003cp\u003elist ( $usec , $sec ) = explode ( ” ” , microtime ());\u003c/p\u003e\n\u003cp\u003ereturn $usec ;\u003c/p\u003e\n\u003cp\u003e// return ((float)$usec + (float)$sec);\u003c/p\u003e\n\u003cp\u003e} // end func\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e$time1 = date ( ‘ …\u003c/p\u003e"
May 30, 2011
C语言对mysql数据库的操作
"\u003cp\u003e这已经是一相当老的话题。不过今天我才首次使用,把今天的一些体会写下来,也许能给一些新手带来一定的帮助,更重要的是供自己今后忘记的怎么使用而进行查阅的!\u003c/p\u003e\n\u003cp\u003e我们言归正传\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.头文件:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003e#include “/usr/local/mysql/include/mysql/mysql.h” //这个是必需要包含的,下面对mysql的所有操作函数,都出自这里\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e2.定义一个MYSQL变量:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMYSQL mysql;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这里MYSQL是一个用于连接MySql数据库的变量。\u003c/p\u003e\n\u003cp\u003e在后面对mysql数据库的操作中,我们就用这个MYSQL变量作为句柄的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3.定义数据库参数:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003echar host[32]=”localhost”;\u003c/p\u003e\n\u003cp\u003echar user[32]=”username”;\u003c/p\u003e\n\u003cp\u003echar passwd[32]=”pwd”;\u003c/p\u003e\n\u003cp\u003echar dbname[32]=”testdb”;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e4.数据库操作\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e1).初始化数据库:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003emysql_init(\u0026amp;mysql);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e2).连接数据库: …\u003c/p\u003e"
April 27, 2011
Eclipse与MyEclipse的区别
"\u003cp\u003eEclipse 是一个IDE(Integrated Developing Environment),而这个IDE是允许安装第三方开发的插件来使自身的功能得到扩展和增强的,而Myeclipse就是其中的一种有名的插件集之一,主要是为J2EE开发;MyEclipse将开发者常用到的一些有用的插件都集合起来,提供一种高级编程环境,可以比较轻松完成struts,Hibernate,Spring布局,编写strtus-config.xml;但它是收费的,没Eclipse MyEclipse是没用的。lomboz也是类似MyEclipse的插件,不过是免费的,当然功能没有MyEclipse好。\u003c/p\u003e\n\u003cp\u003eEclipse是一个开放源代码,基于Java的可扩张的开发平台,多数人都是将Eclipse作为Java的集成开发环境使用,虽然Eclipse使用Java开发:但Eclipse不仅仅局限于Java开发,还可用于其它语言的开发,如C/C++;Eclipse是一个框架和一组服务,它通过各种插件来构建开发环境,因此只要提供支持C/C++ 插件便能进行相应语言的开发.\u003c/p\u003e\n\u003cp\u003eEclipse最早是由IBM开发的,后 …\u003c/p\u003e"
April 19, 2011
4.1 静态方法和属性-深入PHP面向对象.模式与实践
"\u003cp\u003e摘自: \u003ca href=\"http://www.verycd.com/topics/2830432/\"\u003e深入PHP面向对象.模式与实践\u003c/a\u003e 第四章 高级特性\n\u003cstrong\u003e4.1 静态方法和属性\u003c/strong\u003e\n第2章的所有例子使用的都是对象.我们把类当作生成对象的模板,把对象作为活动组件,对象的方法可以被调用,对象的属性可以被访问.之前的例子也暗示了,面向对象编程中的实际操都是通过类的实例(而不是类本身)完成的.毕竟类仅仅是对象的模板.\u003c/p\u003e\n\u003cp\u003e事实并非如此简单.我们不仅可以通过对象访问方法和属性,还可以通过类来访问它们.这样的方法和属性属性是”静态的”(static),必须用static关键字来声明.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eclass StaticExample{\nstatic public $sNum = 0;\nstatic public function sayHello) {\nprint “hello”;\n}\n}\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"注解static关键字是在php5中引入的在php4程序中不能使用\"\u003e==========================================\n注解:static关键字是在php5中引入的,在php4程序中不能使用.\u003c/h1\u003e\n\u003cp\u003e静态方法是以类作为作用域的函数.静态方法不能访问这个类中的普通属性,因为那些属性属于一个对象,但可以访问静态属性.如果修改了一个静态属性,那么这个类的所有实例都能 …\u003c/p\u003e"
April 16, 2011
如何安装cacti监控nginx插件
"\u003cp\u003eScripts and templates for nginx.\u003c/p\u003e\n\u003cp\u003eNginx –\u003c/p\u003e\n\u003cp\u003eProvide graphing nginx clients statistics (active, reading, writing, waiting) and nginx socket statistics (accepts, handled, requests). It’s a formal devision used only for graphs usability.\u003c/p\u003e\n\u003cp\u003eFor use do next steps:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eEnable nginx http_stub_status_module at configure stage (if requared).\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEnable stub status. Add to nginx.conf (in any server context):\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003elocation /nginx_status {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003estub_status on;\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch1 id=\"disable-access_log-if-requared\"\u003edisable access_log if requared\u003c/h1\u003e\n\u003cp\u003eaccess_log off;\u003c/p\u003e\n\u003cp\u003e#allow …\u003c/p\u003e"
April 1, 2011
深入理解ob_flush和flush的区别
"\u003cp\u003eob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑…\u003c/p\u003e\n\u003cp\u003e其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..\u003c/p\u003e\n\u003cp\u003eob_*系列函数, 是操作PHP本身的输出缓冲区.所以, ob_flush是刷新PHP自身的缓冲区.\u003c/p\u003e\n\u003cp\u003e而flush, 严格来讲, 这个只有在PHP做为apache的Module(handler或者filter)安装的时候, 才有实际作用. 它是刷新WebServer(可以认为特指apache)的缓冲区.\u003c/p\u003e\n\u003cp\u003e在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针, 间接的调用apache的api: ap_rflush刷新apache的输出缓冲区, 当然手册中也说了, 有一些apache的其他模块, 可能会改变这个动作的结果..\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。\u003c/p\u003e\n\u003cp\u003e甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape浏览器会在接受到换 …\u003c/p\u003e\u003c/blockquote\u003e"
April 1, 2011
php中ob_start函数 积累
"\u003cp\u003e确实自己写不出来,只能看看别人的经验总结。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePHP的ob_start();用法\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e用PHP的ob_start();控制您的浏览器cache\u003c/p\u003e\n\u003cp\u003eOutput Control 函数可以让你自由控制脚本中数据的输出。它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况。输出控制函数不对使用 header() 或 setcookie(), 发送的文件头信息产生影响,只对那些类似于 echo() 和 PHP 代码的数据块有作用。\n我们先举一个简单的例子,让大家对Output Control有一个大致的印象:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eExample 1.\u003c/p\u003e\n\u003cp\u003e程序代码:\u003c/p\u003e\n\u003cp\u003eob_start(); //打开缓冲区\necho “Hellon”; //输出\nheader(“location:”); //把浏览器重定向到\nob_end_flush();//输出全部内容到浏览器\n?\u0026gt;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e所有对header()函数有了解的人都知道,这个函数会发送一段文件头给浏览器,但是如果在使用这个函数之前已经有了任何输出(包括空输出,比如空格,回车和换行)就会提示出错。如果我们去掉第一行的ob_start(),再执行此程序,我们会发现 …\u003c/p\u003e"
March 31, 2011
php Safe_mode影响参数
"\u003cp\u003esafe_mode是唯一PHP_INI_SYSTEM属性,必须通过php.ini或httpd.conf来设置。要启用safe_mode,只需修改php.ini: safe_mode = On 或者修改httpd.conf,定义目录:\u003c/p\u003e\n\u003cp\u003eOptions FollowSymLinks php_admin_value safe_mode 1重启apache后safe_mode就生效了。启动safe_mode,会对许多PHP函数进行限制,特别是和系统相关的文件打开、命令执行等函数。\u003c/p\u003e\n\u003cp\u003e所有操作文件的函数将只能操作与脚本UID相同的文件\u003c/p\u003e\n\u003cp\u003e虽然safe_mode不是万能的(低版本的PHP可以绕过),但还是强烈建议打开安全模式,在一定程度上能够避免一些未知的攻击。不过启用 safe_mode会有很多限制,可能对应用带来影响,所以还需要调整代码和配置才能和谐。被安全模式限制或屏蔽的函数可以参考PHP手册。\u003c/p\u003e\n\u003cp\u003e函数名\u003c/p\u003e\n\u003cp\u003e限制\u003c/p\u003e\n\u003cp\u003edbmopen()\u003c/p\u003e\n\u003cp\u003e检查被操作的文件或目录是否与正在执行的脚本有相同的 UID(所有者)。\u003c/p\u003e\n\u003cp\u003edbase_open()\u003c/p\u003e\n\u003cp\u003e检查被操作的文件或目录是否与正在执行的脚本有相同的 UID(所有者)。 …\u003c/p\u003e"
March 23, 2011
遍历memcache中已缓存的key
"\u003cp\u003e最近需要做一个缓存管理的功能。其中有一个需要模糊匹配memcached的key然后进行删除匹配上的key对应的数据。\u003c/p\u003e\n\u003cp\u003e难点在于memcache 没有提供模糊匹配key删除缓存的功能,也没有提供遍历memcache key的功能。在网上search了下,\u003c/p\u003e\n\u003cp\u003e点击10个连接有9个都是一篇文章的copy。网上最流行的方法发现key不能正确的获得。baidu google 全用上了就是没有解决。。。\u003c/p\u003e\n\u003cp\u003e最后还是抱着试试的心态,终于把问题给解决了。废话少说。说说,我实现的代码:\u003c/p\u003e\n\u003cp\u003e遍历memcache的可以需要有一下几个步骤:\u003c/p\u003e\n\u003cp\u003e1、通过使用memcache 内置方法Memcache::getExtendedStats,首先获得items信息。\u003c/p\u003e\n\u003cp\u003e最后得到的解决类似与\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\n 1 $memcache = new Memcache();\n 2\n 3 $all_items = $memcache-\u0026gt;getExtendedStats(\u0026#39;items\u0026#39;);\n 4\n 5 var_export($all_items);\n\u003c/code\u003e\u003c/pre\u003e\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\n 1 array (\n 2 …\u003c/code\u003e\u003c/pre\u003e"
March 23, 2011
windows环境下memcache服务器使用经验
"\u003cp\u003e将memcache服务器安装包解压到C:\\memcached文件夹后,使用cmd命令窗口安装。\u003c/p\u003e\n\u003cp\u003e1\u0026gt;开始\u0026gt;运行:CMD(确定)\u003c/p\u003e\n\u003cp\u003e2\u0026gt;cd C:\\memcached(回车)\u003c/p\u003e\n\u003cp\u003e3\u0026gt;memcached -d install(回车 这步执行安装)\u003c/p\u003e\n\u003cp\u003e4\u0026gt;memcached -d start(回车 这步执行启动memcache服务器,默认分配64M内存,使用11211端口)\u003c/p\u003e\n\u003cp\u003e此时memcache服务器已经可以正常使用了。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ememcache服务器安全:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMemcache服务器端都是直接通过客户端连接后直接操作,没有任何的验证过程,这样如果服务器是直接暴露在互联网上的话是比较危险,轻则数据泄 露被其他无关人员查看,重则服务器被入侵,况且里面可能存在一些我们未知的bug或者是缓冲区溢出的情况,这些都是我们未知的,所以危险性是可以预见的。 为了安全起见,做两点建议,能够稍微的防止黑客的入侵或者数据的泄露。\u003c/p\u003e\n\u003cp\u003e现在就关于修改memcache服务器配置的问题说明如下:\u003c/p\u003e\n\u003cp\u003e1\u0026gt;用内网ip的方式提供web应用服务器调用,不允许直接通过外网调用,如将memcache服务器放 …\u003c/p\u003e"
March 23, 2011
freebsd+php+memcache、memcached安装和使用
"\u003cp\u003e来源: \u003ca href=\"http://www.lifecrunch.biz/archives/55\"\u003ehttp://www.lifecrunch.biz/archives/55\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"memcache-介绍\"\u003eMemcache 介绍\u003c/h2\u003e\n\u003cp\u003ememcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图 像、视频、文件以及数据库检索的结果等。Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。起初作 者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可以允许不同主机上的多个用户同时 访问这个缓存系统, 这种方法不仅解决了共享内存只能是单机的弊端,同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcache作者对分布式 cache的理解和解决方案。 memcache完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。\u003c/p\u003e\n\u003cp\u003eMemcache官方网站: …\u003c/p\u003e"
March 23, 2011
Memcache VS Memcached VS MemcacheDB
"\u003cp\u003e1、 简单讲Memcache和Memcached都讲的是同一个开源项目http://memcached.org/,只不过Memcached一般指的是后台的cache server(其实也是一个客户端的,参考php手册).而Memcache指的访问cache server的客户端。Memcached提供了两种访问协议,ASCII和Binary。\u003c/p\u003e\n\u003cp\u003e2、 MemcacheDB=Memcached+BerkeleyDB组成的轻量的持久数据库,与前两者是不同的两个东西。\u003c/p\u003e\n\u003cp\u003e3、作为数据库就要讲究consistency,但是Memcached是一种分布式的缓存机制,因此并不严格要求consistency,而且实际上每个memcached server之间本身不通讯也不共享,所谓的分布式是由memcached的客户端程序来决定的。一般分布式算法采用基于server节点数的取余法,这种方法以node数为基础,因此增减服务器就会造成很大hash失效问题。所以改进的算法一般采用consistent hash算法,这种算法取消了以服务器节点数作为基数的理念,而是直接对服务器的节点进行hash,然后散布 …\u003c/p\u003e"
March 23, 2011
Memcache的安全性
"\u003cp\u003eMemcache服务器端都是直接通过客户端连接后直接操作,没有任何的验证过程,这样如果服务器是直接暴露在互联网上的话是比较危险,轻则数据泄 露被其他无关人员查看,重则服务器被入侵,因为Mecache是以root权限运行的,况且里面可能存在一些我们未知的bug或者是缓冲区溢出的情况,这 些都是我们未知的,所以危险性是可以预见的。为了安全起见,我做两点建议,能够稍微的防止黑客的入侵或者数据的泄露。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003e内网访问\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e最好把两台服务器之间的访问是内网形态的,一般是Web服务器跟Memcache服务器之间。普遍的服务器都是有两块网卡,一块指向互联网,一块指向内 网,那么就让Web服务器通过内网的网卡来访问Memcache服务器,我们Memcache的服务器上启动的时候就监听内网的IP地址和端口,内网间的 访问能够有效阻止其他非法的访问。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ememcached -d -m 1024 -u root -l 192.168.0.200 -p 11211 -c 1024 -P /tmp/memcached.pid\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eMemcache服务器端设置监听通过内网的192.168.0.200的ip的11211端口,占 …\u003c/p\u003e"
February 22, 2011
“Xdebug MUST be loaded as a Zend extension in Unknown on line 0 “的解决办法
"\u003cp\u003e\u003cstrong\u003e解决方法:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e找到 php.ini 中的并修改如下:\u003c/p\u003e\n\u003cp\u003e写道\u003c/p\u003e\n\u003cp\u003e;extension=php_xdebug-2.1.0-5.2-vc6.dll\u003c/p\u003e\n\u003cp\u003ezend_extension_ts=”d:/AppServ\\php5\\ext\\php_xdebug-2.1.0-5.2-vc6.dll” //如果有其它提示,将”_ts”去掉就可以了\u003c/p\u003e\n\u003cp\u003exdebug 必须使用 zend_extension_ts 或者 zend_extension 来标明它是zend的扩展\u003c/p\u003e\n\u003cp\u003e写道\u003c/p\u003e\n\u003cp\u003e另:根据 PHP 版本,zend_extension 指令可以是以下之一:\u003c/p\u003e\n\u003cp\u003ezend_extension (non ZTS, non debug build)\u003c/p\u003e\n\u003cp\u003ezend_extension_ts ( ZTS, non debug build)\u003c/p\u003e\n\u003cp\u003ezend_extension_debug (non ZTS, debug build)\u003c/p\u003e\n\u003cp\u003ezend_extension_debug_ts ( ZTS, debug build)\u003c/p\u003e\n\u003cp\u003eZTS:ZEND Thread Safety\u003c/p\u003e\n\u003cp\u003e可通过phpinfo()查看ZTS是否启用,从而决定用zend_extension还 …\u003c/p\u003e"
February 11, 2011
linux实现daemon程序
"\u003cp\u003e\u003cstrong\u003e国外相关文档:()\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e编写Linux系统下Daemon程序的方法步骤\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一、引言 Daemon程序是一直运行的服务端程序,又称为守护进程。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e本文介绍了在Linux下编写Daemon程序的步骤,并给出了例子程序。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、Daemon程序简介\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDaemon是长时间运行的进程,通常在系统启动后就运行,在系统关闭时才结束。一般说Daemon程序在后台运行,是因为它没有控制终端,无法和前台的用户交互。Daemon程序一般都作为服务程序使用,等待客户端程序与它通信。我们也把运行的Daemon程序称作守护进程。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e三、Daemon程序编写规则\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e编写Daemon程序有一些基本的规则,以避免不必要的麻烦。\u003c/p\u003e\n\u003cp\u003e1、首先是程序运行后调用fork,并让父进程退出。子进程获得一个新的进程ID,但继承了父进程的进程组ID。\u003c/p\u003e\n\u003cp\u003e2、调用setsid创建一个新的session,使自己成为新session和新进程组的leader,并使进程没有控制终端(tty)。\u003c/p\u003e\n\u003cp\u003e3、改变当前工作目录至根目录,以免影响可加载文件系统。或者也可以改变到某些特定的目录。\u003c/p\u003e\n\u003cp\u003e4、设置文件创建mask为0,避免创建文件时权限的影响。\u003c/p\u003e\n\u003cp\u003e5、关闭不需要的打开文件 …\u003c/p\u003e"
February 11, 2011
用c语言实现的daemon实例
"\u003cp\u003e守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。\u003c/p\u003e\n\u003cp\u003e守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意,照搬某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e一. 守护进程及其特性\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启 …\u003c/p\u003e"
February 9, 2011
[sed] 鸟哥sed知识补遗
"\u003cp\u003e接自:\u003cstrong\u003e鸟哥Sed知识补遗****格式\u003c/strong\u003e sed [-nefr] [n1,n2] 动作\u003c/p\u003e\n\u003cp\u003e-n 安静模式,只有经过sed处理过的行才显示出来,其他不显示。\u003c/p\u003e\n\u003cp\u003e-e 直接在命令行模式上进行sed的操作。貌似是默认选项,不用写。\u003c/p\u003e\n\u003cp\u003e-f 将sed的操作写在一个文件里,用的时候 -f filename 就可以按照内容进行sed操作了。\u003c/p\u003e\n\u003cp\u003e-r 使之支持扩展正则表达式\u003c/p\u003e\n\u003cp\u003en1,n2 不一定需要, 选择要进行处理的行, 10,20 表示在10~20行之间处理\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e动作\u003c/strong\u003e\na 添加,接字符串,添加到当前行的下一行。\nc 替换, 接字符串,用他们替换n1到n2之间的行。\nd 删除符合模式的行 sed ‘/regexp/d’ // 之间是正则表达式,模式在d前面,d后面一般不接任何内容。\ni 插入,接字符串,添加到当前行的上一行。\u003c/p\u003e\n\u003cp\u003ep 打印,打印某个选择的数据,通常与-n 安静模式一起使用\u003c/p\u003e\n\u003cp\u003es 搜索, 还可以替换,类似与vim里的搜索替换功能。例如 1,20s/old/new/g 替换1~20行的old为new\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意动作最好用’ ‘括起来,防止空格导致错误。\u003c/strong\u003e \u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2011/02/sed.jpg\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/sed.jpg\" alt=\"\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e例子:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e显示 passwd内容,将2~5 …\u003c/p\u003e"
February 9, 2011
[awk] awk学习资料汇总
"\u003cp\u003e原文链接: \u003ca href=\"http://bbs.linuxtone.org/thread-1714-1-1.html\"\u003ehttp://bbs.linuxtone.org/thread-1714-1-1.html\u003c/a\u003e\n一、AWK学习资料汇总\u003c/p\u003e\n\u003cp\u003e1、 \u003ca href=\"http://bbs.linuxtone.org/thread-222-1-1.html\"\u003eawk学习笔记\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e2、 \u003ca href=\"http://bbs.linuxtone.org/thread-678-1-2.html\"\u003eIBM AWK 学习资料\u003c/a\u003e[推荐]\u003c/p\u003e\n\u003cp\u003e3、 \u003ca href=\"http://bbs.linuxtone.org/thread-334-1-2.html\"\u003eawk实例\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e4、 \u003ca href=\"http://bbs.linuxtone.org/thread-267-1-2.html\"\u003eawk学习笔记2\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e5、 \u003ca href=\"http://bbs.linuxtone.org/thread-227-1-2.html\"\u003eawk用法小结\u003c/a\u003e [推荐]\u003c/p\u003e\n\u003cp\u003e6、 \u003ca href=\"http://bbs.linuxtone.org/thread-224-1-2.html\"\u003eawk学习实操\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e7、 \u003ca href=\"http://bbs.linuxtone.org/thread-223-1-2.html\"\u003eAWK:Linux 管理员的智能工具包\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e8、 \u003ca href=\"http://www.linux.gov.cn/shell/awk.htm\"\u003e肥肥的AWK学习笔记\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e9、 \u003ca href=\"http://bbs.linuxtone.org/thread-2777-1-1.html\"\u003eAWK命令小结\u003c/a\u003e [推荐]\u003c/p\u003e"
January 22, 2011
第 7 章进程控制开发
"\u003cp\u003e本章目标\u003c/p\u003e\n\u003cp\u003e文件是 Linux 中最常见最基础的操作对象,而进程则是系统调度的单位,在上一章学习了文件I/O 控制之后,本章主要讲解进程控制开发部分,通过本章的学习,读者将会掌握以下内容。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e掌握进程相关的基本概念\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握 Linux 下的进程结构\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握 Linux 下进程创建及进程管理\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握 Linux下进程创建相关的系统调用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握守护进程的概念\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握守护进程的启动方法\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e掌握守护进程的输出及建立方法\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e学会编写多进程程序\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e学会编写守护进程\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e7.1 Linux 下进程概述\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e7.1.1 进程相关基本概念\u003c/p\u003e\n\u003cp\u003e1.进程的定义\u003c/p\u003e\n\u003cp\u003e进程的概念首先是在60年代初期由MIT的Multics系统和IBM的TSS/360系统引入的。\u003c/p\u003e\n\u003cp\u003e经过了40 多年的发展,人们对进程有过各种各样的定义。现列举较为著名的几种。\u003c/p\u003e\n\u003cp\u003e(1)进程是一个独立的可调度的活动(E. Cohen,D. Jofferson)\u003c/p\u003e\n\u003cp\u003e(2)进程是一个抽象实体,当它执行某个任务时,将要分配和释放各种资源(P. Denning)\u003c/p\u003e\n\u003cp\u003e(3)进程是可以并行执行的计算部分。(S. E. Madnick,J. T. Donovan) …\u003c/p\u003e"
January 22, 2011
6.5.2 文件读写
"\u003cp\u003e\u003cstrong\u003e1.读文件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e(1)fread函数说明\u003c/p\u003e\n\u003cp\u003e在文件流打开之后,可对文件流进行读写等操作,其中读操作的函数为fread。\u003c/p\u003e\n\u003cp\u003e(2)fread函数格式\u003c/p\u003e\n\u003cp\u003efread函数格式如表6.18所示。\u003c/p\u003e\n\u003cp\u003e表6.18 fread函数语法要点\u003c/p\u003e\n\u003cp\u003e所需头文件 #include\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数原型\u003c/strong\u003e size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)\u003c/p\u003e\n\u003cp\u003eptr:存放读入记录的缓冲区\u003c/p\u003e\n\u003cp\u003esize:读取的记录大小\u003c/p\u003e\n\u003cp\u003enmemb:读取的记录数\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数传入值\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003estream:要读取的文件流\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数返回值\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e成功:返回实际读取到的nmemb数目\u003c/p\u003e\n\u003cp\u003e失败:EOF\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2.写文件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e(1)fwrite函数说明\u003c/p\u003e\n\u003cp\u003efwrite函数是用于对指定的文件流进行写操作。\u003c/p\u003e\n\u003cp\u003e(2)fwrite函数格式\u003c/p\u003e\n\u003cp\u003efwrite函数格式如表6.19 所示。\u003c/p\u003e\n\u003cp\u003e表6.19 fwrite函数语法要点\u003c/p\u003e\n\u003cp\u003e所需头文件#include\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数原型\u003c/strong\u003e size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数传入值ptr\u003c/strong\u003e:存放写入记录的缓冲区\u003c/p\u003e\n\u003cp\u003esize:写 …\u003c/p\u003e"
January 22, 2011
6.5 标准 I/O 开发
"\u003cp\u003e本章前面几节所述的文件及I/O 读写都是基于文件描述符的。这些都是基本的I/O 控制,是不带缓存的。而本节所要讨论的I/O 操作都是基于流缓冲的,它是符合ANSI C的标准I/O处理,这里有很多函数读者已经非常熟悉了(如printf、scantf 函数等),因此本节中仅简要介绍最主要的函数。\u003c/p\u003e\n\u003cp\u003e标准 I/O 提供流缓冲的目的是尽可能减少使用read和write调用的数量。标准I/O 提供了3 种类型的缓冲存储。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e· 全缓冲\u003c/strong\u003e。在这种情况下,当填满标准I/O 缓存后才进行实际I/O 操作。对于驻在磁盘上的文件通常是由标准I/O 库实施全缓冲的。在一个流上执行第一次I/O 操作时,通常调用malloc就是使用全缓冲。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e· 行缓冲\u003c/strong\u003e。在这种情况下,当在输入和输出中遇到新行符时,标准I/O 库执行I/O 操作。\n这允许我们一次输出一个字符(如fputc 函数),但只有写了一行之后才进行实际I/O 操作。\n当流涉及一个终端时(例如标准输入和标准输出),典型地使用行缓冲。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e· 不带缓冲\u003c/strong\u003e。标准I/O库不对字符进行缓冲。如果用标准I/O函数写若干字符到不带缓冲的流中,则相当于用write系统的用函数将这些字 …\u003c/p\u003e"
January 21, 2011
6.2 Linux 中文件及文件描述符概述
"\u003cp\u003e正如第1 章中所述,在Linux 中对目录和设备的操作都等同于文件的操作,因此,大大简化了系统对不同设备的处理,提高了效率。Linux 中的文件主要分为4 种:普通文件、目录文件、链接文件和设备文件。\u003c/p\u003e\n\u003cp\u003e那么,内核如何区分和引用特定的文件呢?这里用到的就是一个重要的概念——文件描述符。对于Linux 而言,所有对设备和文件的操作都使用文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。\u003c/p\u003e\n\u003cp\u003e通常,一个进程启动时,都会打开3 个文件:标准输入、标准输出和标准出错处理。这3 个文件分别对应文件描述符为0、1 和2(也就是宏替换STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,鼓励读者使用这些宏替换)。\u003c/p\u003e\n\u003cp\u003e基于文件描述符的I/O 操作虽然不能移植到类Linux 以外的系统上去(如Windows),但它往往是实现某些I/O操作的惟一途径,如Linux中低级文件操作函数、多 …\u003c/p\u003e"
January 19, 2011
用PHP命令行控制脚本[CLI]
"\u003cp\u003eCLI :Command-Line Script(CLI – Command-Line Interface) //翻译;命令行接口\u003c/p\u003e\n\u003cp\u003e字串5\u003c/p\u003e\n\u003cp\u003ePHP CLI(Command Line Interface). \u003ca href=\"http://www.php.net/\"\u003ehttp://www.php.net/\u003c/a\u003e 预设支援CLI 了,什么是CLI,也就是Command Line Interface,简单的说,就是让你可以在系统上当shell 来跑。 如果还不懂,简单的说,就像你写perl 程式一样:\n#!/usr/local/bin/php\necho “Hello World!”;\n?\u0026gt;\u003c/p\u003e\n\u003cp\u003e字串3\n———————————————————官方[PHP 手册]叙述:\u003c/p\u003e\n\u003cp\u003e从版本 4.3.0 开始,PHP 提供了一种新类型的 SAPI(Server Application Programming Interface,服务端应用编程端口)支持,名为 CLI,意为 Command Line Interface,即命令行接口。顾名思义,该 SAPI 模块主要用作 PHP 的开发外壳应用。CLI SAPI 和其它 SAPI 模块相比有很多的不同之处,我们将在本章 …\u003c/p\u003e"
January 13, 2011
3.6.4 Make管理器的使用
"\u003cp\u003e使用Make管理器非常简单,只需在make命令的后面键入目标名即可建立指定的目标,如果直接运行make,则建立Makefile中的第一个目标。\u003c/p\u003e\n\u003cp\u003e此外 make 还有丰富的命令行选项,可以完成各种不同的功能。下表3.17 列出了常用的make命令行选项。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e表3.17 make的命令行选项\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e命 令 格 式 含 义\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e-C dir 读入指定目录下的Makefile\u003c/p\u003e\n\u003cp\u003e-f file 读入当前目录下的file文件作为Makefile\u003c/p\u003e\n\u003cp\u003e-i 忽略所有的命令执行错误\u003c/p\u003e\n\u003cp\u003e-I dir 指定被包含的Makefile所在目录\u003c/p\u003e\n\u003cp\u003e-n 只打印要执行的命令,但不执行这些命令\u003c/p\u003e\n\u003cp\u003e-p 显示make变量数据库和隐含规则\u003c/p\u003e\n\u003cp\u003e-s 在执行命令时不显示命令\u003c/p\u003e\n\u003cp\u003e-w 如果make在执行过程中改变目录,则打印当前目录名\u003c/p\u003e\u003c/blockquote\u003e"
January 13, 2011
3.6.3 Makefile规则
"\u003cp\u003eMakefile 的规则是Make 进行处理的依据,它包括了目标体、依赖文件及其之间的命令语句。一般的,Makefile 中的一条语句就是一个规则。在上面的例子中,都显示地指出了Makefile中的规则关系,如“$(CC) $(CFLAGS) -c $\u0026lt; -o $@”,但为了简化Makefile的编写,make还定义了隐式规则和模式规则,下面就分别对其进行讲解。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e1.隐式规则\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e隐含规则能够告诉make 怎样使用传统的技术完成任务,这样,当用户使用它们时就不必详细指定编译的具体细节,而只需把目标文件列出即可。Make 会自动搜索隐式规则目录来确定如何生成目标文件。如上例就可以写成:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eOBJS = kang.o yul.o\u003c/p\u003e\n\u003cp\u003eCC = Gcc\u003c/p\u003e\n\u003cp\u003eCFLAGS = -Wall -O -g\u003c/p\u003e\n\u003cp\u003esunq : $(OBJS)\u003c/p\u003e\n\u003cp\u003e$(CC) $^ -o $@\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e为什么可以省略后两句呢?因为Make的隐式规则指出:所有“.o”文件都可自动由“.c”\u003c/p\u003e\n\u003cp\u003e文件使用命令“$(CC) $(CPPFLAGS) $(CFLAGS) -c file.c –o file.o”生成。这样“kang.o”和“yul.o”就会 …\u003c/p\u003e"
January 13, 2011
3.6.2 Makefile变量
"\u003cp\u003e上面示例的Makefile在实际中是几乎不存在的,因为它过于简单,仅包含两个文件和一个命令,在这种情况下完全不必要编写Makefile 而只需在Shell 中直接输入即可,在实际中使用的Makefile往往是包含很多的文件和命令的,这也是Makefile产生的原因。下面就可给\u003c/p\u003e\n\u003cp\u003e出稍微复杂一些的Makefile进行讲解:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003esunq\u003c/strong\u003e:kang.o yul.o\u003c/p\u003e\n\u003cp\u003eGcc kang.o bar.o -o myprog\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ekang.o\u003c/strong\u003e : kang.c kang.h head.h\u003c/p\u003e\n\u003cp\u003eGcc –Wall –O -g –c kang.c -o kang.o\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eyul.o\u003c/strong\u003e : bar.c head.h\u003c/p\u003e\n\u003cp\u003eGcc – Wall –O -g –c yul.c -o yul.o\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在这个Makefile中有3 个目标体(target),分别为sunq、kang.o和yul.o,其中第一个目标体的依赖文件就是后两个目标体。如果用户使用命令“make sunq”,则make管理器就是找到sunq目标体开始执行。\u003c/p\u003e\n\u003cp\u003e这时,make会自动检查相关文件的时间戳。首先,在检查“kang.o”、“yul.o”和“sunq”3 个文件 …\u003c/p\u003e"
January 13, 2011
3.6.1 Makefile基本结构
"\u003cp\u003e\u003cstrong\u003e3.6.1 Makefile基本结构\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMakefile 是Make 读入的惟一配置文件,因此本节的内容实际就是讲述Makefile 的编写规则。在一个Makefile中通常包含如下内容:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e需要由make工具创建的目标体(target),通常是目标文件或可执行文件;\u003c/li\u003e\n\u003cli\u003e要创建的目标体所依赖的文件(dependency_file);\u003c/li\u003e\n\u003cli\u003e创建每个目标体时需要运行的命令(command)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e它的格式为:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003etarget: dependency_files\u003c/p\u003e\n\u003cp\u003ecommand\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e例如,有两个文件分别为hello.c 和hello.h,创建的目标体为hello.o,执行的命令为gcc\u003c/p\u003e\n\u003cp\u003e编译指令:gcc –c hello.c,那么,对应的Makefile就可以写为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#The simplest example\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ehello.o: hello.c hello.h\u003c/strong\u003e \u003cstrong\u003e//\u003cstrong\u003e\u003cstrong\u003e要创建的目标体所偏依赖的文件\u003c/strong\u003e\u003c/strong\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003egcc\u003c/strong\u003e **–**\u003cstrong\u003ec hello.c\u003c/strong\u003e **–**\u003cstrong\u003eo hello.o\u003c/strong\u003e \u003cstrong\u003e//\u003cstrong\u003e\u003cstrong\u003e创建目标体要运行的命令\u003c/strong\u003e\u003c/strong\u003e\u003c/strong\u003e\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e接着就可以使用make了。使用make的格式为:make target,这样make就会自动读入Makefile(也可 …\u003c/p\u003e"
January 6, 2011
OAuth 核心 1.0 版 中文翻译版
"\u003cp\u003eOAuth 核心 1.0\nAbstract\nOAuth协议致力于使网站和应用程序(统称为消费方)能够在无须用户透露其认证证书的情况下,通过API访问某个web服务(统称为服务提供方)的受保护资源。更一般地说,OAuth为API认证提供了一个可自由实现且通用的方法。\u003c/p\u003e\n\u003cp\u003e一个典型的例子是某打印服务提供商printer.example.com(消费方),希望在无须用户提供其照片存储站点密码的情况下,访问用户储存在photos.example.net(服务提供方)上的个人照片。\u003c/p\u003e\n\u003cp\u003eOAuth不强求一个特定的用户接口或操作模式,也不限定服务提供方如何验证用户,特别适合认证证书对消费方不可用的情况,例如OpenID。\u003c/p\u003e\n\u003cp\u003eOAuth致力于为托管web服务认证提供统一的体验和实现,形成一个社区驱动的协议。OAuth构建于已被多个站点独立实现的已有协议和最佳化实践之上,是一个被大小服务提供者所支持、并为应用开发者和用户增进持续性和可信度的开放标准。\u003c/p\u003e\n\u003cp\u003e——————————————————————————–\u003c/p\u003e\n\u003cp\u003eTable of Contents\n1. 作者\n2. 记号与惯例\n3. 术语定义\n4. …\u003c/p\u003e"
December 20, 2010
50个非常有用的PHP工具
"\u003ch3 id=\"php是使用最为广泛的开源服务器端脚本语言之一当然php并不是速度最快的但它却是最常用的脚本语言这里有50个有益的php工具可以大大提高你的编程工作\"\u003ePHP是使用最为广泛的开源服务器端脚本语言之一,当然PHP并\u003ca href=\"http://izumi.plan99.net/blog/index.php/2008/01/17/ruby-vs-php-performance/\"\u003e不是速度最快\u003c/a\u003e的,但它却是\u003ca href=\"http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html\"\u003e最常用的脚本语言\u003c/a\u003e。这里有50个有益的PHP工具,可以大大提高你的编程工作:\u003c/h3\u003e\n\u003ch3 id=\"调试工具\"\u003e调试工具\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://code.google.com/p/webgrind/\"\u003eWebgrind\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://xdebug.org/index.php\"\u003eXdebug\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://gubed.mccabe.nu/\"\u003eGubed PHP Debugger\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.php-debugger.com/dbg/\"\u003eDBG\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.php-debug.com/www/\"\u003ePHP_Debug\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://sourceforge.net/projects/php-dyn/\"\u003ePHP_Dyn\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.bluestatic.org/software/macgdbp/\"\u003eMacGDBp\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"测试和优化工具\"\u003e测试和优化工具\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.phpunit.de/\"\u003ePHPUnit\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.simpletest.org/\"\u003eSimpleTest\u003c/a\u003e\n\u003ca href=\"http://www.simpletest.org/\"\u003e\u003cimg src=\"http://www.simpletest.org/images/simpletest-logo.png\" alt=\"Simpletest\"\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://selenium-rc.openqa.org/\"\u003eSelenium\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://matrix.squiz.net/developer/tools/php_cs\"\u003ePHP_CodeSniffer\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://dbug.ospinto.com/\"\u003edBug\u003c/a\u003e\n\u003ca href=\"http://dbug.ospinto.com/\"\u003e\n\u003cimg src=\"http://www.javaeye.com/upload/attachment/70647/69c5a918-6d6b-36fc-a619-1f3e0175fdf4.jpg\" alt=\"\"\u003e\n\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.coderholic.com/php-profile-class/\"\u003ePHP Profile Class\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"文档工具\"\u003e文档工具\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://phpdoc.org/\"\u003ephpDocumentor\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://phpdox.net/\"\u003ePHP DOX\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"安全工具\"\u003e安全工具\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.phpcaptcha.org/\"\u003eSecurimage\u003c/a\u003e :验证码工具。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://trac.anl.gov/scavenger/wiki/WikiStart\"\u003eScavenger\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://php-ids.org/\"\u003ePHP-IDS\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://blog.evaria.com/2007/pixy-the-php-security-scanner/\"\u003ePixy\u003c/a\u003e :代码检查工具。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"图形处理\"\u003e图形处理\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.maani.us/charts4/\"\u003ePHP/SWF Charts\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://pchart.sourceforge.net/index.php\"\u003epChart – a chart-drawing PHP library\u003c/a\u003e\n\u003ca href=\"http://simplepie.org/\"\u003e\n\u003cimg src=\"http://www.javaeye.com/upload/attachment/70649/60c3f0c2-7ac6-3c82-90d7-6584e631eb24.jpg\" alt=\"\"\u003e\n\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://wideimage.sourceforge.net/wiki/MainPage\"\u003eWideImage\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.magickwand.org/\"\u003eMagickWand For PHP\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"代码优化\"\u003e代码优化\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://pear.php.net/package/PHP_Beautifier\"\u003ePHP_Beautifier\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.waterproof.fr/products/phpCodeBeautifier/\"\u003ePHPCodeBeautifier\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://qbnz.com/highlighter/\"\u003eGeSHi – Generic Syntax Highlighter\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"版本控制系统\"\u003e版本控制系统\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://phing.info/trac/\"\u003ePhing …\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e"
November 23, 2010
Allowed memory size of 8388608 bytes exhausted解决方法
"\u003cp\u003e出现该错误的原因:\u003c/p\u003e\n\u003cp\u003e是因为php页面消耗的最大内存默认是为 8M (在PHP的ini件里可以看到) ,如果文件太大 或图片太大 在读取的时候 会发生上述错误。\u003c/p\u003e\n\u003cp\u003e解决办法:\u003c/p\u003e\n\u003cp\u003e1,修改 php.ini\n将memory_limit由 8M 改成 16M(或更大),重启apache服务\u003c/p\u003e\n\u003cp\u003e2,在PHP 文件中 加入 ini_set(”memory_limit”,”100M”);\u003c/p\u003e\n\u003cp\u003e注意:为了系统的其它资源的正常使用 请您不要将 memory_limit设置太大,其中-1为不限\u003c/p\u003e\n\u003cp\u003e3,修改.htaccess 文档(前提是该目录支持.htaccess)\n在文档中新增一句:php_value memory_limit 16M(或更大)\u003c/p\u003e"
November 19, 2010
shell中的test表达式
"\u003cp\u003e摘自:UNIX Shell编程24学时编程\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e10.1.2 使用test\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e更常见的情况是,提供给if语句的清单是一个或更多个test命令,它们通过调用test命令而被激活,语法如下:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003etest expression\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这里,expression为test命令构造的表达式,该表达式的构造使用了特殊选项之一.在计算完表达式的值后,test命令或者返回0(真)或者返回1(假).\u003c/p\u003e\n\u003cp\u003e可用”[“命令对test命令进行缩写:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e[ expression ]\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e这里expression是test命令可以理解的任何有效表达式,该简化格式将是读者可能会踫见的最常用格式.\u003c/p\u003e\n\u003cp\u003etest可理解的表达式类型分为三类:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e文件测试.\n字符串比较.\n数字比较.\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e读者将逐步学业习这三类,另外,还会学习到复合表达式.\u003c/p\u003e\n\u003cp\u003e注意:在使用”[“简写test时,左中括号后面的空格和右括号前面的空格是必需的,如果没有空格,Shell不可能辨别表达式何时开始何时结束.\u003c/p\u003e\n\u003cp\u003e选项\u003c/p\u003e\n\u003cp\u003e描述\u003c/p\u003e\n\u003cp\u003e-b file\u003c/p\u003e\n\u003cp\u003e若文件存在且是一个块特殊文件,则为真\u003c/p\u003e\n\u003cp\u003e-c file\u003c/p\u003e\n\u003cp\u003e若文件存在且是一个字符特殊文件,则为真\u003c/p\u003e\n\u003cp\u003e-d file\u003c/p\u003e\n\u003cp\u003e若文件存在且是一个目录,则为真\u003c/p\u003e\n\u003cp\u003e-e …\u003c/p\u003e"
November 19, 2010
Shell中变量基础
"\u003cp\u003eshell中的只读变量:使用readonly关键字,后面加上变量名即可,如\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#name=’sxf’\u003c/p\u003e\n\u003cp\u003e#readonly name\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e即可.如果后面修改name的值,如\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#name=’tom’\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e会提示\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e"-bash: name: readonly variable"\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e错误信息.\u003c/p\u003e\n\u003cp\u003e在shell中删除变量只要用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eunset variable\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e即可.但不能删除只读变量.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eshell中环境变量分三种:局部变量,环境变量,Shell变量\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e局部变量(local variable)是只在当前shell实例中存在的变量,而由其他Shel启动的程序不能使用该变量.\u003c/p\u003e\n\u003cp\u003e环境变量(environment variable)是Shell的任何子进程都能使用的变量,许多程序要正确运行都需要使用环境变量.通常Shell脚本只定义程序运行时所需要的环境变量.\u003c/p\u003e\n\u003cp\u003eShell变量(Shell variable)是Shell变量的特殊变量,也是Shell正确运行所必需的,这些变量有些是环境变量而有些是局部变量.\u003c/p\u003e\n\u003cp\u003e通常,为清楚地表示该变量是环境变量,一般将赋值语句和导出语句写在同一行,这可以帮助下一个维护该脚本的程序员快速 …\u003c/p\u003e"
November 18, 2010
DDOS攻击分析与预防专题
"\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2010/11/ddos2.jpg\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2010/11/ddos2.jpg\" alt=\"\"\u003e\u003c/a\u003eDDOS是英文Distributed Denial of Service的缩写,意即”分布式拒绝服务”,DDOS的中文名叫分布式拒绝服务攻击,俗称洪水攻击。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eDDoS攻击概念\u003c/strong\u003e\nDDoS攻击手段是在传统的DoS攻击基础之上产生的一类攻击方式。单一的DoS攻击一般是采用一对一方式的,当攻击目标CPU速度低、内存小或者网络带宽小等等各项性能指标不高它的效果是明显的。随着计算机与网络技术的发展,计算机的处理能力迅速增长,内存大大增加,同时也出现了千兆级别的网络,这使得DoS攻击的困难程度加大了 – 目标对恶意攻击包的”消化能力”加强了不少,例如你的攻击软件每秒钟可以发送3,000个攻击包,但我的主机与网络带宽每秒钟可以处理10,000个攻击包,这样一来攻击就不会产生什么效果。\u003c/p\u003e\n\u003cp\u003e这时候分布式的拒绝服务攻击手段(DDoS)就应运而生了。你理解了DoS攻击的话,它的原理就很简单。\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2010/11/ddos.gif\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2010/11/ddos.gif\" alt=\"\"\u003e\u003c/a\u003e如果说计算机与网络的处理能力加大了10倍,用一台攻击机来攻击不再能起作用的话,攻击者使用10台攻击机同时攻击呢?用100台呢?DDoS就是利用更多的傀儡机来发起进攻,以比从前更大的规模来进攻受害者。\n高速广泛连接的网络给大家 …\u003c/p\u003e"
November 18, 2010
PHP autoload 机制
"\u003cp\u003e\u003cstrong\u003e1\u003c/strong\u003e**、简介******\u003c/p\u003e\n\u003cp\u003ePHP5中引入了类的自动装载(autoload)机制。autoload机制可以使得PHP程序有可能在使用类时才自动包含类文件,而不是一开始就将所有的类文件include进来,这种机制也称为lazy loading。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e例子:\u003c/strong\u003e****\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e/* autoload.php */\nfunction __autoload($classname) {\nrequire_once ($classname . “class.php”);\n}\n$person = new Person(”Altair”, 6);\nvar_dump ($person);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e通常PHP5在使用一个类时,如果发现这个类没有加载,就会自动运行__autoload()函数,在这个函数中我们可以加载需要使用的类。\u003c/p\u003e\n\u003cp\u003eautoload至少要做三件事情,\u003cstrong\u003e第一件事是根据类名确定类文件名\u003c/strong\u003e,\u003cstrong\u003e第二件事是确定类文件所在的磁盘路径\u003c/strong\u003e(在我们的例子是最简单的情况,类与调用它们的 PHP程序文件在同一个文件夹下),\u003cstrong\u003e第三件事是将类从磁盘文件中加载到系统中\u003c/strong\u003e。第三步最简单,只需要使用include/require即可。要实现第一 步,第二步的 …\u003c/p\u003e"
November 17, 2010
牛人写的. 高级PHP应用程序漏洞审核技术
"\u003cp\u003e一个安全界的牛人写的. 很不错..\n\u003cstrong\u003e[目录]\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e前言\u003c/li\u003e\n\u003cli\u003e传统的代码审计技术\u003c/li\u003e\n\u003cli\u003ePHP版本与应用代码审计\u003c/li\u003e\n\u003cli\u003e其他的因素与应用代码审计\u003c/li\u003e\n\u003cli\u003e扩展我们的字典\n5.1 变量本身的key\n5.2 变量覆盖\n5.2.1 遍历初始化变量\n5.2.2 parse_str()变量覆盖漏洞\n5.2.3 import_request_variables()变量覆盖漏洞\n5.2.4 PHP5 Globals\n5.3 magic_quotes_gpc与代码安全\n5.3.1 什么是magic_quotes_gpc\n5.3.2 哪些地方没有魔术引号的保护\n5.3.3 变量的编码与解码\n5.3.4 二次攻击\n5.3.5 魔术引号带来的新的安全问题\n5.3.6 变量key与魔术引号\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e5.4 代码注射\n5.4.1 PHP中可能导致代码注射的函数\n5.4.2 变量函数与双引号\n5.5 PHP自身函数漏洞及缺陷\n5.5.1 PHP函数的溢出漏洞\n5.5.2 PHP函数的其他漏洞\n5.5.3 session_destroy()删除文件漏洞\n5.5.4 随机函数\n5.6 特殊字符\n5.6.1 截断\n5.6.1.1 include …\u003c/p\u003e"
November 8, 2010
PHP autoload机制详解
"\u003cp\u003e\u003cstrong\u003e(1) autoload机制概述\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进行复用,同时将来维护时也很便利。这也是OO设计的基本思想之一。在PHP5之前,如果需要使用一个类,只需要直接使用include/require将其包含进来即可。下面是一个实际的例子:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e/* Person.class.php */\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eclass Person {\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003evar $name, $age;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003efunction __construct ($name, $age)\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e{\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$this-\u0026gt;name = $name;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$this-\u0026gt;age = $age;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e/* no_autoload.php */\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003erequire_once (”Person.class.php”);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$person = new Person(”Altair”, 6);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003evar_dump ($person);\u003c/p\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在这个例子 …\u003c/p\u003e"
November 1, 2010
使用FreeBSD构建流量控制防火墙
"\u003cp\u003e\u003cstrong\u003e概述\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e利用FreeBSD内核支持的BRIDGE、IPFIREWALL以及DUMMYNET选项,可以建立基于FreeBSD的透明流量控制防火墙(桥接模式),起到限制流量和包过滤的功能。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e准备\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e可以在任何FreeBSD的兼容硬件上构建流量控制防火墙,但是基于性能和管理上的考虑,建议:\u003c/p\u003e\n\u003cp\u003e使用Intel PII450以上的处理器\u003c/p\u003e\n\u003cp\u003e使用至少128MB RAM\u003c/p\u003e\n\u003cp\u003e使用高性能10/100Mbps自适应网络适配器\u003c/p\u003e\n\u003cp\u003e如果多于一组桥接设备,建议使用双处理器系统\u003c/p\u003e\n\u003cp\u003e另外准备一块单独的网络适配器用于管理\u003c/p\u003e\n\u003cp\u003e——————————————————————————–\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e实例\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e联想万全1300 PC服务器,具有一颗Intel PII300处理器,配置有128MB RAM,主板集成Intel 82557网络适配器,另外安装了4块3Com 3C905B 10/100Mbps自适应PCI网络适配器。\u003c/p\u003e\n\u003cp\u003e——————————————————————————–\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e安装\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e安装最新版本的FreeBSD。可以从www.FreeBSD.org获取当前的FreeBSD版本信息,并且获得安装源文件。可以使用光盘安装和FTP安装方式。为了保证最好的硬件 …\u003c/p\u003e"
October 31, 2010
C语言中指针变量和数组的组合
"\u003cp\u003eint a[10];\u003c/p\u003e\n\u003cp\u003eint * p;\u003c/p\u003e\n\u003cp\u003eC语言规定数组名代表数组中第一个元素(即序号为0的元素)的地址,因此,下面两个语句等价:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ep = \u0026amp;a[0];\u003c/p\u003e\n\u003cp\u003ep = a;\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e摘自:C语言程序设计(第二版)p211\u003c/p\u003e\n\u003cp\u003e(5)指针变量的值是可以改变的,见下例。\u003c/p\u003e\n\u003cp\u003e例10.20 改变指针变量的值。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e#include \u0026lt;stdio.h\u0026gt;\nvoid main()\n{\nchar *a = \u0026#34;I love China!\u0026#34;:\na = a + 7;\nprintf(\u0026#34;%s\u0026#34;, a);\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e运行结果如下:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eChina!\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e指针变量a的值是可以变化的,输出字符串是地从a当时所指向的单元开始输出各个字符,起码到遇’\\0’为止。而数组名虽然代表地址,但它是常量,它的值是不能改变的。下面的用法是错误的:\u003c/p\u003e\n\u003cp\u003echar str[] = {“I love China!”};\u003c/p\u003e\n\u003cp\u003estr = str + 7;\u003c/p\u003e\n\u003cp\u003eprintf(“%s”, str);\u003c/p\u003e\n\u003cp\u003e需要说明,若定义了一个指针变量, 并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。\u003c/p\u003e\n\u003cp\u003e例10.21 用带下标的字符指针变 …\u003c/p\u003e"
October 27, 2010
c语言中的scanf语法
"\u003cp\u003escanf函数,与 \u003ca href=\"http://baike.baidu.com/view/410546.htm\"\u003eprintf\u003c/a\u003e 函数一样,都被定义在 \u003ca href=\"http://baike.baidu.com/view/538727.htm\"\u003estdio.h\u003c/a\u003e 里,因此在使用scanf函数时要加上#include。它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中,其关键字最末一个字母f即为“格式”(format)之意。\u003c/p\u003e\n\u003ch2 id=\"scanf函数的一般形式\"\u003escanf函数的一般形式\u003c/h2\u003e\n\u003cp\u003escanf(格式控制,地址表列)\u003c/p\u003e\n\u003cp\u003eint scanf(char *format[,argument,…]);\u003c/p\u003e\n\u003cp\u003e“格式控制”的含义同printf函数;“地址表列”是由若干个地址组成的表列,可以是变量的地址,或字符串的首地址。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003escanf()函数返回成功赋值的数据项数,读到文件末尾出错时则返回EOF。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e例:使用scanf函数输入数据。\u003c/p\u003e\n\u003cp\u003e在visual c++ 6.0上的编写方式。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003evoid main()\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eint a,b,c;\u003c/p\u003e\n\u003cp\u003eprintf(“please input a,b,c”);\u003c/p\u003e\n\u003cp\u003escanf(“%d,%d,%d”,\u0026amp;a,\u0026amp;b,\u0026amp;c);\u003c/p\u003e\n\u003cp\u003eprintf(“a=%d,b=%d,c=%d”,a,b,c);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e在Dev-C++上运行程序为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003eint …\u003c/p\u003e\u003c/blockquote\u003e"
October 25, 2010
Windows 下为PHP添加扩展模块初探
"\u003cp\u003e说明:\u003c/p\u003e\n\u003cp\u003e本人新手,虽然用过很长时间的php,也写过一些简单php程序,但是一直没有对php的扩展模块有过研究。最近因为开发需要,要给一些php应用扩展功能,虽然手边有以前开发好的C程序,用popen等运行之也可以使用,但是从效率、调用便捷性、代码完整性等方面考虑总是觉得popen方式有些不妥,因此萌生了写个扩展模块的念头。于是乎上网找资料,并且初步完成了一个最基本的php扩展模块的框架。在此特别感谢花总的友情支持。\u003c/p\u003e\n\u003cp\u003ebtw: 本文所说的相关技术已经很陈旧了,实在不适合用“初探”这个词,但是于我个人而言,却又的确是初探,现总结出来,分享之。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e0、环境说明\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e框架生成环境:\u003c/p\u003e\n\u003cp\u003eFreeBSD 6.0-STABLE ( 用各版本 Linux 或者 cygwin 也可以,不过我手边只有 bsd,就用它了 )\u003c/p\u003e\n\u003cp\u003ePHP-4.4.4 源码包 (php-4.4.4.tar.bz2 或 php-4.4.4.tar.gz)\u003c/p\u003e\n\u003cp\u003e开发工具:\u003c/p\u003e\n\u003cp\u003eVC++ 6.0 ( 我没有用 VS .Net,因为 VC++6.0 启动比较快些,而且只是写个DLL而已 )\u003c/p\u003e\n\u003cp\u003e运行环境:\u003c/p\u003e\n\u003cp\u003eWindows 2003\u003c/p\u003e\n\u003cp\u003ePHP-4.4.4 …\u003c/p\u003e"
October 25, 2010
[教程]Linux下C语言对PHP扩展
"\u003cp\u003e\u003cstrong\u003e一,搭建php环境\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e下载php 5.2.6 源码 并解压编译安装,搭建php环境\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二,创建扩展项目\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e进入源码目录\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ecd php5.2.6/ext/\u003c/p\u003e\n\u003cp\u003e./ext_skel –extname=my_ext\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e创建名字为my_ext的项目,最终会生成 my_ext.so\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e三,更改配置和程序\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$ vi ext/my_ext/config.m4\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e根据你自己的选择将\u003c/p\u003e\n\u003cp\u003ednl PHP_ARG_WITH(my_ext, for my_ext support,\u003c/p\u003e\n\u003cp\u003ednl Make sure that the comment is aligned:\u003c/p\u003e\n\u003cp\u003ednl [ –with-my_ext Include my_ext support])\u003c/p\u003e\n\u003cp\u003e修改成\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePHP_ARG_WITH(my_ext, for my_ext support,\u003c/p\u003e\n\u003cp\u003eMake sure that the comment is aligned:\u003c/p\u003e\n\u003cp\u003e[ –with-my_ext Include my_ext support])\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e或者将\u003c/p\u003e\n\u003cp\u003ednl PHP_ARG_ENABLE(my_ext, whether to enable my_ext …\u003c/p\u003e"
October 25, 2010
在Windows下写PHP的C扩展
"\u003cp\u003e安装好如下软件:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eVC++ 6\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ephp二进制环境\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eCygwin.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eI. 下载php的源码包\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e下载后php源码包解压后有个ext目录,这个目录就是负责开发扩展的目录,目录中有默认你扩展的所有源码。还有两个重要的文件:ext_skel , ext_skel_win32.php.\u003c/p\u003e\n\u003cp\u003eext_skel是创建扩展的shell,在windows上无法运行,所以就必须要有Cygwin。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eII. 建立php扩展骨架目录文件\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e如果你的cygwin没有安装在c:\\cygwin,进入php源码包\\ext目录下,修改ext_skel_win32.php :\u003c/p\u003e\n\u003cp\u003e$cygwin_path = ‘c:\\cygwin\\bin’;\u003c/p\u003e\n\u003cp\u003e修改为你的cygwin目录\u003c/p\u003e\n\u003cp\u003e$cygwin_path = ‘d:\\cygwin\\bin’;\u003c/p\u003e\n\u003cp\u003e命令行方式进入ext目录然后运行:\u003c/p\u003e\n\u003cp\u003ephp ext_skel_win32.php –extname=myhello\u003c/p\u003e\n\u003cp\u003e(当然,为了保证上面的命令行能正常运行,首先你得确保你的php目录在系统的环境变量里)\u003c/p\u003e\n\u003cp\u003e运行该命令后,有人发现下面的错误\u003c/p\u003e\n\u003cp\u003eWarning: …\u003c/p\u003e"
October 25, 2010
指针 数字数组和字符数组首地址的输出
"\u003cblockquote\u003e\n\u003cp\u003e#include\n#include\u003c/p\u003e\n\u003cp\u003eint main()\n{\u003c/p\u003e\n\u003cp\u003echar *p;int *p1;\u003c/p\u003e\n\u003cp\u003eint a[10]={1,2,3,4,5,6,7,8,9,0};\nchar str[]=”haohtmlcom”;\np=str;\np1=a;\u003c/p\u003e\n\u003cp\u003eprintf( “%x” , p); /*输出的是地址*/\nprintf(“%s”,p); /*输出的是字符串haohtmlcom*/\u003c/p\u003e\n\u003cp\u003eprintf(“%x”,p1); /*输出的是地址*/\u003c/p\u003e\n\u003cp\u003eprintf(“%s”,p1); /*输出的是字符串,乱码*/\u003c/p\u003e\n\u003cp\u003esystem(“pause”);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003ep,p1中存放的应为字符串,但在输出时还要兼顾前面的输出格式符的控制,如果是%s,则会将p的地址内的数据输出,而不再输出p本身的内容地址.\u003c/p\u003e\n\u003cp\u003eprintf(“%c”, *p);//会输出字符串的第一个字母h\u003c/p\u003e\n\u003cp\u003eprintf(“%d”, *p1);//会输出数组的第一个数字.\u003c/p\u003e\n\u003cp\u003e所以 p,p1存放的都是地址,在用%c,%d时都能作为首地址输出第一个字母或数组元素,但是如果换用,%s,输出字符串,在一个地址空间内是不能存在字符串的,所以编译器会认为是连续空间 …\u003c/p\u003e"
October 20, 2010
linux 下的软件开发之GCC,GDB用法篇
"\u003cp\u003e在为Linux开发应用程序时,绝大多数情况下使用的都是C语言,因此几乎每一位Linux程序员面临的首要问题都是如何灵活运用C编译器。目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序。GCC不仅功能非常强大,结构也异常灵活。最值得称道的一点就是它可以通过不同的前端模块来支持各种语言,如Java、 Fortran、Pascal、Modula-3和Ada等。\u003c/p\u003e\n\u003cp\u003e开放、自由和灵活是Linux的魅力所在,而这一点在GCC上的体现就是程序员通过它能够更好地控制整个编译过程。在使用GCC编译程序时,编译过程可以被细分为四个阶段:\u003c/p\u003e\n\u003cp\u003e========================================\u003c/p\u003e\n\u003cp\u003e◆ 预处理(Pre-Processing)\u003c/p\u003e\n\u003cp\u003e◆ 编译(Compiling)\u003c/p\u003e\n\u003cp\u003e◆ 汇编(Assembling)\u003c/p\u003e\n\u003cp\u003e◆ 链接(Linking)\u003c/p\u003e\n\u003cp\u003e========================================\u003c/p\u003e\n\u003cp\u003eLinux程序员可以根据自己 …\u003c/p\u003e"
October 15, 2010
linux静态链接库与动态链接库的区别及动态库的创建
"\u003cp\u003e\u003cstrong\u003e一、引言\u003c/strong\u003e\n通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。\u003c/p\u003e\n\u003cp\u003e其实,我们也可以把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是如雷贯耳的动态链接库(dynamic link library)技术。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、动态链接库的特点与优势\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e首先让我们来看一下,把库函数推迟到程序运行时期载入的好处:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e可以实现进程之间的资源共享。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e什么概念呢?就是说,某个程序的在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。这样的模式虽然会带来一些“动态链接”额外的开销,却大大的节省了系统的内存资源。C的标准库就是动态链接库,也就是说系统中所有运行的程序 …\u003c/p\u003e"
October 15, 2010
Linux中创建静态库和动态库
"\u003cp\u003e\u003cstrong\u003e函数库分为静态库和动态库两种。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。\u003c/p\u003e\n\u003cp\u003e动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。\u003c/p\u003e\n\u003cp\u003e程序1: hello.h\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#ifndef HELLO_H\u003c/p\u003e\n\u003cp\u003e#define HELLO_H\u003c/p\u003e\n\u003cp\u003evoid hello(const char *name);\u003c/p\u003e\n\u003cp\u003e#endif //HELLO_H\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e程序2: hello.c\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include\u003c/p\u003e\n\u003cp\u003evoid hello(const char *name)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eprintf(“Hello %s!\\n”, name);\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e程序3: main.c\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e#include “hello.h”\u003c/p\u003e\n\u003cp\u003eint main()\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003ehello(“everyone”);\u003c/p\u003e\n\u003cp\u003ereturn 0;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e无论动态库还是静态库都需要用到.o文件来生成,先编译生成.o文件。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e# gcc -c hello.c\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e1:创建静态库\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。 …\u003c/p\u003e"
September 28, 2010
基于Web的IM概览
"\u003cp\u003e基于 WEB 的实时事件通知方式大致有五种方案:HTTP拉取方式(pull),HTTP流,Long Polling,Flash XMLSocket方式,Java Applet。\n首先说下Comet这个词,Comet 这个词是最早由Alex Russell(Dojo Toolkit 的项目 Lead)提出的,称基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推(Push)”技术为“Comet”。\n\u003cstrong\u003e1.HTTP拉取方式(pull)\u003c/strong\u003e\n在这种传统的方法中,客户端以用户可定义的时间间隔去检查服务器上的最新数据。这种拉取方式的频率要足够高才能保证很高的数据精确度,但高频率可能会导致多余的检查,从而导致较高的网络流量。而另一方面,低频率则会导致错过更新的数据。理想地,拉取的时间间隔应该等于服务器状态改变的速度。常见的实现如利用 “” tag,当然利用xmlHttpRequest定时取也是一种方法。\n\u003cstrong\u003e2.HTTP流(Push机制)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eHTTP流有两种形式:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePage Stream: 页面上不间断的HTTP连接响应(HTTP 1.1 Keep Alive).\n通过在 HTML 页面里嵌入一个隐蔵 …\u003c/li\u003e\u003c/ul\u003e"
September 28, 2010
从零开始,安装运行Pushlets所需的Servlet相关环境
"\u003cp\u003e最近在研究基于WEB的聊天程序,了解了长连接相关技术,从网上看了很多文章,但多数是英文的,这让我很头疼。我准备自己动手测试一下网上的开源comet框架,最后我选择的是pushlet,先将我的一些操作步骤写下来和大家一起分享。\u003c/p\u003e\n\u003cp\u003e我先去 \u003ca href=\"http://www.pushlets.com/\" title=\"pushlets\"\u003epushlet官方网站\u003c/a\u003e 下载了相关代码,我选择的是5-feb-2010: v2.0.4 released版本的(下载地址:)。下载了后我解压打开相关文件,里面只有几个文件夹和文件,找了一下,DOC文件夹里面有说明文档,打开index.html,是英文的。按照左侧导航大概浏览一下,最后跳到install上面,硬着头皮打开浏览一下,大概意思是需要Servlet引擎环境。于是开始在Google上面找相关的文章。看了一下大概意思明白,就是需要安装Tomcat。\u003c/p\u003e\n\u003cp\u003e去Tomcat官方网站下载,我下载的是Tomcat 7.0.2 Released版本的(下载地址:)。下载解压出来是一个没有扩展名的文件:apache-tomcat-7.0.2-windows-x86,想到Windows下面的文件应该是EXE的,我将其扩展名改为exe运行,结果闪了一个命令窗口就没有了,在文 …\u003c/p\u003e"
September 26, 2010
Comet—“服务器推”技术
"\u003ch2 id=\"一名称解释\"\u003e一、名称解释:\u003c/h2\u003e\n\u003cp\u003eComet最早是由Alex Russell(Dojo Toolkit 项目主管和Dojo Foundation主席)在自己的博客中提出的术语,他是这样说的:”New services like Jot Live and Meebo are built with a style of data transmission that is neither traditional nor Ajax. Their brand of low-latency data transfer to the browser is unique, and it is becoming ever-more common. Lacking a better term, I’ve taken to calling this style of event-driven, server-push data streaming “Comet”.” “They all use long-lived HTTP connections to reduce the latency with which …\u003c/p\u003e"
September 26, 2010
PHP操作MongoDB
"\u003cp\u003e\u003cstrong\u003e一、MongoDB简介\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMongoDB (名称来自”humongous”) 是一个可扩展的、高性能、开源、模式自由、面向文档的数据库,集文档数据库、键值对存储和关系型数据库的优点于一身。官方站点: \u003ca href=\"http://www.mongodb.org/\"\u003ehttp://www.mongodb.org/\u003c/a\u003e,MongoDB特点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e面向文档存储(类JSON数据模式简单而强大)\u003c/li\u003e\n\u003cli\u003e动态查询\u003c/li\u003e\n\u003cli\u003e全索引支持,扩展到内部对象和内嵌数组\u003c/li\u003e\n\u003cli\u003e查询记录分析\u003c/li\u003e\n\u003cli\u003e快速,就地更新\u003c/li\u003e\n\u003cli\u003e高效存储二进制大对象 (比如照片和视频)\u003c/li\u003e\n\u003cli\u003e复制和故障切换支持\u003c/li\u003e\n\u003cli\u003eAuto-Sharding自动分片支持云级扩展性\u003c/li\u003e\n\u003cli\u003eMapReduce 支持复杂聚合\u003c/li\u003e\n\u003cli\u003e商业支持,培训和咨询\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e二、安装MongoDB\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e安装MongoDB非常的简单,仅需下载压缩包解压运行命令即可,下载地址: \u003ca href=\"http://www.mongodb.org/downloads\"\u003ehttp://www.mongodb.org/downloads\u003c/a\u003e,本文为windows平台,MongoDB运行命令:\u0026gt;bin/mongod。提示:首先要创建存储数据的文件夹,MongoDB 默认存储数据目录为 /data/db/ (或者 c:datadb),当然你也可以修改成不同目录,只需要指定 –dbpath 参数,eg: …\u003c/p\u003e"
September 23, 2010
Suhosin介绍-用Suhosin加强PHP脚本语言安全性
"\u003cp\u003ePHP是一种非常流行之网站脚本语言,但是它本身所固有之安全性是非常薄弱。本文讲述了PHP增强计划(Hardened-PHP project)和新之Suhosi计划,Suhosin提供了增强之PHP之安全配置。\u003c/p\u003e\n\u003cp\u003ePHP是带有争论地但又是最流行之一种网站脚本语言。它之所以流行,是因为它低廉之价格,然而,这低廉之价格导致用PHP写之网站应用程序越来越多之同时也越来越多之展现出PHP本身在安全上之脆弱,这种安全特性显示出PHP是极不可靠,不过同时对这个脚本语言本身而言它又是非常灵活之,使用它就能很容易之实现代码,不过这些代码都是臃肿之且不安全之,虽然是这样它还是一直都拥有很多之使用者。你可以根据实际情况来假设,一次又一次,各种应用软件都体现了这种脆弱性:容易受到SQL注入、跨站脚本、任意执行指令等等之攻击。\u003c/p\u003e\n\u003cp\u003e因为象safe_mode和open_basedir这样内置之PHP安全措施将被忽略,PHP增强计划创建之PHP更具有安全性,同时也对PHP进行校验检查。最初,这些是由增强之PHP补丁完成之,这些补丁需要修补并重新编译PHP自身。最近,PHP增强计划发布了一个名为Suhosin之新工程。 …\u003c/p\u003e"
September 20, 2010
WML标签速查手册(转)比较方便便于速查
"\u003cp\u003e\u003cstrong\u003e结构相关标签****语法及属性\u003c/strong\u003e\n\u0026lt; \u003cstrong\u003ewml\u003c/strong\u003e \u0026gt;\n\u003cstrong\u003e\u003cem\u003elang\u003c/em\u003e\u003c/strong\u003e” \u0026gt;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003econtent\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u0026lt; \u003cstrong\u003ecard\u003c/strong\u003e \u0026gt;\n\u003cstrong\u003e\u003cem\u003ename\u003c/em\u003e\u003c/strong\u003e”\u003c/p\u003e\n\u003cp\u003etitle=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;label\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e”\u003c/p\u003e\n\u003cp\u003enewcontext=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;boolean\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e”\u003c/p\u003e\n\u003cp\u003estyle=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;style\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e”\u003c/p\u003e\n\u003cp\u003eonenterforward=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;url\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e”\u003c/p\u003e\n\u003cp\u003eonenterbackward=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;url\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e”\u003c/p\u003e\n\u003cp\u003eontimer=” \u003ccode\u003e\u0026lt;strong\u0026gt;\u0026lt;em\u0026gt;url\u0026lt;/em\u0026gt;\u0026lt;/strong\u0026gt;\u003c/code\u003e” \u0026gt; …\u003c/p\u003e"
September 9, 2010
WAP中汉字与图像的使用问题
"\u003ch3 id=\"wap显示汉字乱码的问题\"\u003ewap显示汉字乱码的问题\u003c/h3\u003e\n\u003cp\u003e1、可在WEB服务器中设置MIME表时,在text/vnd.wap.wml后加上“;charset=charset_name”,如GB2312汉字 :text/vnd.wap.wml;charset=gb2312\u003c/p\u003e\n\u003cp\u003e2、若你在设计动态WAP网页时,出现汉字显示乱码,你可以在程序中将返回类型指明所使用的字符集。 在程序中,将CHARSET加在向用户浏览 器发送信息的类型后, 按以下方式写: “Content-type: text/vnd.wap.wml;charset=gb2312″。 如在 ASP中:Response.ContentType =”text/vnd.wap.wml; charset=gb2312” ,JSP中\u0026lt;%@page contentType=”text/vnd.wap.wml; charset=gb2312″%\u0026gt;在PHP、PERL等服务器端脚本中比较类似。\u003c/p\u003e\n\u003cp\u003e3、你也可以用字符转换工具来转换,将你的程序代码转换为UTF8、或UNICODE。\u003c/p\u003e\n\u003cp\u003e4、另外一种指定xml,,比较遗憾的是现在部分手机与模拟器并不支持,将来也行会支持。\u003c/p\u003e\n\u003cp\u003e需要注 …\u003c/p\u003e"
September 3, 2010
php中抽象类和接口的概念和区别(二)
"\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e一个子类如果implements一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可,这是抽象类的一个优点\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果一个接口中定义的方法名改变了,那么所有实现此接口的子类显然将无法通过编译,因为它们所实现的方法名已经不存在了,这是接口的一个缺点;而抽象类就不存在这个问题,只是为子类添加了一个新的方法(接口中旧的方法)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e看前面两点,似乎抽象类要比接口有着更多的优点,但它却有着一个难以弥补的缺点:就是一个子类只能有一个父类。A extends B . 这样A就拥有了B的所有方法和功能,但当A还想拥有C的功能的时候。就不能通过 A extends C 来实现, 而需要走一些弯路。目前系统架构的趋势就是由针对抽象(借口,抽象类)而不是具体编程,并且将功能尽可能的细分。 这就需要通过实现多个接口的方式来实现,显然,抽象类无法提供这样的功能。从系统重构的角度来说,一个具体类抽象出接口是十分方便的。只需要写一个接口,里面定义具体类的所有方法,然后在为这个具体类implement这个接口就可以了。而抽象类就要复杂的多,比如说 B extends …\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e"
September 3, 2010
php中抽象类和接口的概念和区别(一)
"\u003cp\u003einterface a {\n//接口内不可以定义属性\n//所有方法必须为抽象方法(既不实现,只定义)\u003c/p\u003e\n\u003cp\u003epublic function method1($param);\nprotected function method2($param);\n}\u003c/p\u003e\n\u003cp\u003e//接口不可被实现,例如\n$instance = new a; //错误\u003c/p\u003e\n\u003cp\u003e//接口实现类必须实现接口的所有方法,且方法参数也必须相同\n//例如\nclass b implaments a{\n//错误,封装应与接口相同\nprotected function method1($param)\n{\n//somecode here…\n}\u003c/p\u003e\n\u003cp\u003e//错误,参数应与接口定义相同\nprotected function method2()\n{\u003c/p\u003e\n\u003cp\u003e}\n}\u003c/p\u003e\n\u003cp\u003e接口功能是实现类似C++中的多重继承的,但其语法更为明了\u003c/p\u003e"
September 3, 2010
PHP的接口与抽象类
"\u003cp\u003e\u003cstrong\u003ePHP\u003c/strong\u003e的接口:为了实现特定功能而预留的类似类的一种类型。接口的主要目的:提供给类类似于模板的框架,以方便类的构建。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e在PHP****中定义接口\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在\u003cstrong\u003ePHP\u003c/strong\u003e中定义接口的形式如下:\u003c/p\u003e\n\u003cp\u003eInterface interfaceName\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eConst 1;\u003c/p\u003e\n\u003cp\u003e……\u003c/p\u003e\n\u003cp\u003eConst 2;\u003c/p\u003e\n\u003cp\u003eFunction methodName1();\u003c/p\u003e\n\u003cp\u003e……\u003c/p\u003e\n\u003cp\u003eFunction methodName2();\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePHP****中单一接口的实现\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e实现接口的语法如下:\u003c/p\u003e\n\u003cp\u003eClass class_name implements interface_name\u003c/p\u003e\n\u003cp\u003e例如:\u003c/p\u003e\n\u003cp\u003eid = $id;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003efunction getID()\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003ereturn $this-\u0026gt;id;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003efunction setName($name)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;name = $name;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003efunction getName()\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003ereturn $this-\u0026gt;name;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003efunction otherFunc() //这是一个接口中不存在的方法\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003eecho “Test”;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ePHP****中多重接口的实现\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在** \u003ca href=\"http://www.phpdo.net/\" title=\"php\"\u003ePHP …\u003c/a\u003e\u003c/p\u003e"
August 26, 2010
linux下php多线程的妙用
"\u003cp\u003e开始用php写后台服务一段时间了.也是在这样的驱动下,不断的学习php语法,体验这一原来一直以为神秘且敬而远之的神奇语言的魅力.最初看php多线程的资料是为了提高程序的处理能力,充分发挥linux多任务的优势.不曾想多线程没用成反到是带来了一系列的意外收获.让之后的许多问题迎刃而解,不敢独享特一一道来.\n本文所讲的东西是源自php的pcntl_fork函数.因为这个函数依赖操作系统fork的实现,所以本文所讲的东西只适用于linux/unix.ok,那么先看看这个函数的用法吧. \u003ca href=\"http://cn.php.net/manual/en/function.pcntl-fork.php\"\u003ephp手册\u003c/a\u003e 上是这么说的:\u003c/p\u003e\n\u003cp\u003e$pid = pcntl_fork();\u003c/p\u003e\n\u003cp\u003eif ($pid == -1) {\u003c/p\u003e\n\u003cp\u003edie(‘could not fork’);\u003c/p\u003e\n\u003cp\u003e} else if ($pid) {\u003c/p\u003e\n\u003cp\u003e// we are the parent\u003c/p\u003e\n\u003cp\u003epcntl_wait($status); //Protect against Zombie children\u003c/p\u003e\n\u003cp\u003e} else {\u003c/p\u003e\n\u003cp\u003e// we are the child\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\n\u003cp\u003e通过pcntl_fork创建一个子进程,如果返回值是-1的话,那么说明子进程创建失败.创建成功的进 …\u003c/p\u003e"
August 17, 2010
$HTTP_RAW_POST_DATA 和 $_POST的区别
"\u003cp\u003e这是手册里写的\u003c/p\u003e\n\u003cp\u003e总是产生变量包含有原始的 POST 数据。否则,此变量仅在碰到未识别 MIME 类型的数据时产生。不过,访问原始 POST 数据的更好方法是 php://input。$HTTP_RAW_POST_DATA 对于 enctype=”multipart/form-data” 表单数据不可用。\u003c/p\u003e\n\u003cp\u003e问题: $HTTP_RAW_POST_DATA == $_POST 吗?\u003c/p\u003e\n\u003cp\u003e照手册所写 ,答案应该就为否。\n假如不一样的话,他们的区别是什么呢?\u003c/p\u003e\n\u003cp\u003e我知道答案了,如下:\u003c/p\u003e\n\u003cp\u003eThe RAW / uninterpreted HTTP POst information can be accessed with:\n$GLOBALS[‘HTTP_RAW_POST_DATA’]\u003c/p\u003e\n\u003cp\u003eThis is useful in cases where the post Content-Type is not something PHP understands (such as text/xml).\u003c/p\u003e\n\u003cp\u003e也就是说,基本上$GLOBALS[‘HTTP_RAW_POST_DATA’] 和 $_POST是一样的。但是如 …\u003c/p\u003e"
August 17, 2010
PHP输入流php://input
"\u003cp\u003e在使用xml-rpc的时候,server端获取client数据,主要是通过php输入流input,而不是$_POST数组。所以,这里主要探讨php输入流php://input\u003c/p\u003e\n\u003cp\u003e对于\u003ca href=\"http://php.net/manual/en/wrappers.php.php\"\u003ephp://input\u003c/a\u003e介绍,PHP官方手册文档有一段话对它进行了很明确地概述。\u003c/p\u003e\n\u003cp\u003e“php://input allows you to read raw POST data. It is a less memory intensive alternative to \u003ca href=\"http://www.php.net/manual/en/reserved.variables.httprawpostdata.php\"\u003e$HTTP_RAW_POST_DATA\u003c/a\u003e and does not need any special php.ini directives. php://input is not available with \u003cem\u003eenctype=”multipart/form-data”\u003c/em\u003e.\n翻译过来,是这样:\n“php://input可以读取没有处理过的POST数据。相较于$HTTP_RAW_POST_DATA而言,它给内存带来的压力较小,并且不需要特殊的php.ini设置。php://input不能用于enctype=multipart/form-data”\u003c/p\u003e\n\u003cp\u003e我们应该怎 …\u003c/p\u003e"
July 27, 2010
PHP Warning: date() [function.date]: It is not safe是什么问题
"\u003cp\u003e\u003cstrong\u003e在用PHP5.3以上的PHP版本时,只要是涉及时间的会报一个”\u003c/strong\u003e PHP Warning: date() [function.date]: It is not safe to rely on the system’s timezone settings. You are \u003cem\u003erequired\u003c/em\u003e to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected ‘UTC’ for ‘8.0/no DST’ instead in **“这样的错。如何解决呢?**\u003cstrong\u003e实际上,从 PHP 5.1.0 ,当对使用date()等函数时,如果timezone设置不正确,在每一次调用时间函数时,都会产生\u003ccode\u003eE_NOTICE\u003c/code\u003e 或者 \u003ccode\u003eE_WARNING\u003c/code\u003e …\u003c/strong\u003e\u003c/p\u003e"
July 24, 2010
X-Cache 和 X-Cache-Lookup headers 的解释
"\u003cp\u003eX-Cache: 表示你的 http request 是由 proxy server 回的 .\nMISS 表 proxy无资料,代理动作, HIT 表 proxy 直接回应\u003c/p\u003e\n\u003cp\u003eX-Pad: 這個是800 年前的 netscape bug 的因素才用的\u003c/p\u003e\n\u003cp\u003e想象你在一个标准的\u003ca href=\"http://vbb.twftp.org/archive/index.php/t-1145.html\"\u003e透明代理\u003c/a\u003e80端口下,并且你正在访问一个运行了内部网络缓存(这样,又是一个代理)的站点。如果你查看HTTP headers查找某些信息,你能够找到像这样的2行,规定domain.tld 代表那个本地网站,proxy.local 代表你的内部的透明代理。\u003c/p\u003e\n\u003cp\u003eX-Cache :HIT from proxy.domain.tld, MISS from proxy.local\nX-Cache-Lookup :HIT from proxy.domain.tld:3128, MISS from proxy.local:3128\u003c/p\u003e\n\u003cp\u003e这2行是什么意思?如果这是你第一次访问那个站点(MISS from proxy.local),并且它的代理的缓存中有一个有效的网页(X-Cache HIT proxy.domain.tld)\u003c/p\u003e\n\u003cp\u003e现在我们刷新了页面 …\u003c/p\u003e"
July 20, 2010
推荐一个很强的PHP图片处理(含缩图)类
"\u003cp\u003e这是目前我找到功能最强大的缩图类了,功能很全,代码写得也很规范。但智能裁切还需要完善一下,现在只能智能裁正方形,要能裁长方形才好。\u003c/p\u003e\n\u003cp\u003e下载:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.21andy.com/blog/wp-content/plugins/coolcode/coolcode.php?p=517\u0026amp;download=thumb_class.php\"\u003ethumb_class.php\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cp\u003e* 基本图片处理,用于完成图片缩入,水印添加\u003c/p\u003e\n\u003cp\u003e* 当水印图超过目标图片尺寸时,水印图能自动适应目标图片而缩小\u003c/p\u003e\n\u003cp\u003e* 水印图可以设置跟背景的合并度\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e* Copyright(c) 2005 by ustb99. All rights reserved\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e* To contact the author write to {@link mailto:ustb80@163.com}\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@author 偶然\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@version $Id: thumb.class.php,v 1.9 2006/09/30 09:31:56 zengjian Exp $\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@package system\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eThumbHandler\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@access public\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e/*\u003c/p\u003e\n\u003cp\u003e使用方法:\u003c/p\u003e\n\u003cp\u003e自动裁切:\u003c/p\u003e\n\u003cp\u003e程序会按照图片的尺寸从中部裁切最大的正方形, …\u003c/p\u003e"
July 20, 2010
PHP图片处理类实现缩放、剪切、相框、水印、锐化、旋转、翻转、透明度、反色等功能
"\u003cp\u003e使用PHP来处理一下图片,还是不错的,下面是找到的一个PHP处理图片的类,可以实现图片的缩放、剪切、相框、水印、锐化、旋转、翻转、透明度、 反色功能操作,够强大吧。文章比较长,所以分页显示,可以一页页复制代码整合就可以使用了。’没有找到相 关图片!’\n);\u003c/p\u003e\n\u003cp\u003e/*\n构造函数:函数初始化\n*/\nfunction __construct($PICTURE_URL){\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;get_info($PICTURE_URL);\u003c/p\u003e\n\u003cp\u003e}\nfunction get_info($PICTURE_URL){\n/*\n处理原图片的信息,先检测图片是否 存在,不存在则给出相应的信息\n*/\n@$SIZE=getimagesize($PICTURE_URL);\nif(!$SIZE){\nexit($this-\u0026gt;ERROR[‘unalviable’]);\n}\u003c/p\u003e\n\u003cp\u003e//得到原图片的信息类型、宽度、高度\n$this-\u0026gt;PICTURE_MIME=$SIZE[‘mime’];\n$this-\u0026gt;PICTURE_WIDTH=$SIZE[0];\n$this-\u0026gt;PICTURE_HEIGHT=$SIZE[1]; …\u003c/p\u003e"
July 6, 2010
FreeBSD查看即时网络流量
"\u003cp\u003e1、数据包 “netstat 1″一秒钟累计一次,”netstat 2″两秒钟累计一次。依此类推\u003c/p\u003e\n\u003cp\u003e2、查看网 卡流量:”systat -if 1″每秒钟刷新一次,”systat -if 2″两秒钟刷新一次,依此类推\u003c/p\u003e"
June 26, 2010
Memcached深度分析
"\u003cp\u003eMemcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减 少数据库负载,提升性能。关于这个东西,相信很多人都用 过,本文意在通过对memcached的实现及代码分析,获得对这个出色的开源软件更深入的了解,并可以根据我们的需要对其进行更进一步的优化。末了将通 过对BSM_Memcache扩展的分析,加深对memcached的使用方式理解。\u003c/p\u003e\n\u003cp\u003e本文的部分内容可能需要比较好的数学基础作为辅助。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e◎Memcached是什么\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在阐述这个问题之前,我们首先要清楚它“不是什么”。很多人把它当作和SharedMemory那种形式的存储载体来使用,虽然memcached使用了 同样的“Key=\u0026gt;Value”方式组织数据,但是它和共享内存、APC等本地缓存有非常大的区别。Memcached是分布式的,也就是说它不是 本地的。它基于网络连接(当然它也可以使用localhost)方式完 成服务,本身它是一个独立于应用的程序或守护进程(Daemon方式)。\u003c/p\u003e\n\u003cp\u003eMemcached使用libevent库实现网络连接服务,理论上可以处理无限多 …\u003c/p\u003e"
June 24, 2010
Five Minutes程延辉 介绍开心农场架构
"\u003cp\u003eFive Minutes 公司程延辉(小名康天) 介绍开心农场架构,social game的技术挑战,支持千万级DAU的social game技术架构。这是一个对于开发者来说,非常精彩,非常有实用性指导的一次演讲,详细介绍了很多技术内幕。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://www.javaeye.com/topics/download/e4f72cf2-2baa-3f4b-9578-d220b6bceea9\"\u003e\u0026raquo;猛击这里下载演讲ppt\u0026laquo;\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eFive Minutes 公司的著名social game 开心农场,目前非常受用户欢迎,包括国外的Facebook,国内的开心网都是如此,是全球最大的social game,台下热烈掌声。呵呵。开心农场这个游戏从介绍看,相当成功,最早是08年9月在xiaonei上线,而后在51等平台推广,包括Facebook。现在已经有1570万游戏用户了,其中包括50万的Facebook用户。\u003c/p\u003e\n\u003cp\u003e开心农场架构主要难点:1。如何存储大规模的用户数据千万级2。如果应对大量访问每天数亿请求量3。如果应对数据的频繁修改,每秒数万次数据修改。\u003c/p\u003e\n\u003cp\u003e解决的方式\u003c/p\u003e\n\u003cp\u003e优化:\u003c/p\u003e\n\u003cp\u003e1。负载均衡,web服务器平行扩展。\u003c/p\u003e\n\u003cp\u003e2。服务器性能优化。\u003c/p\u003e\n\u003cp\u003e3。异步处理,缓存数据接口,Linux内核参数优化,挖掘PHP的效率,用fastcgi模式运行php, …\u003c/p\u003e"
June 11, 2010
php 静态类和方法
"\u003cp\u003e\u003ccode\u003e\u0026lt;?php\u0026lt;br /\u0026gt; /*\u0026lt;br /\u0026gt; //静态属性 或静态方法不需要所在类被实例化就可以使用\u0026lt;br /\u0026gt; //使用方法:类名::静态方法名(静态属性名)\u0026lt;br /\u0026gt; //例子:static.php\u0026lt;br /\u0026gt; */\u0026lt;br /\u0026gt; class Math\u0026lt;br /\u0026gt; {\u0026lt;br /\u0026gt; public static $PI=3.14; //定义静态属性\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e//public $PI=3.14; //静态方法不能调用非静态的属性\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e`//定义一个静态方法,求两个数中的最大值\u003c/p\u003e\u003c/p\u003e\n\u003cp\u003epublic static function getMax($num1,$num2){ //static 关键字\u003c/p\u003e\n\u003cp\u003ereturn $num1 \u003e $num2 ? $num1 : $num2;\u003cbr /\u003e\n}\u003c/p\u003e\n\u003cp\u003e// 定义一个静态方法,求圆面积\u003c/p\u003e\n\u003cp\u003epublic static function getCircleArea($radius){\u003cbr /\u003e\n//return Math::$PI * $radius * $radius;//也行\u003c/p\u003e\n\u003cp\u003ereturn …\u003c/p\u003e\u003c/p\u003e"
June 11, 2010
PHP生成静态页面类
"\u003cp\u003eclass Shtml\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003evar $Templet;\u003c/p\u003e\n\u003cp\u003evar $DataSource;\u003c/p\u003e\n\u003cp\u003evar $Dir;\u003c/p\u003e\n\u003cp\u003evar $fileName;\u003c/p\u003e\n\u003cp\u003evar $mod;\u003c/p\u003e\n\u003cp\u003evar $handle;\u003c/p\u003e\n\u003cp\u003efunction Shtml($fileName=””)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;fileName=$fileName;\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;mod=”wb”;\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;handle=false;\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;Templet = “”;\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;DataSource = array();\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;Dir = “”;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e/// \u0026lt;描述\u0026gt;\u003c/p\u003e\n\u003cp\u003e/// 绑定数据源,参数为一数组。\u003c/p\u003e\n\u003cp\u003e///\u003c/p\u003e\n\u003cp\u003efunction BindData($arr)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;DataSource = $arr;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003e/// \u0026lt;描述\u0026gt;\u003c/p\u003e\n\u003cp\u003e/// 设置文件存放路径。\u003c/p\u003e\n\u003cp\u003e///\u003c/p\u003e\n\u003cp\u003efunction SetDir($dir)\u003c/p\u003e\n\u003cp\u003e{\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;Dir = $dir;\u003c/p\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003cp\u003efunction SetFileName($fileName)\u003c/p\u003e\n\u003cp\u003e{ …\u003c/p\u003e"
June 11, 2010
php设计模式介绍之注册模式
"\u003cp\u003e\u003cstrong\u003e《PHP 设计模式介绍》第五章 注册模式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e我们通常认为避免使用全局变量是一种好的选择,因此,对象经常被作为参数从一段代码传递到另一段。但是传递实例的一个问题就是对象有时候不知道将要 传递给谁——?经过一个函数后才被传递到真正需要这个对象的函数。\u003c/p\u003e\n\u003cp\u003e为了编写,阅读,修改代码的方便,最好能够减少不同对象的数量,并且能够将大量广泛使用的对象统一表示为一个单一,常用的对象。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e问题\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003e你如何通过单一的全局的对象来获取对其它对象的引用?\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e解决方案\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003e“注册模式”就像“对象的电话簿”——储存并且能够取回对对象引用的登记簿。(注:PHP中的“联合数组”也起到了类似“电话簿”的功能。事实上, “注册模式”就是围绕PHP中强大的数组完成的。)“注册模式”的一些特性经常被包含在“单一模式”中(参见第四章),使得“注册模式”成为你整个应用信 息的决定性来源。\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e注释:“注册模式”类主要参考了Martin Fowlerdescribes用java语言实现的Patterns of Enterprise Application Architecture(企业应用程序体系结构模型)。Marcus Baker谢了一篇详细 …\u003c/em\u003e\u003c/p\u003e"
May 26, 2010
php和asp的301 重定向
"\u003cp\u003e\u003cstrong\u003ePHP:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eheader(‘HTTP/1.1 301 Moved Permanently’);\u003c/p\u003e\n\u003cp\u003eheader(‘Location: \u003ca href=\"http://www.haohtml.com/\"\u003ehttp://www.haohtml.com\u003c/a\u003e‘.$request_uri);\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eASP:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u0026lt;%\u003c/p\u003e\n\u003cp\u003eResponse.Status=”301 Moved Permanently”\u003c/p\u003e\n\u003cp\u003eResponse.AddHeader “Location”,” \u003ca href=\"http://www.haohtml.com/\"\u003ehttp://www.haohtml.com/\u003c/a\u003e”\u003c/p\u003e\n\u003cp\u003eResponse.End\u003c/p\u003e\n\u003cp\u003e%\u0026gt;\u003c/p\u003e"
May 15, 2010
错误1920 服务McAfee Framework服务(McAfee Framework)启动失败.确认有足够的权限启动
"\u003cp\u003e确认有足够的权限启动系统服务的解决方法重装至正在启动服务,出现安装程序信息:“错误1920。服务McAfee Framework服务(McAfee Framework)启动失败。确认有足够的权限启动系统服务。”按“忽略(I)”才能继续安装,但最后还是不能升级。\u003c/p\u003e\n\u003cp\u003e经过不断摸索,上官方网站查询资料,找到解决办法如下:\u003c/p\u003e\n\u003cp\u003e打开服务控制台,禁用 McAfee Framework 服务\n重新启动,启动后再进程中(打开任务管理器) 结束 UpdaterUI.exe\u003c/p\u003e\n\u003cp\u003e运行regedit ,删除以下:\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\McAfee Framework\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Network Associates\\TVD\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Network Associates\\ePolicy orchestrator\n以上三个必须删除\u003c/p\u003e\n\u003cp\u003e删除以下目录\nC:\\Program Files\\Network Associates\\Common …\u003c/p\u003e"
May 15, 2010
mcafee不能更新,提示初始化Common updater子系统失败
"\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2010/05/mcafee-autoupdate.jpg\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2010/05/mcafee-autoupdate.jpg\" alt=\"mcafee-autoupdate\"\u003e\u003c/a\u003e升级mcafee时出现初始化Common updater子系统失败,重装修复问题依然存在,不能解决,看图:\u003c/p\u003e\n\u003cp\u003e一共有两种解决办法,其一是复制 FrameworkManifest.xml 这个文件来覆盖,其二是删除 FrameworkManifest.xml并重新安装Common Management Agent (CMA)\u003c/p\u003e\n\u003cp\u003e8.5.0.i版本的FrameworkManifest.xml文件下载:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"http://qingwa.hackroad.com/newblog/template/elegantly/images/download.gif\" alt=\"mcafee不能更新,提示初始化Common updater子系统失败 - 饿狼 - 我们俩\"\u003e下载文件 (已下载 153 次)\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://qingwa.hackroad.com/newblog/attachment.php?fid=9\"\u003e点击这里下载文件: FrameworkManifest.xml\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e官方的bug说明:\u003c/p\u003e\n\u003cp\u003eCorporate KnowledgeBase\u003c/p\u003e\n\u003cp\u003eERROR: McAfee Common Framework returned error fffff95b @ 2 (issue: FrameworkManifest.xml corrupt)\u003c/p\u003e\n\u003cp\u003eCorporate KnowledgeBase ID: KB54520\u003c/p\u003e\n\u003cp\u003ePublished: August 08, 2008\u003c/p\u003e\n\u003cp\u003eEnvironment\u003c/p\u003e\n\u003cp\u003eMcAfee Common Management Agent 3.60 …\u003c/p\u003e"
May 14, 2010
PHP使用接口实现多重继承
"\u003cp\u003ePHP类虽然是单继承的,但是可以通过其它特殊的方式实现多重继承,比如使用接口实现,只要把类的特征抽象为接口,并通过实现接口的方式让对象有多重身 份,通过这样就可以模拟多重继承了。\u003c/p\u003e\n\u003cp\u003e下面就是一个用接口模拟多重继承的例子,源代码如下:\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\n\u003cp\u003einterface UserInterface{ // 定义User的接口\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003efunction getname();\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003einterface TeacherInterface{ //teacher 相关接口\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003efunction getLengthOfService();\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eclass User implements UserInterface { // 实现UserInterface接口\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eprivate$name = “tom”;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003epublicfunction getName(){\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ereturn$this-\u0026gt;name;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e}\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eclass Teacher implements TeacherInterface { // 实现TeacherInterface …\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e"
May 14, 2010
在smarty中增加类似foreach的功能自动加载数据
"\u003cp\u003e在smarty中使用自定义插件来加载数据(见:), 在使用的时候还是感觉不够方便,灵机一动就想写成类似foreach那种标签:\u003c/p\u003e\n\u003cp\u003e第一步:在Smarty_Compiler.class.php的_compile_tag函数中增加:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003eview\u003cbr\u003e\n\u003cbr\u003e\nplain\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003ecopy\u003cbr\u003e\n\u003cbr\u003e\nto clipboard\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003eprint\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003e?\u003c/a\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e//加载\u003c/p\u003e\n\u003cp\u003e数据的开始标签\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ecase‘load’:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e$this-\u0026gt;_push_tag(‘load’);\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ereturn$this-\u0026gt;_complie_load_start($tag_args);\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebreak;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e//加载数据的结束标签\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ecase‘/load’:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e$this-\u0026gt;_pop_tag(‘load’);\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ereturn“”;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebreak;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e第二步:增加一个方法:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003eview\u003cbr\u003e\n\u003cbr\u003e\nplain\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003ecopy\u003cbr\u003e\n\u003cbr\u003e\nto clipboard\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003eprint\u003c/a\u003e \u003ca href=\"http://blog.csdn.net/yycai/archive/2009/12/28/5092770.aspx#\"\u003e?\u003c/a\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e/**\u003c/li\u003e\n\u003cli\u003e* 加载数据\u003c/li\u003e\n\u003cli\u003e* @param $tag_args\u003c/li\u003e\n\u003cli\u003e*/\u003c/li\u003e\n\u003cli\u003efunction _complie_load_start($tag_args)\u003c/li\u003e\n\u003cli\u003e{\u003c/li\u003e\n\u003cli\u003e$key = …\u003c/li\u003e\u003c/ol\u003e"
May 14, 2010
Smarty缩图函数
"\u003cp\u003e下载: \u003ca href=\"http://www.21andy.com/blog/wp-content/plugins/coolcode/coolcode.php?p=703\u0026amp;download=function.thumb.php\"\u003efunction.thumb.php\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e/*\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eSmarty plugin “Thumb”\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePurpose: creates cached thumbnails\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHome: \u003ca href=\"http://www.cerdmann.com/thumb/\"\u003ehttp://www.cerdmann.com/thumb/\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eCopyright (C) 2005 Christoph Erdmann\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThis library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThis library is distributed in the hope that it will be useful, but WITHOUT ANY …\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"
May 14, 2010
Smarty高级特性 – 用户自定义函数使用 SMARTY:: register_function;
"\u003cp\u003eSmarty高级 特性 – 用户自定义函数 使用 SMARTY:: register_function;\u003c/p\u003e\n\u003cp\u003e前言:\n很久不用smarty了,因为大多数项目都是比较轻量型的。前段时间 笔者接了个还算可以的项目,下面有几个程序员 ,与一个美工组为项目团队。为了做快速的布署应用 ,也为了小组成员能形成一个统一的view层的控制,选择了smarty。发现smarty果然还是那么的强大,那么的很黄很暴力。\n作者:无喱头\u003c/p\u003e\n\u003cp\u003e故事背景:\n小张是个很漂亮的美工MM,与无喱头搭档已经很多年。请不要误解,无喱头是有老婆女儿的,他们之前没有任何的暧昧关系,仅仅是同事,或者是上下级。\n在两人的多年合作过程中,在很多地方,已经形成了一种默契。在很多时候,喱头提供封装好的php函数,然后通过一些技术 上的修改,可以直接使用小张在模板里引入php函数,这样可以很方便的把模板切成很多小块,便于维护。并且由于可以自定义一些关键字,小张可能很快的取出 想要的一些数据 。\n比如:\n{phpsoho “sort=article\u0026amp;order=ID …\u003c/p\u003e"
April 28, 2010
PHP图片处理剪切类
"\u003cp\u003e\u0026lt; ?php\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cp\u003e* 基本图片处理,用于完成图片缩入,水印添加\u003c/p\u003e\n\u003cp\u003e* 当水印图超过目标图片尺寸时,水印图能自动适应目标图片而缩小\u003c/p\u003e\n\u003cp\u003e* 水印图可以设置跟背景的合并度\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e* Copyright(c) 2005 by ustb99. All rights reserved\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e* To contact the author write to {@link mailto:ustb80@163.com}\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@author 偶然\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@version $Id: thumb.class.php,v 1.9 2006/09/30 09:31:56 zengjian Exp $\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@package system\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e/**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eThumbHandler\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e@access public\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e*/\u003c/p\u003e\n\u003cp\u003e/*\u003c/p\u003e\n\u003cp\u003e使用方法:\u003c/p\u003e\n\u003cp\u003e自动裁切:\u003c/p\u003e\n\u003cp\u003e程序会按照图片的尺寸从中部裁切最大的正方形,并按目标尺寸进行缩略\u003c/p\u003e\n\u003cp\u003e$t-\u0026gt;setSrcImg(“img/test.jpg”);\u003c/p\u003e\n\u003cp\u003e$t-\u0026gt;setCutType(1);//这一句就OK …\u003c/p\u003e"
April 28, 2010
PHP生成word文档格式试卷的代码
"\u003cp\u003ePHP生 成word文档的代码,这个是用来生产试卷的简单PHP代码\u003c/p\u003e\n\u003cp\u003e以下为引用的内容:试卷生成 difficulty.”\u003c/p\u003e\n\u003cp\u003e”;\n$cout.=” “.$row-\u0026gt;content.”\u003c/p\u003e\n\u003cp\u003e”;\n}//while\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\n’;\n}\u003c/p\u003e\n\u003cp\u003efunction save($path)\n{\u003c/p\u003e\n\u003cp\u003eprint “”;\n$data = ob_get_contents();\u003c/p\u003e\n\u003cp\u003eob_end_clean();\u003c/p\u003e\n\u003cp\u003e$this-\u0026gt;wirtefile ($path,$data);\n}\u003c/p\u003e\n\u003cp\u003efunction wirtefile ($fn,$data)\n{\u003c/p\u003e\n\u003cp\u003e$fp=fopen($fn,”wb”);\nfwrite($fp,$data);\nfclose($fp);\n}\n}\n/*——-word class End——-*/\n$word=new word;\n$word-\u0026gt;start();\necho $cout;\n$wordname=”word/”.time().”.doc”;\n$word-\u0026gt;save($wordname);// 保存word并且结束.\n?\u0026gt;\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"%E2%80%9D%3C?php\"\u003e” target=_blank …\u003c/a\u003e\u003c/p\u003e"
April 26, 2010
开源免费的简易中文分词系统SCWS – PHP版
"\u003cp\u003eSCWS 是 Simple Chinese Words Segmentation 的缩写,即简易中文分词系统。\u003c/p\u003e\n\u003cp\u003e这是一套基于词频词典的机械中文分词引擎,它能将一整段的汉字基本正确的切分成词。词是汉语的基本语素单位,而书写的时候不像英语会在词 之间用空格分开,所以如何准确而又快速的分词一直是中文分词的攻关难点。\u003c/p\u003e\n\u003cp\u003eSCWS 在概念上并无创新成分,采用的是自行采集的词频词典,并辅以一定程度上的专有名称、人名、地名、数字年代等规则集,经小范围测试大概准确率在 90% ~ 95% 之间,已能基本满足一些中小型搜索引擎、关键字提取等场合运用。 SCWS 采用纯 C 代码开发,以 Unix-Like OS 为主要平台环境,提供共享函数库,方便植入各种现有软件系统。此外它支持 GBK,UTF-8,BIG5 等汉字编码,切词效率高。\u003c/p\u003e\n\u003cp\u003e[推荐]首个搭载 SCWS 分词系统的中小型站内全文检索解决方案 – \u003ca href=\"http://www.ftphp.com/\"\u003eFTPHP!\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e以下为本人在win03平台下,php5.2.5+apache2.2.11平台下推荐的方法,特别的简单,用的是gbk的字库的\u003c/p\u003e\n\u003cp\u003e1. …\u003c/p\u003e"
April 22, 2010
PHP生成内置图片Word文档的方法(一)
"\u003cp\u003e一般,有2种方法可以导出doc文档,一种是 使用com,并且作为php的一个扩展库安装到服务器上,然后创建一个com,调用它的方法。安装过office的服务器可以调用一个叫 word.application的com,可以生成word文档,不过这种方式我不推荐,因为执行效率比较低(我测试了一下,在执行代码的时候,服务器 会真的去打开一个word客户端)。理想的com应该是没有界面的,在后台进行数据转换,这样效果会比较好,但是这些扩展一般需要收费。\u003c/p\u003e\n\u003cp\u003e第2种方法,就是用PHP将我们的doc文档内容直接写入一个后缀为doc的文件中即可。使用这种方法不需要依赖第三方扩展,而且执行效率较高。\u003c/p\u003e\n\u003cp\u003eword本身的功能还是很强大的,它可以打开html格式的文件,并且能够保留格式,即使后缀为doc,它也能识别正常打开。这就为我们提供了方便。但是 有一个问题,html格式的文件中的图片只有一个地址,真正的图片是保存在其他地方的,也就是说,如果将HTML格式写入doc中,那么doc中将不能包 含图片。那我们如何创建包含图片的doc文档呢?我们可以使用和html很接近的mht格式。\u003c/p\u003e\n\u003cp\u003emht格式和html很类似,只 …\u003c/p\u003e"
April 19, 2010
魔法引用函数 magic_quotes_gpc和magic_quotes_runtime的区别和用法
"\u003cp\u003ePHP基础002: 魔法引用函数magic_quotes_gpc和magic_quotes_runtime的区别和用法\u003c/p\u003e\n\u003cp\u003ePHP提供两个方便我们引用数据的魔法引用函数magic_quotes_gpc和magic_quotes_runtime,这两个函数如果在 php.ini设置为ON的时候,就会为我们引用的数据碰到单引号’和双引号”以及反斜线 \\ 是自动加上反斜线,帮我们自动转译符号,确保数据操作的正确运行,可是我们在php不同的版本或者不同的服务器配置下,有的 magic_quotes_gpc和magic_quotes_runtime设置为on,有的又是off,所以我们写的程序必须符合on和off两种情 况。那么magic_quotes_gpc和magic_quotes_runtime两个函数有什么区别呢?看下面的说明:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003emagic_quotes_gpc\u003c/strong\u003e\n作用范围是:WEB客户服务端;\n作用时间:请求开始是,例如当脚本运行时.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003emagic_quotes_runtime\u003c/strong\u003e\n作用范围:从文件中读取的数据或执行exec()的结果或是从SQL查询中得到的;\n作用时间:每次当脚本访问运行状态中产生 …\u003c/p\u003e"
April 19, 2010
同服务器多网站的安全设置(windows server+apache+php)
"\u003cp\u003e在windows环境下,如果用IIS做webserver,可以配合ntfs为每个网站设置不同的用户权限,从而让一个网站的程序只能访问自己目 录下的内容.\u003c/p\u003e\n\u003cp\u003e而在windows的apache环 境下,由于apache默认是最高的system权限,因此非常危险,若不做安全设置,随便传一个php shell到任何一个网站上,就能控制整台服务器。\u003c/p\u003e\n\u003cp\u003e要实现这个目标,需要做以下设置:\u003c/p\u003e\n\u003cp\u003e1、在vhost中设置 open_basedir,设置后,php程序将只能打开规定目录下的内容(此指令不受安全模式是否打开的限制)。如下。同时最好把php.ini的 upload_tmp_dir 目录也添加进去,否则可能无法正常上传文件。\u003c/p\u003e\n\u003cp\u003eServerAdmin \u003ca href=\"mailto:admin@abc.com\"\u003eadmin@abc.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eDocumentRoot D:/abc\u003c/p\u003e\n\u003cp\u003eServerName \u003ca href=\"http://www.abc.com/\"\u003ewww.abc.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eErrorLog logs/abc.com-error_log\u003c/p\u003e\n\u003cp\u003eCustomLog logs/abc.com-access_log common\u003c/p\u003e\n\u003cp\u003ephp_admin_value open_basedir “D:/abc;D:/php/temp” …\u003c/p\u003e"
April 17, 2010
JW Media Player 中文文档
"\u003cp\u003e\u003cstrong\u003eThe JW MP3 Player (built with Adobe’s Flash) is the easiest way to add live music or podcasts to your website. It supports playback of a single MP3 file or an RSS, XSPF or ASX playlist, a wide range of flashvars (settings) for tweaking both behavior and appearance and an extensive, documented javascript/actionscript API.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e官方网址 \u003ca href=\"http://www.jeroenwijering.com/?item=JW_Media_Player\"\u003ehttp://www.jeroenwijering.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这篇文档包含了JW MP3 Player,JW FLVPlayer,JW Media Player,JW Image Rotator的安装方法和配置方\n法\u003c/p\u003e\n\u003cp\u003eJW PLAYERS 3.11 文档\u003c/p\u003e\n\u003cp\u003e1,安装 (在你的站点里嵌入)\n2,参数 (配置) …\u003c/p\u003e"
April 17, 2010
JW Player使用简介
"\u003cp\u003e\u003cstrong\u003e一、JW Player是什么?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e简单地说,JW Player是一种基于flash的交互式网页媒体播放器。它是由Jeroen 和 Wijering共同建立的LongTail Video所开发,问世于2005年,当时仍名不经传的YouTube首次采用的播放器就是JW Player。官方网址: \u003ca href=\"http://www.longtailvideo.com/\"\u003ehttp://www.longtailvideo.com/\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eJW Player含:FLV Player、WMV Player、Image Rotator和Desktop Player四种,除了最后一种实为桌面播放器,其他三种都是网页播放器。本篇内容仅限FLV Player。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、JW FLV Media Player简介\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eJW FLV Media Player可播放Adobe Flash Player所支持的媒体,具体包括:FLV、MP4、MP3、AAC、JPG、PNG和GIF等,还支持RTMP、HTTP、实时视频流、各种播放清单 格式、灵活的设置和广泛的javascript API。此外它还提供多种外观、功能性插件来扩展播放器,以便我们可以分享、推荐、搜索、分析甚至广告投放。 …\u003c/p\u003e"
April 13, 2010
smarty缓存使用技巧
"\u003cp\u003e\u003cstrong\u003e一、使用缓存\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e要开启smarty的缓存,只需将caching设为true,并指定cache_dir即可.\u003c/p\u003e\n\u003cp\u003e使用cache_lefetime指定 缓存生存时间,单位为秒\u003c/p\u003e\n\u003cp\u003e要对相同页面生成多个不同的缓存,在display或fetch中加入第二参数cache_id, 如$smarty-\u0026gt;display(‘index.tpl’,$my_cache_id);此特性可用于对不同的$_GET进行不同的缓存\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e二、清除缓存\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eclear_all_cache();//清除所有缓存\u003c/p\u003e\n\u003cp\u003eclear_cache(‘index.tpl’);// 清除index.tpl的缓存\u003c/p\u003e\n\u003cp\u003eclear_cache(‘index.tpl’,cache_id);//清除指定id的缓存\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e三、使用自定义缓存方式\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e设置cache_handler_func使用自定义的函数处理缓存\u003c/p\u003e\n\u003cp\u003e如:\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;cache_handler_func = “myCache”;\u003c/p\u003e\n\u003cp\u003efunction myCache($action, \u0026amp;$smarty_obj, \u0026amp;$cache_content, $tpl_file=null, …\u003c/p\u003e"
April 1, 2010
采用curl库在PHP程序之间传递数组[原创]
"\u003cp\u003e[文章作者:张宴 本文版本:v1.1 最后修改:2007.08.23 转载请注明出处: \u003ca href=\"http://blog.s135.com/\"\u003ehttp://blog.s135.com\u003c/a\u003e]\u003c/p\u003e\n\u003cp\u003e最近在工作中遇到一个问题:a.php程序需要将接收到的数据同时写到“线上运行的正式数据库”和“进行开发调试的测试数据库”。而测试数据库可能经常 会面临对表结构、字段、配置信息做调整等问题,很不稳定,发生错误的概率很高,如果用a.php程序同时写“正式数据库”和“测试数据库”,势必影响到线 上运行的正式服务。\u003c/p\u003e\n\u003cp\u003e于是,我想到用PHP curl扩展库将生成的$data数组post传递一份给b.php程序,然后a.php程序继续往下执行写“正式数据库”的代码。a.php程序 将$data数组传递给b.php程序就完事了,至于b.php如何处理,就不关a.php的事了,b.php程序即使写“测试数据库”失败,也不会对 a.php程序造成影响。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2010/04/curl.gif\"\u003e\u003cimg src=\"http://blog.haohtml.com/wp-content/uploads/2010/04/curl.gif\" alt=\"curl\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e按照这种思路,我写了a.php和b.php的代码:\u003c/p\u003e\n\u003cp\u003ea.php程序源代码:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://blog.s135.com/#\"\u003eview plain\u003c/a\u003e \u003ca href=\"http://blog.s135.com/#\"\u003eprint\u003c/a\u003e \u003ca href=\"http://blog.s135.com/#\"\u003e?\u003c/a\u003e\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e$data[“username”]=“张宴”;\u003c/li\u003e\n\u003cli\u003e$data[“password”]=“不知 道”; …\u003c/li\u003e\u003c/ol\u003e"
April 1, 2010
同一域名对应多个IP时,PHP获取远程网页内容的函数 [原创]
"\u003cp\u003e[文章作者:张宴 本文版本:v1.0 最后修改:2008.12.15 转载请注明原文链接: \u003ca href=\"http://blog.s135.com/post/389/\"\u003ehttp://blog.s135.com/post/389/\u003c/a\u003e]\u003c/p\u003e\n\u003cp\u003ePHP获取远程网页内容有多种方式,例如用自带的file_get_contents、fopen等函数。\u003c/p\u003e\n\u003cp\u003e引用\u003c/p\u003e\n\u003cp\u003eecho file_get_contents(“ \u003ca href=\"http://blog.s135.com/abc.php%22%29;%C2%A0%C2%A0\"\u003ehttp://blog.s135.com/abc.php”);\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\n\u003cp\u003e但是,在DNS轮询等负载均衡中,同一域名,可能对应多台服务器,多个IP。假设 blog.s135.com被DNS解析到72.249.146.213、72.249.146.214、72.249.146.215三个IP,用户每 次访问blog.s135.com,系统会根据负载均衡的相应算法访问其中的一台服务器。\u003c/p\u003e\n\u003cp\u003e上周做一个视频项目时,就碰到这样一类需 求:需要依次访问每台服务器上的一个PHP接口程序(假设为abc.php),查询这台服务器的传输状态。\u003c/p\u003e\n\u003cp\u003e这时就不能直接用 file_get_contents访问 \u003ca href=\"http://blog.s135.com/abc.php\"\u003ehttp://blog.s135.com/abc.php\u003c/a\u003e 了,因为它可能一直重复访问某一台服务器。\u003c/p\u003e\n\u003cp\u003e …\u003c/p\u003e"
March 26, 2010
PHP中echo和print的区别
"\u003cp\u003ePHP 和 HTML 最简单的交互是通过 print 和 echo 语句来实现的,在实际使用中, print 和 echo 两者的功能几 乎是完全一样。可以这么说,凡是有一个可以使用的地方,另一个也可以使用。但是,两者之间也还是一个非常重要的区别:在 echo 函数中,可以同时输出 多个字符串,而在 print 函数中则只可以同时输出一个字符串。同时,echo函数并不需要圆括号,所以echo函数更像是语句而不像是函数。\u003c/p\u003e\n\u003cp\u003eecho 和 print 都不是函数,而是语言结构,\u003cstrong\u003e所以圆括号都不是必需的\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003eecho命令和print命令相同,没有区别 ;\necho函数和print函数有区别;\nprint()有返 回值,当其执行失败(比如断线)时返回flase;\nprintf()和sprintf()类似,均为格式化输出,不同的是前者输出到 标准输出,后者输出到变量。\u003c/p\u003e\n\u003cp\u003e他们的区别在于:\n(1) echo可以输出多个字符串,像下面这样:\necho ‘a’,’b’,’c’;\n如果你非要加上圆括号,注意写成echo (‘a’,’b’,’c’);是错误的,应该写成:\necho …\u003c/p\u003e"
March 26, 2010
windows下安装 Xdebug+WinCacheGrind
"\u003cp\u003e以PHP5.1.4,Windows平台为例(其它PHP版本,其它平台请参看官网文档):\n1. 在 \u003ca href=\"http://www.xdebug.org/download.php\"\u003ehttp://www.xdebug.org/download.php\u003c/a\u003e 下载适合自己php版本的php_xdebug- 2.0.1-5.1.2.dll【有附件提供下载,如果按照以下步骤完成后 phpinfo任无法显示xdebug,那么建议重新下载其他xdebug.dll文件试试 】;\n2. 将下载的xdebug.dll放到php\\ext目录里,可以重命名也可以不重命名,这里我没有重命名。\n3. 编辑php.ini,加入下面几行:\u003c/p\u003e\n\u003cp\u003eextension=php_xdebug-2.0.1-5.1.2.dll\u003c/p\u003e\n\u003cp\u003e;xdebug配置\n[Xdebug]\n;开启自动跟踪\nxdebug.auto_trace = On\n;开启异常跟踪\nxdebug.show_exception_trace = On\n;开启远程调试自动启动\nxdebug.remote_autostart = On\n;开启远程调试\nxdebug.remote_enable = On\n;收集变量\nxdebug.collect_vars = On\n; …\u003c/p\u003e"
March 26, 2010
PHP中如何使用header发送头部信息
"\u003cp\u003e在照彭武兴先生的《PHP BIBLE》中所述,header可以送出Status标头,如\u003c/p\u003e\n\u003cp\u003e就可以让用户浏览器出现文件找不到的404错误,但是我试了这样是不行的。\u003c/p\u003e\n\u003cp\u003e后 来我到w3.org上查了http的相关资料,终于试出来了如何Header出状态代码(Status),与大家分享。\u003c/p\u003e\n\u003cp\u003e其实应该是这样 的:\u003c/p\u003e\n\u003cp\u003e第一部分为 HTTP协议的版本(HTTP-Version)\u003c/p\u003e\n\u003cp\u003e第二部分为状态代码(Status)\u003c/p\u003e\n\u003cp\u003e第三部分为原因短语 (Reason-Phrase)\u003c/p\u003e\n\u003cp\u003e三部分中间用一个空格分开,且中间不能有回车,第一部分和第二部分是必需的,第三部分则是给人看的,可 写可不写甚至乱写。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e还有,这一句的输出必须在Html文件的第一行。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e下面我给出各代码所代表的意思(是从 w3.org上查到的,够权威了):\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e1xx: Informational – Request received, continuing process\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e2xx: Success – The action was successfully received, understood,and accepted\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e3xx: Redirection …\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e"
January 22, 2010
用apache来实现限制ip可以访问phpmyadmin
"\u003cp\u003e为了安全,只允许固定ip才可以访问phpmyadmin,这个由于没有找到在phpmyadmin配置的地方,所以这里用apache来实现这个功能\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eServerAdmin www@163.com\nDocumentRoot “D:\\site\\phpMyAdmin”\nServerName php.haohtml.com\nDirectoryIndex index.php index.shtml\n\n\nOptions Indexes MultiViews\nAllowOverride None\norder deny,allow\nAllow from 192.168.0.7\nDeny from all\n\nAllow from all\n\nOptions FollowSymLinks Includes\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e经过上面一系列的配置,将只允许ip为192.168.0.7的ip才可以访问phpmyadmin,其它的ip都不允许访问.\u003c/p\u003e"
January 8, 2010
解除phpMyAdmin 导入大型MySQL数据库文件大小限制
"\u003cp\u003e今天在WPMZ环境下安装了DEDECMS,朋友将以前网站的数据进行导入时出现了一些问题,提示超出导入大小限制。默认MYSQL只能导入最大2MB的数据,于是我在网上找到了修改的方法,事实证明以下方法是可行的。(修改好后必须重启PHP,可)\n**\nphpMyAdmin 导入大型数据库文件大小限制配置…**\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e修改 php.ini 文件中下列3项的值:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eupload_max_filesize, memory_limit 和 post_max_size\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eupload_max_filesize,上传文件大小\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ememory_limit 设置内存\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003epost_max_size 提交数据的最大值\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e为你想改的大小值.\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e在 phpMyAdmin 的配置文件中修改或加入这个设置:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这个文件一般是在phpMyAdmin目录下的config.inc.php文件\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e$cfg[‘ExecTimeLimit’] = 0; // maximum execution time in seconds (0 for no limit)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e默认为300秒钟,改为0表示不受限制\u003c/p\u003e"
December 31, 2009
smarty局部缓存
"\u003cp\u003eSmarty提供了强大的 缓存功能。但有时我们并不希望整篇文档都被缓存,而是有选择的缓存某一部分内容或某一部分内容不被缓存。例如你在页面上端使用一个带有广告条位置的模板, 广告条可以包含任何HTML、图象、FLASH等混合信息. 因此这里不能使用一个静态的链接,同时我们也不希望该广告条被缓存. 这就需要在 insert 函数指定,同时需要一个函数取广告条的内容信息。smarty也提供了这种缓存控制能力。\u003c/p\u003e\n\u003cp\u003e我们可以使用$smarty-\u0026gt;register_block($params,\u0026amp;$smarty)使整篇页面中的某一块不被缓存。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eindex.tpl:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eXML/HTML代码\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u0026lt;divalign=‘center’\u0026gt;\u003c/li\u003e\n\u003cli\u003ePage created: {“0″|date_format:”%D %H:%M:%S”}\u003c/li\u003e\n\u003cli\u003e\u0026lt;{dynamic}\u0026gt;\u003c/li\u003e\n\u003cli\u003eNow is: {“0″|date_format:”%D %H:%M:%S”}\u003c/li\u003e\n\u003cli\u003e… do other stuff …\u003c/li\u003e\n\u003cli\u003e\u0026lt;{/dynamic}\u0026gt;\u003c/li\u003e\n\u003cli\u003ediv\u0026gt;\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eindex.php:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eXML/HTML …\u003c/p\u003e"
November 17, 2009
sphinx在windows下无法启动的解决办法
"\u003cp\u003e配置完成了sphinx,也安装成为系统服务,但在dos提示符下服务的时候错误\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003esearchd –-install -–config d:/csft3.1/bin/xxxx.conf\u003c/p\u003e\n\u003cp\u003e相应的删除服务命令为:\u003c/p\u003e\n\u003cp\u003esearchd –delete\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e[\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/sphinex-services.jpg\" alt=\"sphinex-services\"\u003e][1]\u003c/p\u003e\n\u003cp\u003e这里有两种办法:\n1.直接把配置文件复制到c:/windows/system32目录里一份就可以了.\n2.在安装服务的时候指定配置文件的物理路径(–config d:/csft3.1/bin/csft.conf)\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e索引或者查询时提示:ERROR: invalid token in 配置文件 line 1 col 1.\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003e该提示表示当前的配置文件的编码不是UTF-8(无BOM头)格式,无法正确解析,请使用编辑软件打开配置文件,另存为UTF-8(无BOM头)格式;\u003c/p\u003e\n\u003cp\u003e错误的编码格式包括:Unicode、Unicode BOM、Unicode big endian、Unicode 低位在前、UTF-8 + BOM、UTF-8 Signature、UTF-8 包含签名等;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e特别注意\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eWindows自带的记事本(Notepad)或者写字 …\u003c/p\u003e"
October 12, 2009
jQuery+PHP实现FCKEditor内容分页
"\u003cp\u003e如题,用jQuery+PHP实现FCKEditor内容分页,如下:\u003c/p\u003e\n\u003cp\u003ePHP分页函数:\n/*\u003cstrong\u003e****\u003cem\u003e*\\\u003c/em\u003e*FCKEditor分页处理***\u003c/strong\u003e****/\nfunction pageBreak($content)\n{\n//把文章内容按照\u003c/p\u003e\n\u003cp\u003e分割成数组\n$content = $content;\n$pattern = “/\u003c/p\u003e\n\u003cp\u003e\u0026lt;/span\u0026gt;\u0026lt;/div\u0026gt;/”;\n$strSplit = preg_split($pattern, $content, -1, PREG_SPLIT_NO_EMPTY); //将文章内容分割成数组\n$count = count($strSplit); //分割后的数组单元数目\n$outStr = “”; //返回的字串\n$i = 1;\u003c/p\u003e\n\u003cp\u003eif ($count \u0026gt; 1 ) {\n$outStr = “\n”;\nforeach($strSplit as $value) {\nif ($i \u0026lt;= 1) {\n$outStr .= “\u003c/p\u003e\n\u003cp\u003e$value\u003c/p\u003e\n\u003cp\u003e”;\n} else {\n$outStr .= “\u003c/p\u003e\n\u003cp\u003e$value\u003c/p\u003e\n\u003cp\u003e”;\n} …\u003c/p\u003e"
July 31, 2009
详细讲解C++ 类的继承
"\u003cp\u003e一个私有的或保护的派生类不是子类,因为非公共的派生类不能做基类能做的所有的事,就是指在公开场合,但是在类内部可以的\u003c/p\u003e\n\u003ch3 id=\"一引言\"\u003e一、引言\u003c/h3\u003e\n\u003cp\u003e在C++中,类是提供封装的逻辑单位,类的每一个对象都包含有描述其自身状态的数据集合,并且通过接收特定的消息来处理这个数据集合。如果程序设计 人员能够通过增加、修改或替换指定类的部分内容的方法对该类进行剪裁,就可以适应不同的应用,从而在很大程度上增强了数据封装的价值,而接下来要讨论的继 承就完全可以实现这种操作。\u003c/p\u003e\n\u003ch3 id=\"二与继承有关的基本概念\"\u003e二、与继承有关的基本概念\u003c/h3\u003e\n\u003cp\u003e继承是一个进程,通过继承,一个对象可以获得另一个对象的属性(包括函数),并可向其中加入属于自己的一些特征。作为C++语言的一种重要机制,用 继承的方法可以自动为一个类提供来自另一个类的操作和数据结构,进而使程序设计人员在一个一般的类的基础上很快建立一个新的类,而不必从零开始设计每个 类。\u003c/p\u003e\n\u003cp\u003e当一个类被其他的类继承时,被继承的类称为基类(可不是鸡肋^_^),又称为父类。\u003c/p\u003e\n\u003cp\u003e继承其他类属性的类称为派生类,又称为子类。\u003c/p\u003e\n\u003cp\u003e一般情况下,继承的进程起源于一个基类的定义,基类定义了其所有派生类的公有属性。从本质上讲,基类具有同一类集合中的公共属 …\u003c/p\u003e"
May 26, 2009
php计算两个数组交集和差集
"\u003cp\u003earray_intersect\n(PHP 4 \u0026gt;= 4.0.1, PHP 5)\u003c/p\u003e\n\u003cp\u003earray_intersect — 计算数组的交集说明\narray array_intersect ( array array1, array array2 [, array …])\narray_intersect() 返回一个数组,该数组包含了所有在 array1 中也同时出现在所有其它参数数组中的值。注意键名保留不变。\u003c/p\u003e\n\u003cp\u003e例子 1. array_intersect() 例子\u003c/p\u003e\n\u003cp\u003e“green”, “red”, “blue”);\n$array2 = array (“b” =\u0026gt; “green”, “yellow”, “red”);\n$result = array_intersect ($array1, $array2);\n?\u0026gt;\u003c/p\u003e\n\u003cp\u003e这使得 $result 成为:\u003c/p\u003e\n\u003cp\u003eArray\n(\n [a] =\u0026gt; green\n [0] =\u0026gt; red\n)\n注: 两个单元仅在 (string) $elem1 === (string) $elem2 时被认为是相同的。也就是说,当字符串的表达是一样的时候。 …\u003c/p\u003e"
May 25, 2009
php中的$_SERVER or $_ENV
"\u003cp\u003e服务器变量:$_SERVER\n注: 在 PHP 4.1.0 及以后版本使用。之前的版本,使用 $HTTP_SERVER_VARS。\u003c/p\u003e\n\u003cp\u003e$_SERVER 是一个包含诸如头信息(header)、路径(path)和脚本位置(script locations)的数组。数组的实体由 web 服务器创建。不能保证所有的服务器都能产生所有的信息;服务器可能忽略了一些信息,或者产生了一些未在下面列出的新的信息。这意味着,大量的这些变量在 CGI 1.1 规范中说明,所以应该仔细研究一下。\u003c/p\u003e\n\u003cp\u003e环境变量:$_ENV\n注: 在 PHP 4.1.0 及以后版本使用。之前的版本,使用 $HTTP_ENV_VARS。\u003c/p\u003e\n\u003cp\u003e在解析器运行时,这些变量从环境变量转变为 PHP 全局变量名称空间(namespace)。它们中的许多都是由 PHP 所运行的系统决定。完整的列表是不可能的。请查看系统的文档以确定其特定的环境变量。\u003c/p\u003e\n\u003cp\u003e其它环境变量(包括 CGI 变量),无论 PHP 是以服务器模块或是以 CGI 处理方式运行,都在这里列出了。\u003c/p\u003e\n\u003cp\u003e这是一个“superglobal”,或者可以描述为自动全局变量。这只不过意味这它在所有的脚本中 …\u003c/p\u003e"
May 5, 2009
php判断浏览器类型
"\u003cp\u003eUA = getenv(“HTTP_USER_AGENT”);\n $start = strpos($this-\u0026gt;UA,”(“)+1;//查看起始位置\n $length = strpos($this-\u0026gt;UA,”)”)-$start;//查看结束位置\n $middle = trim(substr($this-\u0026gt;UA,$start,$length)); //查看内容\n $end = trim(substr($this-\u0026gt;UA,$start+$length+1));//附加内容\n $message = explode(“;”,$middle);//转换成数组\n //———-操作系统—————–\n $os = trim($message[‘2’]);\n $os_array = explode(” “,$os);\n $this-\u0026gt;PLATFORM = trim($os_array[‘0’]);//操作系统\n //————浏览器————\n $brower = trim($message[‘1’]); …\u003c/p\u003e"
March 2, 2009
ZF框架中的MVC
"\u003cp\u003e\u003ca href=\"http://blog.haohtml.com/wp-content/uploads/2009/03/8f5c2e59-c194-407e-93e4-949ca16aa67a.bmp\"\u003e\u003cimg src=\"https://blogstatic.haohtml.com//uploads/2023/09/8f5c2e59-c194-407e-93e4-949ca16aa67a.bmp\" alt=\"\"\u003e\u003c/a\u003e\u003c/p\u003e"
December 3, 2008
配置apache服务器支持shtml
"\u003cp\u003e服务器采用shtml速度会比html慢,比php快。\u003c/p\u003e\n\u003cp\u003eshtml的特点就是能够进行页面包含,能够局部更新页面包含部分。广泛采用可以很容易解决网页中的广告问题,不需要更新全面静态页面。而只需更新一个包含页面即可。\u003c/p\u003e\n\u003cp\u003eapache下配置服务器支持shtml\u003c/p\u003e\n\u003cp\u003e打开文件:httpd.conf\u003c/p\u003e\n\u003cp\u003e去掉前面的 #LoadModule include_module modules/mod_include.so\u003c/p\u003e\n\u003cp\u003eOptions Indexes FollowSymLinks Includes\u003c/p\u003e\n\u003cp\u003eAllowOverride Options FileInfo\nOrder allow,deny\nAllow from all\u003c/p\u003e\n\u003cp\u003e找到下面两句,去掉前面的#\u003c/p\u003e\n\u003cp\u003eAddType text/html .shtml\nAddOutputFilter INCLUDES .shtml\u003c/p\u003e\n\u003cp\u003e重启apache即可。\u003c/p\u003e\n\u003cp\u003e建立页面:\u003c/p\u003e\n\u003cp\u003e测试\u003c/p\u003e\n\u003cp\u003efile为相对于当前文档的路径。\u003c/p\u003e\n\u003cp\u003evirtual为相对于虚拟目录的路径。\n如果需要让所有的html文件支持shtml.只需要修改上面一句。\u003c/p\u003e\n\u003cp\u003eAddOutputFilter INCLUDES .html\u003c/p\u003e"
November 27, 2008
用 P3P 实现隐私参数优选策略
"\u003cp\u003e偶尔在yahoo的 头信息里看到p3p就上网查了一下 放在这里储存\u003c/p\u003e\n\u003cp\u003eprint_r(get_headers());\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\n\u003cp\u003e结果是这样的\u003c/p\u003e\n\u003cp\u003eArray\u003c/p\u003e\n\u003cp\u003e(\u003c/p\u003e\n\u003cp\u003e [0] =\u0026gt; HTTP/1.1 301 Moved Permanently\u003c/p\u003e\n\u003cp\u003e [1] =\u0026gt; Date: Mon, 17 Sep 2007 05:33:26 GMT\u003c/p\u003e\n\u003cp\u003e [2] =\u0026gt; Location: \u003ca href=\"http://cn.yahoo.com/\"\u003ehttp://cn.yahoo.com/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e [3] =\u0026gt; Connection: close\u003c/p\u003e\n\u003cp\u003e [4] =\u0026gt; Content-Type: text/html\u003c/p\u003e\n\u003cp\u003e [5] =\u0026gt; HTTP/1.1 200 OK\u003c/p\u003e\n\u003cp\u003e [6] =\u0026gt; Date: Mon, 17 Sep 2007 05:33:26 GMT\u003c/p\u003e\n\u003cp\u003e [7] =\u0026gt; P3P: policyref=” \u003ca href=\"http://p3p.yahoo.com/w3c/p3p.xml\"\u003ehttp://p3p.yahoo.com/w3c/p3p.xml\u003c/a\u003e“, CP=”CAO DSP COR CU\u003c/p\u003e\n\u003cp\u003eR ADM DEV TAI PSA PSD IVAi IVDi CONi …\u003c/p\u003e"
November 21, 2008
php中$_request与$_post、$_get的区别
"\u003cp\u003ephp中有$_request与$_post、$_get用于接受表单数据,当时他们有何种区别,什么时候用那种最好。\u003c/p\u003e\n\u003cp\u003e一、$_request与$_post、$_get的区别和特点\u003c/p\u003e\n\u003cp\u003e$_REQUEST[]具用$_POST[] $_GET[]的功能,但是$_REQUEST[]比较慢。通过post和get方法提交的所有数据都可以通过$_REQUEST数组获得\u003c/p\u003e\n\u003cp\u003e二、$_post、$_get的区别和特点\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eget是从服务器上获取数据,post是向服务器传送数据。\u003c/li\u003e\n\u003cli\u003eget是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。\u003c/li\u003e\n\u003cli\u003e对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。\u003c/li\u003e\n\u003cli\u003eget传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量 …\u003c/li\u003e\u003c/ol\u003e"
November 20, 2008
动态网页制作技巧PHP:详细彻底学习Smarty
"\u003cp\u003e页面请求变量\n以下是访问页面请求变量诸如get,post,cookies,server,enviroment和session变量的例子. 例如{$smarty.server.SERVER_NAME}取得服务器变量,{$smarty.env.PATH}取得系统环境变量path, {$smarty.request.username}取得get/post/cookies/server/env的复合变量。\u003c/p\u003e\n\u003cp\u003e{$smarty.now}变量用于访问当前时间戳.\n可以用 date_format调节器格式化输出. 例如{$smarty.nowdate_format:”%Y-%m-%d %H:%M:%S”}\u003c/p\u003e\n\u003cp\u003e{$smarty.const}\n你可以直接访问PHP常量. 例如{$smarty.const._MY_CONST_VAL}\u003c/p\u003e\n\u003cp\u003e{$smarty.capture}\n可以通过 {capture}..{/capture}结构 截取的输出可以使用{$smarty} 变量访问.\u003c/p\u003e\n\u003cp\u003e{$smarty.config}\n{$smarty}变量 可以访问已经加载的config变量. …\u003c/p\u003e"
November 13, 2008
require和include基本的区别
"\u003cp\u003e手册里是这么解释的:\u003c/p\u003e\n\u003cp\u003erequire() 和 include() 除了怎样处理失败之外在各方面都完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果你想在丢失文件时停止处理页面,那就别犹豫了,用 require() 吧。include() 就不是这样,脚本会继续运行。同时也要确认设置了合适的include_path。\u003c/p\u003e\n\u003cp\u003e就是说再解析程序时即读取require的文件,而不是解析后,\u003c/p\u003e\n\u003cp\u003e如果不能读取到被require的文件,就不能进行下一步动作。\n所以,不被正确包含就会导致程序的文件,用require比较好。\u003c/p\u003e\n\u003cp\u003e可能效率上也略微高点。\n—————————————————————\u003c/p\u003e\n\u003cp\u003erequire() 无论如何都会包含文件,而 include() 可以有选择地包含:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003ea.php 一定会被包含,而 b.php 一定不会被包含。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在PHP中include和require到底有什么区别呢?看这里的例子就知道了\u003c/p\u003e\n\u003cp\u003e:include.php3的运行结果是:\n 这是inc1.inc文件中的一个变量的值! …\u003c/p\u003e"
November 13, 2008
require和include经典一例抛析
"\u003cp\u003e 在php中,include和require的作用比较容易混淆。下面我以一个经典例子来深刻说明它们的区别。\n 当我们经常访问一个数据库时,可以把连库语句写成一个文件\ncon_db.php3\u003c/p\u003e\n\u003cp\u003e在实际应用时,我们可以在程序中调用这个文件。\n如require(“con_db.php3”)或include(“con_db.php3)\n这时,两个函数的效果是差不多的。\n但如果这样用\nfilename.php3\u003c/p\u003e\n\u003cp\u003e文件到myfun处将不能继续执行,因为函数里无法得到外面的变量(include也是一样的)。除非把$dbh作为一个变量传给函数。这又增加了调用函数的复杂度。\n我们可以通过把require或include放在函数里面来解决这个问题。\n如果用include,文件的第一个函数调用处将顺利通过,但第二个调用将无法执行,原因是不能在没有关闭数据库时在打开一次,也就是说,con_db.php3执行了两次。将include换成require,一切都正常。\n 也就是说,require类似于一次预扫描,在程序执行时,无论在函数里或是函数外,都将先把require的文件执行,且只执行一次。 …\u003c/p\u003e"
November 13, 2008
PHP的命名空间
"\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e摘要:命名变量,函数和类是挺困难的,除了要考虑到变量的名称要易于理解,还要担心是否这个名称在其它某个地方已经使用过. 在一小段脚本中,第二个问题是基本问题. 当你考虑重用你的代码, 在这之后的项目代码必须避免使用你用过的命名. 通常来说,可重用的代码总是包含在函数或类中, 需要处理许多可能发生的命名冲突. 但函数和类之间也可能发生命名冲突. 你可以尝试避免出现这种情况,通过在所有类前添加前缀的方法,或者你可以使用namespace语句.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e标签: \u003ca href=\"http://www.51cto.com/php/search.php?keyword=PHP%C3%FC%C3%FB%BF%D5%BC%E4\"\u003ePHP命名空间\u003c/a\u003e \u003ca href=\"http://www.51cto.com/php/search.php?keyword=PHP\"\u003ePHP\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e命名变量,函数和类是挺困难的,除了要考虑到变量的名称要易于理解,还要担心是否这个名称在其它某个地方已经使用过. 在一小段脚本中,第二个问题是基本问题. 当你考虑重用你的代码, 在这之后的项目代码必须避免使用你用过的命名. 通常来说,可重用的代码总是包含在函数或类中, 需要处理许多可能发生的命名冲突. 但函数和类之间也可能发生命名冲突. 你可以尝试避免出现这种情况,通过在所有类前添加前缀的方法,或者你可以使用namespace语句.\u003c/p\u003e\n\u003cp\u003eNamespace关键字给一块代码命名. 在这个代码块外部,脚本必须用操作 …\u003c/p\u003e"
November 13, 2008
把表记录生成数组
"\u003cp\u003e以下是来自phpcms2008程序global.func.php文件部分函数,仅供参考:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunction cache_read($file, $path = ”, $iscachevar = 0)\n{\n if(!$path) $path = CACHE_PATH;\n $cachefile = $path.$file;\n if($iscachevar)\n {\n global $TEMP;\n $key = ‘cache_’.substr($file, 0, -4);\n return isset($TEMP[$key]) ? $TEMP[$key] : $TEMP[$key] = @include $cachefile;\n }\n return @include $cachefile;\n}\n\nfunction cache_write($file, $array, $path = ”)\n{\n if(!is_array($array)) return false;\n $array = “”;\n $cachefile = ($path ? $path : CACHE_PATH).$file; …\u003c/code\u003e\u003c/pre\u003e"
November 12, 2008
PHP命名空间的分隔符是“\”
"\u003cp\u003ePHP最终开始支持namespace(命名空间)。 \u003cem\u003e但是经过开发者\u003ca href=\"http://wiki.php.net/_media/rfc/php.ns.txt?id=rfc%3Anamespaceseparator\u0026amp;cache=cache\"\u003e几个小时的讨论后\u003c/a\u003e,他们决定\u003ca href=\"http://news.php.net/php.internals/41374\"\u003e采用 “\\”\u003c/a\u003e 作为分隔符,而不是更流行的“ :: ”。\u003ca href=\"http://loveandtheft.org/2008/10/26/set-sail-for-fail-php-namespaces/\"\u003eFredrik Holmström\u003c/a\u003e指出了这种分隔方法可能会产生的问题,如打字出错(但不会出现错误提示),IDE兼容性问题,字符数字等等,\u003ca href=\"http://wiki.php.net/rfc/namespaceseparator\"\u003e好处\u003c/a\u003e则是容易输入和分析。”\u003c/em\u003e\u003c/p\u003e"
November 11, 2008
用PHP调用Oracle存储过程
"\u003cp\u003e PHP程序访问数据库,完全可以使用存储过程,有人认为使用存储过程便于维护,不过仁者见仁,智者见智,在这个问题上,偶认为使用存储过程意味着必须要DBA和开发人员更紧密配合,如果其中一方更变,则显然难以维护。\u003c/p\u003e\n\u003cp\u003e 但是使用存储过程至少有两个最明显的优点:速度和效率。使用存储过程的速度显然更快。\n 在效率上,如果应用一次需要做一系列SQL操作,则需要往返于PHP与ORACLE,不如把该应用直接放到数据库方以减少往返次数,增加效率。\n但是在INTERNET应用上,速度是极度重要的,所以很有必要使用存储过程。\n偶也是使用PHP调用存储过程不久,做了下面这个列子。\u003c/p\u003e\n\u003cp\u003e代码:-\u003c/p\u003e\n\u003cp\u003e//建立一个TEST表\nCREATE TABLE TEST (\n ID NUMBER(16) NOT NULL,\n NAME VARCHAR2(30) NOT NULL,\n PRIMARY KEY (ID)\n);\u003c/p\u003e\n\u003cp\u003e//插入一条数据\nINSERT INTO TEST VALUES (5, ‘PHP_BOOK’);\u003c/p\u003e\n\u003cp\u003e//建立一个存储过程\nCREATE OR …\u003c/p\u003e"
October 29, 2008
7.6. 分发器 第 7 章 Zend_Controller
"\u003ch2 id=\"76分发器\"\u003e7.6. 分发器\u003c/h2\u003e\n\u003ch3 id=\"761概述\"\u003e7.6.1. 概述\u003c/h3\u003e\n\u003cp\u003e分发是取得请求对象,提取其中的模块名,控制器名,动作名以及可选参数,然后实例化控制器并调用其中的动作的整过过程。如果其中的模块、控制器或者动作没能找到,将使用它们的默认值。 \u003ccode\u003eZend_Controller_Dispatcher_Standard\u003c/code\u003e 指定每个控制器和动作的默认值为 \u003ccode\u003eindex\u003c/code\u003e,模块的默认值为 \u003ccode\u003edefault\u003c/code\u003e,允许开发人通过 \u003ccode\u003esetDefaultController()\u003c/code\u003e、 \u003ccode\u003esetDefaultAction()\u003c/code\u003e 和 \u003ccode\u003esetDefaultModule()\u003c/code\u003e 改变默认值设定。\u003c/p\u003e\n\u003cp\u003e缺省模块\u003c/p\u003e\n\u003cp\u003e当创建模块程序,你可能也需要缺省模块的命名空间(缺省配置中,缺省模块_没有_命名空间)。从 1.5.0 开始,可以在前端控制器或你的派遣器里通过指定 \u003ccode\u003eprefixDefaultModule\u003c/code\u003e 为 true 来实现。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\n// In your front controller:\n$front-\u0026gt;setParam(\u0026#39;prefixDefaultModule\u0026#39;, true);\n\n// In your dispatcher: …\u003c/code\u003e\u003c/pre\u003e"
October 29, 2008
7.11. 使用传统的模块目录结构 第 7 章 Zend_Controller
"\u003ch2 id=\"711使用传统的模块目录结构\"\u003e7.11. 使用传统的模块目录结构\u003c/h2\u003e\n\u003ch3 id=\"7111简介\"\u003e7.11.1. 简介\u003c/h3\u003e\n\u003cp\u003e传统的模块目录结构允许你把不同的MVC应用程序分离成为独立的单元,并和不同的前端控制器配合再使用。示例一下这样的目录结构:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003edocroot/\n index.php\napplication/\n default/\n controllers/\n IndexController.php\n FooController.php\n models/\n views/\n scripts/\n index/\n foo/\n helpers/\n filters/\n blog/\n controllers/\n IndexController.php\n models/\n views/\n scripts/\n index/ …\u003c/code\u003e\u003c/pre\u003e"
October 26, 2008
php构造函数和析构函数
"\u003cp\u003e构造函数\nvoid __construct ([ mixed $args [, $… ]] )\nPHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。\u003c/p\u003e\n\u003cp\u003eNote: 如果子类中定义了构造函数则不会暗中调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。\u003c/p\u003e\n\u003cp\u003eExample#1 使用新标准的构造函数\u003c/p\u003e\n\u003cp\u003eclass BaseClass {\u003c/p\u003e\n\u003cp\u003efunction __construct() {\nprint “In BaseClass constructor\\n”;\n}\n}\u003c/p\u003e\n\u003cp\u003eclass SubClass extends BaseClass {\nfunction __construct() {\nparent::__construct();\nprint “In SubClass constructor\\n”;\n}\n}\u003c/p\u003e\n\u003cp\u003e$obj = new BaseClass();\n$obj = new SubClass();\n?\u0026gt;\n为了实现向后兼容性, …\u003c/p\u003e"
October 26, 2008
php范围解析操作符(::)
"\u003cp\u003e范围解析操作符(::)\n范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。\u003c/p\u003e\n\u003cp\u003e当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。\u003c/p\u003e\n\u003cp\u003e把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是 Zend 开发小组在写 Zend Engine 0.5 (被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。\u003c/p\u003e\n\u003cp\u003eExample#1 在类的外部使用 :: 操作符\u003c/p\u003e\n\u003cp\u003eself 和 parent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。\u003c/p\u003e\n\u003cp\u003eExample#2 :: from inside the class definition\u003c/p\u003e\n\u003cp\u003e当一个子类覆盖其父类中的方法时,PHP 不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。这种机制也作用于 构造函数和析构函数、重载 及 魔术 函数。\u003c/p\u003e\n\u003cp\u003eExample#3 调用父类的方法\u003c/p\u003e\n\u003cp\u003emyFunc();\u003c/p\u003e\n\u003cp\u003e?\u0026gt;\u003c/p\u003e\n\u003cp\u003eStatic Keyword …\u003c/p\u003e"
October 26, 2008
php中访问控制
"\u003cp\u003e访问控制\n对属性或方法的访问控制,是通过在前面添加关键字 public、protected 或 private 来实现的。由 public 所定义的类成员可以在任何地方被访问;由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由 private 定义的类成员则只能被其所在类访问。\u003c/p\u003e\n\u003cp\u003e对类成员的访问控制\n类成员都必须使用关键字public、protected 或 private 进行定义\u003c/p\u003e\n\u003cp\u003eExample#1 声明类成员\u003c/p\u003e\n\u003cp\u003epublic;\u003c/p\u003e\n\u003cp\u003eecho $this-\u0026gt;protected;\necho $this-\u0026gt;private;\n}\n}\u003c/p\u003e\n\u003cp\u003e$obj = new MyClass();\necho $obj-\u0026gt;public; // 这行能被正常执行\necho $obj-\u0026gt;protected; // 这行会产生一个致命错误\necho $obj-\u0026gt;private; // 这行也会产生一个致命错误\n$obj-\u0026gt;printHello(); // 输出 Public、Protected 和 Private\u003c/p\u003e\n\u003cp\u003e/** …\u003c/p\u003e"
October 22, 2008
PHP V5.2 中的新增功能,第 5 部分: 跟踪文件上传进度
"\u003cp\u003e级别: 中级\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"http://haohtml.com/wp/wp-admin/#author\"\u003eTracy Peterson\u003c/a\u003e (\u003ca href=\"mailto:tracy@tracypeterson.com?subject=%E8%B7%9F%E8%B8%AA%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E8%BF%9B%E5%BA%A6\u0026amp;cc=dwxed@us.ibm.com\"\u003etracy@tracypeterson.com\u003c/a\u003e), 自由撰稿人, Consultant\u003c/p\u003e\n\u003cp\u003e2007 年 6 月 08 日\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePHP V5.2 为开发人员添加了 hook 以利用实时跟踪文件上传进度的功能。本文是 “\u003ca href=\"http://www.ibm.com/developerworks/cn/opensource/os-php-v52/\"\u003ePHP V5.2 中的新增功能\u003c/a\u003e” 系列文章(共五部分)的第 5 部分,将向您展示如何监视文件上传并相应地编写代码,以及如何创建 PHP 进度条。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e Web 2.0 是 Internet 上最炙手可热的时髦字眼,投资者纷纷把资金投入到涉及这项技术的投资项目中。数以百万计的 Web 站点和应用程序覆盖的描述性术语有很多。使用 Web 2.0,我们将描述一类 Web 站点,这些站点都提供了了解 Internet 上数以百万计用户心声的途径。与众不同之处在于它们全都为用户提供了交流和分享与共同利益相关的观点和数据的场所,这些站点可以快速生成大量内容。\u003c/p\u003e\n\u003cp\u003e 每个用户都将提供某种内容 —— 评论咖啡店、上班路线等。\u003ca href=\"http://www.youtube.com/\"\u003eYouTube\u003c/a\u003e 在这点上是一个优秀示例,为人们提供一个空间可以上传视频并使其他用户可以观看这些视频并提供反 …\u003c/p\u003e"
October 22, 2008
MVC模式的PHP实现
"\u003cp\u003e作者:Harry Fuecks 翻译:Easy Chen\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMVC模式在网站架构中十分常见。它允许我们建立一个三层结构的应用程式,从代码中分离出有用的层,帮助设计师和开发者协同工作以及提高我们维护和扩展既有程式的能力。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003e视图(View)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e“视图”主要指我们送到Web浏览器的最终结果??比如我们的脚本生成的HTML。当说到视图时,很多人想到的是模版,但是把模板方案叫做视图的正确性是值得怀疑的。\u003c/p\u003e\n\u003cp\u003e对视图来说,最重要的事情可能是它应该是“自我意识(self aware)”的,视图被渲染(render)时,视图的元素能意识到自己在更大框架中的角色。\u003c/p\u003e\n\u003cp\u003e以XML为例,可以说XML在被解析时,DOM API有着这样的认知??一个DOM树里的节点知道它在哪里和它包含了什么。 (当一个XML文档中的节点用SAX解析时只有当解析到该节点时它才有意义。)\u003c/p\u003e\n\u003cp\u003e绝大多数模板方案使用简单的过程语言和这样的模板标签:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;p\u0026gt;{some_text}\u0026lt;/p\u0026gt;\n\u0026lt;p\u0026gt;{some_more_text}\u0026lt;/p\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e它们在文档中没有意义,它们代表的意义只是PHP将用其他的东西来替换 …\u003c/p\u003e"
October 15, 2008
PHP 危险函数解释
"\u003cp\u003e*** 在编译 PHP 时,如无特殊需要,一定禁止编译生成 CLI 命令行模式的 PHP 解析支持。\n可在编译时使用 –disable-cli。一旦编译生成 CLI 模式的 PHP,则可能会被入侵者\n利用该程序建立一个 WEBShell 后门进程或通过 PHP 执行任意代码!\u003c/p\u003e\n\u003cp\u003ephpinfo()\n功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。\n危险等级:中\u003c/p\u003e\n\u003cp\u003epassthru()\n功能描述:允许执行一个外部程序并回显输出,类似于 exec()。\n危险等级:高\u003c/p\u003e\n\u003cp\u003eexec()\n功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。\n危险等级:高\u003c/p\u003e\n\u003cp\u003esystem()\n功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。\n危险等级:高\u003c/p\u003e\n\u003cp\u003echroot()\n功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式\nPHP 时才能工作,且该函数不适用于 Windows” onclick=”tagshow(event)” class=”t_tag”\u0026gt;Windows 系统。\n危险等级:高\u003c/p\u003e\n\u003cp\u003escandir()\n功能描 …\u003c/p\u003e"
May 1, 2008
ADODB详解
"\u003cp\u003eADODB参考手册:\u003c/p\u003e\n\u003cp\u003ePHP在数据库的支持上是很令人称道的,几乎所有的知名数据库系统都有对应的函数库支持,而且支持得很完整。但遗憾的是,每一群数据库支持函数无论在名称或参数结构上,都有很大的差异,这使得PHP的系统开发者在面临更换数据库时,总会觉得痛苦万分。\u003c/p\u003e\n\u003cp\u003e难道这个问题就没有解决方法吗?当然有,答案就是将要介绍的ADODB这个PHP类库。\u003c/p\u003e\n\u003cp\u003eADODB提供了完整的方法和属性,可以用来控制数据库系统,更棒的是你只要记得它的功能即可,因为不同的数据库系统,只要修改一个属性值,ADODB就会自动依据设定取用正确的PHP函数。\u003c/p\u003e\n\u003cp\u003e此外,再配合数据库系统修改SQL命令,这样PHP系统就可以在最短的时间内更换到另一个数据库系统;如果在编写程序时,对SQL命令能做妥善规划,那就更快了。\u003c/p\u003e\n\u003cp\u003e经过以上的介绍,相信你已经对ADODB的功用有所了解了,以下为ADODB的详细介绍。\u003c/p\u003e\n\u003cp\u003e下载ADODB:可以在http://adodb.sourceforge.net/ 取得最新版的ADODB(见图17-2)。\u003c/p\u003e\n\u003cp\u003e图17-2\u003c/p\u003e\n\u003cp\u003eADODB的最新版本是adodb495a版,根据需要,可以下载完整版本的ADODB。如果您主要使 …\u003c/p\u003e"
April 12, 2008
说说大型高并发高负载网站的系统架构
"\u003cp\u003e 原文链接:(俊麟 Michael’s blog ) \u003ca href=\"http://www.toplee.com/blog/71.html\"\u003ehttp://www.toplee.com/blog/71.html\u003c/a\u003e\n 注:原文链接后的相关评论也很精彩,建议也参考一下原文链接后的评论。\u003c/p\u003e\n\u003cp\u003e 我在CERNET做过拨号接入平台的搭建,而后在Yahoo\u0026amp;3721从事过搜索引擎前端开发,又在MOP处理过大型社区猫扑大杂烩的架构升级等工作,同时自己接触和开发过不少大中型网站的模块,因此在大型网站应对高负载和并发的解决方案上有一些积累和经验,可以和大家一起探讨一下。\u003c/p\u003e\n\u003cp\u003e 一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求都很简单,随着互联网业务的不断丰富,网站相关的技术经过这些年的发展,已经细分到很细的方方面面,尤其对于大型网站来说,所采用的技术更是涉及面非常广,从硬件到软件、编程语言、数据库、WebServer、防火墙等各个领域都有了很高的要求,已经不是原来简单的html静态网站所能比拟的。\u003c/p\u003e\n\u003cp\u003e 大型网站,比如门户网站。在面对大量用户访问、高并发请求方面,基本的解决方案集 …\u003c/p\u003e"
March 10, 2008
清除缓存,php,html,jsp,asp中防止模式窗口页面不更新的情况
"\u003cp\u003e清除缓存,php,html,jsp,asp中防止页面不更新的情况\nCode:\u003c/p\u003e\n\u003cp\u003eHTML\u003c/p\u003e\n\u003cp\u003eASP\u003c/p\u003e\n\u003cp\u003e\u0026lt;%\u003c/p\u003e\n\u003cp\u003eResponse.Expires = -1\u003c/p\u003e\n\u003cp\u003eResponse.ExpiresAbsolute = Now() – 1\u003c/p\u003e\n\u003cp\u003eResponse.cachecontrol = “no-cache”\u003c/p\u003e\n\u003cp\u003e%\u0026gt;\u003c/p\u003e\n\u003cp\u003ePHP\u003c/p\u003e\n\u003cp\u003eheader(“Expires: Mon, 26 Jul 1997 05:00:00 GMT”);\u003c/p\u003e\n\u003cp\u003eheader(“Cache-Control: no-cache, must-revalidate”);\u003c/p\u003e\n\u003cp\u003eheader(“Pragma: no-cache”);\u003c/p\u003e\n\u003cp\u003eJSP\u003c/p\u003e\n\u003cp\u003eresponse.setHeader(“Pragma”,”No-Cache”);\u003c/p\u003e\n\u003cp\u003eresponse.setHeader(“Cache-Control”,”No-Cache”);\u003c/p\u003e\n\u003cp\u003eresponse.setDateHeader(“Expires”, 0);\u003c/p\u003e"
January 13, 2008
Adodb的十个实例
"\u003cp\u003e本想学pear的,可是网上看到的几篇帖子对adodb的评价相当高,所以改学了这个。\u003c/p\u003e\n\u003cp\u003eADODB的优点有这几个(网上说的,不是我说的):\u003c/p\u003e\n\u003cp\u003e1、速度比pear快一倍;\u003c/p\u003e\n\u003cp\u003e2、支持的数据库类型比pear多很多,甚至可以支持ACCESS;\u003c/p\u003e\n\u003cp\u003e3、无须安装,无须服务器支持(对新手来说,这点很重要吧)\u003c/p\u003e\n\u003cp\u003eTutorial\u003c/p\u003e\n\u003cp\u003eExample 1: Select Statement\u003c/p\u003e\n\u003cp\u003e任务: 连接一个名为Northwind的Access数据库, 显示 每条记录 的前两个字段.\u003c/p\u003e\n\u003cp\u003e在这个实例里, 我们新建了一个ADOC连接(ADOConnection)对象, 并用它来连接一个数据库. 这个连接采用PConnect 方法, 这是一个持久 连接. 当我们要查询数据 库时, 我们可以随时调 用这个连接的Execute()函数. 它会返回一个ADORecordSet对象 which is actually a cursor that holds the current row in the array fields[]. 我们使用MoveNext()从一个记录转向下一个记录 .\u003c/p\u003e\n\u003cp\u003eNB: …\u003c/p\u003e"
November 21, 2007
PHP5中的时间相差八小时的解决办法
"\u003cp\u003e\u003cstrong\u003e法一:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003ePHP5系列版本新增了时区设置,默认为格林威治时间,与中国所在的东8区正好相差8个小时\u003c/p\u003e\n\u003cp\u003e找到php.ini中的“;date.timezone =”这行,将“;”去掉,改成“date.timezone = PRC”(PRC:People’s Republic of China 中华人民共和国),重启Apache,问题解决。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e法二:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e安装好php5后,在论坛不经意间,在论坛上看到有人说php5.1.2的时间显示整整少8个小时,\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\necho date(\u0026#34;Y-m-d H:i:s\u0026#34;);\n?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e结果自己测试果然是相差8小时。\u003c/p\u003e\n\u003cp\u003e后来经过在论坛上找资料,结果终于解决,在php5以及起以上的版本,要输出本地的时间(限中国),可以这么写\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\u0026lt;?php\ndate_default_timezone_set(\u0026#39;Asia/Shanghai\u0026#39;);\necho date(\u0026#39;Y-m-d H:i:s\u0026#39;);\n?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样时间相差八小时的问题就解决了!!~~~\u003c/p\u003e"
November 20, 2007
Smarty中in_array函数的应用
"\u003cp\u003ephp脚本:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$Action= array(“article”,”soft”,”news”);\n$smarty = new Smarty();\n$smarty-\u0026gt;assign(“Action”,$Action);\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e模板:\u003c/p\u003e\n\u003cp\u003e在数组内非数组内的值\u003c/p\u003e"
October 19, 2007
用PHP的ob_start();控制您的浏览器cache
"\u003cp\u003e Output Control 函数可以让你自由控制脚本中数据的输出。它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况。输出控制函数不对使用 header() 或 setcookie(), 发送的文件头信息产生影响,只对那些类似于 echo() 和 \u003ca href=\"/?tag=php\"\u003ePHP\u003c/a\u003e 代码的数据块有作用。\u003c/p\u003e\n\u003cp\u003e我们先举一个简单的例子,让大家对Output Control有一个大致的印象:\nExample 1.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eob_start(); //打开缓冲区\necho “Hellon”; //输出\nheader(“location:index.php”); //把浏览器重定向到index.php\nob_end_flush();//输出全部内容到浏览器\n?\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e所有对header()函数有了解的人都知道,这个函数会发送一段文件头给浏览器,但是如果在使用这个函数之前已经有了任何输出(包括空输出,比如空格,回车和换行)就会提示出错。如果我们去掉第一行的ob_start(),再执行此程序,我们会发现得到了一条错误提示:”Header had all ready send by”!但是加 …\u003c/p\u003e"
October 13, 2007
PHP让页面马上过期
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eheader(\u0026#34;Expires: \u0026#34;.gmdate(\u0026#34;D, d M Y H:i:s\u0026#34;,time()-1).\u0026#34; GMT\u0026#34;);\nheader(\u0026#34;Last-Modified: \u0026#34;.gmdate(\u0026#34;D, d M Y H:i:s\u0026#34;).\u0026#34; GMT\u0026#34;);\nheader(\u0026#34;Cache-Control: no-cache, must-revalidate\u0026#34;);\nheader(\u0026#34;Pragma: no-cache\u0026#34;);\n\u003c/code\u003e\u003c/pre\u003e"
October 12, 2007
利用ajax实现同步通信
"\u003cp\u003e1。创建ajax 对象, 可以用以下通用代码, 此代码适合各种浏览器\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003efunction newXMLHttpRequest()\n{\n var xmlreq = false;\n if (window.XMLHttpRequest)\n {\n xmlreq = new XMLHttpRequest();\n }\nelse\n { if (window.ActiveXObject)\n { try\n { xmlreq = new ActiveXObject(\u0026#34;Msxml2.XMLHTTP\u0026#34;);\n }\n catch (e1)\n {\n try\n {\n xmlreq = new ActiveXObject(\u0026#34;Microsoft.XMLHTTP\u0026#34;);\n }\n catch (e2)\n { }\n }\n }\n }\n return xmlreq;\n}\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e2。发送数据,ajax有2种方处理数据,同步和异步\u003c/p\u003e\n\u003cp\u003e同步:\u003c/p\u003e\n\u003cp\u003efunction get_xmlhttp()\u003c/p\u003e\n\u003cp\u003e{ var …\u003c/p\u003e"
September 25, 2007
ADODB中GetOne($sql)与GetRow($sql)的区别
"\u003cp\u003e**GetOne($sql)**Executes the SQL and returns the first field of the first row as an array. The recordset and remaining rows are discarded for you automatically. If an error occur, false is returned. 执行SQL指令,并且以阵列的方式回传第一笔记录的第一个栏位。资料集及其余的记录将会被自动清除,如果发生错误,就回传 false 值。译者注:这个功能在验证某笔记录在不在特别有用,可以减少系统记忆体及资源的用量。\u003c/p\u003e\n\u003cp\u003e**GetRow($sql)**执行SQL指令,并且以阵列的方式回传第一笔记录。资料集及其馀的记录将会被自动清除,如果发生错误,就回传 false 值。其中GetOne($sql)为了检测某一条记录是否存在时,特别有用,(如,用户在注册前,可以检测用户名是否已经被占用,比较适合GetOne($ql)).如果此时需要除检测该记录是否存在,并保存该记录的信息,就要用 …\u003c/p\u003e"
September 18, 2007
php上传大文件注意事项
"\u003cp\u003e 最近用php传大文件的时候,总是传不上,起始只是看了一下php.ini里的max_post_size的值,默认是8M,一直没有搞清楚到底是怎么回事,后来在一篇文章上看到还有一个upload_max_filesize 参数,这时才明白怎么回事,结果把默认的2M改成8M,重新上传,结果ok,上传成功了!\u003c/p\u003e\n\u003cp\u003e 以下是常见的一些上传附件时的一些问题,大家可以参考一下:\u003c/p\u003e\n\u003cp\u003e用php上传文件,问题最多的就是上传大体积文件时出现错误。\n这就涉及到php的配置文件:php.ini\u003c/p\u003e\n\u003cp\u003e在此配置文件中,有这么几个值是跟文件上传有密切关系的:\nfile_uploads = on //是否允许系统支持文件上传\n;upload_tmp_dir //临时文件的存储路径,linux下为系统默认路径,win32下需要指定\nupload_max_filesize = 2m //允许文件上传最大体积\u003c/p\u003e\n\u003cp\u003epost_max_size = 2m //通过post方法给php时,php所能接受的最大数据容量\u003c/p\u003e\n\u003cp\u003e如果你上传的文件体积在8m一下(通常情况),那修改以上设置就可以满足你的要求了。。\u003c/p\u003e\n\u003cp\u003e但要 \u0026gt;8m,那除了上面几 …\u003c/p\u003e"
September 17, 2007
Smarty中类的继承
"\u003cp\u003e\u003cstrong\u003eExtended Setup\u003c/strong\u003e\nThis is a continuation of the basic installation, please read that first!\nA slightly more flexible way to setup Smarty is to extend the class and initialize your Smarty environment. So instead of re-\npeatedly setting directory paths, assigning the same vars, etc., we can do that in one place. Lets create a new directory /\nphp/includes/guestbook/ and make a new file called setup.php. In our example environment, /php/includes is in\nour include_path. Be sure you set this up too, or …\u003c/p\u003e"
September 15, 2007
PHP fsockopen 简单抓取网页内容
"\u003cp\u003e 这几天在做采集的东东,\u003ca href=\"/?tag=php\"\u003ephp\u003c/a\u003e提供了很多访问远程计算机内容的方法,文件系统的函数些都支持读取远程文件,而fsockopen是争对于socket接口的编程函数,在网上搜了一下发现用这个函数来读取http内容也比较多,但是没有一个比较完善和适合我的,在某个小偷程序上改改,轻而易举的完善fsockopen请求http协议内容,从而获取请求内容.代码如下:\u003c/p\u003e\n\u003cp\u003efunction get_page_content($url){\u003c/p\u003e\n\u003cp\u003e$url = eregi_replace(‘^http://’, ”, $url);\u003c/p\u003e\n\u003cp\u003e$temp = explode(‘/’, $url);\u003c/p\u003e\n\u003cp\u003e$host = array_shift($temp);\u003c/p\u003e\n\u003cp\u003e$path = ‘/’.implode(‘/’, $temp);\u003c/p\u003e\n\u003cp\u003e$temp = explode(‘:’, $host);\u003c/p\u003e\n\u003cp\u003e$host = $temp[0];\u003c/p\u003e\n\u003cp\u003e$port = isset($temp\u003ca href=\"/?tag=php\"\u003e1\u003c/a\u003e) ? $temp\u003ca href=\"/?tag=php\"\u003e1\u003c/a\u003e : 80;\u003c/p\u003e\n\u003cp\u003e$fp = @fsockopen($host, $port, \u0026amp;$errno, \u0026amp;$errstr, 30);\u003c/p\u003e\n\u003cp\u003eif …\u003c/p\u003e"
September 15, 2007
用PHP写mail时的注意事项
"\u003cp\u003e今天看书,看到mail函数,就自己练着写了个简单的程序。\u003c/p\u003e\n\u003cp\u003e要注意的一点是,mail函数的使用,需要在php.ini里边配置。\n[mail function]\n; For Win32 only.\nSMTP = localhost\nsmtp_port = 25\u003c/p\u003e\n\u003cp\u003e; For Win32 only.\n;sendmail_from = \u003ca href=\"mailto:me@example.com\"\u003eme@example.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e配置后\n[mail function]\n; For Win32 only.\nSMTP = smtp.tom.com //指定你的邮箱smtp\nsmtp_port = 25\u003c/p\u003e\n\u003cp\u003e; For Win32 only.\nsendmail_from = \u003ca href=\"mailto:boy805@tom.com\"\u003eboy805@tom.com\u003c/a\u003e //你所使用的邮箱\u003c/p\u003e\n\u003cp\u003e配置好后要记得重启apache啊!\u003c/p\u003e\n\u003cp\u003e不过真是怪了,在单位写的就发送成功了,在家写一样一样的就没成功,大家来看看~~\u003c/p\u003e"
August 18, 2007
adodb教程:产生 Update 及 Insert 的SQL指令
"\u003cp\u003e\u003ca href=\"/?tag=adodb\"\u003eADODB\u003c/a\u003e 1.31版起,新增了两个资料集函数:GetUpdateSQL()及GetInsertSQL()。这允许你在执行了像”Select * FROM table query Where…”这样的查询函数後,建立一个 $rs-\u0026gt;fields复本,改变这些栏位,然後自动产生出更新或是新增的SQL指令。以下我们展示如何运用这些函数,我们将存取一个资料表,带有下列栏位:(ID,FirstName,LastName,Created)。在这些函数被执行前,你需要藉由一个对资料表的查询指令(select)来初始化一个资料集。 #==============================================\u003c/p\u003e\n\u003cp\u003e# GetUpdateSQL() 及 GetInsertSQL() 范例码\u003c/p\u003e\n\u003cp\u003e#==============================================\u003c/p\u003e\n\u003cp\u003einclude(‘ADOdb.inc.php’);\u003c/p\u003e\n\u003cp\u003einclude(‘tohtml.inc.php’);#==========================\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e# …\u003c/strong\u003e\u003c/p\u003e"
August 6, 2007
adodb和smarty分页类
"\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eclass show_Pager\n\n{\n\nprotected$_total; //记录总数\n\nprotected$pagesize; //每一页显示的记录数\n\npublic$pages; //总页数\n\nprotected$_cur_page; //当前页码\n\nprotected$offset; //记录偏移量\n\nprotected$pager_Links; //url连接\n\nprotected$pernum = 5; //页码偏移量,这里可随意更改\n\npublicfunction __construct($total,$pagesize,$_cur_page)\n\n{\n\n$this-\u0026gt;_total=$total;\n\n$this-\u0026gt;pagesize=$pagesize; …\u003c/code\u003e\u003c/pre\u003e"
August 6, 2007
smarty中$cache_lifetime属性的使用
"\u003cp\u003eSetting$cache_lifetimepercache\u003c/p\u003e\n\u003cp\u003erequire(‘Smarty.class.php’);\u003c/p\u003e\n\u003cp\u003e$smarty=newSmarty;\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;caching=2;//lifetimeispercache\u003c/p\u003e\n\u003cp\u003e//setthecache_lifetimeforindex.tplto5minutes\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;cache_lifetime=300;\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;display(‘index.tpl’);\u003c/p\u003e\n\u003cp\u003e//setthecache_lifetimeforhome.tplto1hour\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;cache_lifetime=3600;\u003c/p\u003e\n\u003cp\u003e$smarty-\u0026gt;display(‘home.tpl’);\u003c/p\u003e\n\u003cp\u003e//NOTE:thefollowing$cache_lifetimesettingwillnotworkwhen$caching=2.\u003c/p\u003e\n\u003cp\u003e//Thecachelifetimeforhome.tplhasalreadybeenset …\u003c/p\u003e"
August 4, 2007
ADODB中几个有用的函数
"\u003cp\u003e**GetOne($sql,$inputarr=false)**Executes the SQL and returns the first field of the first row. The recordset and remaining rows are discarded for you automatically. If an error occur, false is returned.**GetRow($sql,$inputarr=false)**Executes the SQL and returns the first row as an array. The recordset and remaining rows are discarded for you automatically. If an error occurs, false is returned.\u003cstrong\u003eGetAll($sql,$inputarr=false)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eExecutes the SQL and returns the all the rows as a 2-dimensional array. …\u003c/p\u003e"
July 22, 2007
Smarty实例 – 使用ADODB连接数据库
"\u003cp\u003e今天就先来说说ADODB.说到ADODB,可能做过ASP的都知道WINDOWS平台的ADO组件,但我们这里的ADODB不是微软的那个数据库操作组件,而是由php语言写的一套数据库操作类库,先让我们来看看它倒底有什么样的优点.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e以标准的SQL语句书写的数据库执行代码在进行数据库移植时不用更改源程序,也就是说它可以支持多种数据库,包括ACCESS.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e提供与微软ADODB相似的语法功能.这一点对于从ASP转行到PHP的人们是一大福音,它的很多操作都与WINDOWS中的ADODB相似.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e可以生成\u003ca href=\"http://smarty.php.net\"\u003eSmarty\u003c/a\u003e循环需要的二维数组,这样会简化smarty开发.这一点是等会我给大家演示.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持数据库的缓存查询,最大可能的提高查询数据库的速度。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e其它的实用功能.\n虽然说优点很多,但是由于这个类库非常的庞大,光它的主执行类就107K,所以如果大家考虑执行效率的话就要认真想想了.不过说实话,它的功能还是很强大的,有很多的很实用的功能,使用它的这些功能,可以非常方便的实现我们想要的功能.所以对于那些老板没有特殊要求时大家不防用用它.\n**一、如何得到ADODB? 它的运行环境是什么?\n** …\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e"
July 18, 2007
在PHP中如何远程链接Mysql数据库?
"\u003cp\u003eMySQL是可以远程调用的,但用户要有远程调用的权限。\u003c/p\u003e\n\u003cp\u003e在增加用户的时候有一个host 选项,是任何主机 或 locahost,你选用 any host,这样,你就可以远程调用了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-mysql\" data-lang=\"mysql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003emysql_pconnect\u003c/span\u003e(\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e“\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e192\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e168\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e.\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e:\u003cspan style=\"color:#ae81ff\"\u003e3306\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e″\u003c/span\u003e,\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e”\u003c/span\u003eroot\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e”\u003c/span\u003e,\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e”\u003c/span\u003epassword\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e”\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e"