网络编程tcp协议与socket以及单例的补充

一、单例补充

  • 实现单列的几种方式
#方式一:classmethod

# class Singleton:
#
# __instance = None
#
# @classmethod
# def singleton(cls):
#
# if not cls.__instance:
# cls.__instance = cls()
#
# return cls.__instance
#
# obj1 = Singleton.singleton()
# obj2 = Singleton.singleton()
# print(obj1)
# print(obj2)
# <__main__.Singleton object at 0x000002127F230D08>
# <__main__.Singleton object at 0x000002127F230D08> #方式二: __new__
# class Singleton:
#
# __instance = None
#
# def __new__(cls, *args, **kwargs):
#
# if not cls.__instance:
# cls.__instance = object.__new__(cls)
#
# return cls.__instance
#
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1)
# print(obj2)
# <__main__.Singleton object at 0x00000257AAE10A88>
# <__main__.Singleton object at 0x00000257AAE10A88> #方式三:装饰器
# def singleton(cls): #cls---> Father
#
# __instance = {}
#
# def inner(*args, **kwargs):
# if cls not in __instance:
# obj = cls(*args, **kwargs)
# __instance[cls] = obj
#
#
# return __instance[cls]
# return inner
#
# @singleton
# class Father:
# pass
#
# print(Father())
# print(Father())
# <__main__.Father object at 0x000001F17EB21548>
# <__main__.Father object at 0x000001F17EB21548> #方式四
先定义一个Singletoncls的py文件内容如下:
class Singletoncls:
pass obj = Singletoncls()
# from Singletoncls import obj
# print(obj)
# from Singletoncls import obj
# print(obj)
# from Singletoncls import obj
# print(obj)
# <Singletoncls.Singletoncls object at 0x00000249CD25BE48>
# <Singletoncls.Singletoncls object at 0x00000249CD25BE48>
# <Singletoncls.Singletoncls object at 0x00000249CD25BE48> # 方式五:元类

二、tcp协议以及粘包问题

  • 理论知识
传输层:
-tcp协议
-udp协议
端口(port):标识一台计算机上的某一个软件。
-0-1024:禁止使用,因为是操作系统在用
-8000---->以后接着用 - 以下的一些软件的固定端口不要碰:
django:8000
mysql:3306
redis:6379
flask:5000
tomcat:8080
mongodb:27017
...
要想要传输数据,必须建立双向通道 1、tcp协议:三次握手,四次挥手
-tcp协议建立双向通道 - 三次握手,键连接:
1:客户端向服务端发送建立连接的请求
2:服务端返回收到的请求信息给客户端,并且发送往客户端建立的请求
3:客户端接收到服务端的请求,返回请求成功给服务端,完成双向连接 - 反馈机制:
客户端往服务端发送请求,服务端必须返回响应
告诉客户端收到请求了,并且将服务端的数据一并返回给客户端
c--->s:一次请求,必须有一次响应 - 缺点:
- 洪水攻击:
指的是通过伪造大量的请求,往对方服务器发送请求
导致对方服务器跟不上,以至于瘫痪。
Linux系统有个参数可以限制 - 半连接池listen:限制用户在同一时间段内的访问数量 - 四次挥手,断开连接
1:客户端向服务端发送断开连接的请求
2:服务端返回收到请求的信息给客户端
3:服务端确认所有的数据发送完成以后,再发送同意断开连接的请求给客户端
4:客户端返回收到断开连接的请求,给服务端 2、socket套接字通信:
- 什么是socket?
socket是一个模块,又称套接字,用来封装 互联网协议(应用层以下的层) - 为什么要有socket?
socket可以实现 互联网协议应用层已下的层的工作
- 提高开发效率 - 怎么使用socket?
import socket
写socket套接字:
client
sever 3、粘包问题
-1)问题:无法确认对方发送过来的数据的大小 -2)问题:在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送 解决:确认对方数据的大小 4、解决粘包问题(struct模块)
-无论那一段发送数据
-客户端
-1)先制作报头,并发送(struct)
-2)发送真实数据 服务端
-1)接收报头,并解包获取 真实的数据长度
-2)根据真实数据长度 接收真实数据
recv(真实数据长度)

