一、网络简介
1. 网络的定义
信息传递和共享虚拟平台
2. ip
网络设备的唯一编号 ip分类
- ipv4
- ipv6:可编号的网络设备数目大
3.ip和域名的关系
域名解析 www.baidu.com<==>35.156.69.79
4. ip相关命令
ifconfig ping
5.端口和端口号
端口:数据传输的通道
端口号:端口的编号 0-65535 分类:
- 知名端口号: 0-1023 , 不可占用,已经分配给了特定的服务,例如 22 80 等
- 动态端口号: 1024-65535 , 程序员可以绑定,没有绑定会自动分配
二. socket
1.socket定义
网络通讯的工具
- tcp
- udp
2.tcp
面向连接的、可靠的、基于字节流的传输层通信协议
-
三次握手机制:
- 可靠性:
- 采用发送应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
- 客户端请求流程:
3.编码转换
# 编码
str.encode(encoding=‘utf-8’)
# 解码
str.decode(encoding=‘utf-8’)
4.socket客户端和服务端的实现
-
客户端实现
import socket if __name__ == '__main__': # AF_INET 代表使用ipv4 # SOCK_STREAM表示基于TCP协议 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 这里绑定IP和端口 client.bind(('localhost', 8080)) # 这里配置要连接的服务端地址和端口号 client.connect(('localhost', 8081)) while True: text = input('请输入要传输的数据:') # 向服务端发送数据 client.send(text.encode(encoding='utf-8')) # 接受服务端返回的数据,参数表示定要接收的最大数据量 msg = client.recv(1024) msg = msg.decode(encoding='utf-8') print('服务端返回:', msg) if msg == 'quit': print('服务端请求断开连接!!!') break # 关闭客户端socket client.close()
-
服务端实现(单线程版):
import socket if __name__ == '__main__': # 创建server端套接字 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口复用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定IP和端口 server.bind(('', 8081)) # 设置端口复用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置最大等待建立连接的个数 server.listen(10) # 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞 # 1. 专门和客户端通信的套接字: service_client_socket # 2. 客户端的ip地址和端口号: ip_port server_client_socket, ip_port = server.accept() print(server_client_socket) print('客户端的ip地址和端口号:', ip_port) while True: # 接收客户端发送的数据, 这次接收数据的最大字节数是1024 msg = server_client_socket.recv(1024) msg = msg.decode(encoding='utf-8') print('接收到客户端发来的数据:', msg) if msg == 'quit': print('客户端请求断开连接!!!') break text = input('请输入要返回给客户端的信息;') server_client_socket.send(text.encode(encoding='utf-8')) # 关闭服务与客户端的套接字, 终止和客户端通信的服务 server_client_socket.close() # 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务 server.close()
-
服务端(多线程版):
import socket import threading def process_data(server_client_socket, ip_port): while True: # 接收客户端发送的数据, 这次接收数据的最大字节数是1024 msg = server_client_socket.recv(1024) msg = msg.decode(encoding='utf-8') print('接收到客户端发来的数据:', msg) if msg: # text = input('请输入要返回给客户端的信息;') server_client_socket.send('ok,问题正在处理中...'.encode(encoding='utf-8')) else: print('客户端请求断开连接!!!', ip_port) break # 关闭服务与客户端的套接字, 终止和客户端通信的服务 server_client_socket.close() if __name__ == '__main__': # 创建套接字dict,用来复用 # 创建server端套接字 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口复用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定IP和端口 server.bind(('', 8081)) # 设置端口复用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置最大等待建立连接的个数 max_num = 2 server.listen(max_num) # 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞 # 1. 专门和客户端通信的套接字: service_client_socket # 2. 客户端的ip地址和端口号: ip_port for i in range(max_num): server_client_socket, ip_port = server.accept() print(server_client_socket) print('客户端的ip地址和端口号:', ip_port) t = threading.Thread(target=process_data, args=(server_client_socket, ip_port)) t.setDaemon(True) t.start() # 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务 # server.close()
5. send和recv原理剖析
三.HTTP
1. URL
统一资源定位符 协议: http, https, ftp ,规定数据发送和接收的格式 域名: www.baidu.com , 找到服务端IP, 端口默认80,可以不写 资源路径: /news/ 查询参数: /pic?path=xxx.jpg
2.HTTP协议
- 定义:超文本传输协议,用在http服务器和web浏览器之间的传输
- 请求方式
- GET
- POST
-
请求报文格式 请求行:请求方式 资源路径 协议版本 请求头:请求信息 请求体:封装好的请求信息(GET类型不需要)
- 响应报文 GET和POST请求响应的报文格式是相同的 响应行:协议版本 状态码(200:成功 4XX:资源不存在 5XX:服务器内部错误) 响应头:请求信息 响应体:封装好的响应信息
3.查看HTTP请求流程
再谷歌浏览器中,右键检查,点击Network
4. 自己搭建静态服务器
-
Python自带的http服务器
python3 -m http.server
- 自己搭建静态服务器
- 创建TCP服务器
- 接收浏览器访问数据
- 解析浏览器发过来的请求(资源路径)
- 根据解析的字眼路径,获取路径资源
- 按照响应报文方式组织响应数据,传递回去(响应体)
- 关闭连接
-
web服务器返回指定页面
-
多任务版服务器
import socket import threading def work(client_socket): while True: data = client_socket.recv(1024).decode() print(data) if not data: break array = data.split(' ') uri = array[1] if uri == '/': uri = '/index.html' try: with open('./static' + uri, 'rb') as f: res_data = f.read() except: res_line = 'HTTP/1.1 404 Not Found\r\n' res_header = 'server: python\r\n' res_body = "404 Not Found, Sorry!" res = (res_line + res_header + '\r\n' + res_body).encode() client_socket.send(res) else: res_line = 'HTTP/1.1 200 OK\r\n' res_header = 'server: python\r\n' res_body = res_data res = (res_line + res_header + '\r\n').encode() + res_body client_socket.send(res) client_socket.close() if __name__ == '__main__': server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_socket.bind(("", 8080)) server_socket.listen(128) while True: client_socket, ip_port = server_socket.accept() print('ip_port:', ip_port) t = threading.Thread(target=work, args=(client_socket,)) t.setDaemon(True) t.start() server_socket.close()
-
面向对象版本
通过sys.argv来获取命令行参数
import socket import threading import sys class WebServer(): def __init__(self, port): self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_socket.bind(("", int(port))) self.server_socket.listen(128) def start(self): while True: client_socket, ip_port = self.server_socket.accept() print('ip_port:', ip_port) t = threading.Thread(target=self.work, args=(client_socket,)) t.setDaemon(True) t.start() self.server_socket.close() def work(self, client_socket): while True: data = client_socket.recv(1024).decode() print('客户端发送:', data) if not data: break array = data.split(' ') uri = array[1] print(uri) if uri == '/': uri = '/index.html' try: with open('./static' + uri, 'rb') as f: res_data = f.read() except: res_line = 'HTTP/1.1 404 Not Found\r\n' res_header = 'server: python\r\n' res_body = "404 Not Found, Sorry!" res = (res_line + res_header + '\r\n' + res_body).encode() client_socket.send(res) else: res_line = 'HTTP/1.1 200 OK\r\n' res_header = 'server: python\r\n' res_body = res_data res = (res_line + res_header + '\r\n').encode() + res_body client_socket.send(res) finally: client_socket.close() def main(): arr = sys.argv print(arr) if len(arr) < 2: s = WebServer(8080) s.start() return port = arr[1] if port.isdigit(): s = WebServer(port) s.start() return else: print('命令格式有误!') if __name__ == '__main__': main()