1 接口与归一化设计

1.1 归一化概念:

  归一化的好处:

  1.归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大降低了使用者的使用难度。

  2.归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合

  继承的两种用途

  一:继承基类的方法,并且做出自己改变或者扩展(代码重用):实践中,继承的这种用途意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

  二:声明某个子类兼容于某基类,定义一个接口类(模仿java的Interface),接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

  1. class Interface:
  2. '''
  3. 定义接口Interface类来模仿接口的概念,
  4. python中压根就没有interface关键字来定义一个接口。
  5. '''
  6. def read(self): # 定接口函数read
  7. pass
  8.  
  9. def write(self): # 定义接口函数write
  10. pass
  11.  
  12. class Txt(Interface): # 文本,具体实现read和write
  13. def read(self):
  14. print('文本数据的读取方法')
  15.  
  16. def write(self):
  17. print('文本数据的读取方法')
  18.  
  19. class Sata(Interface): #磁盘,具体实现read和write
  20. def read(self):
  21. print('硬盘数据的读取方法')
  22.  
  23. def write(self):
  24. print('硬盘数据的读取方法')
  25.  
  26. class Process(Interface):
  27. def read(self):
  28. print('进程数据的读取方法')
  29.  
  30. def write(self):
  31. print('进程数据的读取方法')
  32.  
  33. t = Txt()
  34. s = Sata()
  35. p = Process()
  36.  
  37. t.read() # 运行结果:文本数据的读取方法
  38. s.read() # 运行结果:硬盘数据的读取方法
  39. p.read() # 运行结果:进程数据的读取方法

1.2 抽象类

  了解知识点

  与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

  借助abc模块,进行模拟抽象类

  1. import abc
  2. class Interface(metaclass=abc.ABCMeta):
  3. '''
  4. 定义接口Interface类来模仿接口的概念,
  5. python中压根就没有interface关键字来定义一个接口。
  6. '''
  7. @abc.abstractmethod
  8. def read(self): # 定接口函数read
  9. pass
  10. @abc.abstractmethod
  11. def write(self): # 定义接口函数write
  12. pass
  13.  
  14. class Txt(Interface): # 文本,具体实现read和write
  15. def read(self):
  16. pass
  17.  
  18. def write(self):
  19. pass
  20.  
  21. t = Txt()

1.3 多态

  面向对象的多态、多态性

  多态:指的是同一种事物的多种形态

  动物有多种形态:人、狗、猪

  1. # 多态:同一种事物的多种形态
  2. class Animal: # 同一类事物:动物
  3. def talk(self):
  4. pass
  5.  
  6. class People(Animal): # 动物的形态之一:人
  7. def talk(self):
  8. print('say hello')
  9.  
  10. class Dog(Animal): # 动物的形态之二:狗
  11. def talk(self):
  12. print('say wangwang')
  13.  
  14. p=People()
  15. d=Dog()
  16. p.talk()
  17. d.talk()

1.4 多态性

  多态性:可以在不考虑实例类型的前提下使用实例

  1. # 多态:同一种事物的多种形态
  2. class Animal: # 同一类事物:动物
  3. def talk(self):
  4. pass
  5.  
  6. class People(Animal): # 动物的形态之一:人
  7. def talk(self):
  8. print('say hello')
  9.  
  10. class Dog(Animal): # 动物的形态之二:狗
  11. def talk(self):
  12. print('say wangwang')
  13.  
  14. # 多态性:可以在不考虑实例类型的前提下使用实例
  15. p=People()
  16. d=Dog()
  17.  
  18. def Talk(animal):
  19. animal.talk()
  20.  
  21. Talk(p)
  22. Talk(d)

1.5 多态性的好处

  多态性的好处:

  1.增加了程序的灵活性

  2.增加了程序可扩展性

1.6 鸭子类型

  Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

  python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

  也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

  利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

  1. # 二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
  2. class TxtFile:
  3. def read(self):
  4. pass
  5.  
  6. def write(self):
  7. pass
  8.  
  9. class DiskFile:
  10. def read(self):
  11. pass
  12. def write(self):
  13. pass

2 封装