三、socket套接字

  • socket套接字初级版本
  • 演示
-sever:

'''
先启动套接服务端
''' import socket #买手机
sever = socket.socket() #绑定手机卡
sever.bind(
('127.0.0.1', 9876)
) #半连接池
sever.listen(5) #最多同时五个人坐椅子,实际上==6 print(
'服务端正在运行...'
) #等待电话接入
#coon:指的是服务端往客户端的管道
coon, addr = sever.accept() #接听对方讲话的内容
#data客户端发送过来的消息
data = coon.recv(1024) #一次性可接受1024bytes的数据
print(data) >>>服务端正在运行...
>>>b'hello' #挂电话
coon.close() -client:
'''
先启动服务端后再启动客户端
''' import socket #买手机
client = socket.socket() #拨打电话
client.connect(
('127.0.0.1', 9876)
) print('客户端正在运行...') #必须发送bytes类型的数据
#开始讲话
client.send(b'hello')
# 或client.send('hello'.encode('utf_8'))
>>>客户端正在运行...
  • socket套接字升级版本
- sever

'''
注意:
客户端法送一次,我服务端就得先接受一次,之后才可以再向客户端发送消息
''' import socket #买手机
sever = socket.socket() #绑定手机卡
#里面绑定的是一个元祖
sever.bind(
('127.0.0.1', 9876)
) #半连接池
sever.listen(5) print('服务端正在等待服务...') #等待电话接入
#coon:指的是服务端往客户端的管道 coon, addr = sever.accept() #接听对方讲话的内容
data = coon.recv(1024)
print(data) #服务端往客户端发送消息
coon.send(b'hi i am sever') #挂电话
coon.close() >>>服务端正在等待服务...
>>>b'hello i am client...' - client
'''
启动服务端后再启动客户端
'''
import socket #买手机
client = socket.socket() #拨号
client.connect(
('127.0.0.1', 9876)
) print('客户端正在发送请求...') client.send(b'hello i am client...') #接收服务端的请求
data = client.recv(1024) print(data) client.close()
>>>客户端正在发送请求...
>>>b'hi i am sever'
  • socket套接字高级版本
-sever

import socket

#买手机
sever = socket.socket() #绑定手机卡
sever.bind(
('127.0.0.1', 9876)
) #半连接池
sever.listen(5) print('服务端正在运行...') #等待电话接入
coon, addr = sever.accept() while True:
#接收对方讲话内容
#data客户端发送过来的消息
data = coon.recv(1024)
if len(data) == 0:
break
if data.decode('utf-8') == 'q':
break
print(data.decode('utf-8')) send_data = input('服务端...') coon.send(send_data.encode('utf-8')) #挂电话
coon.close()
服务端正在运行...
服务端...你好啊亚峰 -client import socket #买手机
client = socket.socket() #拨打电话
client.connect(
('127.0.0.1', 9876)
) print('客户端正在发送请求...') while True:
send_data = input('客户端>>>:').strip()
client.send(send_data.encode('utf-8'))
data = client.recv(1024)
if data.decode('utf-8') == 'q':
break
if len(data) == 0:
break print(data.decode('utf-8')) client.close()
>>>客户端正在发送请求...
>>>客户端>>>:你好啊热巴
>>>好啊亚峰
  • socket套接字终级版本
- sever

import socket

