技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 系统架构 --> 手机应用/服务器开发的一些总结(二)

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

浏览:2926次  出处信息

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

   既然选择原生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. 实时监控Android设备网络封包    (阅读:4657)
  2. 手机应用/服务器开发的一些总结(一)    (阅读:3290)
  3. iOS设备唯一标识获取策略    (阅读:2267)
  4. Android桌面应用的设计探讨    (阅读:1569)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1