Varnish的子进程

VCL

	Varnish配置语言VCL是一种“域”专有类型的配置语言,用于描述Varnish Cache的请求处理和文档高速缓存策略。
当加载新配置时,Manager进程会创建VCC进程,然后将VCL代码转换为C代码,C代码被gcc编译成共享对象,然后共享对象被加载到cacher进程中。
VCL有多个状态引擎(state engine),状态之间存在相关性,但状态引擎彼此间互相隔离。
每个状态引擎可使用return(x)指明关联至哪个下一级引擎,每个状态引擎对应于vcl文件中的一个配置段,即为subroutine。
vcl_hash --> return(hit) --> vcl_hit

varnish的有限状态机

	实际上
vcl_recv ——>vcl_purge/vcl_pipe/vcl_hash
vcl_hash——>vcl_miss/vcl_hit
其他的如图所示
vcl_hash --> return(X) --> vcl_X VCL工作流看作是一个有限状态机 。
每个请求被分开处理,每个请求在任何给定的时间都是独立于其他人的,状态是相关的但也是孤立的。
内置的VCL代码始终存在,并附加在您自己的VCL下面。
当Varnish处理请求时,它首先解析请求本身,稍后Varnish将请求方法从头文件中分离出来,验证它是否是有效的HTTP请求等等。
当基本解析完成后,首先检查策略以作出决定,策略是VCL代码用于做出决定的一组规则。
每个状态都在VCL编码中有对应的可用参数,在VCL上的状态被概念化为子进程,在VCL中采用的等待状态描述中的等待状态即不是参数也不是返回值。
每个内置的子程序以前缀vcl_开始,被return(action)终止,退出当前状态并指示varnish进入下一个状态,其中action是一个关键词用于指定期望的输出。
子进程可以检查和操控http报文头部区域和各种其他方面的请求,并指示如何处理请求。
varnish创建的子进程被挂在varnish的工作中,这些子进程被以vcl_为前缀来命名的,而我们自己的进程就不能以其为前缀命名。
我们称这些有关状态的子进程为状态引擎(state engine),VCL有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离,每个状态引擎可使用return(x)指明关联至哪个下一级引擎,每个状态引擎对应于vcl文件中的一个配置段,即为subroutine。
vcl_recv的默认配置:
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
} if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
}

客户端和后端工作线程的详细的varnish请求流程

	Client Side:
vcl_recv, vcl_pass, vcl_hit, vcl_miss, vcl_pipe, vcl_purge, vcl_synth, vcl_deliver
Backend Side:
vcl_backend_fetch, vcl_backend_response, vcl_backend_error
vcl_recv:
hash:vcl_hash
pass: vcl_pass
pipe: vcl_pipe
synth: vcl_synth
purge: vcl_hash --> vcl_purge
vcl_hash:
lookup:
hit: vcl_hit
miss: vcl_miss
pass, hit_for_pass: vcl_pass
purge: vcl_purge
两个特殊的引擎:
vcl_init:在处理任何请求之前要执行的vcl代码:主要用于初始化VMODs;
vcl_fini:所有的请求都已经结束,在vcl配置被丢弃时调用;主要用于清理VMODs;

VCL语法

		VCL文件以vcl 4.0开始;
//,#和/ * * /是注释
子进程用sub关键字声明
没有循环,状态有限的变量
用下一个关键字作为return()函数的参数来终止语句,即:return(action)
特定领域
从Varnish 4.0开始,每个VCL文件必须首先在文件顶部用一个特殊的标记声明它的版本。
块由花括号分隔,以分号结尾。
VCL中的子程序既不带参数,也不返回值。
VCL中的子程序只能通过HTTP头交换数据。
VCL有终止语句,而不是传统的返回值。
子程序在执行return(*action*)语句时结束执行。
该行action告诉varnish下一步该做什么。
VCL有两个指令来使用来自另一个文件的内容,这些指令是include和import,并用于不同的目的。
include用于从另一个文件插入VCL代码,Varnish查找被varnishd的vcl_dir参数指定目录中的文件,请注意include语法中的引号。
import用于加载VMOD并将其功能提供给VCL代码,Varnish将查找VMOD以加载到由varnishd的vmod_dir参数指定的目录。
请注意import语法中缺少引号,你可以使用varnishtest中的include和import。
三类主要语法:
sub subroutine {
...
} if CONDITION {
...
} else {
...
} return(), hash_data()

