[华为云在线课程][Python网络编程][Python网络编程][二][学习笔记]
1.Python网络编程
1.1.Socket简介
Socket套接字是对TCP/IP协议的封装,自身而非协议而是一套调用的接口规范(API)。Socket一般分为TCP网络编程和UDP网络编程。
1.2.Python中的网络编程
Python提供了两个级别访问的网络服务:
- 低级别的网络服务支持基本的Socket,提供了标准的BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
- 高级别网络服务模块SocketServer,提供了服务器中心类,可以简化网络服务器的开发。
Python还具有提供对特定应用级网络协议(如FTP,HTTP等)的更高级别访问的库。
1.3.Python Socket模块
Python中的Socket模块,可以简单快捷的实现基础的网络通信,Socket模块中提供了以下属性和方法:
- 创建Socket
- 地址绑定
- TCP、UDP协议实现
- 接收、发送数据
1.4.创建socket
socket.socket([family[,type[,proto]]]):创建套接字
- family:套接字家族可以使AF_UNIX或者AF_INET
- type:套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或者SOCK_DGRAM
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
1.5.服务器端常用方法和属性
绑定主机地址和端口号
- host=socket.gethostname() #获取本地主机名
- s.bind((host,port)) #绑定地址和端口
开始TCP监听(转化为被动连接)
- s.listen(n) #n至少为1
接受客户端连接
- s.accept() #等待连接
主动初始化TCP服务器连接
- s.connect(address)
- address:host,port
接收数据
- s.recv(bufsize[,flags]) #从套接字接收TCP数据,返回字节对象。bufsize指定一次接收的最大数据量
- s.recvfrom(bufsize[,flags]) #接收UDP数据,与revc()类似,返回值为字节对象和地址(bytes,address)
1.6.通用方法
发送数据
- s.send(bytes,[,flags]) #发送数据给套接字
- s.sendall(bytes[,flags]) #持续从bytes发送数据,直到所有数据都已发送或发生错误为止(成功返回None,失败则抛出异常)
- s.sendto(bytes,address) #发送UDP数组,将数据发送到套接字,address是形式为(ipaddr,port)的元组。返回值是发送的字节数
- s.sendfile(file,offset=0,count=None) #发送文件
关闭socket
- s.close()
获取socket地址
- s.getpeername() #返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)
- s.getsockname() #返回套接字自己的地址
设置连接超时时间
- s.settimeout(timeout) #设置套接字操作的超时期,单位为s
1.7.UDP通信流程
服务器端
- 创建socket
- 绑定地址
- 发送/接收数据
- 关闭
客户端
- 创建socket
- 接收/发送
- 关闭
1.8.UDP通信实现
创建socket
- udp_socket=socket(AF_INET,SOCK_DGRAM)
绑定地址相关信息
- udp_socket.bind(local_addr) #可选
等待接收/发送数据
- recv_data=udp_socket.recvfrom(1024)
关闭套接字
- udp_socket.close()
1.9.TCP通信流程
服务器端
- 创建socket
- 绑定端口
- 转化为被动连接
- 接收客户端连接
- 接收/发送数据
- 关闭
客户端
- 创建socket
- 连接服务器
- 发送/接收数据
- 关闭
1.10.TCP通信实现
TCP服务器
- 创建socket:tcp_server=socket(AF_INET,SOCK_STREAM)
- 绑定地址:tcp_server.bind(address)
- 被动连接:tcp_server.listen(128)
- 等待客户端连接:client_socket,clientAddr=tcp_server_.accept()
- 接收/发送数据:recv_data=client_socket.recv(1024)
- 关闭socket:client_socket.close()
2.socket UDP实验
2.1.新建工程
在PyCharm中新建工程后新建文件夹UDP,在里面新建.py文件
2.2.实现简单的UDP客户端通信程序
编写udp_client.py
from socket import *
udp_socket = socket(AF_INET, SOCK_DGRAM)
dest_addr = ('127.0.0.1', 2233) # 测试脚本或者网络调试助手所在主机的地址
udp_socket.sendto('你好'.encode('utf8'), dest_addr)
udp_socket.sendto('你好'.encode('utf8'), dest_addr)
udp_socket.close()
编写测试udp_server.py
from socket import *
udp_socket = socket(AF_INET, SOCK_DGRAM)
udp_socket.bind('127.0.0.1', 2233) # 绑定要测试的IP地址
recv_data, addr = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
print('收到%s:%s发来的信息 -- %s' % (addr[0], addr[1], recv_data))
recv_data, addr = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
print('收到%s:%s发来的信息 -- %s' % (addr[0], addr[1], recv_data))
udp_socket.close()
运行测试脚本
python udp_server.py
运行udp_client.py
python udp_client.py
测试脚本输出:
收到127.0.0.1:64546发来的信息 -- b'\xe4\xbd\xa0\xe5\xa5\xbd'
收到127.0.0.1:64546发来的信息 -- 你好
收到127.0.0.1:54945发来的信息 -- b'\xe4\xbd\xa0\xe5\xa5\xbd'
收到127.0.0.1:54945发来的信息 -- 你好
2.3.绑定端口号
发现端口号每次都不固定,如果想绑定端口号,要在客户端更改代码
from socket import *
udp_socket = socket(AF_INET, SOCK_DGRAM)
dest_addr = ('127.0.0.1', 2233) # 创建套接字
bind_dest_addr = ('', 2233) # 要绑定的端口号
udp_socket.bind(bind_dest_addr) # 进行绑定
udp_socket.sendto('你好'.encode('utf8'), dest_addr)
udp_socket.sendto('你好'.encode('utf8'), dest_addr)
udp_socket.close()
输出结果:
收到127.0.0.1:2233发来的信息 -- b'\xe4\xbd\xa0\xe5\xa5\xbd'
收到127.0.0.1:2233发来的信息 -- 你好
收到127.0.0.1:2233发来的信息 -- b'\xe4\xbd\xa0\xe5\xa5\xbd'
收到127.0.0.1:2233发来的信息 -- 你好
3.socket TCP实验
3.1.新建文件
在PyCharm中新建工程后新建文件夹TCP,在里面新建.py文件
3.2.实现TCP服务器端程序
新建文件tcp_server.py
from socket import *
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('', 7788)
# 绑定
tcp_server_socket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcp_server_socket.listen(128)
# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
# client_socket 用来为这个客户端服务
# tcp_server_socket 就可以省下来专门等待其他新客户端的链接
client_socket, clientAddr = tcp_server_socket.accept()
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024) # 接收1024个字节
print('接收到的数据为:', recv_data.decode('gbk'))
# 发送一些数据到客户端
client_socket.send('thank you!'.encode('gbk'))
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
client_socket.close()
3.3.实现TCP客户端程序
新建文件tcp_client.py
from socket import *
# 创建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))
# 提示用户输入数据
send_data=input('请输入要发送的数据:')
tcp_client_socket.send(send_data.encode('gbk'))
# 接收对方发送出来的数据,最大接收1024个字节
recvData=tcp_client_socket.recv(1024)
print('接收到的数据为:',recvData.decode('gbk'))
# 关闭套接字
tcp_client_socket.close()
客户端结果
请输入服务器ip:127.0.0.1
请输入服务器port:7788
请输入要发送的数据:HELLO
接收到的数据为: thank you!
服务端结果
接收到的数据为: HELLO
3.4.TCP文件服务器实践
基于socket模块和TCP协议实现文件下载程序的服务器端和客户端。
新建脚本文件tcp_server_file.py
from socket import *
import sys
from TCP.tcp_server import tcp_server_socket
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():
if len(sys.argv) != 2:
port = 2333
else:
port = int(sys.argv[1])
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('', port)
# 绑定本地信息
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_client_file.py
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)
# 如果接收到数据再创建文件,否则不创建
if recv_data:
with open('[接收]' + file_name, 'wb') as f:
f.write(recv_data)
# 关闭套接字
tcp_client_socket.close()
if __name__ == "__main__":
main()
- 点赞
- 收藏
- 关注作者
评论(0)