• Python 网路编程读书笔记x UDP


    UDP 协议基础

    在IP网络层,所有的数据包会向一个指定的主机传输

    Source IP  -> Destination IP

    但是两台机器之间可能有许多独立的应用需要进行通信,因此为了区分不同的应用,所以有了端口号(port number)

    Source (IP : port number) -> Destination (IP : port number)

    通过这四个变量就可以确定一个特定的会话。

    在Client 和 Server 进行通信时,通过Server会被分配一个固定的端口号。例如DNS服务器 port 53

    而 Client 会有一个随机选取的端口号 例如 Pport 4137

    UDP 协议会直接把数据包从Source 传递到 Destination 

    但是

    Client如何知道Server的端口号是多少?

    1. Convention:IANA组织已经为许多知名的服务分配了固定的端口号,例如 Port 53 是DNS

    2. Automatic configuration:当一个计算机第一次接入网络中时,可以使用DHCP协议获取服务的IP地址,通过将获取的IP地址与常用的服务的端口号结合,就可以访问该服务

    3. Manual configuration: 在剩下的情况中,可以采用人工分配。每一次在获取一个服务的时候,输入IP地址和端口号。

    IAAN 端口号分配

     Well known ports (0-1023)最常见和广泛使用的服务的端口号。在Unix 系统中,这些端口号不能被用户程序使用,以避免恶意程序伪装成重要的服务。

     Registered ports (1024-19151)这些端口,通常不会被操作系统认为是特殊的服务,用户编写的程序可以使用这些端口。但是这些端口可以向IANA注册特殊的服务。IANA推荐最好避免将端口分配给不相关的程序。

     The remaining port numbers (49152–65535) 这些端口都可以自由使用的,Client 随机选择端口号是通常从这里选择。

    每一个端口号,有一个非数字的名字。在Python中可以使用getserverbyname 来获取这些非 数字 的名字 对应的端口号。

    import socket
    socket.getservbyname('domain')

    例如以上代码可以获取 domain 服务的端口号 “53”

    著名的服务名称及其端口号通常存储在linux 和mac 的 /etc/services 目录下。

    Sockets

    import argparse, socket
    from datetime import datetime
    MAX_BYTES = 65535
    def server(port):
      sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      sock.bind(('127.0.0.1', port))
      print('Listening at {}'.format(sock.getsockname()))
      while True:
        data, address = sock.recvfrom(MAX_BYTES)
        text = data.decode('ascii')
        print('The client at {} says {!r}'.format(address, text))
        text = 'Your data was {} bytes long'.format(len(data))
        data = text.encode('ascii')
        sock.sendto(data, address)
    def client(port):
      sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      text = 'The time is {}'.format(datetime.now())
      data = text.encode('ascii')
      sock.sendto(data, ('127.0.0.1', port))
      print('The OS assigned me the address {}'.format(sock.getsockname()))
      data, address = sock.recvfrom(MAX_BYTES) # Danger!
      text = data.decode('ascii')
      print('The server {} replied {!r}'.format(address, text))

    在以上的代码中使用socket()方法创建了一个socket, AF_INET 是socket 种类, 而SOCK_DGRAME 是数据包数据类型,意味这它将在IP网络中使用UDP。

    该socket 之后会通过blind 方法和一个(IP,port)绑定在一起。(如果端口号已经被使用,那么这个步骤会失败。OSError: [Errno 98] Address already in use)

    socket.getsockname() 会返回一个包含IP地址和端口号的元组。

    socket.recvfrom(MAX_BYTES) 告诉程序server 将会接受最大长度为65535的报文。recvfrom 会一直等待,直到从客户端成功收到一个数据。

    一旦收到了报文,recvform()将会返回client 地址 以及它发送的数据包的内容。 使用python 将这些数据包转换成字符串,并输出。

    if __name__ == '__main__':
        choices = {'client': client, 'server': server}
        parser = argparse.ArgumentParser(description='Send and receive UDP locally')
        parser.add_argument('role', choices=choices, help='which role to play')
        parser.add_argument('-p', metavar='PORT', type=int, default=1060,help='UDP port (default 1060)')
        args = parser.parse_args()
        function = choices[args.role]
        function(args.p)

    这段代码,通过命令行参数选择执行客户端还是服务器,程序。 -p 用来设置端口号

     PROMISCUOUS CLIENT

     一个客户端可能会接收并记录它收到的所有的数据包,而且不会考虑该数据包是否来自正确的地址,这样的client 称之为 promiscuous client。

    这样的client 可以用来对网络进行监控,然而他也有可能产生问题,使得client 收到虚假的数据包。为了避免这个问题需要做亮点检查

  • 相关阅读:
    8 -- 深入使用Spring -- 5...3 使用@CacheEvict清除缓存
    8 -- 深入使用Spring -- 5...2 使用@Cacheable执行缓存
    tomcat 的 server.xml配置文件
    WEB-INF目录与META-INF目录的作用
    一个tomcat设置多个端口,多个端口对应多个应用
    8 -- 深入使用Spring -- 5...1 启用Spring缓存
    8 -- 深入使用Spring -- 5... Spring 3.1 新增的缓存机制
    8 -- 深入使用Spring -- 4...6 AOP代理:基于注解的XML配置文件的管理方式
    eclipse中设置文件的编码格式为utf-8
    MySQL 触发器简单实例
  • 原文地址:https://www.cnblogs.com/xiexindut/p/4192563.html
Copyright © 2020-2023  润新知