#买手机
sever = socket.socket() #绑定手机卡
sever.bind(
('127.0.0.1', 9876)
) #半连接池
sever.listen(5) print('服务端正在服务...') #循环实现可接受多个用户访问
while True: coon, addr = sever.accept()
print(addr) #循环实现通信
while True:
try:
#监听代码是否有异常出现
#接听对方讲话的内容
#data客户端发送过来的消息
data = coon.recv(1024) if len(data) == 0:
break if data.decode('utf-8') =='q':
break print(data.decode('utf-8')) send_data = input('服务端>>>...') #服务端向客户端发送消息
coon.send(send_data.encode('utf-8')) except Exception as e:
print(e)
break #挂电话
coon.close() >>>
服务端正在服务...
('127.0.0.1', 52467)
我想找迪丽热巴
服务端>>>...你好啊亚峰,我是热巴,有什么能帮你吗
热巴youare beautiful
服务端>>>...谢谢亚峰 -client import socket #买手机 client = socket.socket() #拨打号码
client.connect(
('127.0.0.1', 9876)
) print('客户端正在发送请求...') while True:
send_data = input('客户端>>>:')
client.send(send_data.encode('utf-8'))
data = client.recv(1024) if data.decode('utf-8') == 'q':
break if len(data) == 0:
break print(data.decode('utf-8'))
>>>
client.close()
客户端正在发送请求...
客户端>>>:我想找热巴
你好啊亚峰,我是热巴,有什么能帮你吗
客户端>>>:热巴you are beautiful
谢谢亚峰
客户端>>>:

四、粘包问题

  • 粘包问题的出现以及几种情况
  • 第一个问题
-sever
#问题一不知道数据的具体长度
# import socket
#
# import subprocess
#
# #买手机
# sever = socket.socket()
#
# #绑定电话卡
# sever.bind(
# ('127.0.0.1', 9867)
# )
#
# #半整数池
# sever.listen(5)
#
# while True:
# coon, addr = sever.accept()
# print(addr)
#
# while True:
# try:
# #recv从内存中获取数据
# cmd = coon.recv(1024)
#
# if len(cmd) == 0:
# continue
# cmd = cmd.decode('utf-8')
# if cmd == 'q':
# break
#
# #调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
# obj = subprocess.Popen(
# cmd, shell=True, stdout=subprocess.PIPE,
# stderr=subprocess.PIPE
# )
# #结果交给result变量名
# result = obj.stdout.read() + obj.stderr.read()
# print(len(result))
#
# #windows默认是gbk
# print(result.decode('gbk'))
#
# #将结果返回给客户端
# coon.send(result)
# except Exception as e:
# print(e)
# break
#
# coon.close() -client
# import socket
#
# client = socket.socket()
#
# client.connect(
# ('127.0.0.1', 9867)
# )
#
# while True:
#
# cmd = input('客户端输入的内容:')
#
# client.send(cmd.encode('utf-8'))
#
# data = client.recv(19190)
#
# print(len(data))
#
# print(data.decode('gbk'))
  • 第二种问题
-sever

#问题二:当发送多次传入的数据长度却不是很长的时候,服务端多次接收后面接收的没内容

import socket

sever = socket.socket()

sever.bind(
('127.0.0.1', 9000)
) sever.listen(5) coon, addr = sever.accept() data = coon.recv(10)
print(data) data = coon.recv(1024)
print(data) data = coon.recv(1024)
print(data)
>>>b'hellohello'
>>>b'hello'
>>>b'' - client
#问题二
import socket client = socket.socket() client.connect(
('127.0.0.1', 9000)
) client.send(b'hello')
client.send(b'hello')
client.send(b'hello')

五、解决粘包问题

  • 演示
- sever

import socket
import subprocess
import struct sever = socket.socket() sever.bind(
('127.0.0.1', 9000)
) sever.listen(5) while True:
coon, addr = sever.accept()
print(addr) while True:
try: #获取客户端传过来的报头
header = coon.recv(4) #解包获取真实的数据长度
data_len = struct.unpack('i', header)[0] #准备接收真实数据
cmd = coon.recv(data_len) if len(cmd) == 0:
continue cmd = cmd.decode('utf-8') if cmd == 'q':
break #调用subprocess连接终端,对终端进行操作,并获取操作后的正确或错误的结果
obj = subprocess.Popen(
cmd, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
) #结果交给result变量名
result = obj.stdout.read() + obj.stderr.read() print('发送给客户端的真实长度', len(result)) #将结果返回给客户端,做一个报头,返回给客户端
header = struct.pack('i', len(result))
print(len(header))
coon.send(header)
coon.send(result) except Exception as e:
print(e)
break coon.close() - client import struct
import socket client = socket.socket() client.connect(
('127.0.0.1', 9000)
) while True: cmd = input('客户端输入的内容:') cmd_bytes = cmd.encode('utf-8') #做一个报头
header = struct.pack('i', len(cmd_bytes)) print(len(header)) client.send(header) #待服务器确认长度以后,再发送真实数据长度
client.send(cmd_bytes) #接收服务端返回的报头
s_header = client.recv(4) #解包,接收服务端返回的真实数据
data_len = struct.unpack('i', s_header)[0] result = client.recv(data_len) print('接收服务器返回的真实数据长度', len(result))
print(result.decode('gbk'))
  • 演示二
