#前言 读《深入理解计算机系统》,里面有一个关于浮点数的造成28死亡的事件 #事件背景 ``` On February 25, 1991, during the Gulf War, a Patriot missile defense system let a Scud get through. It hit a barracks, killing 28 people. The problem
#janus janus是一个轻量级的API网关和管理平台。实现对外提供openapi(如http接口)的鉴权认证(票据是否正确),权限控制(是否有权限访问cgi)和频率限制等功能。这避免了每一个对外提供的接口重复做这些公共事情。 #频率控制 简单地,保存一个kv,以限制的维度(例如IP)为key,以访问次数为值判断。如果指定时间内,达到指定的次数,则认为超过频率限制。 复杂地,如 1. 对不
结构化非常清晰 创建一个generator,然后对里面的数据进行操作 proto包对generator的Request进行操作 ``` func Marshal(pb Message) ([]byte, error) { ``` 注意pb是一个Message,一个接口 ``` // Message is implemented by generated protocol buffer mess
#为什么要梳理临时变量 协程栈大小限制为128k,太大的局部变量有风险。 #现有的梳理方法 function_read是同事提供的检查局部变量风险的工具 function_read.tgz ``` chapmanou@dev:~/handle/var$ tar -tf function_read.tgz function_read libelf.so libdwarf.so ``` 运行方法 `
#为什么要梳理临时变量 协程栈大小限制为128k,太大的局部变量有风险。 #现有的梳理方法 function_read是同事提供的检查局部变量风险的工具的 function_read.tgz ``` chapmanou@dev:~/handle/var$ tar -tf function_read.tgz function_read libelf.so libdwarf.so ``` 运行方法
#体验流程 1. 在网页编辑内容 2. 点击生成二维码 3. branch应用扫描二维码,发布 #评价 整个流程无需用户登录,简洁方便。 先"猜想"一下设计方案 #猜想方案 1. 生成二维码的时候,后台生成一个标识码,例如dk58359d45b46d8,并将用该标志码拼接为一个url。 如 ``` http://branchapp.net/draft/detail/dk58359d45b46d

背景

选了付费问答类题目,在体验分答的过程中,发现分答的模式,提问者的答案被偷听是需要1元,提问者可以分成0.5元。想到几个问题:
1. 有哪些问题是可以赚到钱的。
2. 哪些人是在分答上赚到钱的。
3. 哪些人才是分答上最受欢迎的。
4. 能否从分答的数据上分析用户是否活跃,有没有前景。
显然,这些数据是无法直接在网上直接找到的。要想得到答案,需要爬取分答的数据。
之前没有搞过类似爬取,想尝试爬取的乐趣
图片标题

打算怎么玩

通常的数据爬取都用python,也有很多成熟的爬取方案。但是,我想尝试一下Go。一来温习一下Go相关知识。二来学习Go上其他没有接触过的东西

数据爬取

抓包

  1. 电脑安装配置神器OWSAP ZAP,设置代理服务器,用来截取手机数据
  2. 手机设置代理服务器地址
  3. 手机打开分答应用,打开各个页面看看请求的链接和返回的数据格式

分析请求和数据

需要分析出哪些数据是从哪些链接请求来的,返回数据的格式。
1. 获取账户信息

http://apis-fd.zaih.com/v1/accounts/587503258

返回的结果是json格式

