如何用Python实现http客户端和服务器
功能:客户端可以向服务器发送get,post等请求,而服务器端可以接收这些请求,并返回给客户端消息。
客户端:
#coding=utf-8 import http.client from urllib import request, parse def send_get(url,path,data):#get请求函数 conn = http.client.HTTPConnection(url) conn.request("GET", path) r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.read() print(data1) # conn.close() def send_post(url,path,data,header):#post请求函数 conn = http.client.HTTPConnection(url)#建立连接 conn.request("POST", path,data,header)#用request请求,将信息封装成帧 r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.read() print(data1) # conn.close() def send_head(url,path,data,header): conn = http.client.HTTPConnection(url) conn.request("HEAD", path,data,header) r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.headers # print(data1) # conn.close() def send_put(url,path,filedata,header): conn = http.client.HTTPConnection(url) conn.request("PUT", path,filedata,header) r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.read() # print(data1) conn.close() def send_option(url,path,data,header): conn = http.client.HTTPConnection(url) conn.request("OPTION", path,data,header) r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.headers # print(data1) # conn.close() def delete_option(url,path,filename,header): conn = http.client.HTTPConnection(url) conn.request("DELETE", path, filename, header) r1 = conn.getresponse() print(r1.status, r1.reason) data1 = r1.read() # print(data1) conn.close() if __name__ == '__main__': url="localhost:8100" data = { 'my post data': 'I am client , hello world', } datas = parse.urlencode(data).encode('utf-8') headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"} while True: command = input("输入请求的命令:") if command =='get': print("----------发送get请求:-----------") send_get(url,path="",data="None") elif command=='post': print("----------发送post请求-----------") send_post(url, path="",data=datas,header=headers) elif command =='put': print("----------发送put请求-----------") file = input("输入要发送的文件名:") tfile=open(file,encoding="UTF-8",mode='r') filedatas=tfile.read() fileheaders = {"Content-type": "text/plain", "Accept": "text/plain",\ "content-length":str(len(filedatas))} send_put(url, path="E:/pythonProject2/httpweb/", filedata=filedatas, header=fileheaders) elif command=='head': print("----------发送head请求:-----------") send_head(url, path="", data=datas, header=headers) elif command=='option': print("----------发送option请求:-----------") send_option(url,path="",data=datas,header=headers) elif command=='delete': print("----------发送delete请求-----------") file = input("输入要删除的文件名:") fileheaders = {"Content-type": "text/plain", "Accept": "text/plain"} delete_option(url, path="E:/pythonProject2/httpweb/", filename = file, header=fileheaders) elif command == 'exit': break
服务端:
import socket import re import os import threading import urllib.parse def service_client(new_socket): # 为这个客户端返回数据 # 1.接收浏览器发过来的请求,即http请求 # GET / HTTP/1.1 request = new_socket.recv(1024).decode('utf-8') request_header_lines = request.splitlines() print(request_header_lines) data = request_header_lines[-1] # ret = re.match(r'[^/]+(/[^ ]*)', request_header_lines[0]) ret = list(request_header_lines[0].split(' '))[1] method = list(request_header_lines[0].split(' '))[0] path_name = "/" if method == 'GET': if ret: path = ret path_name = urllib.parse.unquote(path) # 浏览器请求的路径中带有中文,会被自动编码,需要先解码成中文,才能找到后台中对应的html文件 print("请求路径:{}".format(path_name)) if path_name == "/": # 用户请求/时,返回咖啡.html页面 path_name = "/咖啡.html" # 2.返回http格式的数据给浏览器 file_name = 'E:/pythonProject2/httpweb/HTML/' + path_name try: f = open(file_name, 'rb') except: response = "HTTP/1.1 404 NOT FOUND\r\n" response += "\r\n" response += "------file not found------" new_socket.send(response.encode("utf-8")) else: html_content = f.read() f.close() # 准备发给浏览器的数据 -- header response = "HTTP/1.1 200 OK\r\n" response += "\r\n" new_socket.send(response.encode("utf-8")) new_socket.send(html_content) # 关闭套接字 if method == 'POST': if ret: path = ret path_name = urllib.parse.unquote(path) # 浏览器请求的路径中带有中文,会被自动编码,需要先解码成中文,才能找到后台中对应的html文件 print("请求路径:{}".format(path_name)) if path_name == "/": # 用户请求/时,返回咖啡.html页面 path_name = "/咖啡.html" # 2.返回http格式的数据给浏览器 file_name = 'E:/pythonProject2/httpweb/HTML/' + path_name response = "HTTP/1.1 200 OK\r\n" response += "\r\n" new_socket.send(response.encode("utf-8")) new_socket.send(file_name.encode("utf-8")+' data:'.encode("utf-8")+data.encode("utf-8")) if method == 'PUT': if ret: path = ret path_name = urllib.parse.unquote(path) # 浏览器请求的路径中带有中文,会被自动编码,需要先解码成中文,才能找到后台中对应的html文件 print("请求路径:{}".format(path_name)) if path_name == "/": # 用户请求/时,返回咖啡.html页面 path_name = "/咖啡.html" # 2.返回http格式的数据给浏览器 file_name = list(request_header_lines[0].split(' '))[1] +'test.txt' content = data.encode('utf-8') response = "HTTP/1.1 200 OK\r\n" response += "\r\n" with open(file_name, 'ab') as f: f.write(content) new_socket.send(response.encode("utf-8")) new_socket.send("finish".encode("utf-8")) if method=='HEAD': if ret: path =ret path_name = urllib.parse.unquote(path) print("请求路径:{}".format(path_name)) if path_name =="/": path_name = "/咖啡.html" response = "HTTP/1.1 200 ok\r\n" new_socket.send(response.encode("utf-8")) new_socket.send(str(request_header_lines[1:]).encode("utf-8")) if method=='OPTION': if ret: path = ret path_name = urllib.parse.unquote(path) print("请求路径:{}".format(path_name)) if path_name == "/": path_name = "/咖啡.html" response = "HTTP/1.1 200 ok\r\n" new_socket.send(response.encode("utf-8")) new_socket.send("OPTIONS GET,HEAD,POST,PUT,DELETE".encode("utf-8")) if method =='DELETE': if ret: path = ret path_name = urllib.parse.unquote(path) # 浏览器请求的路径中带有中文,会被自动编码,需要先解码成中文,才能找到后台中对应的html文件 print("请求路径:{}".format(path_name)) if path_name == "/": # 用户请求/时,返回咖啡.html页面 path_name = "/咖啡.html" deletename = request_header_lines[-1] # print(path_name+deletename) os.remove(path_name+deletename) # 2.返回http格式的数据给浏览器 content = data.encode('utf-8') response = "HTTP/1.1 200 OK\r\n" response += "\r\n" # with open(file_name, 'ab') as f: # f.write(content) new_socket.send(response.encode("utf-8")) new_socket.send("finish".encode("utf-8")) # 关闭套接字 new_socket.close() def main(): # 用来完成整体的控制 # 1.创建套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2.绑定 tcp_server_socket.bind(("0.0.0.0", 8100)) # 3.变为监听套接字 tcp_server_socket.listen(128) while True: # 4.等待新客户端的链接 new_socket, client_addr = tcp_server_socket.accept() # 5.为这个客户端服务 print("为",client_addr,"服务") t = threading.Thread(target=service_client, args=(new_socket,)) t.start() # 关闭监听套接字 tcp_server_socket.close() if __name__ == '__main__': main()