Python-Level2-day10:网络传输基础知识,UDP套接字传输方法实现

1. 网络编程

1.1 网络基础知识

1.1.1 什么是网络

  • 什么是网络 : 计算机网络功能主要包括实现资源共享,实现数据信息的快速传递。

1.1.2 网络通信标准

  • 面临问题

    1. 不同的国家和公司都建立自己的通信标准不利于网络互连

    2. 多种标准并行情况下不利于技术的发展融合

  • OSI 7层模型img编辑 蓝色部分是应用层工程师完成,绿色是通信运维工程师完成

    • 好处

      1. 建立了统一的通信标准

      2. 降低开发难度,每层功能明确,各司其职

      3. 七层模型实际规定了每一层的任务,该完成什么事情

  • TCP/IP模型

    • 七层模型过于理想,结构细节太复杂

    • 在工程中应用实践难度大

    • 实际工作中以TCP/IP模型为工作标准流程,每个层都有自己的协议规范,我们只需要遵循每层次对应的协议进行编程即可。img编辑

  • 网络协议

    • 什么是网络协议:在网络数据传输中,都遵循的执行规则。

    • 网络协议实际上规定了每一层在完成自己的任务时应该遵循什么规范。

  • 需要应用工程师做的工作 : 编写应用工功能,明确对方地址,选择传输服务。

1.1.3 通信地址

  • IP地址

    • IP地址 : 即在网络中标识一台计算机的地址编号。

    • IP地址分类

      • IPv4 : 192.168.1.5

      • IPv6 :fe80::80a:76cf:ab11:2d73

    • IPv4 特点

      • 分为4个部分,每部分是一个整数,取值分为0-255

    • IPv6 特点(了解)

      • 分为8个部分,每部分4个16进制数,如果出现连续的数字 0 则可以用 ::省略中间的0

    • IP地址相关命令

      • ifconfig : 查看Linux系统下计算机的IP地址img编辑 本机测试地址不能与其他计算机通信

      • ping [ip]:查看计算机的连通性

    • 公网(外网)IP和内网(私网,局域网)IP

      • 公网IP指的是连接到互联网上的公共IP地址,大家都可以访问。

      • 内网IP指的是一个局域网络范围内由网络设备分配的IP地址。

      • 不同网段内的ip地址可以相同,同一个网段内必不同。内网ip在同一局域网内可以通信,不同局域网不能通信,需要借助公网。

      img编辑

  • 端口号

    • 端口:网络地址的一部分,在一台计算机上,每个网络程序对应一个端口。

    • 端口号特点

      • 取值范围: 0 —— 65535 的整数

      • 一台计算机上的网络应用所使用的端口不会重复,操作系统每次自动随机分配

      • 通常 0——1023 的端口会被一些有名的程序或者系统服务占用,个人一般使用 > 1024的端口

1.1.4 服务端与客户端

  • 服务端(Server):服务端是为客户端服务的,服务的内容诸如向客户端提供资源,保存客户端数据,处理客户端请求等。端口固定的

  • 客户端(Client) :也称为用户端,是指与服务端相对应,为客户提供一定应用功能的程序,我们平时使用的手机或者电脑上的程序基本都是客户端程序。端口是操作系统自动分配的

1.2 UDP 传输方法

1.2.1 套接字简介

  • 套接字(Socket) : 实现网络编程进行数据传输的一种技术手段,网络上各种各样的网络服务大多都是基于 Socket 来完成通信的。

  • Python套接字标准库编程模块:import socket

1.2.3 UDP套接字编程

  • 创建套接字

    sockfd=socket.socket(family,type)
    功能:创建套接字
    参数:family  网络地址类型 AF_INET表示ipv4(默认就是这个参数)
         type    套接字类型 SOCK_DGRAM 表示udp套接字 (也叫数据报套接字) 
    返回值: 套接字对象
  • 绑定地址(只有服务端将端口固定,客户端一般不用写)

    • 本地地址 : 'localhost' , '127.0.0.1'-------本地测试ip(即别人不能通过网络访问你,只能自己访问自己,叫测试,模拟网络访问)

    • 网络地址 : '172.40.91.188' (通过ifconfig查看)

    • 自动获取地址: '0.0.0.0' 程序猿基本直接写这个地址

    sockfd.bind(addr)
    功能: 绑定服务端本机网络地址
    参数: 二元元组 (ip,port)  ('0.0.0.0',8888)

img编辑

"""
    套接字的基础函数示例
"""
import socket
​
# 创建udp套接字对象,即选择udp网络服务。
udp_socket = socket.socket(socket.AF_INET,
                           socket.SOCK_DGRAM)
