• Day-17: 网络编程


    ---恢复内容开始---

      现有的互联网通讯方式,是服务器端的进程与客户端进程的通信。Python中进行网络编程,就是在Python程序本身这个进程内,连接别的服务器进程的通信端口进行通信。

      互联网协议上包含了上百种协议标准,但是,最重要的是两个协议:TCP和IP协议。所以,互联网协议简称TCP/IP协议。

      通信时必须知道双方的标识,而一台计算机可能同时接入多个网络,就会有两个或多个IP地址。所以,IP地址实际上对应的是计算机的网络接口,通常是指网卡。

      IP协议将数据分割成一小块一小块,然后通过IP包发送出去。特点:按块发送,不保证能到达,也不保证能顺序到达。

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

    特点:握手连接,对IP包编号,确保顺序收到,若掉包,则自动重发。

      一个IP包,包含传输数据,源IP地址和目标IP地址,源端口和目标端口。

      IP是标识在网络中的电脑的位置,而一台电脑上会有多个网络通信进程,所以端口则是标识目标进程在该电脑上的位置。

    • TCP编程

      首先要理解socket表示“打开一个网络链接”,而创建一个socket需要知道目标计算机中的ip,端口号,然后再指定所用的协议。

      客户端:主动发起链接的叫客户端。

    # 导入socket库:
    import socket
    # 创建一个socket:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接:
    s.connect(('www.sina.com.cn', 80))

      客户端导入socket库后首先创建socket网络链接,socket.AF_INET指定使用IPv4协议,socket.AF_INET6指定使用IPv6协议。SOCK_STREAM指定使用面向流的TCP协议。然后输入所需的ip和端口号,进行链接,注:其中域名会自动转换成ip。

      这里指的一提的是:网络服务小于1024的端口号都是Internet标准服务的端口,有固定的用处,大于1024的则可以任意使用。其中,80端口为网页服务端口,25为SMTP服务端口,FTP服务为21端口。

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

      然后以HTTP格式发送数据,发起请求。

      TCP协议只是建立了大致的双向通道,而至于怎么协调,得依据具体的协议来决定,如HTTP协议规定客户端必须先发起请求,服务端才能返回数据。

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

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

    # 关闭连接:
    s.close()

      最后,调用close()方法关闭Socket,一次完整的网络通信就结束了。

      网络通讯结束后,就可以对接受到的数据进行相应的处理了:

    header, html = data.split('
    
    ', 1)
    print header
    # 把接收的数据写入文件:
    with open('sina.html', 'wb') as f:
        f.write(html)

      将HTTP头和网页分离一下,把HTTP头打印出来,网页内容保存到文件,就得到了新浪的首页。

      服务器:服务器端是提供服务的一方。首先,和客户端一样,建立一个socket:

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

      客户端接下来是设置要连接的端口和ip,所以,此时,服务器端要绑定端口和ip:

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

      服务器肯能有多块网卡,也就是多个ip。可以只绑定到一块网卡的ip地址上;也可以使用0.0.0.0绑定到所有的网络地址;还可以用127.0.0.1绑定本机地址,此时,就有本机的客户端才能连接。

      接着,调用listen()方法开始监听端口,传入的参数指定最大的链接数量:

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

      然后,服务器通过一个永久循环来接受客户端的连接,accept()会等待并返回一个客户端的连接:

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

      每个连接必须创建一个新的线程(或进程)来处理,不然无法同时应付多个客户端。

      而对于连接之后的处理是,服务器先发送一条欢迎消息,然后等待客户端数据,并加上Hello再发送给客户端。如果发送了exit字符串,就直接关闭连接。

      相应的测试客户端程序:

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接:
    s.connect(('127.0.0.1', 9999))
    # 接收欢迎消息:
    print s.recv(1024)
    for data in ['Michael', 'Tracy', 'Sarah']:
        # 发送数据:
        s.send(data)
        print s.recv(1024)
    s.send('exit')
    s.close()

      客户端和服务端同时运行就可以看到效果:

    • UDP编程

      TCP是建立可靠的连接,UDP则是面向无连接的协议。使用UDP时,只需要知道对方的IP地址和端口号,不需要建立稳定连接,就可以直接发数据包。但是,能不能到达就不知道了。

      它相比于TCP的特点是,速度快,但是不够稳定可靠,适用于不太重要的连接。

      与TCP类似,UDP分为客户端和服务端。服务器首先需要建立socket,然后绑定端口:

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口:
    s.bind(('127.0.0.1', 9999))

      其中,SOCK_DGRAM指定这个socket的类型是UDP。绑定端口与TCP一样,但是不需要调用listen()方法,而是直接接收来自任何客户端的数据:

    print 'Bind UDP on 9999...'
    while True:
        # 接收数据:
        data, addr = s.recvfrom(1024)
        print 'Received from %s:%s.' % addr
        s.sendto('Hello, %s!' % data, addr)

      recvfrom()方法返回数据和客户端的地址与端口。这样,服务器接收到数据后,就可以直接调用sendto()就可以把数据用UDP发给客户端。

      而客户端上,首先也是建立socket连接,但是不用建立稳定的连接,所以不要调用connet(),直接通过sendto()将数据传给服务器。

    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for data in ['Michael', 'Tracy', 'Sarah']:
        # 发送数据:
        s.sendto(data, ('127.0.0.1', 9999))
        # 接收数据:
        print s.recv(1024)
    s.close()

      从服务器接收数据仍是调用recv()方法。

      效果如图:

      总的来说,UDP不需要建立稳定的连接,所以数据可能不能安全到达,但是速度快。另外,服务器中绑定的UDP端口与TCP端口互不冲突。

     注:本文为学习廖雪峰Python入门整理后的笔记

  • 相关阅读:
    评教说明
    使用firebird2.1与dbEntry.net做的设备报修小程序
    不知道为什么IList.Contains()总是返回FALSE
    DbEntry.net复合索引设置
    招生网上报名程序090512.rar
    aspnetdb生成
    推荐工具ActiveWriter
    dbEntry.net CK.K的高级应用
    tomcat添加虚拟子目录
    短信网关与短信猫
  • 原文地址:https://www.cnblogs.com/likely-kan/p/7545242.html
Copyright © 2020-2023  润新知