博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2020-04-12 18:34  隐灰子  阅读(208)  评论(0编辑  收藏  举报

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,因此服务器可以通过

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