​
# 服务端绑定地址3个方法
​
# 1 测试地址  客户端通过127.0.0.1访问且需在同一计算机写客户端程序数据传输
# udp_socket.bind(("127.0.0.1",8888))
​
# 2  网络地址  客户端通过192.168.159.136访问,端口号随意不与其他运行的程序冲突就绪
#             本机可以访问服务端,同一个网段内的其他主机也可以访问这个计算机服务端。
udp_socket.bind(("192.168.159.136", 8888))
​
# 3 自动检测合适网卡地址 等同以上两种情形
# udp_socket.bind(("0.0.0.0", 8888))
​

  • 消息收发

    data,addr = sockfd.recvfrom(buffersize)
    功能: 接收UDP消息
    参数: 每次最多接收多少字节--发多了我就丢弃
    返回值: data  接收到的内容,必须字节串
            addr  自动获取到消息发送方地址
​
    n = sockfd.sendto(data,addr)
    功能: 发送UDP消息
    参数: data  发送的内容 必须字节串格式
          addr  目标地址
    返回值:发送的字节数

  • 关闭套接字

    sockfd.close()
    功能:关闭套接字
"""
udp服务端流程示例
    重点代码
"""
from socket import *
​
# 创建udp套接字
udp_socket = socket(type=SOCK_DGRAM)  # 第一个不写参数默认ipv4,只写第二个参数用关键字传参UDP服务
​
# 服务端需要绑定端口,客户端也可以不需要绑定端口,操作系统帮你自动分配
udp_socket.bind(("0.0.0.0", 8888))
​
#  服务端先接收数据 (recvfrom阻塞函数:执行到他是时候暂停了,等满足执行条件才会执行,即有数据发过来)
while True:
    data, addr = udp_socket.recvfrom(4)  # 返回值是元组
    if data == b'##':  # 服务器端是一个长期运行,不能退出
        break
    print("从客户端地址", addr, "收到:", data.decode())  # 客户端口操作系统随机分配
    n = udp_socket.sendto(b"Thankss", addr)
    print("服务端发送了Thankss给客户端:%d bytes" % n)
​
# 关闭套接字
udp_socket.close()
​
​
"""
udp客户端访问流程
    重点代码
    自此以后调试基本用不上了,多个程序配合不好用
"""
from socket import *
​
# 服务端地址,端口号要与服务端一样
ADDR = ("127.0.0.1", 8888)
​
# 创建udp套接字:要与服务端选择相同的UDP套接字协议
udp_socket = socket(AF_INET, SOCK_DGRAM)
​
# 循环发送接收消息 与服务端配置
while True:
    msg = input(">>")
    udp_socket.sendto(msg.encode(), ADDR)
    if msg == "##":
        break
    data, addr = udp_socket.recvfrom(1024)
    print(data.decode(), addr)
​
udp_socket.close()
​
# 客户端可以绑定自己的地址,但是么有必要,因为别人不访问你
# 客户端不需要知道自己地址是多少,因为服务端口会自动获取你的地址
​
​
​
练习01:
编写一个udp服务端和客户端程序完成下面功能
从客户端输入单词,发送给服务端,然后从服务端得到
单词解释打印出来  输入##退出
服务端可以利用 dict数据库进行单词查找
​
plus版: 使用面向对象编程完成
编程序规矩记住
​
"""
    客户端
"""
from socket import *
​
# 服务端地址
ADDR = ("127.0.0.1", 8000)
​
​
class QueryWord:
    def __init__(self):
        self.sock = socket(type=SOCK_DGRAM)
​
    def close(self):
        self.sock.close()
​
    def query(self):
        while True:
            word = input("Word:")
            if not word:
                break
            self.sock.sendto(word.encode(), ADDR)
            mean, addr = self.sock.recvfrom(1024)
            print("%s: %s" % (word, mean.decode()))
​
​
if __name__ == '__main__':
    query = QueryWord()
    query.query()
    query.close()
​
​
​
"""
    服务端
"""
from socket import *
import pymysql
​
​
class Dict:
    def __init__(self):
        self.args = {
            "host": "localhost",
            "port": 3306,
            "user": "root",
            "password": "123456",
            "database": "dict",
            "charset": "utf8"
        }
        self.__connect()  # 连接
​
    def __connect(self):
        self.db = pymysql.connect(**self.args)
        self.cur = self.db.cursor()
​
    def close(self):
        self.cur.close()
        self.db.close()
​
    def get_mean(self, word):
        sql = "select mean from words where word=%s;"
        self.cur.execute(sql, [word])
        mean = self.cur.fetchone()  # (mean,) None
        if mean:
            return mean[0]  # 返回解释
        else:
            return "Not Found"
