热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Python的Asyncore异步Socket模块及实现端口转发的例子

asyncore模块是封装过的处理socket事件的模块,采用异步的处理方式,这里我们讲来讲解Python的Asyncore异步Socket模块及实现端口转发的例子,需要的朋友可以参考下

Asyncore模块提供了以异步的方式写入套接字服务客户端和服务器的基础结构。

只有两种方式使一个程序在单处理器上实现“同时做不止一件事”。多线程编程是最简单和最流行的方式,但是有另一种很不一样的技术,可以使得我们保持多线程的几乎所有优势,却不用真正使用多线程。 如果你的程序主要是受I/O限制的,这是唯一可行的方式。如果你的程序是受处理器限制的,则先发制人的调度线程可能是你真正需要的。但是,很少网络服务器是受处理器限制的。

如果您的操作系统支持在其I / O库的 select() 系统调用(几乎所有系统都支持),那么你可以用它一次处理多个通信信道;当你的I/O在后台忙碌时处理其他工作。虽然这一策略似乎很奇怪很复杂,尤其是最开始的时候,这在很多方面比多线程编程更容易理解和控制。asyncore 模块为你解决了很多困难,使你能快速构建复杂的高性能网络服务器和客户端。对于会话应用程序和协议, asynchat 模块是非常有用的。

两个模块背后的想法就是创建一个或者多个网络 通道, 及 asyncore.dispatcher 和 asynchat.async_chat 类的实例. 如果你没有提供自己的映射的话,创建通道会把这两个实例加到由 loop() 函数使用的全局映射中。

一旦初始化通道被创建,调用 loop() 函数会激活通道服务,这会持续到最后一个通道(包括所有在异步服务中被加到映射中的通道)被关闭。
该模块文件包含一个loop()函数和一个dispatcher基类,其中loop()函数是全局函数,负责检查一个保存着dispatcher实例的dict,也被称为channel。
每一个继承dispatcher类的对象,都可以看作需要处理的socket,因此使用时我们只需定义一个继承dispatcher的类,然后重写一些方法就行,一般都是以handle_开头的方法。

端口转发的示例
如果你的程序想在同一时间做一件一上的事情,多线程是最快也最普遍的方式,但还有一个方式,在I/O流量很大的时候特别实用。如果你的操作系统支持select函数,你就可以让I/O在后台读写。这个模块听起来很复杂,但实际上有很多方式可以理解它,这个文档帮你解决了这些问题。
我感觉这个模块应该是一个以事件驱动的异步I/O,跟C++的事件选择模型类似。每当发生了读、写事件后,会交由我们重写的事件函数进行处理。
我这里有一个使用asyncore模块编写端口转发脚本,从这个脚本可以大概了解asyncore的基本使用。
在文章中,所说的客户端就是我们的电脑,服务端是转发到的地址。也就是客户端发送到这个脚本的信息,这个脚本转发到服务端上。
首先,定义一个forwarder类:

class forwarder(asyncore.dispatcher):
  def __init__(self, ip, port, remoteip,remoteport,backlog=5):
    asyncore.dispatcher.__init__(self)
    self.remoteip=remoteip
    self.remoteport=remoteport
    self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
    self.set_reuse_addr()
    self.bind((ip,port))
    self.listen(backlog)

  def handle_accept(self):
    conn, addr = self.accept()
    # print '--- Connect --- '
    sender(receiver(conn),self.remoteip,self.remoteport)

这个类继承自asyncore模块的dispatcher类(它就是我们的主要的类,其中包括了一些之后要重载的函数),构造函数获得5个参数,第1、2个参数是脚本监听的本地IP和端口,第3、4个参数是服务端的IP和端口。第5个参数是listen函数的参数,等待队列最大长度。
如何使用这个类,只需要如下新建一个对象,把相应IP和端口传入,再进入loop即可:

forwarder(options.local_ip,options.local_port,options.remote_ip,options.remote_port)
asyncore.loop()

进入loop后相当于开启了一个守护线程,在后台一直运行着,等待socket事件的发生。
因为我们这个脚本是端口转发工具,所以实际上运行的过程是:客户端连接这个脚本的端口,让后发送给这个端口的数据脚本自动转发到服务端地址和端口。所以,首先接收到的应该是连接消息(accept事件)。
那么,当accept事件发生后,就进入了handle_accept函数中。所以我们看到,handle_accept函数实际上就是调用了accept函数接收了客户端连接对象和地址。获得了之后又新建了一个sender类对象,这个对象定义如下:

class sender(asyncore.dispatcher):
  def __init__(self, receiver, remoteaddr,remoteport):
    asyncore.dispatcher.__init__(self)
    self.receiver=receiver
    receiver.sender=self
    self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    self.connect((remoteaddr, remoteport))

  def handle_connect(self):
    pass

  def handle_read(self):
    read = self.recv(4096)
    # print '<-- %04i'%len(read)
    self.receiver.to_remote_buffer += read

  def writable(self):
    return (len(self.receiver.from_remote_buffer) > 0)

  def handle_write(self):
    sent = self.send(self.receiver.from_remote_buffer)
    # print '--> %04i'%sent
    self.receiver.from_remote_buffer = self.receiver.from_remote_buffer[sent:]

  def handle_close(self):
    self.close()
    self.receiver.close()

