转一篇总结的比较好的

Product Placement

Andulka
$LAYYYTER

★

ellievsbear
will byers stan first human second
Jules of Nature
TVSTRANGERTHINGS

pixel skylines
styofa doing anything
Today's Document

JVL
Game of Thrones Daily
Misplaced Lens Cap
"I'm Dorothy Gale from Kansas"
No title available

#extradirty

if i look back, i am lost
Lint Roller? I Barely Know Her
One Nice Bug Per Day
seen from United States
seen from Poland

seen from Romania

seen from China

seen from Malaysia
seen from United States
seen from Lithuania

seen from Singapore

seen from United States
seen from Sweden
seen from Argentina

seen from United States
seen from United States

seen from United Kingdom
seen from Romania

seen from Brazil
seen from United States

seen from T1

seen from Singapore
seen from Lithuania
@nic87chen
转一篇总结的比较好的
关于Android无法正确显示虚线的问题
从android3.0开始,安卓关闭了硬件加速功能,所以就不能显示了,所以就是在 AndroidManifest.xml,application或者是在activity中把硬件加速的功能关掉就可以了 增加设置:android:hardwareAccelerated="false" 但是上述方法实测在4.4.2或以下有效,6则无效了。 最有效的方法实在虚线的View中增加设置: <View android:layerType="software"
关于android 图片OOM
OOM = OutOfMemoryError
加载图像的占用内存大小 原理上是等于width * height * 每个像素占用的字节数
在一个1920*1080的图像中
如果使用RGB,则每个像素占用3个字节,则加载后内存占用约为5.9m
如果使用ARGB,则每个像素占用4个字节,则加载后内存占用约为7.9m
所以,加载的图片如果不是有透明半透明的像素在内,请务必选用RGB,配置项在BitmapFactory.Options 的inPreferredConfig = Bitmap.Config.RGB_565;
图片加载优化通常使用BitmapFactory.Options 的 inSampleSize 来控制加载的图片大小,但这个选项有个局限性,就是必须要使用大于1的整数,如果是1,则没变化,如果是2,则算法为:2分之1的宽乘以2分之1的高,则原图缩小了4分之一。通常用来加载缩小后的图片然后显示到ImageView中,这样就能达到省内存的效果,最大限度地避免OOM了。
当然,说到的局限性主要在,如果需求是图片在加工前不能被缩放,或者说inSampleSize缩放的大小不能满足需求,则就不能用这个方法了。比如说,拼接图片:我们的需求是把几个1920*1080 (当然,或者还有更大的)的图片,以缩放的形式打印到宽为1280的图片上,(android的API 并不支持直接直接把原图在不完全加载整个图片到内存的情况下缩放到指定宽高,至少目前找不到这个方法)用inSampleSize=2的话,宽度则变成960了,不符合1280的要求,这就没办法不把整个图片加载到内存中。确实咨询了几个android开发比较资深的童鞋,这目前还没有其他解决方案。
不管怎么样,最大限度地遵循以下优化原则来避免OOM:
1.尽量不要生成BitMap对象(java图像库中的图片对象),这是个胖子。但是我想,尽量不用的话,这可以吗?
2.用于view显示的Bitmap必须先缩放。
3.生产的BitMap 在不使用的时候,必须显式的 recycle()。但加载到View中显示的Bitmap必须不能recycle ,否则会报引用错误。
HTC 手机刷机后无信号
解决方法:
通过拨号 *#*#4636#*#* 进入手机测试信息
选择手机信息
设置首选网络类型 移动号码 选择 GSM auto (PRL) 电信号码 选择 CDMA auto (PRL) 或 LTE/CDMA auto(PRL)
然后右上角菜单 选择无线通信频道--》auto 过十几秒手机就有信号了,可以打电话试试
如果还不能上网, 打开海卓HiAPN -> 手动选择APN设置,选择相应的服务商:移动,联通,电信,然后隔一会就能上网了。
如果上面首选网络类型选择了LTE,然后你的手机以及SIM卡支持4G,然后你也开通了4G服务,则网络通信处则显示LTE。
我的HTC J One (日版 m7 htl 22)确实显示了LTE,说明了它是支持4G的,
系统 Android 5.0.1 基带 1.24.11.0617 版本 GEP5.01 v3.0 Edaoke
移动和电信号码,按照上面的方法都能正常打电话和上网。 就是有个奇怪的地方:手机信号图标上有个感叹号,不知道啥意思
python时间格式化指令
%a 英文星期的简写 Mon %A 英文星期的完整编写 Monday %b 英文月份的简写 Jun %B 英文月份的完整编写 June %c 显示本地的日期和时间 06/30/14 01:03:17 %I 小时数,取值在01~12之间 01 %j 显示从本年第一天开始到当天的天数 181 %w (week) 显示今天是星期几,0表示星期天 1 %W 显示当天属于本年的第几周,星期一作为一周的第一天进行计算 26 ==> 26*7 = 182天 %x 本地的当天日期 06/30/14 %X 本地的当天时间 01:09:54 %y 年份,取值在00~99之间 14 %Y 年份完整的拼写 2014 %m (month) 月份,取值在01~12之间 06 %d (day) 日期数,取值在1~31之间 30 %H (Hour) 小时数,取值在00~23之间 01 %M (Minute) 分钟数,取值在01~59之间 04 %S 秒 58
关于tornado异步驱动的一些链接
https://github.com/tornadoweb/tornado/wiki/Links
多进程监听一个socket的理解
首先,我们先来通过进程对系统文件的操作了解一下什么是文件描述符(另一个名字:句柄)以及它与进程的关系,它是一个可以IO操作的对象,保存在操作系统中的文件描述符表中来维护。 一个进程建立,会在进程表中建立对应的项,而这个进程项下包含了一个文件描述符表,在该进程中打开的文件描述符都会保存在这里。 一个进程打开一个文件,则会在文件描述符表、系统文件表、内存索引节点表中建立一些对应关系,如图的进程1
实际上,当新建第二个毫不一样的程序(图上进程2)打开跟进程1同一个文件时,内核会在系统文件表中新建一个项指向相同的内存索引节点。 扩展:这时他们之间的IO操作都是相对独立的互不影响的,所以在实际操作时多个不同进程对同一个文件进行操作时会造成不同的读写操作被覆盖的情况。 而socket,在进程中同样是一个文件描述符,但它是一个特殊文件类型,跟文件不一样,它不能通过一个具体路径去放访问到。 那么怎么让多个进程同时操作这个文件描述符呢?那就是Fork了。 我们先来了解下进程组成: 1.可执行的程序(二进制或sh等可执行脚本) 2.数据 3.上下文环境 fork操作执行时: 1.给新进程分配新的内存空间、进程ID 2.复制父进程的数据、上下文环境到这块新的内存空间 3.程序则使用共享内存 如下图
这时子进程保存了父进程的文件描述符的所有副本,可以进程跟父进程一样的操作了。 对于监听一个socket来说,多个进程同时在accept处阻塞,当有一个连接进入,多个进程同时被唤醒,但之间只有一个进程能成功accept,而不会同时有多个进程能拿到该连接对象,操作系统保证了进程操作这个连接的安全性。 扩展:上述过程,多个进程同时被唤醒,去抢占accept到的资源,这个现象叫“惊群”,而根据网上资料,Linux 内核2.6以下,accept响应时只有一个进程accept成功,其他都失败,重新阻塞,也就是说所有监听进程同时被内核调度唤醒,这当然会耗费一定的系统资源。 而2.6以上,则已经不存在惊群现象了,但是由于开发者开发程序时使用了如epoll等异步通知技术,仍然会造成惊群,如有需要更高性能要求,或许参考nginx的实现方案,这里就不详述了。 再贴一个简单的fork例子
# coding=utf8 import os, socket, sys, random print os.getpid(), 'process start' s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("", 8000)) s.listen(10) # 最多链接数,请求排队,队列满则拒绝请求 gb = 'a' print os.getpid(), 'global value[%s]:' %gb, id(gb) for i in range(3): pid = os.fork() # fork后,父进程以及子进程的上下文环境都是执行到当前位置,然后继续往下执行 lv = None if pid == 0: # pid=0 子进程获取到的状态 conn, address = s.accept() # 在有连接进入之前,所有进程都阻塞在这里 conn.recv(1) conn.send('ok') print 'i am child', os.getpid(), 'this socket is', id(s), "Accept from", address print os.getpid(), 'global value[%s]:' %gb, id(gb) gb = 'b%s' %os.getpid() print os.getpid(), 'after setter global value[%s]:' %gb, id(gb), 'local value[%s]:' %lv, id(lv) if not lv: lv = 'c%s' %os.getpid() print os.getpid(), 'after setter local value[%s]:' %lv, id(lv) break else: # pid>0 父进程获取到的状态;pid=-1为系统异常状态 print os.getpid(), "fork", i, "process id =", pid print os.getpid(), 'end!'
当你理解上述知识后,自己实现一个高性能服务也不再是什么难事了,或者去看其他服务器框架(比如tornado)也能找到类似代码。
关于百度地图LBS云存储234签名错误
LBS云存储接口必须用for_server模式,所以必须要签名,按照官方的介绍get 和post的接口请求方式不同,签名方法也有差异,其实tm官网也写的不清楚,我这总结下: get:参数必须按照官方api文档定义的key的顺序排序参数。 post:参数key必须按照从小到大字母排序。 注意,参数签名时和发送请求时都必须进行urlencode,包括其中所有符号,本人就是因为没有把“/”转义,所以在发送一些带url的参数时返回234签名失败
任务调度之 Celery
场景:当你在某些程序执行过程中需要另外执行一些不需马上返回结果的任务,这个任务可以交给其他进程去执行,以提高原程序的效率,这时就需要使用一些任务调度服务,比如这次的主角“celery”。
Celery 是一个py开发的模块,安装啥的就不说了。 <a href="https://github.com/celery/celery" title="Github开源之" target="_blank">Github 开源之</a> 安装之后你则发现命令行下有一个新的可执行命令:celery 路径一般为:/usr/local/bin/celery 这就是执行任务调度的主要worker程序了 ## 写个简易的任务试试:tasks.py
# coding=utf8 from celery import Celery celery = Celery('tasks', backend='redis', broker='redis://localhost:6379/0') @celery.task(bind=True, max_retries=3, default_retry_delay=1*6) def do(self, word): print 'hi:::', word try: raise ValueError, 'eee' except Exception as e: raise self.retry(exc=e, countdown=60)
## 如何运行? 就是刚才说到的celery worker 命令行到tasks.py所在目录,执行命令:
celery -A tasks worker --loglevel=warn
这就是Celery的Terminal了,可以看见任务调度的过程以及相应日志,可以将该worker运行到后台,也可以用管道重定向输出到日志文件,这些就不细说了。 ## worker有了,如何发起调度? 单独执行py函数一样
# python >>> from tasks import do >>> r = do.delary('nic') >>> r.status 'RETRY'
## 咦,为啥是'RETRY'? 不急,来从头到脚解释一下这个程序 引入模块,创建实例,使用redis作为任务调度队列,(可以使用其他,比如amqp) 实例化Celery,源码在 https://github.com/celery/celery/blob/master/celery/app/base.py # 108行,关于参数的说明注释实在少... 其中参数,第一个大概是名字,在worker进程输出日志的时候能看到, 第三个参数则是任务队列使用的服务协议以及地址 至于第二个参数,GitHub上的官方示例中,是不填这参数的,经过实验,不带该参数,是能正常调度任务的,执行什么的都没问题,但是一旦使用到里面关于执行结果的函数或属性,则会报错
# AttributeError: 'DisabledBackend' object has no attribute '_get_task_meta_for'
光看代码,一头雾水,查了好多资料以及源码,发现是跟这个backend参数有关系,参考资料: 原文地址http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html#id11 请mark之 Keeping Results If you want to keep track of the tasks’ states, Celery needs to store or send the states somewhere. There are several built-in result backends to choose from: SQLAlchemy/Django ORM, Memcached, Redis, AMQP (RabbitMQ), and MongoDB – or you can define your own. For this example you will use the amqp result backend, which sends states as messages. The backend is specified via the backend argument to Celery, (or via the CELERY_RESULT_BACKEND setting if you choose to use a configuration module):
# 大概意思就是,如果要查询结果的话就需要一个消息后端来传递执行结果,如果使用跟任务队列一样的服务作为消息服务,则直接写协议名 app = Celery('tasks', backend='amqp', broker='amqp://')
Or if you want to use Redis as the result backend, but still use RabbitMQ as the message broker (a popular combination):
# 大概意思就是,如果要想将消息队列与任务队列区分开来,则可以另外设置不同的服务后端 app = Celery('tasks', backend='redis://localhost', broker='amqp://')
然后就是task的常用参数: 1.bind 有点资料上涉及到这个参数,但官方也没说清楚是什么,经过试验,默认值是False,如果bind=True,被装饰的函数第一个参数为task 实例对象本身,所以像例子上的“self",有啥用?不急... 2.max_retries 从名字上可以看出,最大重试次数 3.default_retry_delay 默认重试间隔时间,秒,名字还是很好理解的 往下看,基于测试,写了个try except,报了个Error,这时终于使用到了 “self”了,对,需要重试执行任务,则使用到了self.retry 函数 也就是说若你需要保持你自己的任务函数的干净度,将上述bind=False时,则使这个任务函数完全不包含关于celery的任何代码侵入,当然同时就没法使用celery.task带来的重试机制的便利。 retry函数中的常用参数: 1.exc 异常堆栈的保存 2.countdown 可选重试间隔时间,否则使用default_retry_delay 设定,秒 执行任务调度:
>>> do.delay(...) >>> type(do) <class 'celery.local.PromiseProxy'>
经过装饰的函数,其实已经不是函数了,而是一个对象,经过试验,当然你仍然可以直接执行 do(...)以此实现在当前进程中执行原函数,因为这是一个callbale对象。 要通过任务调度方式来执行任务,则使用该对象的delary函数,通过名字看出来是“延迟”的意思。 执行发现,重试执行的期间不会打印该异常堆栈,只会打印retry等一些普通信息,知道最后一次执行仍然失败,才会打印出异常堆栈,执行成功则不打印。 最后来解释一下上述r.status >>> 'RETRY' 通过上述代码发现,其实这个任务是永远不会执行成功的,只会一直报错,celery worker会一直重试直到重试机会花光, 所以在重试期间执行status 时发现它是RETRY 状 当然还有一个状态函数就是 ready()表示是否执行完毕,重试期间它的结果是 False 重试完了最后结果是
>>> r.status 'FAILURE' # 最后结果为失败 >>> r.ready() True #真正的执行完了
当然,这个任务对象可以通过dir(r)来获取可以使用的函数,相信功能强大的它能满足你对任务调度的需求。
PostgreSQL 一点点
才接触这玩意,不太熟悉
psql -U 用户名 db名
\d ---> 显示所有表
\d 表名 ---> 显示这个表结构
\q ---> 退出
除法:
y/x 在PG里如果想做除法并想保留小数,但"/" 运算结果为取整,并且会截掉小数部分
可以像这样:
select round(y::numeric/x::numeric,2);
批量服务器管理之fabric
fabric 是一个可以远程执行shell命令的工具,实现基于Python,使用也基于Python。
能用来干嘛? 既然能远程执行shell命令,那说明它能远程ssh登录linux系统,并且能通过shell来操作服务。 也就是说,我们能用它来维护服务器,而且是批量的。 大到可以执行各种监控命令,小则可以实现上传、部署、启动、重启、关闭自己的应用,实现服务自动化部署。
工作原理也就是ssh。所以注意:实用的时候最后用不需输入密码的登陆,否则脚本运行时提示需要手动输入密码。
简单在客户端机器上安装一下,服务器则不需安装了:
sudo easy_install fabric
安装完毕后 系统里应该多了一个fab的可执行应用
which fab /usr/local/bin/fab
写个fabric脚本试试。 注意:fab 默认执行当前目录下文件名为fabfile.py的脚本,如果用了别的名字,则需要手动指定:-f xx.py
def hi(word): print 'hi', word
执行 fab hi:word=nic
hi nic Done.
可见其执行方式以及传参方式。调用方式很实用、简单,简单理解,不再啰嗦。 下面说说其核心功能!当然是linux shell命令的执行了!
1. local 本地执行 2. run 远程执行 3. put 把本地文件上传到远程 4. get 把远程文件下载到本地
from fabric.api import local, env, run def lc(): local('pwd') local('cd /') local('pwd') env.hosts = ['[email protected]:22'] env.password = 'yunfan' def ssh(): run('pwd') run('cd /tmp') run('pwd')
# 注意 env的配置必须要放在ssh函数体之外,否则会报错“No hosts found. Please specify (single) host string for connection”。
执行:fab lc 输出:
[localhost] local: pwd /{{当前执行fab命令所在目录}} [localhost] local: cd / [localhost] local: pwd /{{当前执行fab命令所在目录}} Done.
执行:fab ssh 输出:
[[email protected]:22] Executing task 'ssh' [[email protected]:22] run: pwd [[email protected]:22] out: /home/yunfan [[email protected]:22] out: [[email protected]:22] run: cd /tmp [[email protected]:22] run: pwd [[email protected]:22] out: /home/yunfan [[email protected]:22] out: Done.
可见每次执行的命令都相对于固定目录, 本地:当前执行fab命令所在目录 远程:ssh用户home目录 如果需要到具体一个目录中进行操作,则需要使用lcd (顾名思义,local cd), cd (远程 cd) 增加代码:
from fabric.api import lcd, cd def lc_dir(): local('pwd') with lcd('/tmp'): local('pwd') def ssh_dir(): run('pwd') with cd('/tmp'): run('pwd')
执行命令:fab lc_dir
[localhost] local: pwd /{{当前执行fab命令所在目录}} [localhost] local: pwd /tmp
执行命令:fab ssh_dir
[[email protected]:22] Executing task 'ssh_dir' [[email protected]:22] run: pwd [[email protected]:22] out: /home/yunfan [[email protected]:22] out: [[email protected]:22] run: pwd [[email protected]:22] out: /tmp [[email protected]:22] out: Done.
可见,已经能成功进入目标目录,其他的内容基本上就是shell命令了。 然后,上传、下载文件,增加代码:
from fabric.api import put, get def put_f(): local('cat tt') with cd('/tmp'): put('tt', '/tmp/') run('ls') run('cat tt') def get_f(): with cd('/tmp'): get('tt_rm', 'tt_rm')
随便在当前目录写了个文件名为tt的文件,往里面写点内容 测试,运行:fab put_f
[[email protected]:22] Executing task 'put_f' [localhost] local: cat tt hi this is test file [[email protected]:22] put: tt -> /tmp/tt [[email protected]:22] run: ls [[email protected]:22] out: tt [[email protected]:22] out: ...其他文件 [[email protected]:22] run: cat tt [[email protected]:22] out: hi this is test file
下载文件则不详述了。 可见文件就是这么简单的被传送到远程服务器指定路径上。 注意:put命令也相对于当前用户home目录来执行,而且在with cd操作下也无效(把put的第二参数去掉,测试便知),所以有必要指定上传路径。 奇怪的是,get命令没有这样的情况。
其他: 多个服务器统一用户名:
env.user = 'username'
多个服务器统一试用同一ssh key方式登录的配置
env.key_filename = "~/.ssh/id_rsa"
带password的:
env.password='xxx'
多个服务器不同密码的:
env.passwords = {'192.168.1.1':'passwd1','192.168.1.2':'passwd2','192.168.1.3':'passwd3'}
至于多个key,则没找到相关介绍。
若要分组操作不同的服务器,则使用
env.roledefs = { 'servers1': ['user1@host1:port1', ], 'servers2': ['user2@host2:port2', ] }
然后在对应的任务前使用装饰器roles
from fabric.api import roles @roles('servers1') def task1(): pass
最后,注意: 使用fabric 中途无法切换用户执行命令的, 可以试试
run('su user1')
切换后则变成了登陆ssh 一样的待输入命令的状态,由于这类命令都是等待用户下一步输入指令的,所以fabric无法自行终止。
以上只是fabric常用的功能,当然更多的功能或许需要在使用的过程进行更深入的探索。
mysql编译安装
Table 'mysql.plugin' doesn't exist
由于是自己编译安装,自己设置了数据库目录,所以在启动的时候就报了这个错!弄了很久才发现my.cnf 中的
[mysqld] datadir = /usr/local/mysql/data/ #/var/lib/mysql
跟编译时的参数不一样!修改后就能成功启动!
下面再简单记一下编译安装的过程
遇到很多包要安装,这里就不记了,Ubuntu 跟Centos 等都不太一样,根据提示找包就好了。
解压后cd mysql-5xxx 目录
cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/usr/local/mysql/data \ -DSYSCONFDIR=/etc \ -DWITH_MYISAM_STORAGE_ENGINE=1 \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_MEMORY_STORAGE_ENGINE=1 \ -DWITH_READLINE=1 \ -DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock \ -DMYSQL_TCP_PORT=3306 \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_PARTITION_STORAGE_ENGINE=1 \ -DEXTRA_CHARSETS=all \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci
cmake 完成后 再 make 最后 sudo make install
创建mysql用户
groupadd mysql useradd -g mysql mysql
修改刚才安装的目录权限
chown -R mysql:mysql /usr/local/mysql
然后初始化数据库
cd /usr/local/mysql
scripts/mysql_install_db --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --user=mysql ./bin/mysqld_safe &
正确启动后修改root密码 还有创建系统服务等
./bin/mysqladmin -u root password '123'
cp support-files/mysql.server /etc/init.d/mysql
Linux挂载新磁盘
#su
#fdisk /dev/sdb
####进入fdisk模式
Command (m for help):p //查看新硬盘的分区
Command (m for help):n //创建新分区
可以用m命令来看fdisk命令的内部命令;n命令创建一个新分区;d命令删除一个存在的分区;p命令显示分区列表;t命令修改分区的类型ID号;l命令显示分区ID号的列表;a命令指定启动分区;w命令是将对分区表的修改存盘让它发生作用。 Command action e extended //输入e为创建扩展分区 p primary partition (1-4) //输入p为创建主分区, 这里我们选择p
Partion number(1-4):1 //第一个扩展分区,按你需求可以最多分4个主分区 First Cylinder(1-1014,default 1): 1 //第一个主分区起始的磁盘块数 Last cylindet or +siza or +sizeM or +sizeK: +1024MB //可以是以MB为单位的数字或者以 磁盘块数,这里我们输入+1024MB表示分区大小为1G。 这样我们就创建完一个分区,如果要创建更多分区可以照上面的步骤继续创建。 创建完后用w保存分区。 Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks. 这样就分区完,我们还要进行格式化 #mkfs -t ext3 -c /dev/sdb1 //如果有多个分区,则分区修改为sdb2这样 格式化完后我们需要进行挂载分区, #mkdir www //创建/www目录,我们将把新的分区挂到www下 #mount /dev/sdb1 /www //将/dev/sdb1挂载到/www # df //用df命令进行查看 Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda2 3771316 1388956 2190788 39% / /dev/sda1 101089 9463 86407 10% /boot none 62988 0 62988 0% /dev/shm /dev/sdb1 485906 8239 452580 2% /www //看到了,这就是我们刚 才新挂载的分区 到这里我们工作已接近尾声了,不过我们如果这样就结束的话,我们每次重新启动服务器后都要 进行手工挂载,这样很麻烦,我们需要修改/etc/fstab文件来进行自动挂载。 #vi /etc/fstab
在文件的末尾填加如下内容: /dev/sdb1 /www ext3 defaults 1 2
关于 python socket 非阻塞
先看一下我稍微封装了下的代码
# coding=utf8
import socket
class Client(object): # socket client def __init__(self, host, port, timeout=None, name=None): self.name = name self.host = host self.port = int(port) self.timeout = timeout self._s = None def start(self): try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # PF_INET, AF_INET: Ipv4网络协议; PF_INET6, AF_INET6: Ipv6网络协议. # SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议。 s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # TCP_NODELAY 设置即时发送. 1表示true, 让该设置生效
s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 128) # 设置发送区换冲 最小值是 2048? 难道跟操作系统有关系? 当大于最小值时,获取到的结果则是输入值的2倍,系统实现? s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1024) # 设置接收区换冲 最小值是 2288? 难道跟操作系统有关系? 当大于最小值时,获取到的结果则是输入值的2倍,系统实现? # s.settimeout(self.timeout) # 只有阻塞状态才有效 s.connect((self.host, self.port)) s.setblocking(0) # 设置为非阻塞
# print s.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF), s.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) except socket.error, e: if e.errno == 115: # [Errno 115] Operation now in progress log.warn('socket connect maybe something wrong [Operation now in progress]') else: s.close() raise except: s.close() raise self._s = s self.fd = self._s.fileno() @property def closed(self): if self._s: return False return True def close(self): try: if self._s: self._s.close() except: pass self._s = None def send(self, content): try: return self._s.send(content) except: self.close() raise def recv(self, length): try: return self._s.recv(length) except socket.error, e: if e.errno == 11: # [Errno 11] Resource temporarily unavailable log.warn('socket recv maybe something wrong [Resource temporarily unavailable]') except: self.close() raise
上面的代码包含了两个特殊的“错误”:
从东冲一直沿着海岸线穿越到西冲,艰险的石头和山坡,过程中虽然受了一点点伤,但我学会了不在害怕面对!
今天新婚回来的同事发了盒喜糖,感觉心里暖暖的。 他们的故事开头像是电视剧的情节:他初中喜欢一女生,结果被那女生耍,现在的那个她当时看不过去救了他,从此他迷上了她。英雄救美的开始带来了一段长跑了十二年的感情,现在终于水到渠成结婚了! 只羡鸳鸯不羡仙
简单gevent TCPserver例子
# coding=utf8 import gevent from gevent import server, monkey monkey.patch_os() def do(socket, remote_address): print 'new socket come' f = socket.makefile() m = f.read(1) print 'read!' f.write('you mean [%s]\n' %m) f.flush() if m == 's': f.write('I will sleep') f.flush() for i in range(20): gevent.sleep(1) f.write('.') f.flush() f.write('\nfinish!\n') f.close() s = server.StreamServer(('0.0.0.0', 8080), do, backlog=512) s.pre_start() print 'listening ...' try: s.start_accepting() s._stopped_event.wait() except KeyboardInterrupt: print '\nbye!'