26、套接字
Socket层
Socket套接字,是从osi七层抽象出来的抽象层,抽象了网络层和传输层,跟语言无关,任何语言都会有socket的封装。Socket是专门给开发人员用的
一、基于Tcp的socket套接字(重点)
1.1、服务端
import socket # 导入socket模块
'''
第一个socket是模块名,第二个socket是模块下的类名。
server=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
我们参数可以不写,不写默认就是TCP服务端
'''
server = socket.socket()
# 绑定地址跟端口,传一个元组,监听的地址,监听的端口
server.bind(('127.0.0.1', 8008)) # 192.168.12.44
# 监听,半连接池是5,可以缓冲5个
server.listen(5)
# 等待用户连接(看源码,有两个返回结果)
# sock是连接对象,以后这个服务端和客户端交互,使用这个对象交互。 addr是客户端地址(ip和端口)
sock, addr = server.accept()
# 接收客户端发给我的消息
data = sock.recv(1024)
print(data) # 打印
# 服务端给客户端发送消息(必须是byte格式)
sock.send(b'hello,world')
sock.close() # 关闭连接对象
server.close() # 关闭服务
1.2、客户端
import socket
# 创建socket对象
client = socket.socket()
# 连接服务端
client.connect(('127.0.0.1', 8008))
# 给服务端发送信息
client.send(b'sb')
# 收到了服务端的信息
data = client.recv(1024)
print(data) # 打印
client.close() # 关闭
二、加入链接循环的套接字服务端
我们需要服务端服务客户端完毕之后,继续服务下一个客户,而不是服务一次就关闭,则需要加入链接循环。
2.1 服务端
import socket # 导入socket模块
'''
type=socket.SOCK_STREAM -是TCP服务端
type=socket.SOCK_DGRAM -是UDP服务端
'''
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.bind(('127.0.0.1', 8008)) # 绑定地址跟端口
server.listen(5) # 监听
while True:
sock, addr = server.accept() # 等待用户连接
data = sock.recv(1024) # 接受客户端传来的信息
print(data) # 打印
sock.send('hello,world'.encode('utf-8')) # 给客户端发送信息
sock.close() # 关闭连接对象
server.close() # 关闭服务
2.2 客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8008))
client.send('sb'.encode('utf-8'))
data = client.recv(1024)
print(data)
client.close()
三、加入通信循环的套接字服务端
我们需要服务端服务客户端时,客户端可以不停的发送消息,服务端一直为客户端服务。一个客户端结束后,服务端还可以继续服务下一个,需要加入通信循环
3.1 服务端
import socket # 导入socket模块
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.bind(('127.0.0.1', 8008)) # 绑定地址跟端口
server.listen(5) # 监听
print('开始等待客户端连接')
while True:
sock, addr = server.accept() # 等待用户连接
while True:
try:
data = sock.recv(1024) # 接受客户端传来的信息
if len(data) == 0: # 表示客户端正常断开了,结束通信循环
break
print(data.decode('utf-8')) # 解码,打印用户消息
sock.send('hello,world'.encode('utf-8')) # 服务端给客户端发送消息
except Exception as e: # 表示客户端非正常断开,需要异常捕获
print(e)
break
sock.close() # 关闭连接对象
server.close() # 关闭服务
3.2 客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8008))
while True:
input_data = input('请输入发送给客户端的内容(输入q退出):')
if input_data == 'q':
break
client.send(input_data.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
client.close()
四、基于UDP的套接字客户端和服务端
4.1 服务端
import socket
# udp的服务端
server = socket.socket(type=socket.SOCK_DGRAM)
# 监听地址和端口
server.bind(('127.0.0.1', 82))
# 不需要listen,直接建立链接
print('等待客户端发送数据:')
while True:
#recvfrom回返回数据和客户端的地址
data,addr = server.recvfrom(1024)
print(data)
print(addr)
server.sendto(data.upper(), addr)
server.close()
4.2 客户端
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
client.sendto(b'sb',('127.0.0.1',82))
# data,addr=client.recvfrom(1024)
# data,_=client.recvfrom(1024)
data = client.recv(1024)
print(data)
# print(addr)
client.close()
五、客户端从服务端下载文件
5.1、服务端
import socket
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.bind(('127.0.0.1', 81))
server.listen(1)
print('开始等待客户端连接了')
while True:
sock, addr = server.accept()
print(sock)
print('客户端的地址是:', addr)
# 等待客户端发送过来的数据,如果客户端没有发送数据,会一直等着
while True:
try:
data = sock.recv(1024)
if len(data) == 0: # 这个表示客户端正常断开了,结束通信循环
break
print(data.decode('utf-8'))
# 客户端传入一个文件名,直接打开文件,发送给客户端
with open(data, 'rb') as f:
sock.send(f.read())
except Exception as e:
print(e) # 客户端非正常断开,需要异常捕获
break
sock.close()
server.close()
5.2、客户端
import socket
client=socket.socket()
client.connect(('127.0.0.1',81))
while True:
input_data=input('''
请选择要下载的文件
1.txt
2.txt
3.txt
按q退出
''')
if input_data=='q':
break
client.send(input_data.encode('utf-8'))
data=client.recv(1024)
with open('download_'+input_data,'wb') as f:
f.write(data)
print('%s下载成功'%input_data)
client.close()