python学习day7

目录

 一、反射

二、socket

三、socketserver


 

一、反射

python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

 1 class Foo(object):
 2  
 3     def __init__(self):
 4         self.name = 'wupeiqi'
 5  
 6     def func(self):
 7         return 'func'
 8  
 9 obj = Foo()
10  
11 # #### 检查是否含有成员 ####
12 hasattr(obj, 'name')
13 hasattr(obj, 'func')
14  
15 # #### 获取成员 ####
16 getattr(obj, 'name')
17 getattr(obj, 'func')
18  
19 # #### 设置成员 ####
20 setattr(obj, 'age', 18)
21 setattr(obj, 'show', lambda num: num + 1)
22  
23 # #### 删除成员 ####
24 delattr(obj, 'name')
25 delattr(obj, 'func')

详细解析:

当我们要访问一个对象的成员时,应该是这样操作:

 1 class Foo(object):                                                 
2 3 def __init__(self): 4 self.name = 'tom' 5 6 def func(self): 7 return 'func'
8 9 obj = Foo() 10 11 # 访问字段 12 obj.name 13 # 执行方法 14 obj.func()

 

那么问题来了?
a、上述访问对象成员的 name 和 func 是什么? 
答:是变量名
b、obj.xxx 是什么意思? 
答:obj.xxx 表示去obj中或类中寻找变量名 xxx,并获取对应内存地址中的内容。
c、需求:请使用其他方式获取obj对象中的name变量指向内存中的值 “tom”
1 class Foo(object):
2  
3     def __init__(self):
4         self.name = 'tom'
5  
6 # 不允许使用 obj.name
7 obj = Foo()
View Code

答:有两种方法,如下:

 1 class Foo(object):
 2 
 3     def __init__(self):
 4         self.name = 'alex'
 5 
 6     def func(self):
 7         return 'func'
 8 
 9 # 不允许使用 obj.name
10 obj = Foo()
11 
12 print obj.__dict__['name']
方法一
 1 class Foo(object):
 2 
 3     def __init__(self):
 4         self.name = 'alex'
 5 
 6     def func(self):
 7         return 'func'
 8 
 9 # 不允许使用 obj.name
10 obj = Foo()
11 
12 print getattr(obj, 'name')
方法二

d、比较三种访问方式

  • obj.name
  • obj.__dict__['name']
  • getattr(obj, 'name')

答:第一种和其他种比,...
      第二种和第三种比,...

结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

 1 import sys
 2 
 3 class WebServer(object):
 4     def __init__(self,host,port):
 5         self.host = host
 6         self.port = port
 7 
 8     def start(self):
 9         print('start')
10 
11     def stop(self):
12         print("stop")
13 
14     def restart(self):
15         self.stop()
16         self.start()
17 
18 if __name__ == "__main__":
19     server = WebServer('localhost',333)
20     if hasattr(server,sys.argv[1]):
21         func = getattr(server,sys.argv[1])
22         func()
例子

 

类也是对象

 1 class Foo(object):
 2  
 3     staticField = "old boy"
 4  
 5     def __init__(self):
 6         self.name = 'wupeiqi'
 7  
 8     def func(self):
 9         return 'func'
10  
11     @staticmethod
12     def bar():
13         return 'bar'
14  
15 print getattr(Foo, 'staticField')
16 print getattr(Foo, 'func')
17 print getattr(Foo, 'bar')

模块也是对象

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 
4 def dev():
5     return 'dev'
home.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3  
 4 """
 5 程序目录:
 6     home.py
 7     index.py
 8  
 9 当前文件:
10     index.py
11 """
12  
13  
14 import home as obj
15  
16 #obj.dev()
17  
18 func = getattr(obj, 'dev')
19 func() 
index.py

二、socket

socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

socket和file的区别:

  • file模块是针对某个指定文件进行【打开】【读写】【关闭】
  • socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

socket服务端与客户端交流示意图:

425762-20151212160019653-1079393936


socket()模块函数

使用socket.socket()函数来创建套接字,语法如下:

socket(socket_family,socket_type,protocol=0)

如前所述,参数一:socket_family(地址簇)

socket.AF_UNIX    只能用于单一的UNIX系统进程间通信

socket.AF_INET     IPV4(默认)

socket.AF_INET6   IPV6

参数二:socket_type(类型)

socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDP

socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务

参数三:protocol(协议)

0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

创建一个TCP/IP的套接字,你要这样调用socket.socket():

tcpsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

同样的,创建一个UDP/IP的套接字,你要这样:

udpsocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

套接字对象(内建)方法:

函数描述
服务器套接字函数 
s.bind(address)绑定地址(主机名,端口号对)到套接字
s.listen(backlog)开始TCP监听
s.accept()被动接受TCP客户端连接,(阻塞式)等待链接的到来
客户端套接字函数 
s.connect()主动初始化TCP服务器连接
s.connect_ex()connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数 
s.recv()接收TCP数据
s.send()发送TCP数据
s.sendall()完整发送TCP数据(不停调用s.send())
s.recvfrom()接收UDP数据
s.sendto()发送UDP数据
s.getpeername()链接到当前套接字的远端的地址(TCP连接)
s.getsockname()当前套接字的地址
s.getsockopt()返回指定套接字的参数
s.setsockopt()设置指定套接字的参数
s.close()关闭套接字
面向模块的套接字函数 
s.setblocking()设置套接字的阻塞与非阻塞模式
s.settimeout()设置阻塞套接字操作的超时时间
s.gettimeout()得到阻塞套接字操作的超时时间
面向文件的套接字函数 
s.fileno()套接字的文件描述
s.makefile()创建一个与该套接字相关联的文件对象