2.1 隐藏

  在python中用双下划线开头的方式将属性隐藏起来

  1. class Foo:
  2. __N = 1111 # _Foo__N
  3. def __init__(self,name):
  4. self.__Name=name # self._Foo__Name=name
  5.  
  6. def __f1(self): # _Foo__f1
  7. print('f1')
  8. def f2(self):
  9. self.__f1() # self._Foo__f1()
  10.  
  11. f = Foo('egon')
  12. # print(f.__N) # 把数据类型隐藏起来了
  13.  
  14. # 这种隐藏需要注意的问题:
  15. # 1:这种隐藏只是一种语法上变形操作,并不会将属性真正隐藏起来
  16. print(Foo.__dict__)
  17. print(f.__dict__) # 运行结果:{'_Foo__Name': 'egon'}
  18. print(f._Foo__Name) # 运行结果:egon
  19. print(f._Foo__N) # 运行结果:1111
  20.  
  21. # 2:这种语法级别的变形,是在类定义阶段发生的,并且只在类定义阶段发生
  22. Foo.__x = 123123
  23. print(Foo.__dict__) # 运行结果:...'__doc__': None, '__x': 123123}
  24. print(Foo.__x) # 运行结果:123123
  25. f.__x = 123123123
  26. print(f.__dict__) # 运行结果:{'_Foo__Name': 'egon', '__x': 123123123}
  27. print(f.__x) # 运行结果:123123123
  28.  
  29. # 3:在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,
  30. # 而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,
  31.  
  32. # 子类是无法覆盖的。
  33. class Foo:
  34. def __f1(self): # _Foo__f1
  35. print('Foo.f1')
  36.  
  37. def f2(self):
  38. self.__f1() # self._Foo_f1
  39.  
  40. class Bar(Foo):
  41. def __f1(self): # _Bar__f1
  42. print('Bar.f1')
  43.  
  44. b = Bar()
  45. b.f2() # 运行结果:Foo.f1

2.2 封装数据属性

  1. # 封装不是单纯意义的隐藏
  2. # 1:封装数据属性:将属性隐藏起来,然后对外提供访问属性的接口,
  3. # 关键是我们在接口内定制一些控制逻辑从而严格控制使用对数据属性的使用
  4. class People:
  5. def __init__(self,name,age):
  6. if not isinstance(name,str):
  7. raise TypeError('%s must be str' %name)
  8. if not isinstance(age,int):
  9. raise TypeError('%s must be int' %age)
  10. self.__Name=name
  11. self.__Age=age
  12. def tell_info(self):
  13. print('<名字:%s 年龄:%s>' %(self.__Name,self.__Age))
  14.  
  15. def set_info(self,x,y):
  16. if not isinstance(x,str):
  17. raise TypeError('%s must be str' %x)
  18. if not isinstance(y,int):
  19. raise TypeError('%s must be int' %y)
  20. self.__Name=x
  21. self.__Age=y
  22.  
  23. p=People('egon',18)
  24. p.tell_info() # 运行结果:<名字:egon 年龄:18>
  25.  
  26. p.set_info('Egon',19)
  27. p.tell_info() # 运行结果:<名字:egon 年龄:19>

2.3 封装函数属性

  封装函数属性的目的:隔离复杂度

  1. # 2:封装函数属性:为了隔离复杂度
  2. # 取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
  3. # 对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
  4. # 隔离了复杂度,同时也提升了安全性
  5.  
  6. class ATM:
  7. def __card(self):
  8. print('插卡')
  9. def __auth(self):
  10. print('用户认证')
  11. def __input(self):
  12. print('输入取款金额')
  13. def __print_bill(self):
  14. print('打印账单')
  15. def __take_money(self):
  16. print('取款')
  17.  
  18. def withdraw(self):
  19. self.__card()
  20. self.__auth()
  21. self.__input()
  22. self.__print_bill()
  23. self.__take_money()
  24.  
  25. a = ATM()
  26. a.withdraw()
  27. # 运行结果:
  28. # 插卡
  29. # 用户认证
  30. # 输入取款金额
  31. # 打印账单
  32. # 取款

