• python 网络编程


    一、网络基础

      1、mac地址(我的电脑上有网卡,网卡上有mac地址)

        head中包含的源和目标地址由来:ethernet规定接入internet的设备都必须具备网卡,发送端和接收端的地址便是指网卡的地址,即mac地址。

        mac地址:每块网卡出厂时都被烧制上一个世界唯一的mac地址,长度为48位2进制,通常由12位16进制数表示(前六位是厂商编号,后六位是流线号)

      2、ip地址(我到某个地方插上网线,路由器或交换机中的DHCP服务为我自动分配IP地址。)

        IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的

        地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

        IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,

        其中,a,b,c,d都是0~255之间的十进制整数。例如:   

       IP: 192.168.13.84
    IPv4
    00000000.00000000.00000000.00000000
    0~255 0~255 0~255 0~255
    IPv6
    00000000.00000000.00000000.00000000.00000000.00000000
      3、子网掩码
        所谓”子网掩码”,就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分全部为1,主机部分全部为0。比如,IP地址172.16.10.1,
        如果已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。
        知道”子网掩码”,我们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,否则为0),然后比较结果是否相同,
        如果是的话,就表明它们在同一个子网络中,否则就不是。 例如:
    比如,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?两者与子网掩码分别进行AND运算,
    
    172.16.10.1:10101100.00010000.00001010.000000001
    255255.255.255.0:11111111.11111111.11111111.00000000
    AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
    
     
    
    172.16.10.2:10101100.00010000.00001010.000000010
    255255.255.255.0:11111111.11111111.11111111.00000000
    AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
    结果都是172.16.10.0,因此它们在同一个子网络。

       4、网关ip(网关是路由器与服务器的接口)

        一个局域网的网关IP通常是ip地址的第四个点分十进制为1

        如一个局域网中的某台电脑的ip地址为   192.168.13.84    那么网关ip通常为192.168.13.1

       5、arp协议 ——查询IP地址和MAC地址的对应关系    

       地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议
       主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;
       收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
      6、端口 ————端口是为了将同一个电脑上的不同程序进行隔离。
       IP是找电脑
       端口是找电脑上的程序
           示例:     
           MySQL是一个软件,软件帮助我们在硬盘上进行文件操作。默认端口:3306
            Redis是一个软件,软件帮助我们在内存里进行数据操作。默认端口:6379
        网站默认端口:80 ,访问时:http://www.luffycity.com:80
        网站默认端口:443 ,访问时:https://www.luffycity.com:443

          范围:
        1 - 65535
        1 - 1024

       一般情况:
      8000
      8001
       7、DNS服务器
        DNS(Domain Name Server,域名服务器)是进行域名(domain name)和与之相对应的IP地址 (IP address)转换的服务器。
         - 域名解析
            www.luffycity.com  47.95.64.113
        www.oldboyedu.com 101.200.195.98
         - 连接
        sk = socket.socket()
        sk.connect(('47.95.64.113',80))
        问题来了,域名和IP的对应关系在哪里?
          本地:
      Win本地电脑:
      C:WindowsSystem32driversetchosts
    11.11.11.11 luffycicy.com
      Linux/Mac电脑:
      /etc/hosts

      DNS服务器:全球顶级DNS服务器13台
      www.luffycity.com 47.95.64.113
       8、网络划分
         局域网
          广播
            主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要),
            由于其不用路径选择,所以其网络成本可以很低廉。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。
            在数据网络中也允许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。
          单播
    广播风暴
         城域网
         广域网
       9、TCP协议与UDP协议
        TCP协议
         TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;
         电子邮件、文件传输程序。
         当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“握手”之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的通信。
         三次握手、四次挥手模型
        

         

        以下为三次握手,四次挥手的白话版本:

          socket客户端向服务端发起连接请求:三次握手

                    client.connect((....))
    客户端 服务端
    我能打你吗
    来呀来呀
    好的,我这就来
    -----------------------------
    client.send('发送数据')
    收发数据 收发数据

    客户端和服务端断开连接:四次挥手
    client.close() 或 conn.close()
    -----------------------------
    我要断开连接
    断开就断开,等我处理一些手头的事情
    ...
    我处理完了,断开吧。
    拜拜



         补充:断开连接时,反应到代码上:抛出异常/发送空内容;
       UDP协议:
         UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。
         使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。
        

              

       10、OSI七层模型

        7层:

          自己写的代码:自己代码+框架
      应用层,使用软件。 打开软件或网站
      表示层,看到数据,如图片和视频。 生产数据:szwwd
      会话层,保持登录或链接状态。 应用偷偷携带一点其他数据:令牌 19rRNAwf8GVe6xyT9kJPIu5SlQc

      socket模块:
      传输层,TCP/UDP [TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]
      网络层,IP 【IP】【[TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]】
      数据链路层,MAC [MAC][【IP】【[TCP][szwwd|19rRNAwf8GVe6xyT9kJPIu5SlQc]】]
      物理层,将数据转换成电信号发送

            

                    

                    

    二、软件开发的架构

      1.C/S架构

        C/S即:Client与Server ,中文意思:客户端与服务器端架构,这种架构也是从用户层面(也可以是物理层面)来划分的。

        这里的客户端一般泛指客户端应用程序EXE,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。
     2.B/S架构
        B/S即:Browser与Server,中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的。

        Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要大家去安装什么应用程序,只需在浏览器上通过HTTP请求服务器端相关的资源(网页资源),客户端Browser浏览器就能进行增删改查。
    三、socket(套接字)
      1、理解socket
        Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,
        让Socket去组织数据,以符合指定的协议。
    2、网络编程事例
    import socket
    
    # 创建服务端socket对象
    server = socket.socket()
    
    # 绑定IP和端口
    server.bind(('192.168.13.155',8000))
    
    # 后边可以等5个人
    server.listen(5)
    
    print('服务端准备开始接收客户端的连接')
    # 等待客户端来连接,如果没人来就傻傻的等待。
    # conn是客户端和服务端连接的对象(伞),服务端以后要通过该对象进行收发数据。
    # addr是客户端的地址信息。
    # #### 阻塞,只有有客户端进行连接,则获取客户端连接然后开始进行通信。
    conn,addr = server.accept()
    
    print('已经有人连接上了,客户端信息:',conn,addr)
    
    # 1024表示:服务端通过(伞)获取数据时,一次性最多拿1024字节。
    data = conn.recv(1024)
    print('已经有人发来消息了',data)
    
    # 服务端通过连接对象(伞)给客户端回复了一个消息。
    conn.send(b'stop')
    
    # 与客户端断开连接(放开那把伞)
    conn.close()
    
    # 关闭服务端的服务
    server.close()
    服务器端
    import socket
    
    client = socket.socket()
    
    # 向服务端发起连接请求(递伞)
    # 阻塞,去连接,直到连接成功后才会继续向下走。
    client.connect(('192.168.13.155',8000))
    
    # # 链接上服务端后,向服务端发送消息
    client.send(b'hello')
    
    # 等待服务端给他发送消息
    data = client.recv(1024)
    print(data)
    
    # 关闭自己
    client.close()
    客户端

      3、黏包

           黏包成因:

          黏包现象只发生在tcp协议中:

          1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

          2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

       黏包的解决方案:

          引入struct模块,构建报头数据

    import struct    #将一定长度的数字类型转换成固定长度的四个字节
    
    res=struct.pack("i",12345)
    print(res)      #b'90x00x00'
    print(len(res))  #4
    print(type(res))   #<class 'bytes'>
    
    
    obj=struct.unpack("i",res)
    print(obj)     #(12345,)
    print(obj[0])   #12345
    print(type(obj[0]))    #<class 'int'>
    struct模块的作用
    import subprocess      #执行终端命令
    
    res=subprocess.Popen("dir",
                         shell=True,
                         stderr=subprocess.PIPE,
                         stdout=subprocess.PIPE)
    print(res.stdout.read().decode("gbk"))    #执行终端的dir命令,打印当前目录下的文件信息
    subprocess模块
    import struct
    import socket
    import json
    import hashlib
    
    sock=socket.socket()
    sock.bind(('127.0.0.1',8800))
    sock.listen(5)
    while 1:
        print("server is working....")
        conn,addr= sock.accept()
        while 1:
    
            # 接收json的打包长度
            file_info_length_pack=conn.recv(4)
            file_info_length=struct.unpack("i",file_info_length_pack)[0]
    
            # 接收json字符串
            file_info_json=conn.recv(file_info_length).decode("utf8")
            file_info=json.loads(file_info_json)
    
            action=file_info.get("action")
            filename=file_info.get("filename")
            filesize=file_info.get("filesize")
    
            # 循环接收文件
            md5=hashlib.md5()
            with open("put/"+filename,"wb") as f:
                recv_data_length=0
                while recv_data_length<filesize:
                    data=conn.recv(1024)
                    recv_data_length+=len(data)
                    f.write(data)
                    # MD5摘要
                    md5.update(data)
                    print("文件总大小:%s,已成功接收%s"%(filesize,recv_data_length))
    
            print("接收成功!")
            conn.send(b"OK")
            print(md5.hexdigest())
            md5_val=md5.hexdigest()
            client_md5=conn.recv(1024).decode("utf8")
            if md5_val==client_md5:
                 conn.send(b"203")
            else:
                 conn.send(b"204")
    server端
    import socket
    import os
    import json
    import struct
    import hashlib
    
    sock=socket.socket()
    sock.connect(("127.0.0.1",8800))
    while 1 :
        cmd=input("请输入命令:") # put 111.jpg
    
        action,filename=cmd.strip().split(" ")
        filesize=os.path.getsize(filename)
    
        file_info={
            "action": action,
            "filename": filename,
            "filesize": filesize,
        }
        file_info_json=json.dumps(file_info).encode("utf8")
    
        ret=struct.pack("i",len(file_info_json))
        # 发送 file_info_json的打包长度
        sock.send(ret)
        # 发送 file_info_json字节串
        sock.send(file_info_json)
        # 发送 文件数据
        md5=hashlib.md5()
        with open(filename,"rb") as f:
            for line in f:
                sock.send(line)
                md5.update(line)
    
        data=sock.recv(1024)
        print(md5.hexdigest())
        md5_val=md5.hexdigest()
        sock.send(md5_val.encode("utf8"))
        is_valid=sock.recv(1024).decode('utf8')
        if is_valid=="203":
            print("文件完整!")
        else:
            print("文件上传失败!")
    client端

    四、socketserver(实现并发操作)

    import socketserver
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            self.request
            self.client_address
            self.server
            # 编写代码
    
    server = socketserver.ThreadingTCPServer(('192.168.13.84',8001,),MyServer)
    """
    server.server_address = server_address
    server.RequestHandlerClass = RequestHandlerClass
    server.__is_shut_down = threading.Event()
    server.__shutdown_request = False
    server.socket = socket....
        - socket.bind
        - socket.listen
    """
    server.serve_forever()
    解析socketserver
    import threading
    import requests
    import uuid
    
    url_list = [
        'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg',
        'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
        'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg',
    ]
    
    def task(url):
        """"""
    
        """
        1. DNS解析,根据域名解析出IP
        2. 创建socket客户端    sk = socket.socket()
        3. 向服务端发起连接请求 sk.connect()
        4. 发送数据(我要图片) sk.send(...)
        5. 接收数据            sk.recv(8096)
    
        接收到数据后写入文件。
        """
        ret = requests.get(url)
        file_name = str(uuid.uuid4()) + '.jpg'
        with open(file_name, mode='wb') as f:
            f.write(ret.content)
    
    for url in url_list:
    
        t = threading.Thread(target=task,args=(url,))
        t.start()
    基于多线程编写简单的爬虫
    import uuid    #生成随机的字符串
    v = str(uuid.uuid4())
    print(v)     #834a64c0-2850-4822-8241-f5776e06dd14
    uuid模块的使用
    import os
    size = os.stat(r'D:sylars15day311.进度条.py').st_size
    print(size)      #计算文件的大小
    
    
    #也可使用os.path.getsize('文件路径')   来获取文件的大小
    如何获取文件大小
    import shutil
    shutil.move('c.txt','a.txt')    #修改文件名称
    
    shutil.rmtree('文件路径')     #删除文件夹
    shutil模块修改文件名称或者删除文件夹

     




    
    
    
    
        



  • 相关阅读:
    sql TRUNCATE 和 delete 的区别
    visual studio 2005 service pack 1
    gac 详细的步骤
    简单判断用户重复登录,记录一下
    [转]在SQL Server中使用CLR调用.NET方法
    xml 解析之 JDOM解析
    Java反射机制——反射 API(Day_04)
    结合JVM 浅谈Java 类加载器(Day_03)
    jsoup select 选择器(Day_02)
    SQLite在Android中的使用
  • 原文地址:https://www.cnblogs.com/fengchong/p/9620854.html
Copyright © 2020-2023  润新知