• 今日单词

    recipe

    |ˈresəpi| n

    1. ~ (for sth) set of instructions for preparing food dish, including ingredients required. 烹饪法;食谱 [做定语]

      recipe books, cards

    2. ~ for sth (fig 比喻) method of achieving sth 方法;秘诀;诀窍

      what is your recipe for success?

      His plans are a recipe for disaster.

  • how to write go code

    看了https://golang.org/doc/code.html, 觉得主要是讲了关于golang的Lib组织形式, 简单记录一下.

    简介

    本文描述了获取,构造和安装Go包以及Go工具的标准方法. go tool(就是go这个命令, 下面包含build run等命令)需要把你的代码按一定的格式组织起来.

    代码组织

    概述

    • 一般来说, 所有的Go代码都放在一个单独的workspace
    • 一个workspace包含多个版本控制仓库
    • 每个仓库里面包括一个或者多个packages
    • 一个package包含一个或者多个Go源代码, 这些源代码需要在一个单独的目录下面
    • package的路径决定了它的import path

    Workspaces

    一个workspace是这样一个目录结构, 包括下面三个子目录:

    • src 包含Go的源码
    • pkg 包含packagecfqj
    • bin 包含可执行命令

    go tool会build源码, 然后把结构安装到pkg和bin目录下.

    GOPATH 环境变量

    GOPATH环境变量定义的你的workspace位置. 它是你需要的惟一一个环境变量. 它一定不能Go的安装路径使用同一个目录.

    $ mkdir $HOME/work
    $ export GOPATH=$HOME/work
    

    为了方便, 可以把bin子目录放在PATH变量下

    $ export PATH=$PATH:$GOPATH/bin
    

    import path

    import path是能惟一确认package路径的字符串.

    标准库的路径都是一个短路径, 像fmt, net/http. 你自己的代码, 需要选一个基础路径, 尽量不要和以后的标准库或者其他的第三方库有冲突.

    比如说可以用 github.com/user做为基础路径, 在workspace下面新建一个目录存放你的源码.

    你的第一个程序

    在workspace目录下, 新建一个package目录做为package path.

    $ mkdir $GOPATH/src/github.com/user/hello
    

    下一步, 在这个目录下创建一个hello.go:

    package main
    
    import "fmt"
    
    func main() {
            fmt.Printf("Hello, world.\n")
    }
    

    下面就可以build和install你的程序.

    $ go install github.com/user/hello
    

    注意, 你可以在任意路径下运行这个命令, go会自己找到的. 如果你已经在包目录下面了, 直接跑 go install 也可以.

    $ cd $GOPATH/src/github.com/user/hello
    $ go install
    

    会在GOPATH/bin下面生成一个hello可执行文件.

    你的第一个库

    让我们来写一个库, 并在hello中调用它

    同样的, 先选一个package路径, 在这里我们用github.com/user/stringutil.

    $ mkdir $GOPATH/src/github.com/user/stringutil
    

    在这个路径下创建go文件, reverse.go

    // Package stringutil contains utility functions for working with strings.
    package stringutil
    
    // Reverse returns its argument string reversed rune-wise left to right.
    func Reverse(s string) string {
        r := []rune(s)
        for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
            r[i], r[j] = r[j], r[i]
        }
        return string(r)
    }
    

    现在可以build了(好像没什么用, 就是测试一下是不是能编译)

    $ go build github.com/user/stringutil
    

    不会生成任何文件. 如果来go install, 可以在pkg目录下生成package对象.

    我们在hello中引用它, 修改$GOPATH/src/github.com/user/hello/hello.go

    package main
    
    import (
        "fmt"
    
        "github.com/user/stringutil"
    )
    
    func main() {
        fmt.Printf(stringutil.Reverse("!oG ,olleH"))
    }
    

    安装hello, 同时它的依赖(stringutil)也会被安装.

    $ go install github.com/user/hello
    

    Package names

    go源码的第一行必须是

    package name
    

    在这里, name就是这个包被引用用的名字,一个包里面的所有文件都必须用同一个名字.

    包名需要是引用路径的最后一个元素, 如果包被引用为srypto/rto13, 包名则应该是rto13.

    可执行文件的名字一定要是main.

    一个二进制文件中引用的包, 并不要求它们的名字不一样, 但是完整路径肯定不能相同.

  • 今日单词

    idiomatic

    See Effective Go for tips on writing clear, idiomatic Go code.

    ˌɪdɪəˈmætɪk

    adj
    (a) in accordance with the particular nature or structure of a language, dialect, etc 符合某一语言或者方言的习惯或者特点的

    She speaks fluent and idiomatic French. 她说得一口又流利又地道的法语.

    (b) containing an idiom or idoms 含有习语的

    an idiomatic expression, language 固定词组,成语多的语言.

  • 今日单词

    sparingly

    Use parent-child relationships sparingly, and only when there are many more children than parents.

    ˈspeərɪŋli

    adv 节俭地 ‹spend›; 量少地 ‹eat›; 谨慎地 ‹praise›

    to use something sparingly

    she gives her advice sparingly

  • O_CLOEXEC 2

    接上午的问题 O_CLOEXEC, execve呢, 就是exec系列函数中的一个,具体可以参见Unix环境高级编程第二版8.10节.

    当进程调用一种exec函数时, 该进程执行的程序完全替换成新进程,而新程序则从其main函数开始执行. 因为exec并不创建新进程,所以前后的进程ID并未改变. exec只是用一个全新的程序替换了当前进程的正文,数据,堆和栈段.

    现在来测试一下O_CLOEXEC这个参数的作用.

    貌似, 一般来说, exec会在folk之后调用. 为了让例子看起来更简单, 我就在当前程序中调用exec. 测试的大概流程是这样.

    不带O_CLOEXEC这个参数, 打开一个文件. 然后再exec一个sleep程序, sleep 10秒.
    程序运行时, 新开一个shell拿lsof观察被打开的文件, 是否被占用.

    如果不带O_CLOEXEC参数打开文件, 在exec之后, 这个文件使用被占用.

    如果带O_CLOEXEC参数打开文件, exec之后, 文件就不再被占用了.

    cloexec.c

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    int main(int argc, const char *argv[])
    {
        int fd = open("cloexec.c",O_RDWR);
        printf("%d\n",fcntl(fd, F_GETFD, FD_CLOEXEC));
        sleep(5);
    
        execl("/tmp/cloexec/sleep",(char *)0);
    
        return 0;
    }
    

    sleep.c

    #include <unistd.h>
    #include <stdio.h>
    
    int main(int argc, const char *argv[])
    {
        sleep(5);
        printf("sleep done\n");
        return 1;
    }
    
  • O_CLOEXEC

    默认情况下,一个文件描述符在execve之后,还是保持打开状态的. open一个文件的时候, 可以使用FD_CLOEXEC这个flag,改变这个初始值.

    在open的时候带上这个flag,就可以避免再次使用fcntl去设置,因为用fcntl设置的时候是线程不安全的, 可能在fork或者execve的时候出现问题.

    问题, execve是个什么问题? 为什么会牵扯到文件描述符? 问题2, 如果是整个函数退出(main函数退出), 文件描述符是关闭的吧?

    下午又了解了一下, 问题1的回答见O_CLOEXEC 2 问题2的回答应该是”是”, 在Unix环境高级编程第三章讲到.

  • Atom中在新tab打开文件

    自动升级到1.7.3之后,发现每次打开文件时候总是在当前tab,可是我有时候也需要在新的tab页打开.

    搜索了之后, 才知道现在atom多了smart tab功能, 也就是说如果文件没有被改动,打开下一个文件时, 就会覆盖当前的tab,否则在新tab打开.

    如果想强制在新tab打开, 只需要双击文件名就好了.

    隐藏的好深啊…

  • 问题 文件的物理结构是什么样的

    文件系统中, 文件的物理结构是什么样的呢? 文件系统中, 怎么定义的文件的存储呢? 先记下这个问题, 以后看.

    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main(){
        int f = open("blank",O_WRONLY);
        if (f<0){
            perror("open error");
        }
        printf("%d\n",f);
        write(f,"abcdefg",7);
        lseek(f,10000000,SEEK_CUR);
        write(f,"abcdefg\n",8);
        close(f);
    }
    

    写一个空洞文件.

    root@2d3967f5850a:/tmp/test# ll blank
    -rw-r--r-- 1 root root 10000015 May  6 03:56 blank
    root@2d3967f5850a:/tmp/test# du -sh blank
    104K    blank 
    

    文件在大概10M, 但实际占用的磁盘空间只有104K

    但读取文件时候, 是会读取10M字节的内容的, cat blank > blank2, 然后再du也可以佐证.

    那文件系统中, 文件的物理结构是什么样的呢? 文件系统中, 怎么定义的文件的存储呢? 先记下这个问题, 以后看.

  • 通过nc来远程跑命令

    公司服务器登陆用了OTP(one time password), 每次登陆服务器都要输入不同的token, 有些麻烦. 大家讨论有哪些办法可以绕过去. 我想到了nc.

    以下全部没有任何实际价值, 仅供娱乐!

    在服务器上面:

    tail -0f p | nc -k -l 8000 | bash >> p
    

    在自己机器上面:

    nc 172.17.0.3 8000
    

    甚至可以传文件!

    先在自己机器上通过nc在服务器运行

    nohup nc -l 8001 > /tmp/a &
    

    然后在自己机器:

    cat 1 | nc 172.17.0.3 8001
    
  • umask使用

    umask是shell里面内置的一个命令. 设置进程的文件模式创建屏蔽码, 这个屏蔽码会在open/mkdir/mkfifo/mknod等系统调用时使用, 用来关闭文件模式中对应位置的权限位.

    op1@5ef1a50fef8f:~$ umask
    0002
    op1@5ef1a50fef8f:~$ touch 1
    op1@5ef1a50fef8f:~$ ll
    total 24
    -rw-rw-r-- 1 op1  op1     0 May  2 02:10 1
    op1@5ef1a50fef8f:~$ umask 0077
    op1@5ef1a50fef8f:~$ umask
    0077
    op1@5ef1a50fef8f:~$ rm 1
    op1@5ef1a50fef8f:~$ touch 1
    op1@5ef1a50fef8f:~$ ll
    total 24
    -rw------- 1 op1  op1     0 May  2 02:11 1