惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
V2EX - 技术
V2EX - 技术
P
Privacy & Cybersecurity Law Blog
T
The Exploit Database - CXSecurity.com
美团技术团队
WordPress大学
WordPress大学
博客园 - 司徒正美
S
Securelist
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
Attack and Defense Labs
Attack and Defense Labs
Security Latest
Security Latest
L
LINUX DO - 最新话题
NISL@THU
NISL@THU
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
腾讯CDC
Y
Y Combinator Blog
The Hacker News
The Hacker News
Security Archives - TechRepublic
Security Archives - TechRepublic
IT之家
IT之家
T
Threatpost
Hugging Face - Blog
Hugging Face - Blog
Scott Helme
Scott Helme
S
SegmentFault 最新的问题
Cyberwarzone
Cyberwarzone
C
Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
U
Unit 42
B
Blog
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
小众软件
小众软件
V
Vulnerabilities – Threatpost
J
Java Code Geeks
V
Visual Studio Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
博客园 - 【当耐特】
Microsoft Security Blog
Microsoft Security Blog
S
Security @ Cisco Blogs
雷峰网
雷峰网
Help Net Security
Help Net Security
The Last Watchdog
The Last Watchdog
Recent Announcements
Recent Announcements
G
Google Developers Blog
C
CERT Recently Published Vulnerability Notes
T
Troy Hunt's Blog
MyScale Blog
MyScale Blog

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
Socket学习笔记
种瓜 · 2019-06-10 · via 夜行人

文章目录

前言

尽管我更喜欢ZeroMQ,但Socket无处不在。

经常会用到它,在此做个梳理。

诡异的翻译

Network socket被翻译作网络套接字,是不是一脸懵逼?我始终没搞懂套接字是什么意思, 中文里有这个词吗?它是音译吗? 就像沙发(sofa)? 看起来高深莫测。

在网络上搜了一圈,得出的结论是: 莫名其妙的翻译。我喜欢陈振玥在考证这个词出处时吐槽的:

其实我也很不喜欢这种生涩的译名,比如context设备上下文、handle句柄、macro宏,我小时候自己看计算机书籍好辛苦的,都是汉字但就是不知道在说什么。

socket的中文翻译是插座、灯泡插口、插孔。似乎可有看作接入电力系统的interface。从这个意义来说,Network socket的含义是非常清晰的: 网络插座, 网络的接口,就像插座是电力系统的接口。

ps: 台湾直接采用字面直译,把socket依然译成插座。

是什么

wikipedia给出的解释是很清晰的:

socket是一种操作系统提供的进程间通信机制。

socket接口是TCP/IP网络最为通用的API。

现代常见的socket接口大多源自Berkeley sockets标准。在socket接口中,以IP地址及通信端口组成socket address。

此外,一些细节值得注意:

在同一台计算机上,TCP协议与UDP协议可以同时使用相同的port而互不干扰。

简史

Socket Programming in Python (Guide)一文给出了Socket极简史:

Socket 有一段很长的历史,最初是在1971 年被用于 ARPANET,随后就成了 1983 年发布的 Berkeley Software Distribution (BSD) 操作系统的 API,并且被命名为 Berkeleysocket

测试工具

一个理想的测试工具,往往是学习相关领域知识的利器。

有测试工具在手,意味着可以随时动手来实践理论和尝试新想法,如《Mindstorms》说的,通过亲身操作,将知识内化

netcat(nc)ncat是非常理想的socket测试工具,其中netcat被称为网络工具中的瑞士军刀, 但我更偏好ncat(更清晰)。他们既可以轻松构建socket server,又可以轻松构建socket client。如果每次做实验都要一堆Python样板代码来运行client、server,而且许多参数还可能忘记,让人顿感疲惫,就不愿动手了。

socket client

为了让socket client能够工作,我们首先得有一个socket server。实际上今天的http server基本都是socket server。所以我们可以从这儿开始。

我们使用ncat作为socket client,请求模式为ncat <host/ip> <port>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
➜  ~ ncat baidu.com 80
GET / HTTP/1.0

HTTP/1.1 200 OK
---
Date: Mon, 10 Jun 2019 10:15:29 GMT
Server: Apache
Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
ETag: "51-47cf7e6ee8400"
Accept-Ranges: bytes
Content-Length: 81
Cache-Control: max-age=86400
Expires: Tue, 11 Jun 2019 10:15:29 GMT
Connection: Close
Content-Type: text/html

<html>
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
</html>

GET / HTTP/1.1是我们client给server的内容。http server将返回响应内容,这是一种请求、应答模式。

自建socket server

有很多中方式构建socket server,我们从一个最简单的开始,使用ncat构建一个tcp echo server。服务会将我们发送过去的任何信息回传。

ncat -l 8000 --keep-open --exec "/bin/cat"

新开一个shell,与serve通信:ncat 127.0.0.1 8000

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
➜  ~ ncat 127.0.0.1 8000
hello
hello
world
world
1
1
2
2
3
3
4
4

