美文网首页Python语言自学Python入门与进阶
Python高级知识点学习(七)

Python高级知识点学习(七)

作者: kakarotto | 来源:发表于2018-10-26 18:28 被阅读3495次

    HTTP、Socket、TCP概念

    socket属于常用的http协议之下的让我们可以使用tcp/ip协议的一个接口。

    socket编程

    image.png

    socket编程的模式其实是非常固定的。

    上图:

    • 左侧server端
    • 右侧client端

    server必须是随时处于一个监听的状态和服务的状态,因为不知道客户端什么时候会发送来请求。

    绑定协议、地址、端口。

    每一个应用程序只能占用一个端口,服务器a到服务器b发数据时,数据是不知道是由哪个应用程序接受的,这时候就需要端口机制,每一个应用程序提供一个端口。

    socket连接后,只要不关闭连接,服务端可以一直给客户端发送请求,但是在http中,只完成一次发送数据就停止了。
    编写测试代码:
    新建文件sever.py

    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定ip 端口
    server.bind(('0.0.0.0', 8000))
    # 监听
    server.listen()
    sock, addr = server.accept()
    
    # 接受client端发来的数据
    data = sock.recv(1024)
    # 打印数据
    print(data.decode('utf8'))
    # 给client发数据
    sock.send("hello".encode("utf8"))
    # 关闭
    server.close()
    sock.close()
    

    新建文件client.py

    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1', 8000))
    # 给server端发数据
    client.send("allen".encode("utf-8"))
    # 接受server端发来的数据
    data = client.recv(1024)
    # 打印数据
    print(data.decode('utf8'))
    # 关闭
    client.close()
    

    首先运行server.py,再运行client.py,观察打印结果,可以看到,数据发送接收已经是实现。

    socket实现简单聊天

    要实现双向交流,肯定不能做close操作,改为一直while循环,
    代码:
    修改srever.py

    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(("0.0.0.0", 8000))
    server.listen()
    sock, addr = server.accept()
    
    while True:
        # 接受client端发来的数据
    
        data = sock.recv(1024)
        # 打印数据
        print(data.decode('utf8'))
    
        re_data = input()
        # 给client发数据
        sock.send(re_data.encode("utf8"))
    

    修改client.py:

    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1', 8000))
    while True:
        # 输入消息
        re_data = input()
        client.send(re_data.encode("utf8"))
        # 接受client端发来的数据
        data = client.recv(1024)
        # 打印数据
        print(data.decode('utf8'))
    

    运行server.py ,再运行client.py,在client.py中输入要发送的文字,在server.py中观察接收到的文字,再在server.py中发送文字,在client.py中查看。

    以上就是实现了最初级的基本聊天过程。
    如果要在网页上做一个聊天模块,一般都是需要用web socket来实现。

    socket多用户聊天

    所谓多用户聊天,其实平时我们也经常遇到。
    假如你是一位线上客服人员,你需要接待的人员可能同时有多位,当你和A用户聊天时,并不妨碍和B用户C用户给你发消息,而你回消息,回给A用户的消息只有A用户可以看到,B用户是看不到的,接着看如何实现这种功能。
    首先client.py的代码不用改动,只需修改server.py:

    import socket
    import threading
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('0.0.0.0', 8000))
    server.listen()
    
    
    def handle_sock(sock, addr):
        while True:
            data = sock.recv(1024)
            print(data.decode("utf8"))
            re_data = input()
            sock.send(re_data.encode("utf8"))
    
    while True:
        sock, addr = server.accept()
        #用线程去处理新接收的连接(用户)
        client_thread = threading.Thread(target=handle_sock, args=(sock, addr))
        client_thread.start()
    

    上边代码把接受处理逻辑放到了线程中,每一个线程存放一个不同的socket,主线程来查看有哪些线程进入。
    运行server.py,再运行多个client.py,client.py给server发消息,测试可发现可实现上边的客服功能。

    注:真正客服系统要比这个复杂得多,以上代码仅供测试。

    socket模拟http请求

    我们平常所用到的requests包,是基于 urllib,urllib实际上是基于socket上来完成的。
    requests - urlib - socket
    如何通过socket去完成类似urllib中http请求呢?

    http请求无非就是在tcp协议之上加了一些协议,只要按照这个协议发,就会返回数据。
    看代码:

    import socket
    from urllib.parse import urlparse
    
    def request_demo(url):
        # url拆分
        url = urlparse(url)
        host = url.netloc
        path = url.path
        if path == "":
            path = "/"
    
        # 建立socket连接
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect((host, 80)) 
        client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8"))
    
        data = b""
        # 每次读取1024大小,循环知道读取完毕
        while True:
            d = client.recv(1024)
            if d:
                data += d
            else:
                break
    
        data = data.decode("utf8")
        print(data)
        client.close()
    
    
    if __name__ == "__main__":
        url = 'http://www.baidu.com'
        request_demo(url)
    
    运行结果包含两部分:
    第一部分request header
    第二部分html源码
    

    建立连接的过程是比较费时的,一般在使用socket编程都是为了解决长连接的问题,而不是说每发送一个请求数据返回就把它关掉。

    很多时候我们需要一个交互的过程,这时候socket就派上用场了,有了socket后我们的代码灵活性高,它完全可以让我们将整个过程变得可以操控。

    相关文章

      网友评论

        本文标题:Python高级知识点学习(七)

        本文链接:https://www.haomeiwen.com/subject/zniqtqtx.html