例:(win环境)

server端

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    print('server waiting...')
    conn,addr = sk.accept()
    client_data = conn.recv(1024)
    print(str(client_data,'utf8'))
    conn.sendall(bytes('不要回答,不要回答,不要回答','utf8'))

    conn.close()

client端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.connect(ip_port)

sk.sendall(bytes('请求占领地球','utf8'))

server_reply = sk.recv(1024)
print(str(server_reply,'utf8'))

sk.close()

连续交互通信实例:

 

server端:(win环境)

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    print('server waiting...')
    conn,addr = sk.accept()
    client_data = conn.recv(1024)
    print(str(client_data,'utf8'))
    conn.sendall(bytes('不要回答,不要回答,不要回答','utf8'))
    while True:
        try:
            client_data = conn.recv(1024)
            print(str(client_data,'utf8'))
            server_response = input('>>>:').strip()
            
        except Exception:
            print("client closed,break")
            break
        conn.send(bytes(server_response,'utf8'))
    conn.close()

server端:(Linux环境)

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    print('server waiting...')
    conn,addr = sk.accept()
    client_data = conn.recv(1024)
    print(str(client_data,'utf8'))
    conn.sendall(bytes('不要回答,不要回答,不要回答','utf8'))
    while True:
        client_data = conn.recv(1024)
        print(str(client_data,'utf8'))
        server_response = input('>>>:').strip()
if not client_data:break
        conn.send(server_response)

    conn.close()

client端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.connect(ip_port)

sk.sendall(bytes('请求占领地球','utf8'))
server_reply = sk.recv(1024)
print(str(server_reply,'utf8'))
while True:
    user_input = input(">>>").strip()
    sk.send(bytes(user_input,'utf8'))
    server_reply = sk.recv(1024)
    print(str(server_reply,'utf8'))

sk.close()

模拟实现简单ssh功能:

server端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket
import subprocess
ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)

while True:
    print('server waiting...')
    conn,addr = sk.accept()
    while True:
        client_data = conn.recv(1024)
        if not client_data:break
        print("recv cmd:",str(client_data,'utf8'))
        cmd = str(client_data,'utf8').strip()
        cmd_call = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
        cmd_result = cmd_call.stdout.read()
        if len(cmd_result) == 0:
            cmd_result = b"cmd execution has no output..."
        ack_msg = bytes("CMD_RESULT_SIZE|%s"%len(cmd_result),"utf8")
        conn.send(ack_msg)
        client_ack = conn.recv(50)
        if client_ack.decode() == "CLIENT_READY_TO_RECV":
            conn.send(cmd_result)

    conn.close()

client端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',9999)

sk = socket.socket()
sk.connect(ip_port)
while True:
    user_input = input("cmd:").strip()
    if len(user_input) == 0:continue
    if user_input == "q":break
    sk.send(bytes(user_input,'utf8'))
    #ack_msg = b"CMD_RESULT_SIZE|%s",len(cmd_result)
    server_ack_msg = sk.recv(100)
    cmd_res_msg = str(server_ack_msg.decode()).split("|")
    print("server response:",cmd_res_msg)
    if cmd_res_msg[0] == "CMD_RESULT_SIZE":
        cmd_res_size = int(cmd_res_msg[1])
        sk.send(b"CLIENT_READY_TO_RECV")
    res = ''
    received_size = 0
    while received_size < cmd_res_size:
        data = sk.recv(500)
        received_size += len(data)
        res += str(data.decode())
    else:
        print(str(res))
        print("----------recv doen----------")
sk.close()

三、sockeserver

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

425762-20151226114322968-1230975336

 

例:

server端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
    def setup(self):
        print("Building secure connection chanel...")
    def handle(self):
        print("New Conn:",self.client_address)
        while True:

            data = self.request.recv(1024)
            if not data:break
            print("Client Says:",data.decode())
            self.request.send(data)
    def finish(self):
        print("client conn is done...")
if __name__ == '__main__':
    HOST, PORT = "localhost", 50007
    # 把刚才写的类当作一个参数传给ThreadingTCPServer这个类,下面的代码就创建了一个多线程socket server
    server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
    # 启动这个server,这个server会一直运行,除非按ctrl-C停止
    server.serve_forever()

client端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',50007)

sk = socket.socket()
sk.connect(ip_port)
while True:
    msg = input(">>:").strip()
    sk.sendall(bytes(msg,'utf8'))
    server_reply = sk.recv(1024)
    print("Server Reply:",str(server_reply,'utf8'))
sk.close()

转载于:https://www.cnblogs.com/spykids/p/5279848.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值