如何用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

服务器:

# -*- coding: utf-8 -*-

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()
posted @ 2023-01-23 15:20  萧海~  阅读(851)  评论(0编辑  收藏  举报