zoukankan      html  css  js  c++  java
  • Python 实现进程间通信(网络编程)

    网络编程

      1):网络编程是什么意思,网络编程指的是不同机器之间通过网编相互发信息,我们常用的“QQ”,“微信”,“邮箱” 都个网编编程的应用;

      网编编程在技术上还有另一个叫法叫“进程间通信”,进程间通信这个名字能更好体现技术的内涵,说白了就是一个进程给另一个进程发

      信息;

      2):网络编程中的两个重要的角色,“服务端”,“客户端” 从技术上来讲“服务端”是被动的,它监听在某个“套结字(socket)”上,被动的

      等待“客户端”的连接;也就是说连接是由“客户端”主动发起的,所以“客户端”是主动的。

      3):主动&被动对应着两套不同的行为,对于被动的“服务端”来说它有三个技术上的步骤要做 “第一步:bind”,“第二步:listen”,“

      三步 accept” 这三步是基本的“套路”不要问我为什么,我也想知道;不过总的来说前两步叫“监听”,第三步叫“接收一个客户端连接

      对于“客户端”它的套路就比较少了只有一步:“唯一一步:connect” 成功后就能与服务器之间有进行信息的收发了。

    从最低层的socket来实现一个翻译功能

      我在这要实现的“翻译”功能比较“牛逼”,总的来说是这样的;客户端向服务器发送一串小写字母,服务器端把小写“翻译”成大写后返回

      我的服务器主机的IP是“172.16.192.100”

      1): 服务端代码

    #! /usr/bin/env python3
    
    import socket

    if __name__ == "__main__": #定义一个服务端的tcp套节字 with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s_sock: s_host = ('172.16.192.100',9999) s_sock.bind(s_host) # 第一步:bind s_sock.listen(5) # 第二步:listen print("服务端启动完成 监听在 {0}".format(s_host)) while True: c_sock,c_addr = s_sock.accept() # 第三步:接收客户端连接 print("收到来自 {0} 的连接请求".format(c_addr)) c_data = c_sock.recv(1024) # 读取客户端发来的数据 c_str = str(c_data,"utf-8") # 由字节序列转码成utf-8字符串 print("收到来自 {0} 的信息 '{1}' ".format(c_addr,c_str)) c_sock.sendall( bytes(c_str.upper(),"utf-8")) # 翻译成大写发送到客户端

      2): 客户端代码

    import socket
    from datetime import datetime
    
    
    if __name__ == "__main__":
        data = ' '.join(sys.argv[1:])
        with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as sock:
            sock.connect(('172.16.192.100',9999))
            print("client {0} 发送 {1}".format(datetime.now(),data))
            sock.sendall(bytes(data,"utf-8"))
    
            received_data = sock.recv(1024)
            print("client {0} 收到 {1}".format(datetime.now(),received_data))

      3): 服务端的运行情况

    python3 server.py 
    服务端启动完成 监听在 ('172.16.192.100', 9999)
    收到来自 ('172.16.192.1', 52160) 的连接请求
    收到来自 ('172.16.192.1', 52160) 的信息 'Hello world 123'

      4): 客户端的运行情况

    python3 client.py Hello world 123
    client 2018-09-19 16:42:46.973864 发送 Hello world 123
    client 2018-09-19 16:42:46.974519 收到 b'HELLO WORLD 123'

     【Python对网络编程做了什么

      从上面的内容可以看出“服务端”是有它的固定套路的,Python把这些通用的“套路”抽象了来了,如果我们使用python写上面的那种“服务端”

      &“客户端”的程序的话就大的方便了。

      服务端直接这样写就行了:

    import socketserver
    
    class UpHander(socketserver.BaseRequestHandler):
        def handle(self):
            """
            self.request  引用的是与客户端通信用的socket对象
            """
            data = self.request.recv(1024) # 接收1024个字节
            print("接收到来自 {0} 的信息 {1}".format(self.client_address,str(data)))
            self.request.sendall(data.upper()) # 把接收到的数据变成大写再发出去
    
    if __name__ == "__main__":
        server_ip = ('172.16.192.100',9999) # 定义服务端监听的ip与端口
        with socketserver.TCPServer(server_ip,UpHander) as server:
            server.serve_forever()

      通过“重写”socketserver.BaseRequestHandler.handle 方法来实现我们要的功能,也就是说我们不要太在意网络编程的技术细节了;注意

      了上面的这个实现是“串行”的,也就是说server端只有一个进程来做处理,如果是要实现一个并行处理的服务端的话也是分分钟的事

    多线程版本的服务端编程

      1): 服务端代码

    #! /usr/bin/env python3
    
    """
    用python标准库实现一个简单的c/s架构的服务
    """
    
    import socketserver
    import socket
    import time
    import threading
    
    class UpHander(socketserver.BaseRequestHandler):
        def handle(self):
            """
            self.request  引用的是与客户端通信用的socket对象
            """
            data = self.request.recv(1024) # 接收1024个字节
            cur_thread = threading.current_thread()
            print("服务端线程号 {0} 接收到来自 {1} 的信息 {2}".format(cur_thread.name,self.client_address,str(data)))
            time.sleep(5)
            self.request.sendall(data.upper()) # 把接收到的数据变成大写再发出去
    
    
    class MultiThreadTcpServer(socketserver.ThreadingMixIn,socketserver.TCPServer):
        pass
    
    if __name__ == "__main__":
        with MultiThreadTcpServer(('172.16.192.100',9999),UpHander) as s_sock:
            s_thread = threading.Thread(target=s_sock.serve_forever)
            s_thread.daemon=True
            s_thread.start()
            print("多线程版本的服务端已经启动...")
            while True:
                time.sleep(10) # 使服务端永不退出

      2): 客户端代码

    import socket
    from datetime import datetime
    
    
    if __name__ == "__main__":
        data = ' '.join(sys.argv[1:])
        with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as sock:
            sock.connect(('172.16.192.100',9999))
            print("client {0} 发送 {1}".format(datetime.now(),data))
            sock.sendall(bytes(data,"utf-8"))
    
            received_data = sock.recv(1024)
            print("client {0} 收到 {1}".format(datetime.now(),received_data))

      开启两个客户端观察效果

    1:
    python3 client.py Hello world 123
    client 2018-09-19 17:47:38.084209 发送 Hello world 123
    client 2018-09-19 17:47:43.091790 收到 b'HELLO WORLD 123'
    
    
    2:
    
    python3 client.py Hello world
    client 2018-09-19 17:47:38.803440 发送 Hello world
    client 2018-09-19 17:47:43.811177 收到 b'HELLO WORLD'

      由时间上可以看出来请求是并行的

    总结

      可以看出用socketserver模块来做“服务器”,“客户端”的编程是非常方便的

    学习交流

     -----------------------------http://www.sqlpy.com-------------------------------------------------

    -----------------------------http://www.sqlpy.com-------------------------------------------------

  • 相关阅读:
    JavaScript连等赋值
    vue入坑总结
    form表单与后台请求的关系
    JavaScript构造函数、继承的理解
    前端知识未学习点
    js垃圾回收机制
    前端闭包
    html中strong与b,em与i标签的区别(转帖)
    Docker 搭建开源跳板机_jumpserver (运维开源堡垒机_jumpserver) Centos_7.0
    python EasyUI + Django--整合 CSRF 防护去除
  • 原文地址:https://www.cnblogs.com/JiangLe/p/9675169.html
Copyright © 2011-2022 走看看