视频加载失败

基于 TCP 协议的简单套接字

3151 字
16 分钟
基于 TCP 协议的简单套接字

基于TCP协议的简单套接字(打电话模型)#

【一】简单版1.0#

服务端#

# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
# socket.SOCK_STREAM :流式协议 ----> TCP协议 ----> 所有数据是一个整体
# socket.SOCK_DGRAM : 报协议 ----> 每一次数据都是单独一部分
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.绑定手机卡 ---> 192.168.1.50(本机IP地址)
# 0.0.0.0(任意IP地址) ---> 关联公网IP才会起作用 ----> 服务器用
# 127.0.0.1(本机固定IP地址) ---> 只有本机才能访问这个地址(测试用)
# 端口号:0-65535, 1024以前的都被系统保留使用
# phone.bind(('ip', port))
phone.bind(('127.0.0.1', 8080))
# 【3】.开机 -- 监听状态
# 5 :指的是半连接池的大小
phone.listen(5)
print(f'服务器启动,开始监听ip:>>>{"127.0.0.1"},port:>>>{8080}')
# (1)服务器启动,开始监听ip:>>>127.0.0.1,port:>>>8080
# 【4】.等待电话链接请求:拿到电话链接 conn
# 返回的是双向通路 --- 操作系统维持链接
# conn : 双向通路的链接
# client_addr : 客户端的iP和端口
conn, client_addr = phone.accept()
print('这是服务端的conn:>>>', conn)
# (3)这是服务端的conn:>>> <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 5249)>
print('这是服务端的client_addr:>>>', client_addr)
# (4)这是服务端的client_addr:>>> ('127.0.0.1', 5249)
# 【5】.接收消息
# 1024 :最大接受的数据量为1024 bytes类型,收到的是bytes类型
data = conn.recv(1024)
# 对接受的二进制数据进行解码
print('从客户端接受的数据:>>>>', data.decode('utf-8'))
# (5)从客户端接受的数据:>>>> is running for 发送信息
# 发消息 返回消息状态等信息
conn.send(data.upper())
# 【6】.关闭连接(必选的回收资源操作) conn
# 完成后断开连接
conn.close()
# 【7】.关机(可选操作)
phone.close()

客户端#

# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.拨通服务端电话
# connect(('服务端ip', 服务端端口))
phone.connect(('127.0.0.1', 8080))
# (2)
# 【3】.通信
# send(二进制数据类型)
phone.send('is running for 发送信息'.encode('utf8'))
# 接受服务端返回的数据
data = phone.recv(1024)
# 打印返回的消息 解码
print(data.decode('utf8'))
# (6)IS RUNNING FOR 发送信息
# 【4】.关闭连接(必选的回收资源操作)
phone.close()

上面的问题就是信息只能传输一次

【二】升级版2.0#

加上通信循环

【1】版本2.1 - 通信循环结束条件#

服务端#

# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
# socket.SOCK_STREAM :流式协议 ----> TCP协议 ----> 所有数据是一个整体
# socket.SOCK_DGRAM : 报协议 ----> 每一次数据都是单独一部分
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.绑定手机卡 ---> 192.168.1.50(本机IP地址)
# 0.0.0.0(任意IP地址) ---> 关联公网IP才会起作用 ----> 服务器用
# 127.0.0.1(本机固定IP地址) ---> 只有本机才能访问这个地址(测试用)
# 端口号:0-65535, 1024以前的都被系统保留使用
# phone.bind(('ip', port))
phone.bind(('127.0.0.1', 8080))
# 【3】.开机 -- 监听状态
# 5 :指的是半连接池的大小
phone.listen(5)
print(f'服务器启动,开始监听ip:>>>{"127.0.0.1"},port:>>>{8080}')
# (1)服务器启动,开始监听ip:>>>127.0.0.1,port:>>>8080
# 【4】.等待电话链接请求:拿到电话链接 conn
# 返回的是双向通路 --- 操作系统维持链接
# conn : 双向通路的链接
# client_addr : 客户端的iP和端口
conn, client_addr = phone.accept()
print('这是服务端的conn:>>>', conn)
# (3)这是服务端的conn:>>> <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 5249)>
print('这是服务端的client_addr:>>>', client_addr)
# (4)这是服务端的client_addr:>>> ('127.0.0.1', 5249)
while True:
# 【5】.接收消息
# 1024 :最大接受的数据量为1024 bytes类型,收到的是bytes类型
data = conn.recv(1024)
if data.decode('utf-8') == 'q':
break
# 对接受的二进制数据进行解码
print('从客户端接受的数据:>>>>', data.decode('utf-8'))
# (5)从客户端接受的数据:>>>> is running for 发送信息
# 发消息 返回消息状态等信息
conn.send(data.upper())
# 【6】.关闭连接(必选的回收资源操作) conn
# 完成后断开连接
conn.close()
# 【7】.关机(可选操作)
phone.close()

客户端#

# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.拨通服务端电话
# connect(('服务端ip', 服务端端口))
phone.connect(('127.0.0.1', 8080))
# (2)
while True:
# 【3】.通信
# send(二进制数据类型)
msg = input('请输入需要发送的消息:>>>>').strip()
phone.send(f'{msg}'.encode('utf8'))
# 加入结束条件强制结束通信
if msg == 'q':
break
# 接受服务端返回的数据
data = phone.recv(1024)
# 打印返回的消息 解码
print(data.decode('utf8'))
# (6)IS RUNNING FOR 发送信息
# 【4】.关闭连接(必选的回收资源操作)
phone.close()

输入的信息为空时,会阻塞通信

阻塞在服务端的反馈信息位置

客户端的接受信息不能为空

【2】版本2.2 - 用户输入信息为空时阻塞#

客户端#

# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.拨通服务端电话
# connect(('服务端ip', 服务端端口))
phone.connect(('127.0.0.1', 8080))
# (2)
while True:
# 【3】.通信
# send(二进制数据类型)
msg = input('请输入需要发送的消息:>>>>').strip()
phone.send(f'{msg}'.encode('utf8'))
if len(msg) == 0: continue
# 加入结束条件强制结束通信
if msg == 'q':
break
# 接受服务端返回的数据
data = phone.recv(1024)
# 打印返回的消息 解码
print(data.decode('utf8'))
# (6)IS RUNNING FOR 发送信息
# 【4】.关闭连接(必选的回收资源操作)
phone.close()

服务端#

# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
# socket.SOCK_STREAM :流式协议 ----> TCP协议 ----> 所有数据是一个整体
# socket.SOCK_DGRAM : 报协议 ----> 每一次数据都是单独一部分
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.绑定手机卡 ---> 192.168.1.50(本机IP地址)
# 0.0.0.0(任意IP地址) ---> 关联公网IP才会起作用 ----> 服务器用
# 127.0.0.1(本机固定IP地址) ---> 只有本机才能访问这个地址(测试用)
# 端口号:0-65535, 1024以前的都被系统保留使用
# phone.bind(('ip', port))
phone.bind(('127.0.0.1', 8080))
# 【3】.开机 -- 监听状态
# 5 :指的是半连接池的大小
phone.listen(5)
print(f'服务器启动,开始监听ip:>>>{"127.0.0.1"},port:>>>{8080}')
# (1)服务器启动,开始监听ip:>>>127.0.0.1,port:>>>8080
# 【4】.等待电话链接请求:拿到电话链接 conn
# 返回的是双向通路 --- 操作系统维持链接
# conn : 双向通路的链接
# client_addr : 客户端的iP和端口
conn, client_addr = phone.accept()
print('这是服务端的conn:>>>', conn)
# (3)这是服务端的conn:>>> <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 5249)>
print('这是服务端的client_addr:>>>', client_addr)
# (4)这是服务端的client_addr:>>> ('127.0.0.1', 5249)
while True:
# 【5】.接收消息
# 1024 :最大接受的数据量为1024 bytes类型,收到的是bytes类型
data = conn.recv(1024)
if data.decode('utf-8') == 'q':
break
# 对接受的二进制数据进行解码
print('从客户端接受的数据:>>>>', data.decode('utf-8'))
# (5)从客户端接受的数据:>>>> is running for 发送信息
# 发消息 返回消息状态等信息
conn.send(data.upper())
# 【6】.关闭连接(必选的回收资源操作) conn
# 完成后断开连接
conn.close()
# 【7】.关机(可选操作)
phone.close()

客户端强制终止程序时,服务端会产生一系列问题

【3】版本2.3 - 用户信息为空时检测异常#

  • 客户端
# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.拨通服务端电话
# connect(('服务端ip', 服务端端口))
phone.connect(('127.0.0.1', 8080))
# (2)
while True:
# 【3】.通信
# send(二进制数据类型)
msg = input('请输入需要发送的消息:>>>>').strip()
phone.send(f'{msg}'.encode('utf8'))
if len(msg) == 0: continue
# 加入结束条件强制结束通信
if msg == 'q':
break
# 接受服务端返回的数据
data = phone.recv(1024)
# 打印返回的消息 解码
print(data.decode('utf8'))
# (6)IS RUNNING FOR 发送信息
# 【4】.关闭连接(必选的回收资源操作)
phone.close()
  • 服务端
# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
# socket.SOCK_STREAM :流式协议 ----> TCP协议 ----> 所有数据是一个整体
# socket.SOCK_DGRAM : 报协议 ----> 每一次数据都是单独一部分
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.绑定手机卡 ---> 192.168.1.50(本机IP地址)
# 0.0.0.0(任意IP地址) ---> 关联公网IP才会起作用 ----> 服务器用
# 127.0.0.1(本机固定IP地址) ---> 只有本机才能访问这个地址(测试用)
# 端口号:0-65535, 1024以前的都被系统保留使用
# phone.bind(('ip', port))
phone.bind(('127.0.0.1', 8080))
# 【3】.开机 -- 监听状态
# 5 :指的是半连接池的大小
phone.listen(5)
print(f'服务器启动,开始监听ip:>>>{"127.0.0.1"},port:>>>{8080}')
# (1)服务器启动,开始监听ip:>>>127.0.0.1,port:>>>8080
# 【4】.等待电话链接请求:拿到电话链接 conn
# 返回的是双向通路 --- 操作系统维持链接
# conn : 双向通路的链接
# client_addr : 客户端的iP和端口
conn, client_addr = phone.accept()
print('这是服务端的conn:>>>', conn)
# (3)这是服务端的conn:>>> <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 5249)>
print('这是服务端的client_addr:>>>', client_addr)
# (4)这是服务端的client_addr:>>> ('127.0.0.1', 5249)
while True:
# 【5】.接收消息
# 1024 :最大接受的数据量为1024 bytes类型,收到的是bytes类型
try:
data = conn.recv(1024)
if len(data) == 0:
# 在 unix 系统里,一旦data收到的内容为空
# 就意味着一种异常行为:客户端非法断开了链接
break
if data.decode('utf-8') == 'q':
break
# 对接受的二进制数据进行解码
print('从客户端接受的数据:>>>>', data.decode('utf-8'))
# (5)从客户端接受的数据:>>>> is running for 发送信息
# 发消息 返回消息状态等信息
conn.send(data.upper())
except Exception as e:
break
# 【6】.关闭连接(必选的回收资源操作) conn
# 完成后断开连接
conn.close()
# 【7】.关机(可选操作)
phone.close()

【三】迭代版3.0#

  • 服务端应该满足的特点
    • 服务端一直提供服务
      • 在建立连接与结束链接之间再加上一层 循环
    • 服务端并发提供服务

【1】3.1 - 链接循环(循环建立链接)#

  • 客户端
# -*-coding: Utf-8 -*-
# @File : 客户端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.拨通服务端电话
# connect(('服务端ip', 服务端端口))
phone.connect(('127.0.0.1', 8080))
# (2)
while True:
# 【3】.通信
# send(二进制数据类型)
msg = input('请输入需要发送的消息:>>>>').strip()
phone.send(f'{msg}'.encode('utf8'))
if len(msg) == 0: continue
# 加入结束条件强制结束通信
if msg == 'q':
break
# 接受服务端返回的数据
data = phone.recv(1024)
# 打印返回的消息 解码
print(data.decode('utf8'))
# (6)IS RUNNING FOR 发送信息
# 【4】.关闭连接(必选的回收资源操作)
phone.close()
  • 服务端
# -*-coding: Utf-8 -*-
# @File : 服务端 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/20
import socket
# 【1】.买手机
# socket.SOCK_STREAM :流式协议 ----> TCP协议 ----> 所有数据是一个整体
# socket.SOCK_DGRAM : 报协议 ----> 每一次数据都是单独一部分
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 【2】.绑定手机卡 ---> 192.168.1.50(本机IP地址)
# 0.0.0.0(任意IP地址) ---> 关联公网IP才会起作用 ----> 服务器用
# 127.0.0.1(本机固定IP地址) ---> 只有本机才能访问这个地址(测试用)
# 端口号:0-65535, 1024以前的都被系统保留使用
# phone.bind(('ip', port))
phone.bind(('127.0.0.1', 8080))
# 【3】.开机 -- 监听状态
# 5 :指的是半连接池的大小
phone.listen(5)
print(f'服务器启动,开始监听ip:>>>{"127.0.0.1"},port:>>>{8080}')
# (1)服务器启动,开始监听ip:>>>127.0.0.1,port:>>>8080
# 【4】.等待电话链接请求:拿到电话链接 conn
# ---- 加上链接循环 ----> 循环建链接
while True:
# 返回的是双向通路 --- 操作系统维持链接
# conn : 双向通路的链接
# client_addr : 客户端的iP和端口
conn, client_addr = phone.accept()
# (3)这是服务端的conn:>>> <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 5249)>
print('这是服务端的client_addr:>>>', client_addr)
# (4)这是服务端的client_addr:>>> ('127.0.0.1', 5249)
while True:
# 【5】.接收消息
# 1024 :最大接受的数据量为1024 bytes类型,收到的是bytes类型
try:
data = conn.recv(1024)
if len(data) == 0:
# 在 unix 系统里,一旦data收到的内容为空
# 就意味着一种异常行为:客户端非法断开了链接
break
if data.decode('utf-8') == 'q':
break
# 对接受的二进制数据进行解码
print('从客户端接受的数据:>>>>', data.decode('utf-8'))
# (5)从客户端接受的数据:>>>> is running for 发送信息
# 发消息 返回消息状态等信息
conn.send(data.upper())
except Exception as e:
break
# 【6】.关闭连接(必选的回收资源操作) conn
# 完成后断开连接
conn.close()
# 【7】.关机(可选操作)
phone.close()

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
Profile Image of the Author
Dream
Hello, I'm Dream.
公告
欢迎来到我的博客!爱学习爱进步。
分类
标签
最新动态
站点统计
文章
300
分类
5
标签
26
总字数
640,882
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录