为了方便区分,以下分别使用local,server,remote代表ss客户端,ss服务端,以及ss客户端请求访问的远程主机。

在shadowsocks中,无论对于local还是server,都需要建立两个socket:local_sock和remote_sock
对于local,local_sock用于和进程通讯,server_sock用于和server通讯。
对于server,local_sock用于和local通信,server_sock用于和remote通信。

上一次提到两者的事件处理均使用TCPRelayHandler,先来看一下handle_event函数。

# tcprelay.py

class TCPRelayHandler(object):
    def handle_event(self, sock, event):
        # handle all events in this handler and dispatch them to methods
        if self._stage == STAGE_DESTROYED:
            logging.debug('ignore handle_event: destroyed')
            return
        # order is important
        # remote_socket
        if sock == self._remote_sock:
            if event & eventloop.POLL_ERR:
                self._on_remote_error()
                if self._stage == STAGE_DESTROYED:
                    return
            if event & (eventloop.POLL_IN | eventloop.POLL_HUP):
                self._on_remote_read()
                if self._stage == STAGE_DESTROYED:
                    return
            if event & eventloop.POLL_OUT:
                self._on_remote_write()
        # local_socket
        elif sock == self._local_sock:
            if event & eventloop.POLL_ERR:
                self._on_local_error()
                if self._stage == STAGE_DESTROYED:
                    return
            if event & (eventloop.POLL_IN | eventloop.POLL_HUP):
                self._on_local_read()
                if self._stage == STAGE_DESTROYED:
                    return
            if event & eventloop.POLL_OUT:
                self._on_local_write()
        else:
            logging.warn('unknown socket')

该函数根据传入的socket参数来区别是local_sock,还是remote_sock,将read/write事件的处理分发到各个处理函数。

下面来具体看看这些事件处理函数。

remote_read