这个类也是继承自asyncore.dispatcher,它的构造函数接收3个参数,分别是recv对象(这个之后说到),远端地址,对应端口。
函数中又新建了一个socket,这个socket就是和服务端端口通信的socket,然后调用connect连接这个端口。
之后其实也是进入了一个等待消息的过程,因为我们发送了一个connect,所以下一次接收到的消息应该是connect,而handle_connect是一个pass掉的函数。没有执行任何内容。
在连接完成后,我们就相当于建立好了一个端口转发的通道。当客户端向这个脚本监听的端口发送数据包时,它就会自动转发到服务端端口上。服务端端口返回的数据包,会自动转发到客户端上。
回到构造函数的第1个参数,我们在forwarder类函数中可以看到,传入的是一个receiver(conn)对象,receiver也是一个类,我们来看看这个类的定义:

class receiver(asyncore.dispatcher):
  def __init__(self,conn):
    asyncore.dispatcher.__init__(self,conn)
    self.from_remote_buffer=''
    self.to_remote_buffer=''
    self.sender=None

  def handle_connect(self):
    pass

  def handle_read(self):
    read = self.recv(4096)
    # print '%04i -->'%len(read)
    self.from_remote_buffer += read

  def writable(self):
    return (len(self.to_remote_buffer) > 0)

  def handle_write(self):
    sent = self.send(self.to_remote_buffer)
    # print '%04i <--'%sent
    self.to_remote_buffer = self.to_remote_buffer[sent:]

  def handle_close(self):
    self.close()
    if self.sender:
      self.sender.close()

它也是继承了asyncore.dispatcher,构造函数只接收一个参数,就是connect的返回值,一个连接对象。
实际上这个对象它就是监听、处理与客户端的通信,而之前说的sender对象是监听、处理与服务端的通信。                   


推荐阅读
  • 本文详细分析了在C#中调用服务时遇到服务停止后抛出EndPointNotFoundException所需的时间,以及如何通过调整配置参数来优化这一过程。 ... [详细]
  • 为了和DSP兼容,TSint64和TUint64设置成TSint40和TUint40一样的数结果VC中还是认为是32位的,显然不合适typedefsig ... [详细]
  • 本文探讨了一种方法,通过开发C#应用程序来拦截并处理从遗留系统发出的Http请求,该系统原本依赖于已停止服务的Web服务。解决方案涉及使用代理技术或HTTP监听器来捕获和重定向这些请求。 ... [详细]
  • 解决Office 2013安装失败及Lync登录无响应问题
    本文详细记录了在尝试通过Lync登录Office 365账户时遇到的问题,以及随后尝试安装Office 2013过程中遇到的安装失败情况,并提供了具体的解决方案。 ... [详细]
  • 探讨了requireJS的domReady插件与window.onload事件在实际应用中的不同表现,特别是在处理页面加载过程中图片资源的影响。 ... [详细]
  • 本文探讨了在JavaScript中如何有效地从服务器控件DropDownList中获取绑定的ID值,而非仅仅是显示的文本值。这对于需要根据用户选择动态处理数据的应用场景非常有用。 ... [详细]
  • 解决MySQL Administrator 登录失败问题
    本文提供了解决在使用MySQL Administrator时遇到的登录错误的方法,包括启动变量和服务部分禁用的问题。同时,文章还介绍了通过安全配置模式来解决问题的具体步骤。 ... [详细]
  • 2023年PHP处理请求超时的全面指南
    本文详细介绍了在PHP中处理请求超时的各种方法,包括设置脚本执行时间、处理file_get_contents函数超时以及优化AJAX请求等,适合开发者参考学习。 ... [详细]
  • 本文详细介绍了使用Apache的AB工具和Webbench进行服务器性能测试的过程,分享了实际操作中的测试结果,并探讨了测试过程中遇到的问题及可能的解决方案。 ... [详细]
  • 浏览器、中间件与服务器的交互机制
    本文详细探讨了浏览器、中间件和服务器之间的交互过程,特别是HTTP请求的完整流程,包括DNS解析、TCP连接建立及数据传输等关键步骤。 ... [详细]
  • Sass 是一种 CSS 的预处理器,通过使用变量、嵌套、继承等高级功能,使得 CSS 的编写更加灵活和高效。本文将介绍 Sass 的基本语法及其安装使用方法。 ... [详细]
  • 在最近的项目测试中,我们遇到了一个棘手的问题——当使用 Nginx 作为反向代理服务器时,Tomcat 应用中的 Session 信息会丢失。通过深入研究和多次实验,最终找到了有效的解决方案。 ... [详细]
  • 远程访问用户 Kindle通过电子书实现控制
    介绍自2007年以来,亚马逊已售出数千万台Kindle,令人印象深刻。但这也意味着数以千万计的人可能会因为这些Kindle中的软件漏洞而被黑客入侵。他 ... [详细]
  • 本文介绍了FTP(文件传输协议)的基础知识,包括其定义、如何通过TCP建立控制和数据连接,以及主动模式与被动模式的区别。FTP作为一种重要的文件传输协议,在互联网数据交换中扮演着关键角色。 ... [详细]
  • 深入理解SAP Fiori及其核心概念
    本文详细介绍了SAP Fiori的基本概念、发展历程、核心特性、应用类型、运行环境以及开发工具等,旨在帮助读者全面了解SAP Fiori的技术框架和应用场景。 ... [详细]
author-avatar
日月阁文玩都汇
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有