在本地电脑上有两个python文件 regist.py 、login.py 一个注册,一个登陆。这两个python一个是写用户信息,一个是读用户信息,要怎么作呢?python
经过以前的知识,咱们能够经过 regist.py 序列化一个数据并持久保存到磁盘上,而后 login.py 在取读取这个文件就行。web
可是,当这两个文件在不一样的主机上时,咱们就须要经过网络编程来实现,相似qq、网盘、微信。shell
在这七层中,咱们应该明确:编程
每层运行经常使用物理设备:设计模式
每层运行常见的协议浏览器
要记牢:ip是在网络层,tcp、udp等协议是在传输层。服务器
理解 socket微信
从表现形式来说,socket就是 ip:port,从设计模式来说,socket其实就是一个门面模式,它把复杂的tcp/ip协议族隐藏在socket接口后面,对用户来讲,一组简单的接口就是所有,让socket去组织数据,以符合指定的协议。网络
从python的角度来看,socket就是一个模块,咱们经过调用模块中已经实现的方法创建两个进程之间的链接和通讯。socket = ip:port ip 用来标识互联网中的一台主机的位置,而port是用来标识这台主机上的一个应用程序,因此咱们只要确立了ip和port就能找到一个应用程序,而且使用socket模块来与之通讯。socket
tcp( Transmission Control Protocol ): 可靠的、面向链接的协议、传输效率低全双工通讯、面向字节流。使用tcp应用:web浏览器;电子邮件、文件传输程序。
udp( User Datagram Protocol ): 不可靠的、无链接的服务,传输效率高,一对1、一对多、多对1、多对多、面向报文,尽最大努力服务,无拥塞控制。
使用udp的应用:域名系统;视频流;ip语音
1. 基于tcp协议的socket
tcp是基于连接的,必须先启动服务端,而后再启动客户端去链接服务端
sever端
import socket sock = socket.socket() # 建立 socket 对象 sock.bind(('127.0.0.1', 8080)) # 绑定ip和port sock.listen(5) # 创建监听连接 conn, addr = sock.accept() # 阻塞,随时准备接收客户端连接 res = conn.recv(1024) # 阻塞,等待接收客户端发送过来的数据 conn.send(b'hello client.') # 向客户端发送信息 conn.close() # 关闭本次连接 sock.close() # 关闭服务器socket
client端
import socket sock = socket.socket() # 建立 socket 对象 sock.connect(('127.0.0.1', 8080)) # 去链接服务端的socket sock.send(b'hello server.') # 发送信息给服务端的socket res = sock.recv(1024) # 接收服务端socket发送过来的信息 print(res) sock.close() # 关闭客户端链接
总结:
server端:
(1)建立socket对象
(2)绑定ip:port, 这里 ip为str类型,port为int类型
(3)创建socket监听
(4)准备接收客户端链接并返回socket链接信息和addr信息
(5)conn.send 发送信息、 conn.recv 接收消息
(6)先关闭链接,再关闭 socket
client端:
(1)建立socket对象
(2)经过 connect 尝试去链接服务端的socket
(3)sock.send 发送消息、sock.recv 接收消息
(4)关闭链接的socket
2. 基于UDP协议的socket
udp是无连接的,启动服务以后能够直接接受消息,不须要提早创建连接
server端
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 建立一个服务器的套接字,这里必需要定义 type=socket.SOCK_DGRAM udp_sk.bind(('127.0.0.1', 8080)) # 绑定服务器套接字 msg, addr = udp_sk.recvfrom(1024) # udp服务器端第一次通讯必须是接收信息 print(msg) udp_sk.sendto(b'hello, client.', addr) # 发送信息 udp_sk.close() # 关闭服务器套接字
client端
import socket ip_port = ('127.0.0.1', 8080) # 创建ip、port元组 udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 建立一个服务器的套接字,这里必需要定义 type=socket.SOCK_DGRAM udp_sk.sendto(b'hello server.', ip_port) # 发送消息给服务器端,在udp中第一次交互由客户端发起 back_msg, addr = udp_sk.recvfrom(1024) # 接收数据包括(服务器端数据,套接字信息) print(back_msg) udp_sk.close() # 关闭套接字
练习:使用 socket 模块实现 服务端 和 客户端 链接并执行命令。
import socket import subprocess sk_server = socket.socket() # 建立 socket对象 sk_server.bind(('localhost', 8080)) # 创建socket sk_server.listen(5) # 开启监听 conn, addr = sk_server.accept() # 接收客户端信息 while True: command = conn.recv(1024).decode() cmd_res = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) # 执行命令 stdout = cmd_res.stdout.read() stderr = cmd_res.stderr.read() result = stdout if stdout else stderr res_size = len(result) # 统计命令执行结果大小 print(res_size) conn.sendall(str(res_size).encode()) # 首先发送命令结果大小 response = conn.recv(1024).decode() conn.sendall(result) # 发送命令结果
import socket sk_client = socket.socket() sk_client.connect(('localhost', 8080)) while True: cmd = input('>>>').strip() if not cmd: continue sk_client.sendall(cmd.encode()) res_size = int(sk_client.recv(1024).decode()) # 接收命令结果大小 sk_client.sendall(b'000') revice_size = 0 while res_size != revice_size: # 经过命令大小循环获取数据 data = sk_client.recv(1024) revice_size += len(data) print(data.decode('gbk'))