# tcprelay.py
class TCPRelayHandler(object):
    def _on_remote_read(self):
        # handle all remote read events
        data = None
        try:
            # 从remote_sock读取数据
            data = self._remote_sock.recv(BUF_SIZE)

        except (OSError, IOError) as e:
            if eventloop.errno_from_exception(e) in \
                    (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
                return
        if not data:
            self.destroy()
            return
        self._update_activity(len(data))
        # local,说明server回反了数据
        if self._is_local:
            # 解密数据
            data = self._encryptor.decrypt(data)
        # server,说明remote响应到达
        else:
            # 加密数据
            data = self._encryptor.encrypt(data)
        try:
            # 写到local_sock,对于server就是写回local,对于local就是写回进程
            self._write_to_sock(data, self._local_sock)
        except Exception as e:
            shell.print_exception(e)
            if self._config['verbose']:
                traceback.print_exc()
            # TODO use logging when debug completed
            self.destroy()

remote_write

# tcprelay.py

class TCPRelayHandler(object):
    def _on_remote_write(self):
        # 进入流传输阶段
        self._stage = STAGE_STREAM
        # 如果有需要写的数据
        if self._data_to_write_to_remote:
            data = b''.join(self._data_to_write_to_remote)
            self._data_to_write_to_remote = []
            self._write_to_sock(data, self._remote_sock)
        else:
            # 否则,更新状态
            self._update_stream(STREAM_UP, WAIT_STATUS_READING)

local_read

# tcprelay.py

class TCPRelayHandler(object):
    def _on_local_read(self):
        # handle all local read events and dispatch them to methods for
        # each stage
        if not self._local_sock:
            return

        is_local = self._is_local
        data = None
        try:
            # 尝试读取数据
            data = self._local_sock.recv(BUF_SIZE)
        except (OSError, IOError) as e:
            if eventloop.errno_from_exception(e) in \
                    (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
                return
        if not data:
            self.destroy()
            return
        #
        self._update_activity(len(data))
        if not is_local:
            # server的local_sock,表明为local发来数据
            # 将数据解密
            data = self._encryptor.decrypt(data)
            if not data:
                return
        # 在stream状态,此时已经建立起协议,传输的是向remote的请求细节,以及remote的响应
        if self._stage == STAGE_STREAM:
            # 客户端
            if self._is_local:
                # 将数据加密
                data = self._encryptor.encrypt(data)
            # 直接转发给remote
            self._write_to_sock(data, self._remote_sock)
            return

        # 处于init状态,处理协议细节
        elif is_local and self._stage == STAGE_INIT:
            # TODO check auth method
            # 给进程发送确认信息
            self._write_to_sock(b'\x05\00', self._local_sock)
            self._stage = STAGE_ADDR
            return

        # 处于connecting状态,处理协议细节
        elif self._stage == STAGE_CONNECTING:
            self._handle_stage_connecting(data)
        # local,等待进程发来请求数据,或者server,初始化状态,等待local发来数据
        elif (is_local and self._stage == STAGE_ADDR) or \
                (not is_local and self._stage == STAGE_INIT):
            # 客户端:接受进程的请求信息,服务器:接受客户端的请求信息
            self._handle_stage_addr(data)

local_write

# tcprelay.py

class TCPRelayHandler(object):
    def _on_local_write(self):
        # 如果有数据可写
        if self._data_to_write_to_local:
            data = b''.join(self._data_to_write_to_local)
            self._data_to_write_to_local = []
            # 写到本地sock
            self._write_to_sock(data, self._local_sock)
        else:
            # 更新流状态
            self._update_stream(STREAM_DOWN, WAIT_STATUS_READING)

ss源码学习--事件处理的更多相关文章

  1. ss源码学习--从协议建立到完成一次代理请求

    上一次介绍了ss源码中各个事件处理函数完成的工作,这次具体分析一下协议的建立以及请求数据的传输过程. 因为ss的local和server共用一个类以及一系列的事件处理函数,所以看起来稍显复杂.下面来将 ...

  2. ss源码学习--工作流程

    ss的local端和server端的工作流程相似,因此复用了TCPRelay类和TCPRelayHandler类. 两端均是使用TCPRelay类监听连接,并使用TCPRelayHandler类处理请 ...

  3. Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习

    package cc.aa; import android.os.Environment; import android.view.MotionEvent; import android.view.V ...

  4. Redis源码学习:字符串

    Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...

  5. .NET Core 2.1 源码学习:看 SocketsHttpHandler 如何在异步方法中连接 Socket

    在 .NET Core 2.1 中,System.Net.Sockets 的性能有了很大的提升,最好的证明是 Kestrel 与 HttpClient 都改为使用 System.Net.Sockets ...

  6. Netty 源码学习——EventLoop

    Netty 源码学习--EventLoop 在前面 Netty 源码学习--客户端流程分析中我们已经知道了一个 EventLoop 大概的流程,这一章我们来详细的看一看. NioEventLoopGr ...

  7. Spring5.0源码学习系列之Spring AOP简述

    前言介绍 附录:Spring源码学习专栏 在前面章节的学习中,我们对Spring框架的IOC实现源码有了一定的了解,接着本文继续学习Springframework一个核心的技术点AOP技术. 在学习S ...

  8. Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析

    目录 PriorityBlockingQueue概述 类图结构及重要字段 什么是二叉堆 堆的基本操作 向上调整void up(int u) 向下调整void down(int u) 构造器 扩容方法t ...

  9. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

随机推荐

  1. Jnlp

    java web start解析jnlp文件,从网络宿主中,下载应用程序jar包,并运行. xxx.jnlp <?xml version="1.0" encoding=&qu ...

  2. 《算法》第五章部分程序 part 3

    ▶ 书中第五章部分程序,包括在加上自己补充的代码,字符串高位优先排序(美国国旗排序) ● 美国国旗排序 package package01; import edu.princeton.cs.algs4 ...

  3. Apache-Axis小结

    以前用过axis, 不过好久不弄, 有忘记了.很多很多东西放在收藏夹里面, 但是长时间不去看,结果就是还是不熟悉!现在再简单总结一下吧. Axis开发服务器端webservice其实很简单. 1 下载 ...

  4. gulp 添加版本号 解决浏览器缓存问题

    分别安装gulp-rev.gulp-rev-collerctor.gulp-asset-rev,安装了的略过 npm install gulp-rev --save-dev npm install g ...

  5. 交叉编译zookeeper的C库

    原创文章,转载请正确注明本文原始URL及作者. 今天要编译一个zookeeper的C接口,要编译一个TK1版本. 事情经过这这样的:原来用的是zookeeper-3.4.6版本,但是源码中有个函数是汇 ...

  6. redis异常和注意点

    目录: 1. 修改配置不起作用 2.Connection reset by peer: socket write error 3. redis-cli 查看中文乱码 1. 修改配置不起效果 我们修改了 ...

  7. BBS--功能4:个人站点页面设计(ORM跨表与分组查询)

    查询: 日期归档查询 1 date_format ============date,time,datetime=========== create table t_mul_new(d date,t t ...

  8. Spark/Storm/Flink

    https://www.cnblogs.com/yaohaitao/p/5703288.html  Spark Streaming与Storm的应用场景 对于Storm来说:1.建议在那种需要纯实时, ...

  9. PHP面向对象(抽象类与抽象方法、接口的实现)

    一.抽象类与抽象方法 1,任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的. 2,定义为抽象的类不能被实例化. 3, 被定义为抽象的方法只是声明了其调用方式(参数) ...

  10. 什么是socket?

    1.七层协议简化为四层:应用层.传输层.网络层.链路层:2.套接字是应用层和TCP/IP协议族通信间的软件抽象层,将TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用实现进程在网络中的通信:本地 ...