2.4 静态属性

  1. class Foo:
  2. @property
  3. def f1(self):
  4. print('Foo.f1')
  5.  
  6. f = Foo()
  7. f.f1 # 运行结果:Foo.f1

  示例:计算BMI指数

  1. '''
  2. 例:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,
  3. 如果我们将其做成一个属性,更便于理解)
  4. 成人的BMI数值:
  5. 过轻:低于18.5
  6. 正常:18.5-23.9
  7. 过重:24-27
  8. 肥胖:28-32
  9. 非常肥胖, 高于32
  10.   体质指数(BMI)=体重(kg)÷身高^2(m)
  11.   EX:70kg÷(1.75×1.75)=22.86
  12. '''
  13. class People:
  14. def __init__(self,name,weight,height):
  15. self.name=name
  16. self.weight=weight
  17. self.height=height
  18. @property
  19. def bmi(self):
  20. return self.weight / (self.height**2)
  21.  
  22. p=People('jack',75,1.80)
  23. p.height=1.86
  24. print(p.bmi)

3 面向对象高级

3.1 反射

  通过字符串,反射到真实的属性上,找到真实的属性

  1. class Foo:
  2. x=1
  3. def __init__(self,name):
  4. self.name = name
  5.  
  6. def f1(self):
  7. print('from f1')
  8.  
  9. print(Foo.x) # Foo.__dict__['x']
  10.  
  11. f = Foo('egon')
  12. print(f.__dict__)
  13.  
  14. print(f.name)
  15. print(f.__dict__['name'])
  16.  
  17. # hasattr
  18. print(hasattr(f,'name')) # f.name
  19. print(hasattr(f,'f1')) # f.f1
  20. print(hasattr(f,'x')) # f.x
  21.  
  22. # setattr
  23. setattr(f,'age',18) # f.age=18
  24.  
  25. # getattr
  26. print(getattr(f,'name')) # f.name
  27. print(getattr(f,'abc',None)) # f.abc
  28. print(getattr(f,'name',None)) # f.abc
  29.  
  30. func = getattr(f,'f1') # f.f1
  31. func()
  32.  
  33. # delattr
  34. delattr(f,'name') # del f.name
  35. print(f.__dict__)

3.2 item系列

  Item系类,主要包括:__getitem__、__setitem__、 __delitem__,通过这几个item,可以像操作字典一样,操作对象的属性。

  1. class Foo:
  2. def __getitem__(self, item):
  3. print('=====>get')
  4. return self.__dict__[item]
  5.  
  6. def __setitem__(self, key, value):
  7. self.__dict__[key]=value
  8. # setattr(self,key,value)
  9.  
  10. def __delitem__(self, key):
  11. self.__dict__.pop(key)
  12.  
  13. f = Foo()
  14. f['name'] = "jack" # 设置
  15. print(f["name"]) # 取出属性
  16. del f["name"] # 删除
  17. print(f.__dict__)

3.3 __str__

  通过__str__,打印对象信息

  1. class People:
  2. def __init__(self,name,age,sex):
  3. self.name=name
  4. self.age=age
  5. self.sex=sex
  6.  
  7. def __str__(self): # 在对象被打印时触发执行
  8. return '<name:%s age:%s sex:%s>' %(self.name,self.age,self.sex)
  9.  
  10. p=People('alex',38,'male')
  11. print(p) # 运行结果:<name:alex age:38 sex:male>

3.4 析构方法

  用法:清理一些资源,清理一些python解析器不能清理的资源,例如:清理操作系统的资源,打开文件,向操作系统发起调用,关闭文件句柄资源

  1. class Foo:
  2. def __init__(self, name):
  3. self.name = name
  4.  
  5. def __del__(self): # 在对象资源被释放时触发
  6. print('-----del------')
  7.  
  8. f = Foo("mary")
  9. del f
  10. print('对象被释放')

4 异常

  1. # 逻辑错误
  2. # TypeError
  3. for i in 3:
  4. pass
  5.  
  6. # NameError
  7. aaaaa
  8.  
  9. # ValueError
  10. int('asdfsadf')
  11.  
  12. # IndexError
  13. l=[1,2]
  14. l[1000]
  15.  
  16. #KeyError
  17. d = {'a':1}
  18. d['b']
  19.  
  20. # AttributeError
  21. class Foo:pass
  22. Foo.x

4.1 异常处理

  如果错误发生的条件可预知的,我们需要用if进行处理,在错误发生之前进行预防

  如果错误发生的条件时不可预知的,则需要用到try…except,在错误发生之后进行处理

  1. #基本语法为
  2. try:
  3. # 被检测的代码块
  4. except 异常类型:
  5. # try中一旦检测到异常,就执行这个位置的逻辑
  6. # 示例
  7. try:
  8. f=open('a.txt')
  9. g=(line.strip() for line in f)
  10. print(next(g))
  11. print(next(g))
  12. except StopIteration:
  13. f.close()