VCL函数、关键字和变量

	函数:
regsub(str, regex, sub)
regsuball(str, regex, sub)
ban(boolean expression)
hash_data(input)
synthetic(str)
Keywords:
call subroutine
return(action)
new
set
unset
操作符:
==, !=, ~, >, >=, <, <=
逻辑操作符:&&, ||, !
变量赋值:=
举例:
obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次数;
if (obj.hits>0) {
set resp.http.X-Cache = "HIT via " + server.ip;
} else {
set resp.http.X-Cache = "MISS from " + server.ip;
} 变量类型:
内建变量:
req.*:request,表示由客户端发来的请求报文相关;
req.http.*
req.http.User-Agent, req.http.Referer, ...
bereq.*:由varnish发往BE主机的httpd请求相关;
bereq.http.*
beresp.*:由BE主机响应给varnish的响应报文相关;
beresp.http.*
resp.*:由varnish响应给client相关;
obj.*:存储在缓存空间中的缓存对象的属性;只读; 常用变量:
bereq.*, req.*:
bereq.http.HEADERS
bereq.request:请求方法;
bereq.url:请求的url;
bereq.proto:请求的协议版本;
bereq.backend:指明要调用的后端主机;
req.http.Cookie:客户端的请求报文中Cookie首部的值;
req.http.User-Agent ~ "chrome"
beresp.*, resp.*:
beresp.http.HEADERS
beresp.status:响应的状态码;
reresp.proto:协议版本;
beresp.backend.name:BE主机的主机名;
beresp.ttl:BE主机响应的内容的余下的可缓存时长;
obj.*
obj.hits:此对象从缓存中命中的次数;
obj.ttl:对象的ttl值
server.*
server.ip:varnish主机的IP;
server.hostname:varnish主机的Hostname;
client.*
client.ip:发请求至varnish主机的客户端IP; 用户自定义:
set
unset vcl_backend_response
覆盖某些URL的缓存时间
剥离Set-Cookie不需要的头部字段
剥离Vary头部字段
将helper-headers添加到对象以用于禁止
清理服务器响应
应用其他缓存策略
vcl_backend_response采用以下其中之一会被终止:deliver,retry,abandon。
deliver终止动作可以或者可以不依赖于后端的响应插入对象到缓存中。
retry操作使Varnish通过调用vcl_backend_fetch子程序再次将请求传输到后端。
abandon操作会放弃来自后端的任何响应。
后端可能会响应一个304HTTP头部,当有时间戳if-modified-since在http头部,且请求对象没能被修改时304响应会发生。
如果请求触及一个非新鲜的对象,Varnish将If-Modified-Since头的值添加t_origin到请求中,并将其发送到后端。
304响应不包含消息正文,因此Varnish使用缓存中的实体构建响应,304响应更新缓存对象的属性。
内建vcl_backend_response
sub vcl_backend_response {
if (beresp.ttl <= 0s ||
beresp.http.Set-Cookie ||
beresp.http.Surrogate-control ~ "no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
beresp.http.Vary == "*") {
/*
* Mark as "Hit-For-Pass" for the next 2 minutes
*/
set beresp.ttl = 120s;
set beresp.uncacheable = true;
}
return (deliver);
}
vcl_backend_response内建子进程被设计于避免缓存那些不希望的情况。
例如,避免缓存cookies响应,带有set-cookie http头域的响应,这个内建子进程也避免请求serialization,这个在waiting state选项中有描述。
为避免请求serialization,beresp.uncacheable被设定为true,并轮流创建以hit-fot-pass对象。
hti-fot-pass详细解释了这个对象的类型。
如果你仍然决定通过采用自己设定的来跳过内建vcl_backend_response子进程,请确保绝不要设定beresp.ttl为0。
如果你跳过内建子进程并设置TLL值为0,可以有效地从缓存中删除最终有可能用于避免请求serialization的对象。
berep.ttl的初始值
在varnish运行vcl_backend_response前,beresp.ttl变量就已经被设定了。
beresp.ttl用它在下面找到的第一个值进行初始化:
Cache-Control响应头字段中的s-maxage变量
Cache-Control响应头字段中的max-age变量
Expires响应报头字段
default_ttl参数
默认情况,下面的状态码会被缓存:
200:ok
203:非权威信息
300:多种选择
301:永久移动
302:暂时移动
304:没有修改
307:临时重定向
410:gone
404: Not Found
你可以不采用上面列出的而缓存其他状态码,但你需要在vcl_backend_response中给beresp.ttl设置一个正值。
因为beresp.ttl的设置是在vcl_backend_response执行之前,你可以修改cache-control头域的导引而不英雄beresp.ttl,反之亦然。
后端响应可能包括共享缓存s-maxage的最大响应头字段,通过所有varnish服务该字段覆盖了所有max-age值。
例如,如果后端发送cache-control:max-age=300,s-maxage=3600,所有varnish installations将缓存带有一个age值大于等于3600秒的缓存对象,这就意味着在age为301到3600s间的响应将不会被客户端web浏览器缓存,这是因为age的值超过了max-age。
一个明智的方法是使用s-maxage指令来指示varnish缓存响应。然后,在递送响应前使用vcl_backend_response上的regsub()来删除s-maxage指定。采用这个方法,你可以为varnish servers安全地使用s-maxage,并为客户端设置max-age为持续缓存。
警告 :
请记住,删除或更改Age响应标题字段可能会影响响应在下游的处理方式。删除Age字段的影响取决于下游中间件或客户端的HTTP实施。例如,假设您有三个varnish服务器串行设置。如果您删除Age第一个Varnish服务器中的字段,则第二个Varnish服务器将假定Age=0。在这种情况下,您可能会无意中将陈旧的对象传递给客户端。
示例:
1.设置.jpg urls的TTL设置为60秒
sub vcl_backend_response {
if (bereq.url ~ "\.jpg$") {
set beresp.ttl = 60s;
}
}
上面的例子将以.jpg结尾的所有URL缓存60秒。请记住,内置的VCL仍然被执行。这意味着带有Set-Cookie字段的图像不会被缓存。
2.缓存.JPG 60秒仅当s-maxage不存在
sub vcl_backend_response {
if (beresp.http.cache-control !~ "s-maxage" && bereq.url ~ "\.jpg$") {
set beresp.ttl = 60s;
}
}

