6、网络编程-udp聊天器(2)

思想:先模仿程序再创造

1. 02案例:udp聊天器.py

终端中:vim 02案例:udp聊天器.py
打开终端开始写代码,写代码的先后顺序如下代码块:

函数与函数直接空两行,函数与if之间空两行或者一行

def main():

if __name__ == "__main__":
	main()

按下i开始进入编辑模式,main函数一般是完成主体功能

思路:大体要完成的功能:
1、发数据
2、收数据并打印出来
具体要完成多少次,不清楚,用while true,把收发数据放到里面去,即如下代码:

def main():
while True:
	# 发数据
	# 收数据并打印
if __name__ == "__main__":
	main()

如果流程比较复杂的时候,用注释理思路就不用写序号了,因为可能会改来改去比较麻烦

思路:
写一段流程写一段代码,然后往下推,如果正推无法推进,再倒推
若要完成收发功能,需要套接字,此时需要创建套接字,并且要import

书写规范:
第一个函数和前面的内容也要空两个行
注释#后要空一格

import socket

def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 用循环来处理事情
while True:
	# 发数据
	# 收数据并打印
if __name__ == "__main__":
	main()

思路:
如果想要收数据,需要绑定一个固定端口,绑定信息是一个元组,本地ip用“”表示,指定绑定的端口号假设叫7788

import socket

def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定信息
udp_socket.bind(("",7788))
# 用循环来处理事情
while True:
	# 发数据
	# 收数据并打印
if __name__ == "__main__":
	main()

思路:
接下来就是收发数据,若要发送数据,想要获取发送的内容,用input获取,用变量send_data来接收
发送数据的代码:udp_socket.sendto(内容要转码,(对方的ip即dest_ip,对方的端口即dest_port))
此时发现需要dest_ip和dest_port两个变量,再去发送数据代码上方定义变量

import socket

def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定信息
udp_socket.bind(("",7788))
# 用循环来处理事情
while True:
	# 发数据
	#获取发送的内容
	send_data = input("请输入你要发送的内容:")
	dest_ip = input("请输入对方的ip:")
	dest_port = input("请输入对方的端口:")
	udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
	# 收数据并打印
if __name__ == "__main__":
	main()

思路:
按照正常运行起来的流程顺序,获取对方的ip和port是在获取发送内容前,去调整代码顺序。
命令:
Ese ,大V选中,按上下键调整选中区域,d 剪切 把光标挪到这行前面去,p 粘贴

import socket

def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定信息
udp_socket.bind(("",7788))
# 用循环来处理事情
while True:
	# 发数据
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = input("请输入对方的端口:")
	send_data = input("请输入你要发送的内容:")
	udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
	# 收数据并打印
if __name__ == "__main__":
	main()

思路:接下来完成收数据并打印的代码
书写规范:
print(“s%?%” % (str(recv_data[1]),recv_data[0].decode(“utf-8”)))
%和“”不要连在一起 ,中间加一个空格,%和后面的小括号之间也隔一个空格
如果是和windows之间通信,解码时应把utf-8换成gbk,与mac和linux通信都是utf-8
recv_data[0].decode,因为元组中的第一部分才是数据,所以要加[0]

import socket

def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定信息
udp_socket.bind(("",7788))
# 用循环来处理事情
while True:
	# 发数据
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = input("请输入对方的端口:")
	send_data = input("请输入你要发送的内容:")
	udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
	# 收数据并打印
	recv_data = udp_socket.recvfrom(1024)
	print("s%:s%" % (str(recv_data[1]),recv_data[0].decode("utf-8")))
if __name__ == "__main__":
	main()

至此,以上代码已经完成了收发功能
一般具有独立功能的代码块都要封装到一个函数中,下面将收、发代码块分别进行封装

书写规范:
函数下方“”“ ”“”,三个双引号,代表是对函数的说明文档
命令:esc 大V 上下箭头选中发送数据代码块,d 剪切,光标到新定义的函数下方,p 黏贴
新调整过去的代码,缩进的太多,V选中,小于号,向左调整

import socket


def send_msg():
"""发送消息"""
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = input("请输入对方的端口:")
	send_data = input("请输入你要发送的内容:")
	udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))


def recv_msg():
"""接受消息"""
	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:
	# 发数据
	
	# 收数据并打印
	
if __name__ == "__main__":
	main()

代码块封装完成后,接下来是调用函数

思路:
每次调用函数之前,都要想一下,函数是否需要参数;
虽然上面的def send_msg()中没有参数,但是代码还没进行测试
看一下def send_msg()中的代码,dest_ip、 dest_port 、send_data
都是定义的变量,但是udp_socket.sendto(send_data.encode(“utf-8”),(dest_ip,dest_port))这句代码中的udp_socket还没有定义,所以调用函数时要将udp_socket传进去,实参形参都要补进去,同理,接收数据的函数也需要传递形参和实参

命令:
编辑模式下,u是撤销

import socket


def send_msg(udp_socket):
"""发送消息"""
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = input("请输入对方的端口:")
	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:
	# 发数据
	send_msg(udp_socket)
	# 收数据并打印
	recv_data(udp_socket)
if __name__ == "__main__":
	main()

接下来测试程序
程序运行时报错了
报错时的页面

查看最后一行错误类型和最近出错的代码行数是第10行

命令:
调整报错代码,终端中vim 文件名.py后面跟一个空格 +10 回车 打开文件后光标直接定位到第10行

出错原因是第8行的端口忘记转成数字类型

import socket


def send_msg(udp_socket):
"""发送消息"""
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = int(input("请输入对方的端口:"))
	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:
	# 发数据
	send_msg(udp_socket)
	# 收数据并打印
	recv_data(udp_socket)
if __name__ == "__main__":
	main()

2. 03案例:udp聊天器-升级-可以控制操作.py

因为现有程序必须是一收一发,如果对方不发数据过来,程序就会阻塞,所以要升级
终端中cp 02案例:udp聊天器.py 03案例:udp聊天器-升级-可以控制操作.py

import socket


def send_msg(udp_socket):
"""发送消息"""
	#获取发送的内容
	dest_ip = input("请输入对方的ip:")
	dest_port = int(input("请输入对方的端口:"))
	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(“---聊天器---”)
	print(“1、发送消息”)
	print(“2、接收消息”)
	print(“0、退出”)
	op = input("请输入你想进行的操作:")
	if op == “1”:
		# 发数据
		send_msg(udp_socket)
	elif op == "2":
		# 收数据并打印
		recv_data(udp_socket)
	elif op == "0":
		break
	else:
		print("你输入的指令有误,请重新输入:")
if __name__ == "__main__":
	main()

再对代码进行测试时,会发现,只要每次输入2之后,才会把数据收进来,即使对方已经发送了数据,如果中断中不输入2,数据也不会收进来,说明,发送过来的数据会事先存在操作系统这个管家中,什么时候输入2,什么时候把数据取出来。

漏洞:
如果不用while True,操作系统收入太多数据时,程序有可能会卡死。如果知道对方电脑的端口号,一次性发很大的文件,有可能就会导致对方电脑崩掉,再有新的文件收不进去。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值