4.2 多分支异常

  1. try:
  2. aaaa
  3. print('====>1')
  4. l = []
  5. l[3]
  6. print('====>2')
  7. d = {}
  8. d['x']
  9. print('====>3')
  10. except NameError as e:
  11. print(e)
  12. except IndexError as e:
  13. print(e)
  14. except KeyError as e:
  15. print(e)

4.3 万能异常

  1. try:
  2. # aaaa
  3. print('====>1')
  4. l = []
  5. l[3]
  6. print('====>2')
  7. except Exception as e:
  8. print(e)

4.4 基本结构

  1. try:
  2. aaaa
  3. print('====>1')
  4. l=[]
  5. l[3]
  6. print('====>2')
  7. d={}
  8. d['x']
  9. print('====>3')
  10. except NameError as e:
  11. print(e)
  12. except IndexError as e:
  13. print(e)
  14. except KeyError as e:
  15. print(e)
  16. except Exception as e:
  17. print(e)
  18. else:
  19. print('在没有错误的时候执行')
  20. finally:
  21. print('无论有无错误,都会执行')

4.5 自定义异常

  1. class EgonException(BaseException):
  2. def __init__(self, msg):
  3. self.msg=msg
  4. def __str__(self):
  5. return '<%s>' %self.msg
  6.  
  7. raise EgonException('jack 的异常')

5 Socket编程

  IP + 端口,标识唯一一个软件、应用

  tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

5.1 简单套接字

5.1.1 服务端

  1. import socket
  2.  
  3. # 买手机
  4. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5.  
  6. # 插卡
  7. phone.bind(("127.0.0.1", 8080))
  8.  
  9. # 开机
  10. phone.listen(5)
  11.  
  12. # 等待电话
  13. print("server start...")
  14. conn,client_addr = phone.accept() # tcp链接,client_addr
  15. print("链接", conn)
  16. print(client_addr)
  17.  
  18. # 基于建立的链接,收发消息
  19. client_data = conn.recv(1024)
  20. print("客户端的消息", client_data)
  21. conn.send(client_data.upper())
  22.  
  23. # 挂电话链接
  24. conn.close()
  25.  
  26. # 关机
  27. phone.close()

5.1.2 客户端

  1. import socket
  2. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  3. phone.connect(("127.0.0.1", 8080))
  4.  
  5. phone.send("hello".encode("utf-8"))
  6. server_data = phone.recv(1024)
  7. print("服务端回应的消息", server_data)
  8. phone.close() 

5.2 加上通信循环

5.2.1 服务端

  1. import socket
  2.  
  3. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  4. phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  5. phone.bind(("127.0.0.1", 8080))
  6. phone.listen(5)
  7. print("server start...")
  8. conn,client_addr = phone.accept()
  9.  
  10. while True: # 通讯循环
  11. client_data = conn.recv(1024)
  12. print("客户端的消息", client_data)
  13. conn.send(client_data.upper())
  14.  
  15. conn.close()
  16. phone.close()

5.2.2 客户端

  1. import socket
  2. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  3. phone.connect(("127.0.0.1", 8080))
  4.  
  5. while True:
  6. msg = input(">>").strip()
  7. if not msg:continue
  8. phone.send(msg.encode("utf-8"))
  9. server_data = phone.recv(1024)
  10. print("server back:", server_data.decode("utf-8"))
  11.  
  12. phone.close()

5.3 加上链接循环

5.3.1 服务端

  1. import socket
  2.  
  3. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  4. phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  5. phone.bind(("127.0.0.1", 8080))
  6. phone.listen(5)
  7. print("server start...")
  8.  
  9. while True: # 链接循环
  10. conn,client_addr = phone.accept()
  11. while True: # 通讯循环
  12. try:
  13. client_data = conn.recv(1024)
  14. if not client_data:break # 针对linux系统
  15. conn.send(client_data.upper())
  16. except Exception: # 针对windows
  17. break
  18. conn.close()
  19.  
  20. phone.close()

5.3.2 客户端

  1. import socket
  2. phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3. phone.connect(('127.0.0.1',8080))
  4.  
  5. while True:
  6. msg=input('>>: ').strip()
  7. if not msg:continue
  8. phone.send(msg.encode('utf-8'))
  9. server_data = phone.recv(1024)
  10. print(server_data.decode('utf-8'))
  11.  
  12. phone.close()

