IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

手机应用/服务器开发的一些总结(二)

Vimer 2014-11-30 23:16:14 累计浏览 4,026 次
本机暂存

   上一篇文章聊了下数据存储和常用的传输协议,不过对于自定义传输协议这里留了个坑,正好有点时间,就抓紧填上:)

   既然选择原生socket,那么有个基本的选择就是tcp/udp的问题.

   这个其实还是看业务自己的选择,只是如果选择了udp的话,那么很多问题都可以不用考虑,比如粘包问题。但是udp有个限制是每次传输的数据大小不能超过64K,这个要注意。

   为了考虑复杂的情况,我们还是主要说tcp的实现,这篇文章先说下socket使用相关的一些库和代码吧

Android端开发

   对于android端,我们有两个主要选择:阻塞socket和非阻塞socket。

   阻塞socket就是正常的socket,当调用recv的时候,会阻塞住直到返回数据。

   非阻塞socket在android上可以直接使用nio,因为自己之前一直是做c++和python,所以其实一开始nio的时候真心有些不太使用,把几个要注意的点列一下:

   1. 当网络断线的时候,有些手机如S4,会出现这个问题,channel.finishConnect()会一直等超时 60秒。之后会抛出一个 TimeoutException.

   解决方法是:

channel.socket().setSoTimeout(5)

   来设置成只等5秒。

   比较诡异的是,明明是异步io了,为什么还是会有等待超时的情况。还要在研究下。

   2. 当网络不在线的时候,启动connect,依然可以进入isConnectable的判断中,并且可以调用finishconnect。

   解决方案:finishConnect之后,调用write一个空字符串进去,如果抛出异常就证明没有链接成功

   另外,与linux原生的非阻塞socket的recv不同,nio下channel的 read 结果及意义如下

   -1: socket被关闭,关闭channel,并取消key

   0: 没有数据可读,直接返回即可

   大于0: 读取到的数据长度

Server端开发

   server端的选择就更加丰富一些了,也是分阻塞和非阻塞socket来说吧

阻塞socket

   阻塞socket的最简单即标准库自带的 ThreadingTCPServer,这个会在每个请求来的时候启动一个线程。这种server与预分配进程等方法其实是一个性质,性能是比较大的问题

非阻塞socket

   非阻塞socket的选择也有不少,比如python标准库里的asyncore和asynchat,但是这真的是个很老的库了,只支持select和poll,连epoll都支持不了。但是使用是没有任何问题的

   而作为asyncore的一个替代,tornado提供了一个更好的选择。当然很多人知道tornado是因为他是一个高性能的http server,但是其实他底层封装的ioloop那套异步io库也是可以单独使用的。

   但是基于异步io的server用起来其实是比较痛苦的,因为所有的业务操作都不能阻塞。当然,可以使用类似celery之类的任务分派工具,但是多一层进程通信会导致性能更加下降。

   还好python世界还有另一个选择:gevent,基于gevent写的tcp server在兼顾了性能的同时,大部分的阻塞请求代码都可以直接使用。

   tornado 和 gevent实现的server我都比较喜欢,所以我之前分别在其基础上封装了 tkolagkola,他们的底层都是依赖 kola的。

   之所以要做这样的封装,是因为自己对flask @route 式的写法情有独钟,而这样的封装就是实现了这种风格的编码,当然还有一些更有意思的东西在里面。

   gkola的示例代码如下:

from gkola import Kola, logger
app = Kola()

@app.create_conn
def create_conn(conn):
    logger.error('create_conn')

@app.close_conn
def close_conn(conn):
    logger.error('close_conn')

@app.before_first_request
def before_first_request(request):
    logger.error('before_first_request')

@app.before_request
def before_request(request):
    logger.error('before_request')

@app.after_request
def after_request(request, exc):
    logger.error('after_request')

@app.before_response
def before_response(conn, rsp):
    logger.error('rsp: %s', rsp)

@app.repeat_timer(5)
def repeat_timer():
    logger.error('repeat_timer')

@app.route()
def index(request):
    request.write(dict(
        ret=0,index=True
    ))


app.run('127.0.0.1', 5500)

同分类推荐文章

  1. 「置顶」我做了什么 (2026-05-05 12:13:28)
  2. 万字长文推演:手机不再从 App 开始,Agent OS 如何接管任务入口 (2026-04-28 14:57:22)
  3. Android Perfetto 系列 10 - Binder 调度与锁竞争 (2025-11-16 15:33:30)

查看更多 移动开发 文章 →

建议继续学习

  1. gen_tcp发送进程被挂起起因分析及对策 (累计阅读 37,821)
  2. TCP 的那些事儿(上) (累计阅读 22,696)
  3. 从输入 URL 到页面加载完成的过程中都发生了什么事情? (累计阅读 15,933)
  4. 自建DNS以防止GFW干扰 (累计阅读 13,125)
  5. 浅谈TCP优化 (累计阅读 11,082)
  6. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 10,846)
  7. 查看 Apache并发请求数及其TCP连接状态 (累计阅读 10,070)
  8. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 8,840)
  9. 关于 SOCKS 代理的远端 DNS 解析 (累计阅读 7,986)
  10. websocket 连接 C Server的尝试 (累计阅读 7,925)