VCL子程序

	VCL子进程,在其中定制Varnish的行为。
VCL子例程可用于:
添加自定义标头,更改Varnish错误消息的外观,在Varnish中添加HTTP重定向功能,清除内容以及定义缓存对象的哪些部分是唯一的。
注意
强烈建议尽可能让默认的内置子程序,内置子程序的设计考虑到安全性,这通常意味着它们可以合理的方式处理VCL代码中的任何缺陷。
vcl_recv
规范化客户端输入
选择一个后端Web服务器
重新编写Web应用程序的客户端数据
根据客户端输入决定缓存策略
访问控制列表(ACL)
安全屏障,例如针对SQL注入攻击
修复错误,例如index.htlm- >index.html
vcl_recv是Varnish第一个VCL子进程,将客户端请求解析为其基本数据结构之后执行。
vcl_recv有四个主要用途:
修改客户端数据以减少缓存的多样性。
决定使用哪个Web服务器。
根据客户端数据决定缓存策略。
执行特定Web应用程序所需的重写规则。
在vcl_recv你可以执行以下终止操作:
pass:它通过缓存查找,但它执行Varnish请求流的其余部分。 pass不会将来自后端的响应存储在缓存中。
pipe:此操作创建一个全双工管道,将客户端请求转发到后端,且不查看其内容。后端回复被转发回客户端且不缓存其内容。由于Varnish不再尝试将内容映射到请求上,因此任何子进程的请求发送给活动连接将被通过pipe转发。pipe请求不会出现在任何日志中。
hash:它在缓存中查找请求。
purge:它在缓存中查找请求以便删除它。
synth -从Varnish生成合成响应。这种合成响应通常是一个带有错误信息的网页。 synth也可以用来重定向客户端请求。
同样可以使用vcl_recv来设置以下安全措施。varnish不是入侵检测系统的替代品,但仍可以用来提前阻止一些典型的攻击。简单访问控制列表(ACL)也可以应用到vcl_recv上。
内建的vcl_recv子进程不会缓存所有你想要的,同时也最好不要缓存错误内容而是把它们发送给错误的用户。
重新访问内置的vcl_recv:
sub vcl_recv {
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
例子:
基本设备检测
sub vcl_recv {
if (req.http.User-Agent ~ "iPad" ||
req.http.User-Agent ~ "iPhone" ||
req.http.User-Agent ~ "Android") {
set req.http.X-Device = "mobile";
} else {
set req.http.X-Device = "desktop";
}
} vcl_pass
进入pass模式是调用
sub vcl_pass {
return (fetch);
}
当上一层子进程返回pass动作后才会调用vcl_pass子进程,这动作的请求是在pass模式中设置的,vcl_pass通常作为一个重要的catch-all,服务于vcl_hit和vcl_miss执行结果。
vcl_pass可能会返回是三个动作:fetch、synth、或者是restart。
当返回的的是fetch时,正在进行的请求就采用pass模式。
采用pass模式从请求中抓取的对象不被缓存,但会传递到客户端。
synth和restart返回的动作会调用相关的子进程。
hit-for-pass
当一个对象不应该被缓存是使用
hit-for-pass对象取代抓取的对象
存在TTL
一些请求就不应该被缓存,一个典型的例子就是当一个请求页中含有set-cookie响应头部时,且必须并只能把它递送给所需的客户端。
因此你可以告诉varnish创建个hit-for-pass的对象并存储这个对象到缓存,而不是存储抓取的这个对象,分布式的请求被采用pass模式处理。
当一个对象不需要被缓存是,beresp.uncacheable变量会设置为true。
结果,cacher进程会保持对hit-for-pass对象的hash散列应用,这种情况下,对请求的查找操作会传递给hash来找个hit-for-pass对象,如此类的请求会被vclpass子进程中的pass模式给处理。
如同其他缓存对象一样,hit-for-pass对象也有一个TTL(生命周期)。一旦生命周期过了,这个对象就会从缓存上删除。 vcl_backend_fetch
sub vcl_backend_fetch {
return (fetch);
}
vcl_backend_fetch 可以从vcl_miss或vcl_pass中调用。当vcl_backend_fetch从vcl_miss中调用时,抓取的对象会被缓存。如果vcl_backend_fetch被从vcl_pass中调用时,抓取的对象也不会被缓存的,即使是obj.ttl或obj.keep变量的值比0大。
一个相关的变量是bereq.uncacheable,这个变量指示出从后端来的对象请求是否被缓存。当然从pass请求中来的对象是绝不被缓存的。
vcl_backend_fetch有俩个可能的终端操作,fetch或abandon。fetch动作发送请求给后动,abandon动作调用vcl_synth子进程。内建vcl_bakend_fetch子进程只返回fetch动作。
后端响应被vcl_backend-response还是vcl_backend_error处理取决于响应来之于那个服务。如果Varnish收到语法正确的HTTP响应,则Varnish将控制权交给vcl_backend_response。语法正确的HTTP响应包括HTTP 5xx错误代码。如果Varnish没有收到HTTP响应,则将控制权交给vcl_backend_error。
vcl_hash
定义什么是唯一的请求
vcl_hash终是在vcl_recv后,或者另个子进程范围hash动作关键词。
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (lookup);
}
vcl_hash定义要用于缓存对象的hash key。
Hash key将一个缓存对象与另一个缓存对象区分开来,默认的VCL为vcl_hash添加主机名或ip地址,同时添加请求的url给cache hash。
vcl_hash的一个用法是在cache hash上添加用户名来识别用户指定的数据,当然缓存用户数据时应该谨慎进行,一个更好的选择可能是hash每个会话缓存对象。
vcl_hash子进程返回lookup操作关键字,不像其他动作关键词,lookup是一个操作,而不是子进程,在vcl_hash后的下个状态取决于在缓存中lookup的查找。
当lookup操作没能匹配到任何hash时,它会创建一个带有busy标志的对象并存储在缓存中,然后,请求会被发送到vcl_miss子进程中,一旦请求被处理busy标志会被删除,并从后端的响应中更新对象。
随后遇到busy标记的对象请求将被发送到等待列表中,这个等待名单旨在提高响应性能,这个在waiting state 选项中有解释。
注意:一个高速缓存散列可以指代一个或多个对象变量。对象变量是基于Vary头域的创建的。在一个缓存散列下保留多个变量是比较好的做法,而不是每个变量创建一个散列。
vcl_hit
在lookup操作之后执行,调用vcl_hash,找到(hits)在缓存上的对象。
sub vcl_hit {
if (obj.ttl >= 0s) {
// A pure unadultered hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
// Object is in grace, deliver it
// Automatically triggers a background fetch
return (deliver);
}
// fetch & deliver once we get the result
return (fetch);
}
vcl_hit子进程通常通过调用含有deliver,restart或者synth的return()来进行终止。
如果对象的TTL+grace time没有过时的话,返回的deliver会控制vcl_deliver。
如果过时时间超过了TTL,但没有超过TTL+grace time,deliver会调用与vcl_deliver同步的background fetch。
background fetch是一种异步调用,用来插入一个新的请求对象到缓存中。grace time会在grace模式选项中有解释。
restart重启传输,并增加重启计数器设定值。如果重启的次数比max_restarts设定的值要大,varnish会发出一个guru mediation的错误。
synth(status code,reason)返回指定状态码给客户端并丢弃请求。 vcl_miss
如果一个请求对象没有被lookup操作找到时子进程会被调用。
包含有是否尝试从后端检索文档以及使用那个后端的策略。
sub vcl_miss {
return (fetch);
}
子进程vcl_hit和vcl_miss是相关的。你很少调用他们,因为HTTP请求投吧的修改通常是在vcl_recv中进行。但是,如果你不希望发送X-Varnish头部给后端服务,你可以把它移动动vcl_miss或vcl_pass中。基于这种情况,你可以使用unset bereq ,http,x-varnish。 vcl_deliver
所有请求流程的公共最后退出点,除了通过vcl_pipe的请求。
经常用于添加和移除debug-headers。
sub vcl_deliver {
return (deliver);
}
vcl_deliver子进程是简单的,同样也是对修改varnish的输出很有用的。如果你需要删除一个头部,或添加一个不应该存储在cache中的头部,vcl_deliver可以胜任这个工作。
在vcl_deliver中常用的且被可被修改的变量是:
resp.http.*:发送个客户端的头部,它们可以被set和unset。
resp.status:状态码为200,404,503等
resp.reason:被返回给客户端的http状态信息
obj.hit:在对象上的cache-hits的数。因此,0代表miss,可以评估这个变量来轻松地显示响应是来自缓存命中还是未命中。
req.restarts:在VCL中发出的重启次数 - 如果没有发生,则返回0。 vcl_synth
用于在Varnish中生成内容
错误消息可以在这里创建
其他用例:重定向用户(301/302重定向)
vcl/default-vcl_synth.vcl:
sub vcl_synth {
set resp.http.Content-Type = "text/html; charset=utf-8";
set resp.http.Retry-After = "5";
synthetic( {"<!DOCTYPE html>
<html>
<head>
<title>"} + resp.status + " " + resp.reason + {"</title>
</head>
<body>
<h1>Error "} + resp.status + " " + resp.reason + {"</h1>
<p>"} + resp.reason + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"} );
return (deliver);
}
你可以创建合成响应,例如,在vcl_synth上的个性化错误信息。调用这个子进程你可以做:
return (synth(status_code, "reason"));
注意synth不是一个关键字,而是个带有参数的函数。
你必须为vcl_synth明确地返回status code和reason参数。在resp.http上设置合成响应的头部。
注意:
从 vcl/default-vcl_synth.vcl注意到 {" and "}可以用于创建多行的字段。这个不仅限于synthetic()函数,在其他地址也可以使用。
vcl_synth定义的对象绝不在缓存上存储,对立与vcl_backend_error定义的对象。
例子:
使用vcl_synth重定向请求
sub vcl_recv {
if (req.http.host == "www.example.com") {
set req.http.location = "http://example.com" + req.url;
return (synth(750, "Permanently moved"));
}
}
sub vcl_synth {
if (resp.status == 750) {
set resp.http.location = req.http.location;
set resp.status = 301;
return (deliver);
}
}