发送的所有消息都将被原样返回(echo)。

有了这个简易可靠的tcp echo server,之后测试socket client也要简单多了,不必再临时搭建socket server,到时出了问题,还要排查究竟是在server一侧还是client一侧。

当然你也可以使用在线的tcp echo server: tcpbin, 辅助测试。

socket client

有了socket server,就可以在实操中学习socket了。一般构建socket client开始。让我们暂时忘掉socket server, 只需要知道我们现在有了一个无论我们发送什么都会原样返回的服务即可。把精力集中在socket client上吧。

Pharo socket client

Pharo是smalltalk的现代方言,我现在喜欢在smalltalk里学习任何编程相关概念, 这种可探索的沉浸式编程环境提供了绝佳的学习体验。

Deep into Pharo一书的Chapter 4部分对Socket做了详细讲解

1
2
3
4
5
6
7
8
|localAddress clientSocket data|
clientSocket := Socket newTCP.
localAddress := NetNameResolver addressForName: '127.0.0.1'.
clientSocket
    connectTo: localAddress port: 8000;
    waitForConnectionFor: 10.
clientSocket sendData: 'Hello server'.
clientSocket receiveData.

Python socket client

Python官方文档里提供了最小例子:

1
2
3
4
5
6
7
8
9
import socket

HOST = '127.0.0.1'    # The remote host
PORT = 8000              # The same port as used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b'Hello, world')
    data = s.recv(1024)
print('Received', repr(data))

推荐使用jupyter做实验。

socket server

我们来展示使用代码构建socket server.

Pharo socket server

展示Deep into Pharo一书中的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
| connectionSocket interactionSocket receivedData |
"Prepare socket for handling client connection requests"
connectionSocket := Socket newTCP. connectionSocket listenOn: 8000 backlogSize: 10.
"Build a new socket for interaction with a client which connection request is accepted"
interactionSocket := connectionSocket waitForAcceptFor: 60.
"Get rid of the connection socket since it is useless for the rest of this example"
connectionSocket closeAndDestroy.
"Get and display data from the client"
receivedData := interactionSocket receiveData. receivedData crLog.
"Send echo back to client and finish interaction"
interactionSocket sendData: 'ECHO: ', receivedData. interactionSocket closeAndDestroy.

使用ncat与其交互:

1
2
3
➜  /tmp ncat 127.0.0.1 8000
hello
ECHO: hello

Python socket server

来自Python官方文档里提供的最小例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Echo server program
import socket

HOST = '0.0.0.0'                 # Symbolic name meaning all available interfaces
PORT = 8000              # Arbitrary non-privileged port
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen(1)
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)
            if not data: break
            conn.sendall(data)

Python的非阻塞socket

由于Python的生态比Pharo成熟,对非阻塞/异步socket的支持,Python社区目前已经非常成熟。

因此我们,将在python中讨论非阻塞socket相关的内容。

Socket Programming in Python (Guide)一文围绕Python中的socket有许多精彩讨论。

multiconn-server.py是很有代表性的一个socket server,对其的讨论请参考前头的文章。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import sys
import socket
import selectors
import types

sel = selectors.DefaultSelector()


def accept_wrapper(sock):
    conn, addr = sock.accept()  # Should be ready to read
    print("accepted connection from", addr)
    conn.setblocking(False)
    data = types.SimpleNamespace(addr=addr, inb=b"", outb=b"")
    events = selectors.EVENT_READ | selectors.EVENT_WRITE
    sel.register(conn, events, data=data)


def service_connection(key, mask):
    sock = key.fileobj
    data = key.data
    if mask & selectors.EVENT_READ:
        recv_data = sock.recv(1024)  # Should be ready to read
        if recv_data:
            data.outb += recv_data
        else:
            print("closing connection to", data.addr)
            sel.unregister(sock)
            sock.close()
    if mask & selectors.EVENT_WRITE:
        if data.outb:
            print("echoing", repr(data.outb), "to", data.addr)
            sent = sock.send(data.outb)  # Should be ready to write
            data.outb = data.outb[sent:]


if len(sys.argv) != 3:
    print("usage:", sys.argv[0], "<host> <port>")
    sys.exit(1)

host, port = sys.argv[1], int(sys.argv[2])
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
lsock.bind((host, port))
lsock.listen()
print("listening on", (host, port))
lsock.setblocking(False)
sel.register(lsock, selectors.EVENT_READ, data=None)

try:
    while True:
        events = sel.select(timeout=None)
        for key, mask in events:
            if key.data is None:
                accept_wrapper(key.fileobj)
            else:
                service_connection(key, mask)
except KeyboardInterrupt:
    print("caught keyboard interrupt, exiting")
finally:
    sel.close()

为了理解multiconn-server.py,我们可以将其运行起来之后,使用多个客户端来测试它:ncat 127.0.0.1 8000

todo

  • 对Python非阻塞socket编程做更多细致的讨论。
  • 加入对stream的讨论。

参考