1.1 udp网络程序-发送数据
Socket函数
mySocket = socket(family, type)
函数socket()的参数family用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族。通信协议族在文件sys/socket.h中定义。
函数socket()的参数type用于设置套接字通信的类型,主要有SOCKET_STREAM(流式套接字)、SOCK——DGRAM(数据包套接字)等。
并不是所有的协议族都实现了这些协议类型,例如,AF_INET协议族就没有实现SOCK_SEQPACKET协议类型。
创建一个udp客户端程序的流程是简单,具体步骤如下:
1.创建客户端套接字
2.发送/接收数据
3.关闭套接字
代码如下:
from socket import *
#1.创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2.准备接收方的地址
sendAddr = ('192.168.11.74', 7788)
#3.从键盘获取数据
sendData = input("请输入要发送的数据:")
#4.发送数据到指定的电脑上
udpSocket.sendto(sendData.encode('gbk'), sendAddr)
#5.关闭套接字
udpSocket.close()
1.2 udp网络程序-发送、接收数据
#coding=utf-8
fromsocketimport*
#1.创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2.准备接收方的地址
sendAddr = ('192.168.1.103',8080)
#3.从键盘获取数据
sendData = input("请输入要发送的数据:")
#4.发送数据到指定的电脑上
udpSocket.sendto(sendData, sendAddr)
#5.等待接收对方发送的数据
recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字节数
#6.显示对方发送的数据
print(recvData)
#7.关闭套接字
udpSocket.close()
1.3 udp网络程序-端口问题
会变的端口号
重新运行多次脚本,然后在“网络调试助手”中,看到的现象如下:
说明:
·每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程序,当重新运行时,如果没有确定到底用哪个,系统默认会随机分配
·记住一点:这个网络程序在运行的过程中,这个就唯一标识这个程序,所以如果其他电脑上的网络程序如果想要向此程序发送数据,那么就需要向这个数字(即端口)标识的程序发送即可
1.4 udp 绑定信息
1.绑定信息
还记得在上一节课中,如果一个网络程序在每次运行的时候端口是随机变化的么?
一般情况下,在一天电脑上运行的网络程序有很多,而各自用的端口号很多情况下不知道,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp的端口号一般不绑定
但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?
如果报警电话每天都在变,想必世界就会乱了,所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定
2.绑定示例
#coding=utf-8
fromsocketimport*
#1.创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2.绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
bindAddr = ('',7788)# ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udpSocket.bind(bindAddr)
#3.等待接收对方发送的数据
recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字节数
#4.显示接收到的数据
print(recvData)
#5.关闭套接字
udpSocket.close()
总结
·一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行次程序端口可能会发生变化
·一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的
1.5 udp网络通信过程
1.6 udp应用:echo服务器
参考代码
#coding=utf-8
fromsocketimport*
#1.创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2.绑定本地的相关信息
bindAddr = ('',7788)# ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udpSocket.bind(bindAddr)
num =1
whileTrue:
#3.等待接收对方发送的数据
recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字节数
#4.将接收到的数据再发送给对方
udpSocket.sendto(recvData[0], recvData[1])
#5.统计信息
print('已经将接收到的第%d个数据返回给对方,内容为:%s'%(num,recvData[0]))
num+=1
#5.关闭套接字
udpSocket.close()
1.7 udp应用:聊天室
参考代码
fromsocketimport*
fromtimeimportctime
#1.创建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2.绑定本地的相关信息
bindAddr = ('',7788)# ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udpSocket.bind(bindAddr)
whileTrue:
#3.等待接收对方发送的数据
recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字节数
#4.打印信息
print('【%s】%s:%s'%(ctime(),recvData[1][0],recvData[0]))
#5.关闭套接字
udpSocket.close()
1.8 udp广播
网络编程中的广播
importsocket, sys
dest = ('',7788)
#创建udp套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#对这个需要发送广播数据的套接字进行修改设置,否则不能发送广播数据
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1)
#以广播的形式发送数据到本网络的所有电脑中
s.sendto("Hi", dest)
print("等待对方回复(按ctrl+c退出)")
whileTrue:
(buf, address) = s.recvfrom(2048)
print("Received from %s: %s"% (address, buf))
1.9 udp总结
1. udp是TCP/IP协议族中的一种协议能够完成不同机器上的程序间的数据通信
2. udp服务器、客户端
·udp的服务器和客户端的区分:往往是通过请求服务和提供服务来进行区分
·请求服务的一方称为:客户端
·提供服务的一方称为:服务器
3. udp绑定问题
·一般情况下,服务器端,需要绑定端口,目的是为了让其他的客户端能够正确发送到此进程
·客户端,一般不需要绑定,而是让操作系统随机分配,这样就不会因为需要绑定的端口被占用而导致程序无法运行的情况
1.10 udp模拟qq
1.任务要求:
·使用多线程完成一个全双工的QQ聊天程序
单工、半双工、全双工
单工数据传输只支持数据在一个方向上传输;
半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力.
2.参考代码
from threading import Thread
from socket import *
# 1.收数据,然后打印
def recvData():
while True:
recvInfo = udpSocket.recvfrom(1024)
print(">>%s:%s" % (str(recvInfo[1]), recvInfo[0]))
# 2.检测键盘,发数据
def sendData():
while True:
sendInfo = input("<<")
udpSocket.sendto(sendInfo.encode("gb2312"), (destIp, destPort))
udpSocket = None
destIp = ""
destPort = 0
def main():
global udpSocket
global destIp
global destPort
destIp = input("对方的ip:")
destPort = int(input("对方的ip:"))
udpSocket = socket(AF_INET, SOCK_DGRAM)
udpSocket.bind(("", 4567))
tr = Thread(target=recvData)
ts = Thread(target=sendData)
tr.start()
ts.start()
tr.join()
ts.join()
if __name__ == "__main__":
main()
1.11 TFTP客户端
1. TFTP协议介绍
TFTP(Trivial File Transfer Protocol,简单文件传输协议)
是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议
特点:
·简单
·占用资源小
·适合传递小文件
·适合在局域网进行传递
·端口号为69
·基于UDP实现
2. TFTP下载过程
TFTP服务器默认监听69号端口
当客户端发送“下载”请求(即读请求)时,需要向服务器的69端口发送
服务器若批准此请求,则使用一个新的、临时的 端口进行数据传输
当服务器找到需要现在的文件后,会立刻打开文件,把文件中的数据通过TFTP协议发送给客户端
如果文件的总大小较大(比如3M),那么服务器分多次发送,每次会从文件中读取512个字节的数据发送过来
因为发送的次数有可能会很多,所以为了让客户端对接收到的数据进行排序,所以在服务器发送那512个字节数据的时候,会多发2个字节的数据,用来存放序号,并且放在512个字节数据的前面,序号是从1开始的
因为需要从服务器上下载文件时,文件可能不存在,那么此时服务器就会发送一个错误的信息过来,为了区分服务发送的是文件内容还是错误的提示信息,所以又用了2个字节 来表示这个数据包的功能(称为操作码),并且在序号的前面
因为udp的数据包不安全,即发送方发送是否成功不能确定,所以TFTP协议中规定,为了让服务器知道客户端已经接收到了刚刚发送的那个数据包,所以当客户端接收到一个数据包的时候需要向服务器进行发送确认信息,即发送收到了,这样的包成为ACK(应答包)
为了标记数据已经发送完毕,所以规定,当客户端接收到的数据小于516(2字节操作码+2个字节的序号+512字节数据)时,就意味着服务器发送完毕了
TFTP数据包的格式如下:
�O4;3�m
网友评论