8.6 socket 套接字
什么是socket套接字?
socket套接字充当的就是内置模块的角色.
socket套接字,它是存在于传输层与应用层之间的抽象层
# 作用
1. 避免学习各层的接口,以及协议的使用,socket已经封装好了所有的接口直接使用这些接口或者方法即可,使用起来方便,提升开发效率.
2. socket就是一个模块,通过使用学习模块提供的功能,建立客户端与服务端的通信,使用方便
五层协议:从传输层开始及以下,都是操作系统帮助我们封装的各种head
socket又称为套接字,它是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在socket接口后面,对用户来说,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议.
8.6.1 基于TCP协议的socket
先从服务端说起.服务器端先初始化socket,然后与端口绑定(bild),对端口进行监听(listen),调用accept阻塞,等待客户端连接.这个时候如果在有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务端的连接就建立了.客户端发送数据请求,服务器端接收请求并处理请求,然后回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束.
1. 单个客户通信
# 服务端
import socket
# 1.创建socket对象
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.绑定ip地址和端口
phone.bind(('127.0.0.1',6868))
# 3.监听
phone.listen(5)
# 4.接收连接
conn,addr = phone.accept()
print(conn,addr)
# 5.接收消息
from_client_data = conn.recv(1024)
print(f'来自客户端{addr}的信息{from_client_data.decode("utf-8")}')
# 6.发送消息
to_client = input('>>>')
conn.send(to_client.encode('utf-8'))
conn.close()
phone.close()
# 客户端
import socket
# 1.创建socket对象
phone = socket.socket()
# 2.连接服务器ip和端口
phone.connect(('127.0.0.1',6868))
# 3.发消息
to_server = input('>>>')
phone.send(to_server.encode('utf-8'))
# 4.接收消息
from_server_data = phone.recv(1024)
print(f'来自服务端的消息:{from_server_data.decode("utf-8")}')
phone.close()
2. 通信,连接循环
# 服务端
import socket
phone = socket.socket()
phone.bind(('127.0.0.1',8888))
phone.listen(3)
while 1:
conn,addr = phone.accept()
while 1:
try:
from_client_data = conn.recv(1024)
if from_client_data == b'q':
break
print(f"来自客户端{addr}的消息:{from_client_data.decode('utf-8')}")
to_client = input('>>>').strip()
conn.send(to_client.encode('utf-8'))
except ConnectionResetError:
break
conn.close()
phone.close()
# 客户端
import socket
phone = socket.socket()
phone.connect(('127.0.0.1',6688))
while 1:
to_server = input('>>>').strip()
if to_server.upper() == 'Q':
phone.send('q'.encode('utf-8'))
break
phone.send(to_server.encode('utf-8'))
from_server_data = phone.recv(1024)
print(f'来自服务端的信息{from_server_data.decode("utf-8")}')
phone.close()
3. 远程执行命令
# 服务端
import socket
import subprocess
phone = socket.socket()
phone.bind(('127.0.0.1',6666))
phone.listen(3)
while 1:
conn,addr = phone.accept()
while 1:
try:
cmd = conn.recv(1024)
ret = subprocess.Popen(cmd.decode('utf-8'),
shell = True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result= ret.stdout.read() + ret.stderr.read()
conn.send(result)
except ConnectionResetError:
break
conn.close()
phone.close()
# 客户端
import socket
phone = socket.socket()
phone.connect(('127.0.0.1',6666))
while 1:
cmd = input('>>>').strip()
phone.send(cmd.encode('utf-8'))
result = phone.recv(1024)
print(result.decode('gbk'))
phone.close()
8.6.2 基于UDP协议的socket
先从服务器端说起。服务端先初始化Socket,然后与端口绑定(bind),recvform接收消息,这个消息有两项,消息内容和对方客户端的地址,然后回复消息时也要带着你收到的这个客户端的地址,发送回去,最后关闭连接,一次交互结束.
udp是无链接的,先启动哪一端都不会报错
# 服务端
import socket
udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_server.bind(('127.0.0.1',9000))
while 1:
from_client_date = udp_server.recvfrom(1024) # 接收到的是一个元组形式的数据(bytes类型,(IP,端口)
print(f'来自{from_client_date[1]}的消息:{from_client_date[0].decode("UTF-8")}')
to_client_data = input('>>>')
udp_server.sendto(to_client_data.encode('utf-8'),from_client_date[1])
# 客户端
import socket
udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while 1:
to_server_data = input('>>>').strip()
udp_client.sendto(to_server_data.encode('utf-8'),('127.0.0.1',9000)) # 发送信息加上接收方IP和端口
from_server_data = udp_client.recvfrom(1024)
print(f'来自{from_server_data[1]}的消息:{from_server_data[0].decode("utf-8")}')