Varnish的VCL的更多相关文章

  1. Varnish的vcl子程序

    Varnish的VCL子程序 以下内容参考: http://book.varnish-software.com/4.0/ VCL子进程,在其中定制Varnish的行为.VCL子例程可用于:添加自定义标 ...

  2. 利用varnish做Discuz论坛的缓存服务器

    实验背景:公司有一台BBS服务器,用的是LNMP的架构搭建的.正好手头有一台空闲的虚拟机,于是想着给BBS前端加一台缓存服务器.于是选定了varnish,搜了很多教程,跌跌撞撞的完成了配置.这其中很多 ...

  3. varnish4.1 配置文件default.vcl

    varnish4.1 配置文件default.vcl # This .x VCL file vcl 4.0; backend default { .host = "127.0.0.1&quo ...

  4. Varnish常用相关命令工具

    varnishd启动./varnishd  -f /usr/local/varnish-3.0.2/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1: ...

  5. 学习varnish随笔

    Varnish是一款高性能.开源的反向代理服务器和缓存服务器.Varnish使用内存缓存文件来减少响应时间和网络带宽消耗.这个项目是由挪威的一家报纸Verdens Gang的网络分支起始的,其架构设计 ...

  6. varnish

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  7. Nginx+Varnish 实现动静分离,为服务器分流,降低服务器负载

    相必大家在看加快网站响应速度方面的文章时,都提过这么一条:动静分离.那怎样实现动静分离呢,这里笔者就亲自搭建相关服务实现动静分离. 动静分离是一种架构,就是把静态文件,比如JS.CSS.图片甚至有些静 ...

  8. Varnish安装使用(初学)

    本人对varnish也是新手,这里记录一下安装步骤! 环境:centos6.6 varnish安装包下载:wget https://repo.varnish-cache.org/source/varn ...

  9. varnish状态引擎1

    vcl: state engine:各引擎之间存一定程度上的相关性:前一个engine如果可以有多种下游engine,则上游engine需要用return指明 要转移的下游engine vcl_rec ...

