网络通信-UDP
面向无连接
两台计算机通信的时候,不需要建立连接(逻辑)就可以进行数据的收发,数据可能会丢
- 传输协议: UDP
面向有连接
两台计算机通信的时候,需要先建立连接,再能通信
- 传输协议:TCP
socket简介
socket 网络通信的基本单元,提供的方法可以实现数据的发送和接收
发送数据
udp_socket.sendto(数据,ip和端口)
- 数据必须是二进制格式 字符串.encode()
- ip和端口必须是是元组,(“ip地址”, 端口号)
接收数据
recv_data = udp_socket.recvfrom(1024) 每次接收1024个字节
- recv_data 是一个元组
- 第一个元素 收到的数据的二进制
- 第二个元素 元组,发送方的ip和端口
- 把接收的数据解码 二进制 ---》 字符串 二进制数据.decode("GBK")
# 1、导入模块
import socket
# 2、创建套接字
# socket.socket(协议类型,传输方式)
# 参数一:
# socket.AF_INET 使用IPv4
# socket.AF_INET6 使用IPv6
# 参数二:
# socket.SOCK_DGRAM 使用UDP的传输方式(无连接)
# socket.SOCK_STREAM 使用TCP的传输方式(有连接)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 3、发送数据
udp_socket.sendto("helloword".encode("UTF-8"),("localhost", 8080))
# 4、接收数据 recv_data[0] 接收到的数据的二进制格式,recv_data[1] 元组,对方的ip和端口
recv_data = udp_socket.recvfrom(1024)
print(recv_data)
print(recv_data[0].decode("UTF-8"))
# (b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x81', ('127.0.0.1', 8080))
# 你好!
# 5、关闭套接字
udp_socket.close()
tcp_socket.close()
(b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x81', ('127.0.0.1', 8080))
你好!
python3编码转换
- 编码
字符串.encode() 默认UTF-8字符串
- 解码
二进制.decode() 默认UTF-8字符集
- 解码失败的处理
decode(encoding="字符集", errors="错误处理方式")
错误处理方式有两种:ignore 忽略, strict 严格
# 1、导入模块
import socket
# 2、创建套接字
# socket.socket(协议类型,传输方式)
# 参数一:
# socket.AF_INET 使用IPv4
# socket.AF_INET6 使用IPv6
# 参数二:
# socket.SOCK_DGRAM 使用UDP的传输方式(无连接)
# socket.SOCK_STREAM 使用TCP的传输方式(有连接)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 3、发送数据
udp_socket.sendto("helloword".encode(),("localhost", 8080))
# 4、接收数据 recv_data[0] 接收到的数据的二进制格式,recv_data[1] 元组,对方的ip和端口
recv_data = udp_socket.recvfrom(1024)
print(recv_data)
print(recv_data[0].decode(encoding="GBK", errors="ignore"))
# UnicodeDecodeError: 'gbk' codec can't decode byte 0x81 in position 8: incomplete multibyte sequence decoding with 'GBK' codec failed
# (b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x81', ('127.0.0.1', 8080))
# 你好!
# 5、关闭套接字
udp_socket.close()
(b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x81', ('127.0.0.1', 8080))
浣犲ソ锛
绑定端口 bind()
udp_socket.bind(address)
- address 是一个元组,元组的第一个元素是字符串类型的IP地址,第二个元素 整数端口号
- udp_socket.bind(("192.168.9.88", 8888))
udp_socket.bind(("", 8888))
- ip地址尽可能写为"",好处当计算机由多个网卡的时候,不同网卡的数据都能被接收
# 1、导入模块
import socket
# 2、创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 3、绑定端口
udp_socket.bind(("", 8888))
# 4、数据传输
udp_socket.sendto("helloword".encode(),("localhost", 8080))
recv_data, ip_port = udp_socket.recvfrom(1024)
print(recv_data.decode("UTF-8", errors="ignore"))
print(f"接收到来自:%s的信息: %s" % (str(ip_port), recv_data.decode()))
# 你好!
# 接收到来自:('127.0.0.1', 8080)的信息: 你好!
# 5、关闭套接字
udp_socket.close()
你好!
接收到来自:('127.0.0.1', 8080)的信息: 你好!
UDP广播
# 1、导入模块
import socket
# 2、创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 3、设置广播权限
# PermissionError: [Errno 13] Permission denied
# udp_socket.setsockopt(套接字,属性,属性值)
# socket.SOL_SOCKET 当前的套接字
# socket.SO_BROADCAST 广播属性
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
# 4、发送广播
udp_socket.sendto("helloword".encode(),("255.255.255.255", 8080))
udp_socket.sendto("helloword".encode(),("168.12.15.255", 8080))
# 5、关闭套接字
udp_socket.close()
UDP聊天器
"""
一、功能
1、发送信息
2、接收信息
3、退出系统
二、框架的设计
1、发送信息 send_msg()
2、接收信息 recv_msg()
3、程序的主入口 main()
4、当程序独立运行的时候,才启动聊天器
三、实现步骤
1、发送信息 send_msg()
1) 定义变量接收用户与输入的接收方的IP地址
2)定义变量接收用户与输入的接收方的端口号
3)定义变量接收用户与输入的接收方的内容
4)使用socket的sendto() 发送信息
2、接收信息 recv_msg()
1) 使用socket 接收数据
2)解码数据
3)输出显示
3、主入口main()
1)创建套接字
2)绑定端口
3)打印菜单(循环)
4)接收用户输入的选项
5)判断用户的选择,并且调用对应的函数
6)关闭套接字
"""
import socket
def send_message(udp_socket):
"""返送信息的函数"""
# 1) 定义变量接收用户与输入的接收方的IP地址
ipaddr = input("请输入接收方的IP地址:\n")
# 判断是否需要默认
if len(ipaddr) == 0:
ipaddr = "168.12.1.50"
print("当前接收方默认IP设置为[%s]" % ipaddr)
# 2)定义变量接收用户与输入的接收方的端口号
port = input("请输入接收方的端口号:\n")
if len(port) == 0:
port = "8888"
print("当前接收方默认端口设置为[%s]" % port)
# 3)定义变量接收用户与输入的接收方的内容
content = input("请输入要发送的内容:\n")
# 4)使用socket的sendto()发送信息
udp_socket.sendto(content.encode(), (ipaddr, int(port)))
def recv_msg(udp_socket):
"""接收信息的函数"""
# 1) 使用socket接收数据
recv_data, ip_port = udp_socket.recvfrom(1024)
# 2)解码数据
recv_txt = recv_data.decode()
# 3)输出显示
print('收到', ip_port, '发送的消息:', recv_txt)
def main():
"""程序主入口"""
# 1)创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2)绑定端口
udp_socket.bind(("", 6666))
# 3)打印菜单(循环)
while True:
print('\n\n*****************************')
print('******* 1、发送信息 *******')
print('******* 2、接收信息 *******')
print('******* 3、退出系统 *******')
print('*****************************')
# 4)接收用户输入的选项
sel_num = int(input('请输入选项:\n'))
# 5)判断用户的选择,并且调用对应的函数
if sel_num == 1:
print('您选择的是发送信息')
send_message(udp_socket)
elif sel_num == 2:
print('您选择的是接收信息')
recv_msg(udp_socket)
elif sel_num == 3:
print('系统正在退出中...')
print('退出完成!')
break
else:
print('选项输入错误,请重新输入')
# 6)关闭套接字
udp_socket.close()
if __name__ == '__main__':
# 程序独立运行的时候,才去启动聊天器
main()
*****************************
******* 1、发送信息 *******
******* 2、接收信息 *******
******* 3、退出系统 *******
*****************************
您选择的是发送信息
*****************************
******* 1、发送信息 *******
******* 2、接收信息 *******
******* 3、退出系统 *******
*****************************
您选择的是接收信息
收到 ('168.12.1.50', 8888) 发送的消息: 呵呵呵
*****************************
******* 1、发送信息 *******
******* 2、接收信息 *******
******* 3、退出系统 *******
*****************************
系统正在退出中...
退出完成!