Linux
2018-07-03
date
2018年 07月 03日 星期二 14:09:28 CST
# locale 格式
date +"%c"
2018年07月03日 星期二 14时09分22秒
# RFC3339 格式
date --rfc-3339=s
2018-07-03 14:09:48+08:00
# UTC 时间,ISO 8601 格式
date -u +"%Y-%m-%dT%H:%M:%SZ"
# yyyy-mm-dd hh:mm:ss,mm
date +'%Y-%m-%d %H:%M:%S,%3N'
2018-07-03 14:09:20,902
# 获取时间戳
date +%s
# 时间字符串转时间戳
date -d "2018-07-03 14:09:00" +%s
1530598140
date -d "2018-07-03 14:09:00" +%s --utc
1530626940
# 时间戳转时间字符串
date -d @1530598140
2018年 07月 03日 星期二 14:09:00 CST
date +'%Y-%m-%d %H:%M:%S' -d @1530598140
2018-07-03 14:09:00
# 获取一分钟前的时间
date --rfc-3339=s -d '1 min ago'
date --rfc-3339=s -d '1 minute ago'
date --rfc-3339=s -d '1 minutes ago'
# 获取一个小时前的时间
date --rfc-3339=s -d '1 hour ago'
开发者
2018-06-26
我本来就想记录一下请求搜集服务的,结果扩大化,发现完全兜不住,好吧,就这样吧!
Linux
2018-06-12
total 内存总数
used 使用内存
free 未使用内存
shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)
buffers Memory used by kernel buffers (Buffers in /proc/meminfo)
cached Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
available 可用内存
SMS
2018-06-08
短信的通信协议从 2G 时代一直到现在基本没有什么变化。
- 支持 140 个字节(140 Byte = 140 * 8 bit = 1120 bit)
- 支持 GSM-7 编码,8bit 编码,UCS-2 编码
- GSM-7 每个字符 7 bit,支持英语和西欧语言,配合 National Language Shift Table 功能,能够支持一些其他字母文字的语言。
- UCS-2 每个字符 2 Byte(16 bit),传递一些 GSM-7 框架不支持的语言,比如中文(字符太多,7bit 方案反倒不合适)。
- 8bit 用来传递图片等二进制数据。
- 根据短信协议,如果长度超出范围,需要在短信前面加上一个二进制头部,叫做 UDH(User Data Header)。
- UDH 一共 6 个字节
- 包含一些 SMS 拓展字段
- 对于短信拆分来讲,里面有这一批短信的总条数,和当前这条短信的序号
所以,
- 如果是中文短信,用 UCS-2 编码,每个字符 2 Byte,一条短信最长支持 70 个中文字符(140 Byte / 2)。
- 注意:所有字符,包括 ASCII 中的英文、数字、半角的标点,全部需要转换成 UCS-2 的 2 Byte 编码。
- 如果长于 70 个字符,就需要切割成多条,UDH 头部需要 6 Byte,每条短信还剩 134 Byte,除以二,还能装 67 个字符。
- 例如:140 个中文字符的短信,需要切割成 67 + 67 + 6 三条短信。
- 如果是英文短信,或者部分西欧语言,可以使用 GSM-7 编码,每个字符 7 bit,一条短信最长支持 160 个字符(1120 bit / 7)。
- 如果长于 160 个字符,也是需要切割,除去 UDH 的 6 Byte = 6 _ 8 bit = 48 bit,还剩 1120 bit - 48 bit = 1072 bit,
1072 bit = 7 bit _ 153 + 1 bit,也就是说最多发送 153 个字符(多的那 1 bit 置 0,不参与计费)。
- 例如,320 个英文字符,需要切割成 153 + 153 + 14 三条短信。
- 注意:GSM-7 编码中,9 个拓展字符
^ ~ \ | { } [ ] € 需要算两个字符。非常重要
- 数据通信中都是使用 Byte 为单位,用 GSM-7 编码可能会除不尽,也就是说剩余 1 ~ 7 bit。比如:
- 发送 33 个字,33 * 7 bit = 231 bit,需要 29 Byte (232 bit) 来装,就多了 1 bit
- 同样的方法计算,发送 34 个字多了 2 bit,... 发送 39 个字剩余 7 bit,发送 40 个字正好 35 Byte,没有多余的 bit...
- 根据协议,多余的 bit 需要置零,除非是多出来 7 bit,7 个 0 会和 GSM-7 的
@ 字符冲突,这时候应该置为 0001101,也就是 GSM-7 中的 \r 回车字符。
最后:
- 关于 GSM-7 的详细信息,可以参考:2022/01/05,GSM-7 编码。
- 关于 UDH 的详细信息,可以参考:2022/05/13,CMPP: UDHI 头。
- https://en.wikipedia.org/wiki/Concatenated_SMS
补充:
- 部分通道采用 7 Byte 的 UDH (短信批次标识由 1 Byte 改成 2 Byte),所以短信切割长度是 152 个字符((140 - 7) * 8 / 7)。
- 如果短信采用 GSM-7 编码,UDH 需要按 7 bit 对齐,也就是说如果是 6B 的 UDH,最后需要占用 49 bit,UDH 后面的 1 bit 填 0。
Python
2018-05-26
首先你得有 PyPI 的账号,没有注册的话,不用搞了。
然后你肯定要先准备 setup.py 了,如果这个都没弄就不用搞了。
算了,先贴一个简单的样板吧。
setup.py
# -*- coding: utf-8 -*-
from setuptools import setup
setup(
name='PageageName',
version='0.0.1',
author='YourName',
author_email='YourEmail',
url='PackageSite (e.g. GitHub)',
description='....',
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
packages=['PackageDir'],
install_requires=[
'requests>=2.18.4',
'balabala',
],
extras_require={ # 可选
'dev': [
'balabala...',
],
'test': [
'balabala...',
],
},
classifiers=[
'Development Status :: 3 - Alpha',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'License :: OSI Approved :: MIT License',
],
)
流程
python3 -m pip install twine
rm -rf dist
python3 setup.py sdist bdist_wheel
python2 setup.py sdist bdist_wheel
twine upload dist/*
twine 会询问账号密码,如果不想每次这么麻烦,可以创建 ~/.pypirc 文件。
.pypirc 文件
[distutils]
index-servers =
pypi
[pypi]
repository = https://upload.pypi.org/legacy/
username = your_username
password = your_password
参考资料
Email MIME
2018-05-19
说明
多用途互联网邮件扩展
Multipurpose Internet Mail Extensions
最初的电子邮件标准 RFC 822 只支持发送 ASCII 字符文本内容,通过 MIME 这个拓展(RFC 2822),可以发送所有类型的内容。
后面的 HTTP 协议也是在 MIME 这个框架内构建的,Web 开发者比较熟悉的那几个 Content-xxx 头就是从 MIME 里面来的。
规范文件
| RFC No. |
Type |
Title |
| RFC 2045 |
Standards Track |
Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies |
| RFC 2046 |
Standards Track |
Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types |
| RFC 2047 |
Standards Track |
MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text |
| RFC 2048 |
Best Current Practice |
Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures |
| RFC 2049 |
Standards Track |
Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples |
语法
MIME-Version: 1.0 // MIME 版本
Content-Type: [type]/[subtype]; parameter // 内容类型
Content-Transfer-Encoding: [encoding] // 内容传输编码
Content-Disposition: [disposition] // 内容配置
内容类型 Content-Type
又叫互联网媒体类型(Internet media type)或者 MIME 类型(MIME type)。
类型信息的注册事宜,由 IANA(Internet Assigned Numbers Authority)统一管理。
按照注册来源分成几种类型,只用关心标准数,这个了解一下就行了:
- 标准树
类型名 / 子类型名 [ + 后缀 ] [ ; 可选参数 ]
- 厂商树
类型名 / vnd.子类型名 [ + 后缀 ] [ ; 可选参数 ],例如:application/vnd.debian.binary-package
- 个人树
类型名 / prs.子类型名 [ + 后缀 ] [ ; 可选参数 ]
- 未注册的 x.树
类型名 / x.子类型名 [ + 后缀 ] [ ; 可选参数 ]
常见的类型
详细类型在 IANA 官网有,链接在下面参考资料部分我贴了一个。
| Type |
Subtype |
Description |
| text |
plain |
文本 |
| text |
html |
HTML |
| text |
xml |
XML |
| text |
javascript |
JavaScript |
| text |
css |
CSS |
| text |
csv |
CSV |
| text |
vcard |
vCard 电子名片 |
| image |
bmp |
|
| image |
jpeg |
|
| image |
png |
|
| image |
gif |
|
| image |
webp |
|
| image |
svg+xml |
|
| image |
icon |
|
| audio |
mpeg |
|
| audio |
mp4 |
|
| audio |
ogg |
|
| audio |
webm |
|
| audio |
flac |
|
| video |
mpeg |
|
| video |
mp4 |
|
| video |
ogg |
|
| video |
webm |
|
| application |
xml |
XML |
| application |
json |
JSON |
| application |
ecmascript |
|
| application |
javascript |
|
| application |
zip |
|
| application |
gzip |
|
| application |
pdf |
|
| application |
rss+xml |
|
| application |
atom+xml |
|
| application |
octet-stream |
|
内容传输编码
编码类型主要是这几种:“7bit”,“8bit”,“binary”,“quoted-printable”,“base64”。
SMTP Email
2018-05-18
最常见的三种 SMTP 认证方法:
Python SMTP PythonSimpleServer Email
2018-05-07
Python2
python2 -m smtpd -h
# An RFC 2821 smtp proxy.
# Usage: /usr/lib/python2.7/smtpd.py [options] [localhost:localport [remotehost:remoteport]]
# --nosetuid, -n
# --version, -V
# --class classname, -c classname
# --debug, -d
# --help, -h
Python3
python -m smtpd -h
# An RFC 5321 smtp proxy with optional RFC 1870 and RFC 6531 extensions.
# Usage: /usr/lib/python3.9/smtpd.py [options] [localhost:localport [remotehost:remoteport]]
# --nosetuid, -n 默认会设置用户为 nobody,如果不是 root 会因权限不足失败
# --version, -V
# --class classname, -c classname 默认: PureProxy
# --size limit, -s limit 消息大小限制(RFC 1870 SIZE extension),默认是 33554432 字节,即 32MB
# --smtputf8, -u 启用 SMTPUTF8 扩展(RFC 6531)
# --debug, -d
# --help, -h
# 如果不指定主机,就使用 localhost
# 如果主机是 localhost,端口使用 8025
# 如果是其他主机,端口使用 25
python3 -m smtpd -n
# 默认的 PureProxy 会给转信出去,正常情况会被服务器拒绝
python3 -m smtpd -n -c smtpd.DebuggingServer
Python 3.9 的 PureProxy 有 BUG,会报 process_message() got an unexpected keyword argument 'mail_options'。
自定义黑洞服务器
blackhole.py
import smtpd
import time
class BlackHoleServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
print('%s %s %s -> %s' % (time.strftime('%Y-%m-%d %H:%M:%S'), peer, mailfrom, rcpttos))
setup.py
import setuptools
setuptools.setup(name="blackhole", py_modules=["blackhole"])
附件下载:blackhole.zip
python setup.py install --user
python -m smtpd -n -c blackhole.BlackHoleServer
测试
import smtplib
smtp = smtplib.SMTP('localhost', 8025)
from_addr = 'admin@markjour.com'
to_addr = 'you@markjour.com'
smtp.sendmail(from_addr, to_addr,
f"""From: {from_addr}\nTo: {to_addr}\nSubject: just4fun\n\nhello, world!""")
Python FTP PythonSimpleServer
2018-05-07
FTP 需要 pyftpdlib 包的支持。
Python HTTP PythonSimpleServer
2018-05-07
Python2
在当前目录起 HTTP 服务,可以用于测试和临时性的文件下载服务。
# Default bind to 0.0.0.0:8000
python -m SimpleHTTPServer
# Maybe you want to use port 8080
python -m SimpleHTTPServer 8080
Python3
除了可以指定端口,还可以指定绑定地址、工作目录。
# Also bind to 0.0.0.0:8000
python -m http.server
python -m http.server -h
# usage: server.py [-h] [--cgi] [--bind ADDRESS] [--directory DIRECTORY] [port]
#
# positional arguments:
# port Specify alternate port [default: 8000]
#
# optional arguments:
# -h, --help show this help message and exit
# --cgi Run as CGI Server
# --bind ADDRESS, -b ADDRESS
# Specify alternate bind address [default: all interfaces]
# --directory DIRECTORY, -d DIRECTORY
# Specify alternative directory [default:current directory]
python -m http.server 9999
python -m http.server --bind=127.0.0.1
python -m http.server --bind=127.0.0.1 9999
python -m http.server -d ~/Pictures