1.UDP网络程序-发送数据
创建UDP网络程序流程:
- 创建客户端套接字
- 发送/接收数据
- 关闭套接字
socket套接字介绍: - 在任何类型的通信开始之前,网络应用程序都必须创建套接字。
- 套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个进程)与另一个运行的程序进行通信。这就是所谓的进程间通信。
- 做个比喻,套接字就像一个电话插孔,主机名和端口号就像区号和号码。
套接字分类: - 基于文件的:AF_UNIX
- 面向网络的:AF_INET
- Python只支持AF_INET、AF_UNIX、AF_NETLINK和AF_TIPC家族
面向连接的套接字与无连接的套接字 - 面向连接的套接字:SOCK_STREAM(可靠,开销大)
- 无连接的套接字:SOCK_DGRAM(不可靠,局域网内比较可靠,开销小)
import socket
#创建一个UDP的socket连接
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#获取用户的输入内容
data = input('请输入内容')
#准备接收方的地址和端口号
addr = ('127.0.0.1',8080)
#将用户输入的内容进行编码,并发送到指定的地址和端口
udp_socket.sendto(data.encode('gbk'),addr)
#接收传递过来的消息,并指定接受的字节大小
recv_data = udp_socket.recvfrom(1024)
#接收到的对象是一个元组,元组里有两个元素
print(recv_data)
#元组里的第一个数据显示接收到的内容
print(recv_data[0].decode('gbk'))
#元组里的第二个数据显示发送方的地址和端口号
print(recv_data[1])
#关闭socket连接
udp_socket.close()
2.UDP绑定信息
udp的端口号一般不绑定 但是如果需要做成一个服务器端的程序的话,是需要绑定的,例如110,119,120都必须固定
from socket import *
#创建套接字
udp_socket = socket(AF_INET,SOCK_DGRAM)
#绑定本地的相关信息,如果一个网络程序不绑定,则系统随机分配
local_addr = ('',7788)
udp_socket.bind(local_addr)
#等待接收对方发来的数据
recv_data = udp_socket.recvfrom(1024)
#显示数据
print(recv_data[0].decode('gbk'))
#关闭套接字
udp_socket.close()
总结
- 一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化
- 一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的
3.TCP协议
- TCP协议,传输控制协议。
- TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
- TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,“打电话”。
TCP特点: - 双方必须先建立连接,并为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
- 双方之间的数据传输都可以通过这一个连接进行。
- 完成数据交换后,双方必须断开此连接,以释放系统资源
- 这种连接是一对一的,不适用广播的应用程序,广播用UDP协议
TCP与UDP的区别 - 面向连接(确认有创建三方交握,连接已创建才作传输。)
- 有序数据传输
- 重发丢失的数据包
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制
TCP服务器端
from socket import *
def get_file_content(file_name):
"""获取文件的内容"""
try:
with open(file_name, "rb") as f:
content = f.read()
return content
except:
print("没有下载的文件:%s" % file_name)
def main():
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('', 7890)
# 绑定本地信息
tcp_server_socket.bind(address)
# 将主动套接字变为被动套接字
tcp_server_socket.listen(128)
while True:
# 等待客户端的链接,即为这个客户端发送文件
client_socket, clientAddr = tcp_server_socket.accept()
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024) # 接收1024个字节
file_name = recv_data.decode("utf-8")
print("对方请求下载的文件名为:%s" % file_name)
file_content = get_file_content(file_name)
# 发送文件的数据给客户端
# 因为获取打开文件时是以rb方式打开,所以file_content中的数据已经是二进制的格式,因此不需要encode编码
if file_content:
client_socket.send(file_content)
# 关闭这个套接字
client_socket.close()
# 关闭监听套接字
tcp_server_socket.close()
if __name__ == '__main__':
main()
TCP客户端
from socket import *
def main():
# 创建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的信息
server_ip = input("请输入服务器ip:")
server_port = int(input("请输入服务器port:"))
# 链接服务器
tcp_client_socket.connect((server_ip, server_port))
# 输入需要下载的文件名
file_name = input("请输入要下载的文件名:")
# 发送文件下载请求
tcp_client_socket.send(file_name.encode("utf-8"))
# 接收对方发送过来的数据,最大接收1024个字节(1K)
recv_data = tcp_client_socket.recv(1024)
# print('接收到的数据为:', recv_data.decode('utf-8'))
# 如果接收到数据再创建文件,否则不创建
if recv_data:
with open("[接收]"+file_name, "wb") as f:
f.write(recv_data)
# 关闭套接字
tcp_client_socket.close()
if __name__ == "__main__":
main()