• 06.python—网络编程学习笔记


    python基础知识已经学习结束,今天开始将进行网络编程的学习,加油,you are great!

    1.网络编程基本概念

    1.1网络通信概述

    网络是辅助双方或者多方连接在一起的工具。

    使用网络的目的:联通多方然后进行通信用的,即把数据从一方传递到另外一方。

    为了让在不同的电脑上运行的软件,之间能够互相传递数据,就需要使用网络。

    总结:

          1. 使用网络可以将多方连接在一起,然后进行数据传递。

          2.所谓的网络编程,让在不同电脑上运行的软件进行数据传递,即进程之间的通信。

    1.2 IP地址

    1.什么是地址?

    地址是用来标记地点的。

    2.什么叫IP地址及IP地址的作用?

    用来标记网络上的一台电脑。类似192.168.243.1,在本地局域网上是唯一的。

    1.3Linux、Windows查看网卡信息

    查看网卡信息

    linux: ifconfig

    windows:ipconfig/ 也可以直接在界面看

    关闭网卡:

    Linux:sudo ifconfig ens40 down  (ens40为命令框左侧的网卡名称)

    开启网卡:

    Linux:sudo ifconfig ens40 up  (ens40为命令框左侧的网卡名称)

    1.4 IP地址的分类IPv4和IPv6介绍

    IPV4: 一串数字xxx.xxx.xxx.xxx,共有256*256*256*256 

    ipv6:量级很大,号称地球上的每一粒沙都可以有一个IP,目前还在发展中。

    每一个IP地址包括两个部分,网络地址和主机地址。

    IP地址分成5类

    A类IP:前1个数字是网络号,后3个数字是主机号(其中0和255不可用)

    B类IP:前两个数字是网络号,后两个数字是主机号。

    C类IP:前三个数字是网络号,后1个数字是主机号

    D类IP:用于多点广播。第一个字节是1110开头。

    E类IP:保留地址。

    1.5端口

    IP标示主机,端口来表示主机上的程序。

    1.6端口分类:知名端口、动态端口

    知名端口:大家都默认使用的端口,范围从0~1023

    如80端口分配给http服务

       21端口分配给FTP

    一个程序 要用知名端口,一定要有root权限。

    动态端口:范围是1024~65535

    动态分配是指当一个系统或应用程序需要网络通信时,它向主机申请一个端口,主机从

    可用的端口中分配一个供它使用,当程序关闭时,同时释放所占用的端口号。

    怎么查看端口号?

    用“netstat -an"查看端口状态

    lsof -i[tcp/udp]:2425

    1.7socket介绍

    一台电脑上可以通过进程号pid唯一标识一个进程,网络中的进程则需要IP,协议,端口号一起来标识。

    socket(简称套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同:

    它能实现不同主机间的进程间通信,网络上各种各样的服务大多是基于socket来完成通信的。

    套接字的使用流程与文件的使用流程类似

    创建套接字;使用套接字收/发数据;关闭套接字

    python中使用socket模块的函数socket完成。

    import socket
    socket.socket(AddressFamily,Type)

    socket函数参数解释

    AddressFamily:可以选择AF_INET(就是IPv4)或者AF_UNIX
    Type:套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据套接字,主要用于UDP协议)

    2.UDP

    2.1 UDP发送数据demo

    通过python的socket模块创建套接字,使用udp发送数据。

    import socket
    
    
    def main():
        # 创建一个udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 可以使用套接字收发数据
        # udp_socket.sendto("hahahah", 对方的ip以及port)
        udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
    
        # 关闭套接字
        udp_socket.close()
    
    
    if __name__ == "__main__":
        main()

    桥接:在这里的作用,主要是将两个IP的网络号变成一样,只有网络号一样,才能进行通信。

    选择桥接之后,可以在命令框里输入sudo dhclient(请求别人分享一个IP)

    2.2关闭VMware的虚拟网卡

    开启vm,会有虚拟IP产生,如果要进行网络调试的话,可以将虚拟网卡进行禁用。

    2.3UDP发送数据的强调

    主要是python的语法错误,如缩进等,此处省略。

    2.4运行python程序以及python交互模式,encode编码,发送udp的练习

     1.python3要用sendto发送数据,必须是bytes类型,所以在字符串前面加一个b

    发送任意数据

    import socket
    
    def main():
        # 创建一个udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 从键盘获取数据
        send_data = input("请输入要发送的数据:")
    
        # 可以使用套接字收发数据
        # udp_socket.sendto("hahahah", 对方的ip以及port)
        # udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
        udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.53", 8080))
    
    
        # 关闭套接字
        udp_socket.close()
        
    
    if __name__ == "__main__":
        main()

    带有退出功能的循环发送:

    import socket
    
    def main():
        # 创建一个udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        while True:
    
            # 从键盘获取数据
            send_data = input("请输入要发送的数据:")
    
            # 如果输入的数据是exit,那么就退出程序
            if send_data == "exit":
                break
    
            # 可以使用套接字收发数据
            # udp_socket.sendto("hahahah", 对方的ip以及port)
            # udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
            udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.53", 8080))
    
    
        # 关闭套接字
        udp_socket.close()
        
    
    if __name__ == "__main__":
        main()

    2.5接收udp数据

    循环接收并显示数据

    import socket
    
    def main():
        # 1. 创建套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 2. 绑定一个本地信息
        localaddr = ("", 7788)
        udp_socket.bind(localaddr)  # 必须绑定自己电脑的ip以及port,其他的不行
    
        # 3. 接收数据
        while True:
            recv_data = udp_socket.recvfrom(1024)
            # recv_data这个变量中存储的是一个元组(接收到的数据,(发送方的ip, port))
            recv_msg = recv_data[0]  # 存储接收的数据
            send_addr = recv_data[1]  # 存储发送方的地址信息
            # 4. 打印接收到的数据
            # print(recv_data)
            # print("%s:%s" % (str(send_addr), recv_msg.decode("utf-8")))
            print("%s:%s" % (str(send_addr), recv_msg.decode("gbk")))
        # 5. 关闭套接字
        udp_socket.close()
    
    if __name__ == "__main__":
        main()

    2.6端口绑定的问题

     绑定端口后在循环发送,否则每次打开都是用系统随机端口进行发送

    import socket
    
    def main():
        # 创建一个udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 绑定本地信息
        udp_socket.bind(("", 7890))
    
        while True:
    
            # 从键盘获取数据
            send_data = input("请输入要发送的数据:")
    
            # 可以使用套接字收发数据
            # udp_socket.sendto("hahahah", 对方的ip以及port)
            # udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
            udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.53", 8080))
    
    
        # 关闭套接字
        udp_socket.close()
        
    
    if __name__ == "__main__":
        main()

    2.7网络中的重要概念复习

     1.IP类补充——私有ip

    只能在局域网使用,不能在公网使用的IP。

    A类:10.0.0.0~10.255.255.255

    B类:172.16.00~172.31.255.255

    C类:192.168.0.0~192.168.255.255

    2.8输入对方IP,port,全双工,半双工,单工等

     同一个套接字既可以收也可以发

    import socket
    
    def main():
        # 创建一个udp套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 获取对方的ip/port
        dest_ip = input("请输入对方的ip:")
        dest_port = int(input("请输入对方的port:"))
    
        # 从键盘获取数据
        send_data = input("请输入要发送的数据:")
    
        # 可以使用套接字收发数据
        # udp_socket.sendto("hahahah", 对方的ip以及port)
        # udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
        # udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.53", 8080))
        udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
    
        # 接收回送过来的数据
        recv_data = udp_socket.recvfrom(1024)
        # 套接字是一个可以同时 收发数据
        print(recv_data)
    
    
        # 关闭套接字
        udp_socket.close()
        
    
    if __name__ == "__main__":
        main()

    recvfrom在没有收到消息时,会出现堵塞。

    单工:只能单向,要么发,要么只能收。

    半双工:可以发,也可以收,但是同一时刻只能发或者收。

    全双工:同一时刻既可以发也可以收。socket就属于全双工。

    2.9案例:udp聊天器

    import socket
    
    
    def send_msg(udp_socket):
        """发送消息"""
        # 获取要发送的内容
        dest_ip = input("请输入对方的ip:")
        dest_port = int(input("请输入对方的port:"))
        send_data = input("请输入要发送的消息:")
        udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
    
    
    def recv_msg(udp_socket):
        """接收数据"""
        recv_data = udp_socket.recvfrom(1024)
        print("%s:%s" % (str(recv_data[1]), recv_data[0].decode("utf-8")))
    
    
    def main():
        # 创建套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 绑定信息
        udp_socket.bind(("", 7788))
    
        # 循环循环来进行处理事情
        while True:
            print("-----xxx聊天器-----")
            print("1:发送消息")
            print("2:接收消息")
            print("0:退出系统")
            op = input("请输入功能:")
    
            if op == "1":
                # 发送
                send_msg(udp_socket)
            elif op == "2":
                # 接收并显示
                recv_msg(udp_socket)
            elif op == "0":
                break
            else:
                print("输入有误请重新输入...")
    
    if __name__ == "__main__":
        main()

    3.TCP

    3.1 tcp介绍

    tcp就是传输控制协议。

    tcp通信需要经过创建链接、数据传送、终止链接三个步骤。

    tcp通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于“打电话”。

    udp通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似生活中的“写信”。不太安全。

    3.1.1TCP特点

    a. 面向链接(这种连接是一对一的tcp不适用于广播的应用程序,基于广播的使用udp协议)

    b.可靠传输(发送应答机制、超时重传、错误校验、流量控制和阻塞管理)

    3.2 TCP与UDP的不同点

    a.面向连接(确认创建三方交握,链接已创建才能传输)

    b.有序的数据传输

    c.重发丢失的数据包

    d.舍弃重复的数据包

    e.无差错的数据传输

    f.阻塞与流量控制

    (TCP通信模型UDP通信模型)

    3.2 tcp客户端

    import socket
    
    
    def main():
        # 1. 创建tcp的套接字
        tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 2. 链接服务器
        # tcp_socket.connect(("192.168.33.11", 7890))
        server_ip = input("请输入要链接的服务器的ip:")
        server_port = int(input("请输入要链接的服务器的port:"))
        server_addr = (server_ip, server_port)
        tcp_socket.connect(server_addr)
    
        # 3. 发送数据/接收数据
        send_data = input("请输入要发送的数据:")
        tcp_socket.send(send_data.encode("utf-8"))
    
        # 4. 关闭套接字
        tcp_socket.close()
    
    
    if __name__ == "__main__":
        main()

    3.3 tcp服务器

    tcp服务器流程

    a.socket创建一个套接字

    b.bind绑定IP和port

    c.listen使套接字变为可以被动链接

    d.accept等待客户端的链接

    e.接收/发送数据

    import socket
    
    def main():
        # 1. 买个手机(创建套接字 socket)
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 2. 插入手机卡(绑定本地信息 bind)
        tcp_server_socket.bind(("", 7890))
    
        # 3. 将手机设置为正常的 响铃模式(让默认的套接字由主动变为被动 listen)
        tcp_server_socket.listen(128)
    
        print("-----1----")
        # 4. 等待别人的电话到来(等待客户端的链接 accept)
        new_client_socket, client_addr = tcp_server_socket.accept()
        print("-----2----")
    
        print(client_addr)
    
        # 接收客户端发送过来的请求
        recv_data = new_client_socket.recv(1024)
        print(recv_data)
    
        # 回送一部分数据给客户端
        new_client_socket.send("hahahghai-----ok-----".encode("utf-8"))
    
        # 关闭套接字
        new_client_socket.close()
        tcp_server_socket.close()
    
    
    if __name__ == "__main__":
        main()

    注:监听套接字只为接收客户端,接收到之后,会指派一个新的套接字用于与客户端的通信。

    3.4 案例:下载文件(待补充)

    3.5知识点快速总结,listen里的参数(待补充)

    3.6 QQ不绑定端口、昨日知识点复习

    TCP注意点:

    1)tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器。

    2)tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip,port等信息就好,本地

        客户端可以随机。

    3)tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动,这是做tc p服务器时必须要做的。

    4)当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接而是直接发送,但是tcp必须

       先链接,只有链接成功才能通信。

    5)当一个TCP客户端连接服务器时,服务器会有一个新的套接字,这个套接字用来标记这个客户端,单独为这个

       客户端服务

    6)listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的

    7)关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端

        正常通信。

    8)关闭accept返回的套接字意味着这个客户端已经服务完毕

    9)当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过

       返回数据的长度来区别客户端是否已经下线。

  • 相关阅读:
    记:关于反演
    记:关于费马平方和定理的证明
    【2021集训队互测一】愚蠢的在线法官 题解
    CSP/NOIP2021 赛前集训
    20220108 省选组 总结
    Atcoder比赛总结
    Python读取execl数据写入到mysql
    大家都可以拖动的web小方块——Node.js摸石头系列之七
    创建一个Mybatis工程
    Spring整合Mybatis
  • 原文地址:https://www.cnblogs.com/hongchenlianxinlu/p/12686826.html
Copyright © 2020-2023  润新知