5.4 模拟ssh远程执行命令

5.4.1 服务端

  1. import socket
  2. import subprocess
  3.  
  4. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5. phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  6. phone.bind(("127.0.0.1", 8080))
  7. phone.listen(5)
  8. print("server start...")
  9.  
  10. while True: # 链接循环
  11. conn,client_addr = phone.accept()
  12. while True: # 通讯循环
  13. try:
  14. cmd = conn.recv(1024)
  15. if not cmd:break # 针对linux系统
  16.  
  17. # 执行命令,拿到结果
  18. res = subprocess.Popen(cmd.decode("utf-8"),
  19. shell = True,
  20. stdout = subprocess.PIPE,
  21. stderr = subprocess.PIPE)
  22. stdout = res.stdout.read()
  23. stderr = res.stderr.read()
  24. conn.send(stdout+stderr)
  25. except Exception: # 针对windows
  26. break
  27. conn.close()
  28.  
  29. phone.close()

5.4.2 客户端

  1. import socket
  2. phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3. phone.connect(('127.0.0.1',8080))
  4.  
  5. while True:
  6. cmd = input('>>').strip()
  7. if not cmd:continue
  8. # 发命令
  9. phone.send(cmd.encode('utf-8'))
  10.  
  11. # 收命令的执行结果
  12. cmd_res = phone.recv(1024)
  13.  
  14. # 打印结果
  15. print(cmd_res.decode('gbk'))
  16.  
  17. phone.close()

5.5 粘包现象

  Tcp出现粘包现象,udp不会出现粘包;主要是tcp基于流式的,像水流一样,没有开头,没有结尾,源源不断,会发生粘包;udp,是数据报的,不会出现粘包。

5.5.1 服务端

  1. from socket import *
  2. s = socket(AF_INET, SOCK_STREAM)
  3. s.bind(("127.0.0.1", 8080))
  4. s.listen(5)
  5.  
  6. conn,addr = s.accept()
  7.  
  8. # 收发消息
  9. data1 = conn.recv(1024)
  10. print("data1:", data1)
  11.  
  12. data2 = conn.recv(1024)
  13. print("data2:", data2)
  14.  
  15. conn.close()
  16. s.close()

5.5.2 客户端

  1. from socket import *
  2. c = socket(AF_INET, SOCK_STREAM)
  3. c.connect(("127.0.0.1", 8080))
  4.  
  5. c.send("hello".encode("utf-8"))
  6. c.send("world".encode("utf-8"))
  7. c.close()

5.6 ssh远程执行命令+定制报头

5.6.1 服务端

  1. import socket
  2. import struct
  3. import subprocess
  4. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5. phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  6. phone.bind(("127.0.0.1", 8080))
  7. phone.listen(5)
  8. print("server start...")
  9. while True: # 链接循环
  10. conn,client_addr = phone.accept()
  11. print(conn, client_addr)
  12.  
  13. while True: # 通讯循环
  14. try:
  15. cmd = conn.recv(1024)
  16. if not cmd:break
  17.  
  18. # 执行命令,拿到结果
  19. res = subprocess.Popen(cmd.decode("utf-8"),
  20. shell=True,
  21. stdout=subprocess.PIPE,
  22. stderr=subprocess.PIPE)
  23. stdout = res.stdout.read()
  24. stderr = res.stderr.read()
  25.  
  26. # 制作报头
  27. header = struct.pack("i", len(stdout)+len(stderr))
  28.  
  29. # 先发报头(固定长度)
  30. conn.send(header)
  31. # 再发真实数据
  32. conn.send(stdout)
  33. conn.send(stderr)
  34. except Exception: # 针对windows
  35. break
  36. conn.close()
  37.  
  38. phone.close()

5.6.2 客户端

  1. import socket
  2. import struct
  3.  
  4. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5. phone.connect(("127.0.0.1", 8080))
  6.  
  7. while True:
  8. cmd = input(">>").strip()
  9. if not cmd:continue
  10. # 发命令
  11. phone.send(cmd.encode("utf-8"))
  12.  
  13. # 先收报头
  14. header = phone.recv(4)
  15. total_size = struct.unpack("i", header)[0]
  16.  
  17. # 再收命令的执行结果
  18. recv_size = 0
  19. data = b""
  20. while recv_size < total_size:
  21. recv_data = phone.recv(1024)
  22. recv_size += len(recv_data)
  23. data += recv_data
  24.  
  25. # 打印结果
  26. print(data.decode("gbk"))
  27.  
  28. phone.close()