{"answers_count": 209, "avatar": "http://wx.qlogo.cn/mmopen/RZrGLEga7AiawE5sTQk0kItX6c9JR5dLkkKv1ZTosFv3Llc7upHc26pH8Ls75NYuDsr68pZzbic2UiaZqqgiaLEDVUngOpg0YgtI/0", "followers_count": 16220, "gravity": -1, "id": 587503258, "income": 12777950, "introduction": "u4f17u591au660eu661fu827au4ebau7684u79c1u4ebau60c5u611fu4e13u5bb6uff0cu54a8u8be2u673au6784u82b1u9547u8463u4e8bu957fu3001u767eu4e07u7545u9500u4e66u4f5cu5bb6u2026u672cu5e73u5

为了防止进程异常退出后服务停止,简单的做法,在crontab里定时检测(真有这么做的),若是进程不在就拉起。常见的问题有:检测进程是“存在”的,于是放弃拉起。或者进程是“不存在”的,于是不断地拉起。

很多情况下,程序需要限定有限(单个)进程运行,这个时候需要防止重复运行。
粗暴的做法,是通过ps命令然后grep等工具找到对应的进程名字是否进行判断。
这种方法的问题是,进程的名字并不是识别进程的标识。就好像,人的名字并不是真正地识别人一样(身份证号码)。无法保证其他程序名字和你写的不一样。
长相
那么,能否在自己启动的时候判断是否还有一个另外的自己(进程)

假设能,那么判断期间内将有两个自己,因此跟命题要求不符(只能存在一个进程)
进程只有一个
简单地讲,

不通过外界,你是无法确认是否自己是否还活着的。只能感觉自己将要死,但无法判断是否真的死了。

通过外界判断,需要遵守同样的规则。首先先看

为什么需要pidfile

对于程序来讲,不通过外界,也无法判断自己是否还活着,常见的方法是通过pidfile。

在ubuntu上,由/sbin/start-stop-daemon来负责管理pidfile
如/etc/init.d/ntp

start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE     $NTPD_OPTS

其中,PIDFILE的值

PIDFILE=/var/run/ntpd.pid

文件内容是存放自己pid值,启动的时候,
如果存在pidfile文件,那么读取里面的pid值,并判断pid是否在运行着。

do_pidfile(const char *name)
{
        FILE *f;
        static pid_t pid = 0;

        if (pid)
                return pid_check(pid);

        f = fopen(name, "r");
        if
linux   

本文代码涉及所有文件存放在
https://github.com/ochapman/passwd_demo.git

熟悉linux的人应该用过修改用户密码工具passwd,如下所示:

ochapman@ubuntu14:~/code/pam$ passwd
Changing password for ochapman.
(current) UNIX password:

提示了修改谁的密码,并要求输入当前的密码。
一般情况下,读取当前密码,校验当前密码是否正确,再去更新shadow/passwd文件…
linux下,这类工作主要由PAM承包
图片标题
PAM能抽象到什么程度呢,本文将用一个简单的例子展示PAM的威力。

简单例子

下面是一个简单的例子,实现了passwd的基本功能

/*
 *  passwd_demo
 *  a simple passwd utility for showing PAM usage
 *  derived from shadow
 */

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdlib.h>
#include <security/pam_appl.h>
#include <security/pam_misc.h>

#define SHADOW_PAM_CONVERSATION misc_conv

static struct pam_conv conv = {
    SHADOW_PAM_CONVERSATION,
    NULL
};

void do_pam_passwd (const char *user, bool silent, bool change_expired)
{
    pam_handle_t *pamh = NULL;
    int flags = 0, ret;

    if (silent)
        flags |= PAM_SILENT;
    if (change_expired)
      
linux   

经常阅读后台程序源码的话,会看到在初始化时dup2相关的函数,例如nginx的

fd = open("/dev/null", O_RDWR);
if (fd == -1) {
    ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                  "open(\"/dev/null\") failed");
    return NGX_ERROR;
}

if (dup2(fd, STDIN_FILENO) == -1) {
    ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
    return NGX_ERROR;
}

if (dup2(fd, STDOUT_FILENO) == -1) {
    ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
    return NGX_ERROR;
}
#if 0
if (dup2(fd, STDERR_FILENO) == -1) {
    ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
    return NGX_ERROR;
}
#endif

if (fd > STDERR_FILENO) {
    if (close(fd) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
        return NGX_ERROR;
    }
}

return NGX_OK;

dup2到底做了什么

dup2的定义

int dup2(int oldfd, int newfd);

从内核代码fs/file.c,实际在SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, i

1/2
粤ICP备16013713号