如果我们需要编写基于网络进行数据交互的程序,意味着我们需要自己通过代码来控制我们之前所学习的OSI七层(很繁琐,复杂,类似于我们自己编写操作系统)
socket类似于操作系统,封装了丑陋复杂的接口提供简单快捷的接口
socket也叫套接字
基于文件类型的套接字家族(单机)
AF_UNIX
基于网络类型的套接字家族(联网)
AF_INET

客户端
import socket
# 生成socket对象指定类型和协议
client = socket.socket() # 产生对象
client.connect(('127.0.0.1', 8080)) # 服务端的IP地址和端口
while True:
msg = input('请输入您想要给服务端发送的消息>>>:').strip()
if len(msg) == 0:
print('消息不能为空')
continue
client.send(msg.encode('utf8'))
date = client.recv(1024) # 接收消息
print(date.decode('utf8')) # 打印接收的消息
# client.close() # 关闭与服务端的连接
服务端
import socket
# 这里是产生一个对象,(self, family=-1, type=-1, proto=-1, fileno=None):
server = socket.socket()
name_list = ['张红', '李治']
"""
if fileno is None:
if family == -1:
family = AF_INET 基于网络的套接子
if type == -1:
type = SOCK_STREAM # 流式协议即TCP协议
if proto == -1:
proto = 0
"""
# 绑定一个固定的网址(服务端的必备条件)
server.bind(('127.0.0.1', 8080)) # 127.0.0.1为本地回环地址 只有自己的电脑可以访问
server.listen(5) # 设置半连接池
# 等待接客
sock, addr = server.accept() # 看源码return返回sock,addr,三次握手,建立
print(sock, addr) # sock就是双向通道,addr就是客户端地址
while True:
date = sock.recv(1024) # 通道接收消息,recv后面添加的接收消息的字节
if date.decode('utf8') not in name_list:
print('你谁啊,不认识')
break
# date就是我们所接收到的消息,因为消息是通过二进制传输的,所以需要转服
print(date.decode('utf8')) # 将接收到的消息打印
msg = input('请输入您想要给客户端回复的消息>>>:')
sock.send(msg.encode('utf8'))
# 给客户端发消息,注意转二进制
# sock.close() # 关键通道
代码优化
1.聊天内容自定义
针对消息采用input获取
2.让聊天循环起来
将聊天的部分用循环包起来
3.用户输入的消息不能为空
本质其实是两边不能都是recv或者send,一定是一方收,一方发
4.服务段多次重启可能会报错
Address already in use 主要是mac电脑会报
方式1:改端口号
方式2:博客里面代码拷贝即可
5.当客户端异常断开的情况下 如何让服务端继续服务其他客人
windows服务端会直接报错
mac服务端会有一段时间反复接收空消息延迟报错
异常处理、空消息判断
半连接池的概念
server.listen(5)
当有多个客户端来链接的情况下,我们可以设置等待数量(不考虑并发问题)
假设服务端只有一个人的情况下
在测试半链接池的时候,可以不用input获取消息,直接把消息写死即可