5.7 定制报头的正确方式

5.7.1 服务端

  1. import socket
  2. import struct
  3. import subprocess
  4. import json
  5. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  6. phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  7. phone.bind(("127.0.0.1", 8080))
  8. phone.listen(5)
  9. print("server start...")
  10. while True: # 链接循环
  11. conn,client_addr = phone.accept()
  12. print(conn, client_addr)
  13.  
  14. while True: # 通讯循环
  15. try:
  16. cmd = conn.recv(1024)
  17. if not cmd:break
  18.  
  19. # 执行命令,拿到结果
  20. res = subprocess.Popen(cmd.decode("utf-8"),
  21. shell=True,
  22. stdout=subprocess.PIPE,
  23. stderr=subprocess.PIPE)
  24. stdout = res.stdout.read()
  25. stderr = res.stderr.read()
  26.  
  27. # 制作报头
  28. header_dic = {"total_size":len(stdout)+len(stderr), "md5":None}
  29. header_json = json.dumps(header_dic)
  30. header_bytes = header_json.encode("utf-8")
  31.  
  32. # 1.先发报头的长度(固定4个bytes)
  33. conn.send(struct.pack("i", len(header_bytes)))
  34.  
  35. # 2.再发报头
  36. conn.send(header_bytes)
  37.  
  38. # 3.最后发真实数据
  39. conn.send(stdout)
  40. conn.send(stderr)
  41. except Exception: # 针对windows
  42. break
  43. conn.close()
  44.  
  45. phone.close()

5.7.2 客户端

  1. import socket
  2. import struct
  3. import json
  4.  
  5. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  6. phone.connect(("127.0.0.1", 8080))
  7.  
  8. while True:
  9. cmd = input(">>").strip()
  10. if not cmd:continue
  11. # 发命令
  12. phone.send(cmd.encode("utf-8"))
  13.  
  14. # 先收报头的长度
  15. struct_res = phone.recv(4)
  16. header_size = struct.unpack("i", struct_res)[0]
  17.  
  18. # 再收报头
  19. header_bytes = phone.recv(header_size)
  20. print(header_bytes)
  21. head_json = header_bytes.decode("utf-8")
  22. head_dic = json.loads(head_json)
  23.  
  24. total_size = head_dic["total_size"]
  25.  
  26. # 再收命令的执行结果
  27. recv_size = 0
  28. data = b""
  29. while recv_size < total_size:
  30. recv_data = phone.recv(1024)
  31. recv_size += len(recv_data)
  32. data += recv_data
  33.  
  34. # 打印结果
  35. print(data.decode("gbk"))
  36.  
  37. phone.close()

5.8 服务端实现并发

5.8.1 服务端

  1. import socketserver
  2.  
  3. class MyTcphandler(socketserver.BaseRequestHandler):
  4. def handle(self):
  5. while True: # 通信循环
  6. print(self.request)
  7. data = self.request.recv(1024)
  8. self.request.send(data.upper())
  9.  
  10. if __name__ == '__main__':
  11. # 取代链接循环
  12. server = socketserver.ThreadingTCPServer(("127.0.0.1",8080), MyTcphandler)
  13. server.serve_forever()

5.8.2 客户端

  1. import socket
  2. phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  3. phone.connect(("127.0.0.1", 8080))
  4.  
  5. while True:
  6. msg = input(">>").strip()
  7. if not msg:continue
  8. phone.send(msg.encode("utf-8"))
  9. server_data = phone.recv(1024)
  10. print(server_data.decode("utf-8"))
  11. phone.close()