随机推荐

  1. python 去掉html中其他属性,只保留href 和 src

    https://segmentfault.com/q/1010000010845573 import re #reg=r'\s+[^(href)]*=\"[^<>]+\" ...

  2. window.onload 函数不执行处理

    Google Chrome window.onload = function(){}   函数不执行处理 function pageOnLoad(){} window.onload = pageOnL ...

  3. android开发里跳过的坑——adb connect连不上

    user版本在系统init.rc里已经添加了setprop service.adb.tcp.port 5555 ,但是刷机以后,发现adb connect怎么都连不上,重启电脑,改变网络,巴拉巴拉,能 ...

  4. Codeforces Round #343 (Div. 2)【A,B水题】

    A. Far Relative's Birthday Cake 题意: 求在同一行.同一列的巧克力对数. 分析: 水题~样例搞明白再下笔! 代码: #include<iostream> u ...

  5. SQL server 2008 添加,删除字段

    添加,刪除字段 如果要在数据表中添加一个字段,应该如何表示呢?下面就为您介绍表添加字段的SQL语句的写法,希望可以让您对SQL语句有更深的认识. 通用式: alter table [表名] add [ ...

  6. 【剑指Offer面试题】 九度OJ1385:重建二叉树

    题目链接地址: pid=1385">http://ac.jobdu.com/problem.php?pid=1385 题目1385:重建二叉树 时间限制:1 秒内存限制:32 兆特殊判 ...

  7. 配置文件的备份和IOS 的备份

    分享到 QQ空间 新浪微博 百度搜藏 人人网 腾讯微博 开心网 腾讯朋友 百度空间 豆瓣网 搜狐微博 百度新首页 QQ收藏 和讯微博 我的淘宝 百度贴吧 更多... 百度分享 广场 登录 注册 关注此 ...

  8. CentOS firewall添加开放端口

    添加 firewall-cmd --zone=public --add-port=80/tcp --permanent (–permanent永久生效,没有此参数重启后失效) 重新载入 firewal ...

  9. Win10還原成最乾淨的狀態

    系統不穩定時我們想到的第一個選擇就是重灌,如果你的作業系統是win10將會有另外一個新選擇,就是透過程式進行還原,讓你的電腦回到剛安裝時的清爽. 工具資訊 [軟體名稱]微軟 Refresh Windo ...

  10. visio中怎样画线条或箭头

    1.在"画图"工具栏上,单击"铅笔"工具  或"线条"工具  . (凝视   假设看不到"画图"工具栏,请单击" ...