代码1:基础实现可以用网页向程序请求页面
import socket
import os
import re
web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
web_socket.bind(('', 10241))
web_socket.listen(124)
data = web_socket.accept()
new_socket = data[0]
info = new_socket.recv(1024)
info_str = info.decode()
print(info_str)
info_str = info_str.split('\r\n')
print(info_str[0])
path = re.match(r'\S+\s+/(\S+)\s+\S+', info_str[0])
file_path = path.group(1)
if os.path.exists(file_path):
# 响应行:协议/版本号 状态码\r\n
respond_line = 'HTTP/1.1 200 OK \r\n'
# 响应头:服务器:型号\r\n
respond_hande = 'Server: PYS1.0\r\n'
# 响应体: 内容,网页的内容全部读出来
path = info
f = open('index.html', 'rb')
content = f.read()
f.close()
respond_body = content
respond_data = (respond_line + respond_hande + '\r\n').encode() + respond_body
new_socket.send(respond_data)
new_socket.close()
web_socket.close()
1.添加下面语句,使得程序结束以后可以将端口释放:
web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
2.使用data = web_socket.accept()可以得到一个元组,包含两组数据,一组为:新的套接字;另一组为对端ip和port:
(<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 10241), raddr=('127.0.0.1', 57504)>, ('127.0.0.1', 57504))
3.下面的语句得到的是一串二进制数据,需要进行(.decode())解码才能继续操作:
info = new_socket.recv(1024)
4.上一句经过解码后得到的以下数据(请求行,头,空行(看不出来\r\t),体):
GET /index.html HTTP/1.1 请求行:方法 /路径 版本
Host: localhost:10241 地址,端口
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0 用户代理
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 可以接受的文本类型
Accept-Language: en-US,en;q=0.5 可以接受的语言
Accept-Encoding: gzip, deflate 可以接受的压缩格式
Connection: keep-alive 长链接
Upgrade-Insecure-Requests: 1
代码2:使用协程完成代码1
import socket
import re
import os
import gevent
from gevent import monkey
monkey.patch_all() # 把默认的阻塞模式变为非阻塞的模式 recv accept time.sleep
# 用来进行与客户端交互
def client(new_socket):
info = new_socket.recv(4096)
de_info = info.decode()
hander = de_info.split('\r\n')
web_name = re.match(r'\S+\s+/(\S+)\s+\S+', hander[0])
print(web_name.group(1))
path = web_name.group(1)
print(path)
try:
f = open('static/' + path, 'rb')
content = f.read()
f.close()
respond_body = content
respond_hander = 'Server PYW9.9 \r\n'
respond_line = 'HTTP/1.1 200 OK \r\n'
respond_data = (respond_line + respond_hander + '\r\n').encode() + respond_body
except Exception as e:
respond_body = 'Error'
respond_line = 'HTTP/1.1 404 Error \r\n'
respond_hander = 'Server PYW9.9 \r\n'
respond_data = (respond_line + respond_hander + '\r\n' + respond_body).encode()
finally:
new_socket.send(respond_data)
new_socket.close()
def main():
web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
web_socket.bind(('', 7991))
web_socket.listen(124)
while True:
new_socket, ip_port = web_socket.accept()
print('接收到来自%s的链接请求' % str(ip_port))
gevent.spawn(client, new_socket)
if __name__ == '__main__':
main()
1.在模仿网页发送响应行、头时应该严格按照格式来,对比下面四句:
respond_line = ‘HTTP/1.1 200 OK \r\n’
respond_line = ‘HTTP/ 1.1 200 OK \r\n’
respond_line = ‘HTTP /1.1 200 OK \r\n’
respond_line = ‘HTTP / 1.1 200 OK \r\n’
只有第一句可以完美执行,第2 3 4句在chrome上可以正常浏览,在Firefox上会直接看到网页源码,看不到正常网页。
代码3:对代码2进行封装,并可以在命令行向程序输入参数
import socket
import sys
import re
import gevent
from gevent import monkey
monkey.patch_all() # 把默认的阻塞模式变为非阻塞的模式 recv accept time.sleep
class HTTP_Server():
'''这是一个HTTP服务器端'''
def __init__(self, port):
web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
web_socket.bind(('', port))
web_socket.listen(124)
self.socket = web_socket
def star(self):
while True:
new_socket, ip_port = self.socket.accept()
print('接收到来自%s的链接请求' % str(ip_port))
gevent.spawn(self.client, new_socket)
# 用来进行与客户端交互
def client(self, new_socket):
info = new_socket.recv(4096)
de_info = info.decode()
hander = de_info.split('\r\n')
web_name = re.match(r'\S+\s+/(\S+)\s+\S+', hander[0])
print(web_name.group(1))
path = web_name.group(1)
print(path)
try:
f = open('static/' + path, 'rb')
content = f.read()
f.close()
respond_body = content
respond_hander = 'Server PYW9.9 \r\n'
respond_line = 'HTTP/1.1 200 OK \r\n'
respond_data = (respond_line + respond_hander + '\r\n').encode() + respond_body
except Exception as e:
respond_body = 'Error'
respond_line = 'HTTP/1.1 404 Error \r\n'
respond_hander = 'Server PYW9.9 \r\n'
respond_data = (respond_line + respond_hander + '\r\n' + respond_body).encode()
finally:
new_socket.send(respond_data)
new_socket.close()
def main():
if len(sys.argv) != 2:
print("正确打开方式: python3 web.py 8888")
return
if not sys.argv[1].isdigit():
print("正确打开方式: python3 web.py 8888")
port = int(sys.argv[1])
Http = HTTP_Server(port)
print(HTTP_Server.__doc__)
Http.star()
if __name__ == '__main__':
main()