-sever

import socket
import struct
import json sever = socket.socket() sever.bind(
('127.0.0.1', 9000)
) sever.listen(5) while True: coon, addr = sever.accept()
print(addr) while True:
try:
#获取客户端传来的报头
header = coon.recv(4) #解包,获取真实的数据长度
json_len = struct.unpack('i', header)[0] #接收json(dictionary)的真实长度
json_bytes_data = coon.recv(json_len) #反序列化将bytes类型数据变成json数据
json_data = json_bytes_data.decode('utf-8') back_dic = json.loads(json_data)
print(back_dic)
print(back_dic.get('movie_len')) except Exception as e:
print(e)
break coon.close() >>>('127.0.0.1', 53414)
>>>{'movie_name': '色戒', 'movie_len': 100000}
>>>100000 -client
import struct
import socket
import json client = socket.socket() client.connect(
('127.0.0.1', 9000)
) while True: movie_name = input('请输入上传电影的名字:').strip() #伪装电影真实数据
movie_len = 100000 send_dic = {
'movie_name': movie_name,
'movie_len': movie_len
} #序列化
json = json.dumps(send_dic)
# print(json)
# print(json.encode('utf-8'))
# print(len(json.encode('utf-8'))) json_bytes = json.encode('utf-8') #做一个报头
header = struct.pack('i', len(json_bytes)) #发送报头
client.send(header) #发送真实数据
client.send(json_bytes) >>>请输入上传电影的名字:色戒

最新文章

  1. System.BadImageFormatException : 未能加载文件或程序集“Medici.PaymentRecover, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。试图加载格式不正确的程序。
  2. XCODE UITextField 中的属性和用法
  3. thinkphp开发技巧经验分享
  4. 类似github的框架
  5. (转)WEB第三方打印控件[ASP.NET常用工具]
  6. Unity的物理引擎是如何实现碰撞的呢?
  7. 向linux内核加入系统调用新老内核比較
  8. php使用正则
  9. wind river hypervisor 2.0.2.1
  10. c# Activex开发之HelloWorld
  11. Java SE 8 流库(二)
  12. May 29. 2018 Week 22nd Tuesday
  13. AMD/CMD/CommonJs到底是什么?它们有什么区别?
  14. Oracle中 (+)与left join 的用法区别
  15. 基于 redis 的分布式锁实现 Distributed locks with Redis debug 排查错误
  16. [Java] 例外處裡 try/catch &amp; throws
  17. .Net MVC TextBoxFor 扩展 placeholder 与 class 属性
  18. VMware虚拟机中CentOS 7的硬盘空间扩容
  19. C#编程(八十二)---------- 用户自定义异常类
  20. Linux 时间矫正命令

热门文章

  1. 计划任务cron
  2. inux 内存监控分析
  3. 如何使用TG Pro for Mac的自定义控制功能完全覆盖系统
  4. ES6 学习之 let
  5. java开发,入职半年。对未来迷茫,如何发展?
  6. 微信支付 第三篇 微信调用H5页面进行支付
  7. vs2017 输出 ling to sql 转为执行的sql语句
  8. Oracle VirtualBox安装CentOS 8
  9. diango下载、创建、启动
  10. 12C新功能:在线移动数据文件 (Doc ID 1566797.1)