面向对象&网络编程的更多相关文章

  1. Java面向对象 网络编程 下

    Java面向对象 网络编程  下 知识概要:                   (1)Tcp 练习 (2)客户端向服务端上传一个图片. (3) 请求登陆 (4)url 需求:上传图片. 客户端:   ...

  2. Java面向对象 网络编程 上

     Java面向对象 网络编程 上 知识概要:                     (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...

  3. 第三模块:面向对象&网络编程基础 第2章 网络编程

    01-计算机基础 02-什么是网络 03-五层协议详解 04-传输层详解 05-什么是Socket 06-基于socket实现简单套接字通信 07-在简单套接字基础上加上通信循环 08-客户端与服务端 ...

  4. 第三模块:面向对象&网络编程基础 第1章 面向对象

    我的失败与梦想(一) 我的失败与梦想之为何创办路飞学城 01-编程范式 02-面向过程编程 03-面向对象编程介绍 04-定义类与实例化出对象 05-如何使用类 06-如何使用对象 07-属性查找与绑 ...

  5. 第三模块 面向对象& 网络编程基础 实战考核

    1.简述构造方法和析构方法. 构造方法(__init__):主要作用是实例化时给实例一些初始化参数,或执行一些其它的初始化工作,总之因为这个__init__只要一实例化, 就会自动执行,不管你在这个方 ...

  6. 第三模块:面向对象&网络编程基础 第3章 选课系统作业讲解

    01-选课系统作业讲解1 02--选课系统作业讲解2 03-选课系统作业讲解3 04--选课系统作业讲解4 01-选课系统作业讲解1 02--选课系统作业讲解2 03-选课系统作业讲解3 04--选课 ...

  7. 第三模块:面向对象&网络编程基础 第4章 FTP项目作业讲解

    01-FTP项目需求 02-FTP项目框架搭建 03-FTP项目用户认证 04--FTP项目制定标准定长消息头 05-FTP项目下载功能开发 06-FTP项目下载功能开发2 07-FTP项目ls文件列 ...

  8. 有哪些适合学生参与的 C++,网络编程方面的开源项目?

    有哪些适合学生参与的 C++,网络编程方面的开源项目?   Tinyhttpd是一个超轻量型Http Server,使用C语言开发,全部代码只有502行(包括注释),附带一个简单的Client,可以通 ...

  9. C++网络编程方面的开源项目

    Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能,最多可以模拟3万个并发连接去测试网站的负载能力. ...

随机推荐

  1. /etc/my.cnf

    [client] default-character-set=utf8 [mysqld] tmp_table_size = 2048M max_heap_table_size = 2048M max_ ...

  2. UML和模式应用4:初始阶段(5)--用例编写的准则

    1.前言 本文主要介绍用例编写时所遵循的几条基本准则. 2.用例编写的准则 2.1 以本质的风格编写用例 如系统认证,而不要说 需要输入ID进行认证等 2.2 编写简洁的用例 如系统认证,不要说 这个 ...

  3. 八大最安全的Linux发行版,具备匿名功能,做服务器的首选,web,企业服务器等

    10 best Linux distros for privacy fiends and security buffs in 2017 Introduction The awesome operati ...

  4. nodejs的 new String

    已知rwo4的记录中baitaiid是001// row4为jhlist开始循环结果 for(var i=0;i<row4.length;i++) { var baiTaiId=new Stri ...

  5. Bootstrap3.0学习第一轮(入门)

    详情请查看 http://aehyok.com/Blog/Detail/7.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...

  6. redhat换用centos源

    解除原有源rpm -aq|grep yum|xargs rpm -e --nodepsrpm -aq|grep python-iniparse|xargs rpm -e --nodeps rpm -q ...

  7. SQLServer语言之DDL,DML,DCL,TCL

    数据库语言分类 SQLServer   SQL主要分成四部分: (1)数据定义.(SQL DDL)用于定义SQL模式.基本表.视图和索引的创建和撤消操作. (2)数据操纵.(SQL DML)数据操纵分 ...

  8. 量化投资与Python之NumPy

      数组计算 NumPy是高性能科学计算和数据分析的基础包.它是pandas等其他各种工具的基础.NumPy的主要功能:ndarray,一个多维数组结构,高效且节省空间无需循环对整组数据进行快速运算的 ...

  9. 016_nginx运维问题总结

    一.关于nginx请求包过大的解决思路 message-api.jyall.me.conf nginx报错问题问题定位,经分析跟接入navigator后关联不大,可参考一下结论连接超时抓包分析了一下每 ...

  10. centos6.7环境半虚拟化软件xen及xm配置工具使用详解

    1.xen软件的安装及配置 环境准备: ①操作系统:centos6.7(注意最好使用centos6.7,centos6.5无法使用xen的图形化界面创建操作系统) ②调整虚拟机配置,内存4G(推荐2G ...