标签搜索

目 录CONTENT

文章目录

Python中的网络编程之UDP.md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 4 阅读 / 4,951 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Python中的网络编程之UDP

@[toc]

一、Socket编程

1.什么是客户端/服务器架构

服务器就是一系列硬件或软件,为一个或多个客户端(服务的用户)提供所需的“服务”。它存在唯一目的就是等待客户端的请求,并响应它们(提供服务),然后等待更多请求。说白了就是一个提供服务,一个请求服务得到相应的一个过程。

2.套接字:通信端点

套接字是计算机网络数据结构,它体现了上节中描述的“通信端点”的概念。在任何类型的通信开始之前,网络应用程序必须创建套接字。

可以将它们比作电话插孔,没有它将无法进行通信。

Python只支持AF_UNIX、AF_NETLINK、AF_TIPC 和 AF_INET ,重点使用基于网络的AF_INET.

3.套接字地址:主机-端口对

它是网络通信过程中端点的抽象表示,python使用元组保存:ADDR =(HOST,PORT)。

4.套接字类型

流式套接字(SOCK_STREAM):用于提供面向连接、可靠的数据传输服务

数据报套接字(SOCK_DGRAM):提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。

二、常见的套接字对象方法和属性

名 称描 述
服务端服务器套接字方法
s.bind(ADDR) 将地址(主机名、端口号对)绑定到套接字上
s.listen([backlog])设置并启动 TCP 监听器,如果指定backlog,则必须至少为0(如果低于0,则设置为0);
s.accept()被动接受 TCP 客户端连接,一直等待直到连接到达(阻塞)
客户端客户端套接字方法
s.connect()主动发起 TCP 服务器连接
s.connect_ex()connect()的扩展版本,此时会以错误码的形式返回问题,而不是抛出一个异常
普通通用普通的套接字方法
s.recv()接收 TCP 消息
s.recv_into()接收 TCP 消息到指定的缓冲区
s.send()发送 TCP 消息
s.sendall()完整地发送 TCP 消息
s.recvfrom()接收 UDP 消息
s.recvfrom_into()接收 UDP 消息到指定的缓冲区
s.sendto()发送 UDP 消息
s.getpeername()连接到套接字(TCP)的远程地址
s.getsockname()当前套接字的地址
s.getsockopt()返回给定套接字选项的值
s.setsockopt()设置给定套接字选项的值
s.shutdown()关闭连接
s.close()关闭套接字
s.detach()在未关闭文件描述符的情况下关闭套接字,返回文件描述符
s.ioctl()控制套接字的模式(仅支持 Windows)
阻塞面向阻塞的套接字方法
s.setblocking()设置套接字的阻塞或非阻塞模式
s.settimeout()设置阻塞套接字操作的超时时间
s.gettimeout()获取阻塞套接字操作的超时时间
文件方法面向文件的套接字方法
s.fileno()套接字的文件描述符
s.makefile()创建与套接字关联的文件对象
属性数据属性
s.family套接字家族
s.type套接字类型
s.proto套接字协议

三、创建套接字

函数 socket.socket 创建一个 socket,该函数带有两个参数:

  •  Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
  •  Type:套接字类型,可以是 SOCK_STREAM( 流式套接字,主要用于 TCP 协议)或者SOCK_DGRAM(数据报套接字, 主要用于 UDP 协议)

创建一个tcp socket(tcp套接字):

import socket

# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ...这里是使用套接字的功能(省略)...

# 不用的时候,关闭套接字
s.close()

创建一个udp socket(udp套接字):

import socket

# 创建udp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# ...这里是使用套接字的功能(省略)...

# 不用的时候,关闭套接字
s.close()

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

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

四、UDP网络程序

创建一个基于udp的网络程序流程,具体步骤如下:

  • 创建套接字
  • 发送/接收数据
  • 关闭套接字
    在这里插入图片描述

代码--发送数据:

#coding=utf-8

from socket import *

# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 准备接收方的地址
# '192.168.1.103'表示目的ip地址
# 8080表示目的端口
dest_addr = ('192.168.1.103', 8080)  # 注意 是元组,ip是字符串,端口是数字

# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")

# 4. 发送数据到指定的电脑上的指定程序中
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)

# 5. 关闭套接字
udp_socket.close()

代码--发送接收数据:

#coding=utf-8

from socket import *

# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 准备接收方的地址
dest_addr = ('192.168.236.129', 8080)

# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")

# 4. 发送数据到指定的电脑上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)

# 5. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数

# 6. 显示对方发送的数据
# 接收到的数据recv_data是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])

# 7. 关闭套接字
udp_socket.close()

五、UDP的绑定端口问题

一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp的端口号一般不绑定

但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?

如果报警电话每天都在变,想必世界就会乱了,所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定

#coding=utf-8

from socket import *

# 1. 创建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 7788) #  ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)

# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) #  1024表示本次接收的最大字节数

# 4. 显示接收到的数据
print(recv_data[0].decode('gbk'))

# 5. 关闭套接字
udp_socket.close()

六、UDP聊天器

import socket


def send_msg(udp_socket):
    """获取键盘数据,并将其发送给对方"""
    # 1. 从键盘输入数据
    msg = input("\n请输入要发送的数据:")
    # 2. 输入对方的ip地址
    dest_ip = input("\n请输入对方的ip地址:")
    # 3. 输入对方的port
    dest_port = int(input("\n请输入对方的port:"))
    # 4. 发送数据
    udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    """接收数据并显示"""
    # 1. 接收数据
    recv_msg = udp_socket.recvfrom(1024)
    # 2. 解码
    recv_ip = recv_msg[1]
    recv_msg = recv_msg[0].decode("utf-8")
    # 3. 显示接收到的数据
    print(">>>%s:%s" % (str(recv_ip), recv_msg))


def main():
    # 1. 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2. 绑定本地信息
    udp_socket.bind(("", 7890))
    while True:
        # 3. 选择功能
        print("="*30)
        print("1:发送消息")
        print("2:接收消息")
        print("="*30)
        op_num = input("请输入要操作的功能序号:")

        # 4. 根据选择调用相应的函数
        if op_num == "1":
            send_msg(udp_socket)
        elif op_num == "2":
            recv_msg(udp_socket)
        else:
            print("输入有误,请重新输入...")

if __name__ == "__main__":
    main()

七、python3编码转换

str->bytes:encode编码
bytes->str:decode解码
字符串通过编码成为字节码,字节码通过解码成为字符串。

>>> text = '我是文本'
>>> text
'我是文本'
>>> print(text)
我是文本
>>> bytesText = text.encode()
>>> bytesText
b'\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac'
>>> print(bytesText)
b'\xe6\x88\x91\xe6\x98\xaf\xe6\x96\x87\xe6\x9c\xac'
>>> type(text)
<class 'str'>
>>> type(bytesText)
<class 'bytes'>
>>> textDecode = bytesText.decode()
>>> textDecode
'我是文本'
>>> print(textDecode)
我是文本

其中decode()与encode()方法可以接受参数,其声明分别为:

bytes.decode(encoding="utf-8", errors="strict")
str.encode(encoding="utf-8", errors="strict")

其中的encoding是指在解码编码过程中使用的编码(此处指“编码方案”是名词),errors是指错误的处理方案。

str.encode()
bytes.decode()

0

评论区