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
'<-- i'%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
'--> i'%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 'i
-->'%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 'i
<--'%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对象是监听、处理与服务端的通信。

Python的Asyncore异步Socket模块及实现端口转发的例子的更多相关文章

  1. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  2. python实战第一天-socket模块练习

    操作系统 Ubuntu 15.10 IDE & editor JetBrains PyCharm 5.0.2 ipython3 Python版本 python-3.4.3 导入socket模块 ...

  3. Python网络编程(socket模块、缓冲区、http协议)

      网络的概念:主机   端口  IP  协议 服务器: localhost/127.0.0.1 客户端: 只是在本机启动客户端,用127.0.0.1访问     服务器: 0.0.0.0 客户端: ...

  4. python epoll实现异步socket

    一.同步和异步: 在程序执行中,同步运行意味着等待调用的函数.线程.子进程等的返回结果后继续处理:异步指不等待当下的返回结果,直接运行主进程下面的程序,等到有返回结果时,通知主进程处理.有点高效. 二 ...

  5. Python的网络编程socket模块

    (1)利用socket进行简单的链接 Python里面的socket支持UDP.TCP.以及进程间的通信,socket可以把我们想要发送的东西封装起来,发送过去,然后反解成原来的样子,事实上网路通信可 ...

  6. python标准库中socket模块详解

    包含原理就是tcp的三次握手 http://www.lybbn.cn/data/datas.php?yw=71 这篇讲到了socket和django的联系 https://www.cnblogs.co ...

  7. 【Python】socket模块应用

    [Socket] 本文记录了一些socket模块的简单应用,对于具体原理还没来得及深究. ■ 利用socket模块进行端口连接验证和扫描 在linux中常用nc命令来进行远端端口是否开放的验证.但是这 ...

  8. [译]Python中的异步IO:一个完整的演练

    原文:Async IO in Python: A Complete Walkthrough 原文作者: Brad Solomon 原文发布时间:2019年1月16日 翻译:Tacey Wong 翻译时 ...

  9. Python网络编程之socket应用

    1 引言 本篇主要对Python下网络编程中用到的socket模块进行初步总结.首先从网络基础理论出发,介绍了TCP协议和UDP协议:然后总结了socket中的常用函数:最后通过实际代码展示基本函数的 ...

随机推荐

  1. Nginx入门(二)——双机热备

    upstream backend { server ; server backup; } server { listen ; server_name localhost; #charset koi8- ...

  2. struts--CRUD优化(图片上传)

    1.上传方式 上传到指定文件目录,添加服务器与真实目录的映射关系,从而解耦上传文件与tomcat的关系  文件服务器 2.web代码优化 package com.yuan.crud.web; impo ...

  3. 基础 | BIO、NIO与AIO

    本文链接:https://blog.csdn.net/bingbeichen/article/details/83617163 Java中的IO部分比较复杂,具体可参看书籍<Java NIO&g ...

  4. Linq找不到行或行已更改

    1.发生这种情况第一时间是确认了database明明存在这条数据 2.然后确认了Linq查找的条件中是否有连接条件使得连续更新中发生变化 3.最后发现原来是Linq使用的表实际中有个field由not ...

  5. package.json文件说明解释

    1.package.json是什么? 什么是Node.js的模块(Module)?在Node.js中,模块是一个库或框架,也是一个Node.js项目.Node.js项目遵循模块化的架构,当我们创建了一 ...

  6. NetworkX系列教程(6)-对graph进行操作

    小书匠Graph图论 graph生成后,除了有查看操作,还有移除等操作,还有其他更多操作,具体可以看这里.下面将比较graph操作前后的不同. 目录: 7.对图进行操作 7.1移除某些节点和边 7.2 ...

  7. unity Assetboundle 工具

    Unity Asset Bundle Browser tool https://github.com/Unity-Technologies/AssetBundles-Browser assetboun ...

  8. unity当两个以上Android插件冲突,怎么配置manifest

    https://my.oschina.net/u/3332153/blog/855798 一 问题 当unity导入两个以上package并且都有manifest配置时,unity不会自动合并而是替换 ...

  9. 使用开源软件 jumpserver 搭造自己的堡垒机

    使用开源软件 jumpserver 搭造自己的堡垒机 开软地址:https://github.com/jumpserver/jumpserver 目前版本:1.5.2 测试的时候有少许BUG,但功能却 ...

  10. XGBoost、LightGBM、Catboost总结

    sklearn集成方法 bagging 常见变体(按照样本采样方式的不同划分) Pasting:直接从样本集里随机抽取的到训练样本子集 Bagging:自助采样(有放回的抽样)得到训练子集 Rando ...