zoukankan      html  css  js  c++  java
  • Python学习之旅(三十三)

    Python基础知识(32):网络编程(Ⅰ)

    网络通信是两台计算机上的两个进程之间的通信,而网络编程就是如何在程序中实现两台计算机的通信

    P协议负责把数据从一台计算机通过网络发送到另一台计算机

    TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达

    许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等

    TCP编程

    Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。

    一、客户端

    大多数连接都是可靠的TCP连接。创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器

    1、创建一个基于TCP连接的Socket

    #导入socket
    import socket
    
    #创建一个socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #建立连接,注意参数是一个tuple,包含地址和端口号 s.connect(('www.sina.com.cn', 80))

    TCP连接创建的是双向通道,双方都可以同时给对方发数据。谁先发谁后发,怎么协调,要根据具体的协议来决定

    HTTP协议规定客户端必须先发请求给服务器,服务器收到后才发数据给客户端

    发送的文本格式必须符合HTTP标准

    2、建立TCP连接后,就可以向发送请求,要求返回首页的内容

    #发送数据
    s.send(b'GET / HTTP/1.1
    Host: www.sina.com.cn
    Connection: close
    
    ')

    3、接收服务器返回的数据

    #接收数据
    buffer = []
    while True:
        #每次最多接收1k字节
        d = s.recv(1024)
        if d:
            buffer.append(d)
        else:
            break
    data = b''.join(buffer)

    接收数据时,调用recv(max)方法,一次最多接收指定的字节数,因此,在一个while循环中反复接收,直到recv()返回空数据,表示接收完毕,退出循环

    4、调用close()方法关闭Socket,结束网络通信

    #关闭连接
    s.close()

    保存网页内容到文件

    #把网页内容保存到sina.html文件
    header, html = data.split(b'
    
    ', 1)
    print(header.decode('utf-8'))
    #把接收的数据写入文件
    with open('sina.html', 'wb') as f:
        f.write(html)

    接收到的数据包括HTTP头和网页本身,只需要把HTTP头和网页分离一下,把HTTP头打印出来,网页内容保存到文件

    只需要在浏览器中打开这个sina.html文件,就可以看到新浪的首页了

    HTTP/1.1 302 Moved Temporarily
    Server: nginx
    Date: Fri, 14 Dec 2018 08:07:21 GMT
    Content-Type: text/html
    Content-Length: 154
    Connection: close
    Location: https://www.sina.com.cn/
    X-Via-CDN: f=edge,s=ctc.xiamen.ha2ts4.35.nb.sinaedge.com,c=125.91.244.232;
    X-Via-Edge: 1544774841629e8f45b7d3cd64cde1173d1de

    二、服务器

    服务器进程首先要绑定一个端口并监听来自其他客户端的连接。如果某个客户端连接过来了,服务器就与该客户端建立Socket连接,随后的通信就靠这个Socket连接了

    一个Socket依赖4项:服务器地址、服务器端口、客户端地址、客户端端口来唯一确定一个Socket

    服务器需要同时响应多个客户端的请求,每个连接都需要一个新的进程或者新的线程来处理,否则,服务器一次就只能服务一个客户端

    1、创建一个基于IPv4和TCP协议的Socket

    #创建一个基于IPv4和TCP协议的Socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    2、绑定监听的地址和端口

    #监听端口
    s.bind(('127.0.0.1', 9999))

    服务器可能有多块网卡,可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址

    127.0.0.1是一个特殊的IP地址,表示本机地址,如果绑定到这个地址,客户端必须同时在本机运行才能连接,也就是说,外部的计算机无法连接进来

    端口号需要预先指定。因为我们写的这个服务不是标准服务,所以用9999这个端口号

    注意:小于1024的端口号必须要有管理员权限才能绑定

    3、调用listen()方法监听端口

    传入的参数指定等待连接的最大数量

    s.listen(5)
    print('Waiting for connection...')

    4、通过一个永久循环接受来自客户端的连接

    while True:
        #接受一个新连接
        sock, addr = s.accept()
        #创建新线程来处理TCP连接
        t = threading.Thread(target=tcplink, args=(sock, addr))
        t.start()

    accept()会等待并返回一个客户端的连接

    5、创建新进程处理连接

    每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接

    #创建新进程处理连接
    def tcplink(sock, addr):
        print('Accept new connection from %s:%s...' % addr)
        sock.send(b'Welcome')
        while True:
            data = sock.recv(1024)
            time.sleep(1)
            if not data or data.decode('utf-8') == 'exit':
                break
            sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
        sock.close()
        print('Connection from %s:%s close.' % addr)

    连接建立后,服务器首先发一条欢迎消息,然后等待客户端数据,并加上Hello再发送给客户端

    如果客户端发送了exit字符串,就直接关闭连接

    6、编写一个客户端程序测试这个服务器程序

    #tcp_client.py
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #建立连接
    s.connect(('127.0.0.1', 9999))
    #接收欢迎消息
    print(s.recv(1024).decode('utf-8'))
    for data in [b'Alice', b'Bob', b'Jack']:
        s.send(data)
        print(s.recv(1024).decode('utf-8'))
    s.send(b'exit')
    s.close()

    分别运行tcp_client.py和tcp_server.py

    tcp_server.py的结果:
    Waiting for connection...
    Accept new connection from 127.0.0.1:60647...
    Connection from 127.0.0.1:60647 close.
    
    tcp_client.py的结果:
    Welcome
    Hello, Alice!
    Hello, Bob!
    Hello, Jack!

    参考资料:

    1、廖雪峰学习官网

    2、宁致乐水的博文:https://blog.csdn.net/qq_31603575/article/details/80089707

  • 相关阅读:
    Leetcode 50.Pow(x,n) By Python
    Leetcode 347.前K个高频元素 By Python
    Leetcode 414.Fizz Buzz By Python
    Leetcode 237.删除链表中的节点 By Python
    Leetcode 20.有效的括号 By Python
    Leetcode 70.爬楼梯 By Python
    Leetcode 190.颠倒二进制位 By Python
    团体程序设计天梯赛 L1-034. 点赞
    Wannafly挑战赛9 C-列一列
    TZOJ Start
  • 原文地址:https://www.cnblogs.com/finsomway/p/10120143.html
Copyright © 2011-2022 走看看