网络编程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) >>>请输入上传电影的名字:色戒

网络编程之tcp协议以及粘包问题的更多相关文章

  1. day28 8_7 网络编程之tcp协议

    一.socket模块 socket模块就是用来网络搭建的模块,socket也叫套接字. 创建网络连接,需要使用两个模块进行模拟,一个作为server服务器端,一个作为client客户端. 在服务器端, ...

  2. 网络编程之TCP协议与UDP协议

    了解网络就要了解一些基本的协议今天主要跟大家分享一些关于TCP 协议UDP协议的相关知识 首先介绍一下TCP协议 TCP(Transmission Cintrol Protocol)可靠的.面向连接的 ...

  3. 网络编程之TCP协议怎么使用?

    TCP 通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器会写的数据 表示客户端的类: java.net.Socket;此类实现客户端套接字.套接字是两台机器间通信的端点 套接字:包含了 ...

  4. java 26 - 7 网络编程之 TCP协议代码优化

    上次所写的代码中,客户端和服务器端所进行的数据传输所用的是字节流. 优化: A:这次,为了高效,对这个字节流通过转换流来进行包装,包装成高效字符流. B:这次,传输的数据是通过键盘录入的数据. 服务器 ...

  5. java 26 - 6 网络编程之 TCP协议 传输思路 以及 代码

    TCP传输 Socket和ServerSocket 建立客户端和服务器 建立连接后,通过Socket中的IO流进行数据的传输 关闭socket 同样,客户端与服务器是两个独立的应用程序 TCP协议发送 ...

  6. python六十九课——网络编程之TCP协议

    1.1 概述: TCP协议通过三次握手协议将客户端与服务器端连接,两端使用各自的Socket对象.Socket对象中包含了IO流,供数据传输. 即:TCP协议在客户端与服务器端通过Socket组成了I ...

  7. java 26 - 9 网络编程之 TCP协议多用户上传文件

    TCP实现多用户上传文件: 需要同时给多用户上传文件,这样就得用多线程来实现. 实际上,这样的话,上传的先后顺序和速度就跟客户端的带宽有关:带宽够,就容易抢占到线程的执行权: 首先,创建个线程类:(这 ...

  8. java 26 - 8 网络编程之 TCP协议的练习

    TCP练习: 1.客户端键盘录入,服务器输出文本文件 客户端代码: public class ClientDemo { public static void main(String[] args) t ...

  9. java 26 - 8 网络编程之 TCP协议上传图片

    上次的是上传TXT文件,这次上传的是图片.同样,上传成功需要反馈给客户端. 区别: TXT文件用记事本打开,我们可以看得懂,所以用了缓冲字符流,对通道内的字节流进行包装了. 而图片用记事本打开,我们看 ...

随机推荐

  1. Shell(六):输入/输出重定向

    重定向的作用是将命令的执行结果输出到指定的文件中. 重定向命令列表如下: 文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR). 1.输出重 ...

  2. DiskCatalogMaker for Mac常见问题解答

    DiskCatalogMaker for Mac是Mac上简单实用的磁盘管理工具,可以帮助您对多张光盘使用批量扫描模式, 生成缩略图图像选项,更加清晰,并请将其快速编目引擎与其他编目人员比较,在本篇文 ...

  3. Ubuntu : apt 命令

    apt 命令是一个功能强大的命令行工具,它不仅可以更新软件包列表索引.执行安装新软件包.升级现有软件包,还能够升级整个 Ubuntu 系统(apt 是 Debian 系操作系统的包管理工具).与更专业 ...

  4. 我用 Python 破解了同事的加密压缩包!

    ​ 作者 | 朱小五 又是一杯奶茶. 事情的经过是这样的: ​ ​ 又是奶茶,行吧快点开工,争取李大伟回来之前搞定 李大伟说是6位数字密码 那么我们可以利用python生成全部的六位数字密码 #生成从 ...

  5. Go 开发关键技术指南 | 为什么你要选择 GO?(内含超全知识大图)

    作者 | 杨成立(忘篱) 阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复 Go 即可查看清晰知识大图! 导读:从问题本身出发,不局限于 Go 语言,探讨服务器中常常遇到的 ...

  6. GO汇总

    1.基础 GO语言介绍以及开发环境配置 Go-包 Go-数据类型以及变量,常量 Go-获取变量数据类型 GO-数组与切片 GO-切片拷贝以及赋值 Go-函数 Go-闭包 GO-逻辑判断(if,else ...

  7. 6.Ansible Roles角色实战

    ==Roles小技巧:== 1.创建roles目录结构,手动或使用ansible-galaxy init test roles 2.编写roles的功能,也就是tasks. nginx rsyncd ...

  8. 获取input type=file 的文件内容(纯文本)

    一.获取input type=file 的文件内容(纯文本) 1.需求一 通过点击其他事件,来触发 文件选择框(限定格式为 .c 文件),而不是手动鼠标点击触发. [思路:] step1:将 inpu ...

  9. Linux系统学习 十五、VSFTP服务—匿名用户访问(不推荐使用,不安全)

    匿名用户访问 基本配置: anonymous_enable          #允许匿名用户访问 anon_upload_enable       #允许匿名用户上传 anon_mkdir_write ...

  10. LeetCode--回文数(简单)

    题目描述: 判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解 ...