​
​
class QueryWord:
    def __init__(self, host="0.0.0.0", port=8000):
        self.host = host
        self.port = port
        self.address = (host, port)
        self.dict = Dict()  # 实例化对象
        self.sock = self.__create_socket()
​
    def __create_socket(self):
        # 创建udp套接字
        udp_socket = socket(type=SOCK_DGRAM)
        udp_socket.bind(self.address)
        return udp_socket
​
    def close(self):
        # 关闭套接字
        self.sock.close()
​
    def query(self):
        while True:
            word, addr = self.sock.recvfrom(1024)
            mean = self.dict.get_mean(word.decode())#跨类调用
            self.sock.sendto(mean.encode(), addr)
​
​
if __name__ == '__main__':
    query = QueryWord()
    query.query()
    query.close()
​

  • 服务端客户端流程

    img编辑

1.2.4 UDP套接字特点

  • 可能会出现数据丢失的情况,一次发送就对应一次接受,不会接收第二次,多了数据丢失,发多少接多少,需要自己估算发送字节大小。不会给你分割发送。用于游戏与视频流畅传输。

  • 传输过程简单,实现容易

  • 数据以数据包形式表达传输

  • 数据传输效率较高

homework09.py


"""
编写一个程序,完成简单的注册保存功能
有一个数据库 user  中有一个数据表 user
数据表结构如下
id  name  passwd
​
create database user charset=utf8;
create table user(
id int primary key auto_increment,
name varchar(30) unique,
passwd char(64)
);
​
要求用户名(name)不能重复,如果注册成功
返回True 失败返回False
​
可以在exercise02代码基础上完成
"""
import pymysql
​
​
class User:
    def __init__(self):
        self.args = {
            "host": "localhost",
            "port": 3306,
            "user": "root",
            "password": "123456",
            "database": "user",
            "charset": "utf8"
        }
        self.connect()  # 连接
​
    def connect(self):
        self.db = pymysql.connect(**self.args)
        self.cur = self.db.cursor()
​
    def close(self):
        self.cur.close()
        self.db.close()
​
    def login(self,name,passwd):
        sql = "select name from user where name=%s and passwd=%s;"
        self.cur.execute(sql,[name,passwd])
        if self.cur.fetchone(): # (name,) None
            return True
        else:
            return False
​
​
    def register(self,name,passwd):
        sql = "insert into user (name,passwd) values (%s,%s);"
        try:
            self.cur.execute(sql,[name,passwd])
            self.db.commit()
            return True
        except:
            self.db.rollback()
            return False
​
if __name__ == '__main__':
    user = User()
​
    name = input("Name:")
    passwd = input("Passwd:")
    # if user.register(name,passwd):  # 执行具体事件
    #     print("注册成功")
    # else:
    #     print("注册失败")
​
    if user.login(name,passwd):  # 执行具体事件
        print("登录成功")
    else:
        print("登录失败")
​
    user.close()
​


前情回顾
​
1. 数据库的优化
​
   sql语句优化 表的拆分 : 水平 垂直
​
2. 数据库的备份
​
   表的数据拷贝: create table [tb] select...
​
   数据库的备份: mysqldump -u root -p stu>stu.sql mysql -u root -p stu<stu.sql
​
3. 创建用户和分配权限
​
   create user ... drop user ...
​
   远程登录数据库 --> 配置
​
   权限的分配 grant revoke
​
4. pymysql模块
​
   结构 : 连接数据库 --> 操作 --> 关闭 connect() 读/写 close cursor()
​
   写 : execute() executemany() commit() rollback()
​
   读 : execute() fetchone() fetchmany() fetchall()
​
   文件存储
​
数据管理总结
​
文件处理 : 文件的读写 open() read() write() (必会) 正则表达式 元字符和规则 使用re模块
​
数据库处理 (重点) 基础部分(必会) : 建库建表 增删改查 索引聚合 高级查询 表关联关系 连接查询 数据类型 外键设置
​
高级部分(面试高频,要最后回看): 视图 函数存储过程 事务控制 优化 拆表 备份 用户创建 权限管理
​
pymysql 基础编程
​
​
​
程序修改: 在原有的基础上修改,让客户端能够循环发送消息给服务端 直到 输入 ## 则两侧都结束
​
练习01: 编写一个udp服务端和客户端程序完成下面功能 从客户端输入单词,发送给服务端,然后从服务端得到 单词解释打印出来 输入##退出 服务端可以利用 dict数据库进行单词查找
​
plus版: 使用面向对象编程完成
​
作业 : 1. 重点代码要自己独立完成
      2. 练习自己默写一下
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dpq666dpq666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值