前言

利用 Python 标准库 socket 实现多线程 echo 和 http 程序.

源教程地址: https://www.bilibili.com/video/BV1eg411G7pW/?vd_source=547d8a3d2ce70a88f0a699636396bd6f .

想要了解套接字更多的内容可以阅读 TCP/IP网络编程.

操作系统:Ubuntu 20.04.6 LTS

参考文档

  1. TCP/IP网络通信之Socket编程入门

  2. socket

echo

  1. 在服务器上编写 server.py。服务器 IP 地址为 10.4.3.155
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
60
61
62
63
64
# nc 是linux 下网络测试工具, 可以读写 TCP/UDP 的数据
# Windows 的替代版本 (nmap): https://nmap.org/
# 使用方法,在客户端运行下面命令:
#
# nc 服务器IP地址 端口号
#
# 本案例的测试命令为:
#
# nc 10.4.3.155 1234

import socket
import threading
import os

WEBROOT = os.path.dirname(__file__)

# echo 程序
def handle_client(c, addr):
print(addr, "connected.")

while True:
data = c.recv(1024)
if not data:
break
c.sendall(data)

# http 程序
def handle_http(c, addr):
print(addr, "connected.")

with c:
request = c.recv(1024)

# Parse HTTP headers
headers = request.split(b"\r\n")
file = headers[0].split()[1].decode()

# Load file content
if file == "/":
file = "/index.html"

try:
with open(WEBROOT + file, "rb") as f:
content = f.read()
response = b"HTTP/1.0 200 OK\r\n\r\n" + content
except FileNotFoundErrot:
response = b"HTTP/1.0 404 NOT FOUND\r\n\r\nFile not found!"

# Send HTTP response
c.sendall(response)

# socket.AF_INET 表示 IPv4 地址家族
# socket.SOCK_STREAM 表示 TCP 协议
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# 服务器 IP 地址, 即运行本脚本的主机地址
s.bind(("10.4.3.155", 1234))
s.listen()

while True:
c, addr = s.accept()

t = threading.Thread(target=handle_client, args=(c, addr))
#t = threading.Thread(target=handle_http, args=(c, addr))
t.start()
  1. 在本地计算机上编写客户端脚本 client.py
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# coding=utf-8
import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(("10.4.3.155", 1234))
s.sendall(b"Hello, lyf!")
data = s.recv(1024)
print("Received: ", repr(data))
  1. 在服务器上运行 server.py

  2. 在客户端上运行 client.py


运行结果

  1. 服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(base) luyanfeng@amax:~/my_code/temp$ ls
index.html server.py
(base) luyanfeng@amax:~/my_code/temp$ python server.py
('10.4.3.151', 47222) connected.
('10.4.3.151', 40348) connected.
('10.4.3.151', 53850) connected.
^CTraceback (most recent call last):
File "/home/luyanfeng/my_code/temp/server.py", line 60, in <module>
c, addr = s.accept()
File "/home/luyanfeng/miniconda3/lib/python3.9/socket.py", line 293, in accept
fd, addr = self._accept()
KeyboardInterrupt

(base) luyanfeng@amax:~/my_code/temp$
  1. 客户端:
1
2
3
4
5
6
7
8
9
(base) lyfubuntu@lyfubuntu:~/my_computer_language/temp$ ls
client.py
(base) lyfubuntu@lyfubuntu:~/my_computer_language/temp$ python client.py
Received: b'Hello, lyf!'
(base) lyfubuntu@lyfubuntu:~/my_computer_language/temp$ python client.py
Received: b'Hello, lyf!'
(base) lyfubuntu@lyfubuntu:~/my_computer_language/temp$ python client.py
Received: b'Hello, lyf!'
(base) lyfubuntu@lyfubuntu:~/my_computer_language/temp$

http

  1. 在服务器上编写 server.py。服务器 IP 地址为 10.4.3.155
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
60
61
62
63
64
# nc 是linux 下网络测试工具, 可以读写 TCP/UDP 的数据
# Windows 的替代版本 (nmap): https://nmap.org/
# 使用方法,在客户端运行下面命令:
#
# nc 服务器IP地址 端口号
#
# 本案例的测试命令为:
#
# nc 10.4.3.155 1234

import socket
import threading
import os

WEBROOT = os.path.dirname(__file__)

# echo 程序
def handle_client(c, addr):
print(addr, "connected.")

while True:
data = c.recv(1024)
if not data:
break
c.sendall(data)

# http 程序
def handle_http(c, addr):
print(addr, "connected.")

with c:
request = c.recv(1024)

# Parse HTTP headers
headers = request.split(b"\r\n")
file = headers[0].split()[1].decode()

# Load file content
if file == "/":
file = "/index.html"

try:
with open(WEBROOT + file, "rb") as f:
content = f.read()
response = b"HTTP/1.0 200 OK\r\n\r\n" + content
except FileNotFoundErrot:
response = b"HTTP/1.0 404 NOT FOUND\r\n\r\nFile not found!"

# Send HTTP response
c.sendall(response)

# socket.AF_INET 表示 IPv4 地址家族
# socket.SOCK_STREAM 表示 TCP 协议
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# 服务器 IP 地址, 即运行本脚本的主机地址
s.bind(("10.4.3.155", 1234))
s.listen()

while True:
c, addr = s.accept()

#t = threading.Thread(target=handle_client, args=(c, addr))
t = threading.Thread(target=handle_http, args=(c, addr))
t.start()
  1. server.py 同级目录下编写 index.html
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My test page</title>
</head>
<body>
<p>My cat is very grumpy</p>
</body>
</html>
  1. 在服务器上运行 server.py

运行结果

  1. 打开本地浏览器,输入 http://10.4.3.155:1234/

结语

第七十一篇博文写完,开心!!!!

今天,也是充满希望的一天。