博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
memcached+net缓存
阅读量:6331 次
发布时间:2019-06-22

本文共 28945 字,大约阅读时间需要 96 分钟。

最近对线上项目进行了一次缓存方面的优化,本来6月就该写的,但是项目一直忙,就给自己理由偷懒了

缓存方面的思考参考代震军的文章比较多,文章地址:

http://www.cnblogs.com/daizhj/archive/2009/11/17/1604436.html

http://www.cnblogs.com/daizhj/archive/2009/03/23/1386652.html

 

我以前项目上一直都是,直接使用memcached或者直接使用net本地缓存,二者都是单独使用

这次对项目调整修改了下结构。主要目的是结合二者优势更有效使用缓存,二来也是为了解决网站更新代码缓解数据库查询压力的问题。

先大致说下它们的优点缺点:

1.memcached 优点是,稳定,受外因素影响较小,安全性高。缺点是速度方面不如net缓存,序列化和传输产生的额外开销比较大

2.net缓存,优点是高效,速度极快。缺点是稳定性,安全性差,受应用程序池回收设置影响。

 

针对以上优缺点,决定使用二级缓存模式:客户端-》NET本地缓存-》memcached缓存-》数据库  (NET本地缓存默认5分钟失效,memcached缓存时间设置,一般30分钟以上,个人觉得最后把memcached缓

存当成个永久缓存来设置,缺点就是缓存更新方面的策略需要考虑周全)

这样,当客户端访问本地缓存:

有数据->直接返回
无数据->读取下级缓存(“memcached缓存”)->有数据->返回,同步写份net缓存(无数据则数据库查询,并建立memcached缓存)

-------------------------------------------------------------------------------------------

以上设计经过实际应用,服务器内网和memcached之间的通讯量大大减少,CPU占用资源方面也相对保持稳定状态,不如同之前浮动从10%-30%(现在是10%-15%)。该项目网站日PV大概在250W+

网站缓存方面算是有了个初步的完成,以上还有个很大的优点就是在站点重启的时候,尤其是高并发访问的情况下,net缓存一失效,就可直接通过memcached,而不会直接造成高并发查询数据库,导致

数据库压力上升,如果有一句sql语句查询稍慢,就有可能导致查询死锁的状况出现。哈,这个可是很实际的优点。现在的代码部署了,在网站有用户访问的情况下更新代码不再是问题了

 ----------------------------------------------------------------

上面说了这么多,引入正题,C#网站应用程序中,使用memcached,在windos服务重启会有个情况,网站和memcached之间的socks连接失败,需要网站也同步重启下,服务才能重新连接。那么我刚上面说

的高并发查询情况导致数据库堵了的情况又会出现,而且是net本地缓存,和memcached缓存都丢失了,二者加起来至少3个G的数据

需要解决上面的问题,重新启动网站,而重新启动网站无非也就重新建立了下同memcahced之间的socks连接池,所以解决这问题的关键点是重新构建网站和memcached之间的socks连接池.本着这样的思路

,我这对Memcached.ClientLibrary 进行了扩展

1.
首先扩展定义了接口 ICacheManageConfig.cs

里面定义里个必须实现的方法 void Memcached_Restart(string LogMessage);  用来重建连接池

 

2.在调用memcached客户端组件的数据层,增加了接口实现类CacheManageConfig.cs

 

ExpandedBlockStart.gif
代码
   
public
 
class
 CacheManageConfig : Memcached.ClientLibrary.ICacheManageConfig
    {
        
private
 
static
 Memcached.ClientLibrary.SockIOPool pool 
=
 
null
;
        
        
///
 
<summary>
        
///
 实现接口方法,memcached客户端组件反射调用接口的实现方法
        
///
 
</summary>
        
///
 
<param name="message"></param>
        
public
 
void
 Memcached_Restart(
string
 message)
        {
            _Restart(message);
        } 
        
///
 
<summary>
        
///
 初始化连接池
        
///
 
</summary>
        
public
 
static
 
void
 Memcached_Init()
        {
            Memcached.ClientLibrary.MemcachedSocksMonitor.CacheManageConfigPath 
=
 
"
KM.Brand.DBLib.Cache.CacheManageConfig
"
;
            
//
每次初始化都用新的连接池名
            Memcached.ClientLibrary.MemcachedSocksMonitor.CachePoolName 
=
 
"
pool
"
 
+
 Guid.NewGuid().ToString();
           
string
 memcachedserver 
=
 System.Configuration.ConfigurationManager.AppSettings[
"
memcachedserver
"
];
            
string
[] serverlist 
=
 {memcachedserver};
            pool 
=
 Memcached.ClientLibrary.SockIOPool.GetInstance(Memcached.ClientLibrary.MemcachedSocksMonitor.CachePoolName);
            pool.SetServers(serverlist);
            pool.InitConnections 
=
 
15
;
            pool.MinConnections 
=
 
15
;
            pool.MaxConnections 
=
 
200
;
            pool.SocketTimeout 
=
 
3000
;
            pool.SocketConnectTimeout 
=
 
1000
;
            pool.MaintenanceSleep 
=
 
30
;
            pool.Failover 
=
 
true
;
            pool.Nagle 
=
 
false
;
            
//
socket单次任务的最大时间,超过这个时间socket会被强行中断掉(当前任务失败)
            pool.MaxBusy 
=
 
1000
 
*
 
10
;
            pool.Initialize();
            
//
由于有旧代码使用默认的程序池名字,所以同时初始化一个默认名字的连接池
             pool 
=
 Memcached.ClientLibrary.SockIOPool.GetInstance();
            pool.SetServers(serverlist);
            pool.InitConnections 
=
10
;
            pool.MinConnections 
=
 
10
;
            pool.MaxConnections 
=
 
50
;
            pool.SocketTimeout 
=
 
3000
;
            pool.SocketConnectTimeout 
=
 
1000
;
            pool.MaintenanceSleep 
=
 
30
;
            pool.Failover 
=
 
true
;
            pool.Nagle 
=
 
false
;
            
//
socket单次任务的最大时间,超过这个时间socket会被强行中断掉(当前任务失败)
             pool.MaxBusy 
=
 
1000
 
*
 
10
;
            pool.Initialize();
         }
        
#region
  连接池重建
        
///
 
<summary>
        
///
 连接池重建
        
///
 
</summary>
        
///
 
<param name="message"></param>
        
private
 
static
 
void
 _Restart(
string
 message)
        {
            
if
 (pool 
!=
 
null
)
            {
//
其实可以把缓存管理模块整合到这个项目一起的。哎!               
                pool.Shutdown(Memcached.ClientLibrary.MemcachedSocksMonitor.CachePoolName);
            }
            
//
重新初始化
              Memcached_Init();
            KM.Brand.DBLib.Cache.CacheManage.Dispose(message);
        }
        
#endregion
    }

 

 

3.在网站应用global.asax中配置连接池启动

 

 
protected
 
void
 Application_Start(
object
 sender, EventArgs e)
 {
           
//
初始化memcached连接池
            KM.Brand.DBLib.Cache.CacheManageConfig.Memcached_Init();
}

 

 

4。最关键点,修改memcached客户端源代码实现,回收连接池

主要有新建立了个类,MemcachedSocksMonitor.cs 实现连接池基本操作

 

ExpandedBlockStart.gif
代码
 
public
 
static
 
class
 MemcachedSocksMonitor
    { 
        
private
 
static
 
string
 _CacheManageConfigPath;
        
private
 
static
 
int
 _SocksMaxErrCount;
        
private
 
static
 
string
 _CachePoolName;
        
///
 
<summary>
        
///
 连接池名字
        
///
 
</summary>
        
public
 
static
 
string
 CachePoolName
        {
            
get
 { 
return
 _CachePoolName; }
            
set
 { _CachePoolName 
=
 value;}
        }
        
///
<summary>
        
///
初始化一定要设置
        
///
实现接口ICacheManageConfig的类完整命名空间路径(包含类名),重新建立缓存管理模块单件实例的方法实现名称
        
///
 
</summary>
        
public
 
static
 
string
 CacheManageConfigPath
        {
            
get
 { 
return
 _CacheManageConfigPath; }
            
set
 { _CacheManageConfigPath 
=
 value; }
        }
        
///
 
<summary>
        
///
 执行重建的条件,该数字累加到20就重建连接池,并清零,次数累计保留1分钟
        
///
 
</summary>
        
public
 
static
 
int
 SocksMaxErrCount
        {
            
get
 { 
return
 _SocksMaxErrCount; }
            
set
 { _SocksMaxErrCount 
=
 value; }
        } 
        
///
 
<summary>
        
///
 重建连接池
        
///
 
</summary>
        
public
  
static
 
void
 Restart()
        {
//
识别需要重启,看日志错误 log.Error(GetLocalizedString("set IOException"), exception5);
            ICacheManageConfig CacheDispose 
=
 (ICacheManageConfig)Assembly.Load(CacheManageConfigPath).CreateInstance(
"
Memcached_Restart
"
); 
//
(ICacheManageConfig)Create(DisposeMonthodName);
            CacheDispose.Memcached_Restart(
"
memcached服务连接池传输数据失败,重新生成了连接池!\r\n 无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接!!一分钟内连续出错次数
"
 
+
 SocksMaxErrCount);
        }
        
///
 
<summary>
        
///
 记录传输错误的失败次数,并决定是否要重建连接池
        
///
 这里用了本地缓存,一般情况下这缓存都是不存在的,该方法也很少会执行到
        
///
 
</summary>
        
public
 
static
 
void
 SockIOErrRestatr()
        {
            
//
执行一次就进行一次逻辑处理
            
string
 key 
=
 
"
MemcachedClientLibrarySockIOErrRestatr
"
;
            
object
 value 
=
 System.Web.HttpRuntime.Cache.Get(key);
            
if
 (value 
!=
 
null
)
            {
                
if
 (SocksMaxErrCount 
>
 
20
)
                {
                    
//
执行重建memcached连接池
                    Restart();
                    SocksMaxErrCount 
=
 
0
;
                }
                
else
                {
                    SocksMaxErrCount 
=
 SocksMaxErrCount 
+
 
1
;
                }
            }
            
else
            {
                SocksMaxErrCount 
=
 
1
;
                System.Web.HttpRuntime.Cache.Add(key,
1
null
,DateTime.Now.AddMinutes(
1
), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.High, 
null
);
            } 
        } 
    }

 

 

 

5.SockIOPool.cs 修改Shutdown 函授,也忘记有没其他地方修改了

 

ExpandedBlockStart.gif
代码
   [MethodImpl(MethodImplOptions.Synchronized)]
        
public
 
void
 Shutdown(
string
 poolName)
        {
            
bool
 isDebugEnabled 
=
 Log.IsDebugEnabled;
            
if
 ((
this
._maintenanceThread 
!=
 
null
&&
 
this
._maintenanceThread.IsRunning)
            {
                
this
.StopMaintenanceThread();
            } 
            
bool
 flag2 
=
 Log.IsDebugEnabled;
            ClosePool(
this
._availPool);
            ClosePool(
this
._busyPool);
            
this
._availPool 
=
 
null
;
            
this
._busyPool 
=
 
null
;
            
this
._buckets 
=
 
null
;
            
this
._hostDeadDuration 
=
 
null
;
            
this
._hostDead 
=
 
null
;
            
this
._initialized 
=
 
false
;
            
bool
 flag3 
=
 Log.IsDebugEnabled;
            
//
下面方法是增加的,当memcached重启后,导致当前连接池连接不上,执行停止命令后
            
//
移除失败的连接池,这样重新初始化就会重新建立sock连接池
            
if
 (poolName 
==
 
""
)
            {
                poolName 
=
 GetLocalizedString(
"
default instance
"
);
            }
            Pools.Remove(GetLocalizedString(poolName));
        }

 

 6 MemcachedClient.cs修改,具体忘记改了哪些,全部复制上来好了

 

ExpandedBlockStart.gif
代码
namespace
 Memcached.ClientLibrary
{
    
using
 ICSharpCode.SharpZipLib.GZip;
    
using
 log4net;
    
using
 System;
    
using
 System.Collections;
    
using
 System.Globalization;
    
using
 System.IO;
    
using
 System.Resources;
    
using
 System.Runtime.Serialization;
    
using
 System.Runtime.Serialization.Formatters.Binary;
    
using
 System.Text;
    
using
 System.Text.RegularExpressions;
    
public
 
class
 MemcachedClient
    {
        
private
 
bool
 _compressEnable;
        
private
 
long
 _compressThreshold;
        
private
 
string
 _defaultEncoding;
        
private
 
string
 _poolName;
        
private
 
bool
 _primitiveAsString;
//
Memcached.ClientLibrary.StringMessages
        
private
 
static
 ResourceManager _resourceManager 
=
 
new
 ResourceManager(
"
Memcached.ClientLibrary.StringMessages
"
typeof
(MemcachedClient).Assembly);
        
private
 
const
 
string
 CLIENT_ERROR 
=
 
"
CLIENT_ERROR
"
;
        
private
 
const
 
int
 COMPRESS_THRESH 
=
 
0x7800
;
        
private
 
const
 
string
 DELETED 
=
 
"
DELETED
"
;
        
private
 
const
 
string
 END 
=
 
"
END
"
;
        
private
 
const
 
string
 ERROR 
=
 
"
ERROR
"
;
        
private
 
const
 
int
 F_COMPRESSED 
=
 
2
;
        
private
 
const
 
int
 F_SERIALIZED 
=
 
8
;
        
private
 
static
 ILog log 
=
 LogManager.GetLogger(
typeof
(MemcachedClient));
        
private
 
const
 
string
 NOTFOUND 
=
 
"
NOT_FOUND
"
;
        
private
 
const
 
string
 NOTSTORED 
=
 
"
NOT_STORED
"
;
        
private
 
const
 
string
 OK 
=
 
"
OK
"
;
        
private
 
const
 
string
 SERVER_ERROR 
=
 
"
SERVER_ERROR
"
;
        
private
 
const
 
string
 STATS 
=
 
"
STAT
"
;
        
private
 
const
 
string
 STORED 
=
 
"
STORED
"
;
        
private
 
const
 
string
 VALUE 
=
 
"
VALUE
"
;
        
public
 MemcachedClient(): 
this
(
"
default instance
"
)
        {
          
        } 
        
public
 MemcachedClient(
string
 name)
        {
            
if
 (name 
!=
 
""
)
            {
                
this
.Init(name);
            }
            
else
            {
                
this
.Init();
            }
        }
        
private
 
void
 Init(
string
 key)
        {
            
this
._primitiveAsString 
=
 
false
;
            
this
._compressEnable 
=
 
true
;
            
this
._compressThreshold 
=
 
0x7800L
;
            
this
._defaultEncoding 
=
 
"
UTF-8
"
;
            
this
._poolName 
=
 GetLocalizedString(key);
        }
        
public
 
bool
 Add(
string
 key, 
object
 value)
        {
            
return
 
this
.Set(
"
add
"
, key, value, DateTime.MaxValue, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Add(
string
 key, 
object
 value, DateTime expiry)
        {
            
return
 
this
.Set(
"
add
"
, key, value, expiry, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Add(
string
 key, 
object
 value, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
add
"
, key, value, DateTime.MaxValue, hashCode, 
this
._primitiveAsString);
        }
        
public
 
bool
 Add(
string
 key, 
object
 value, DateTime expiry, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
add
"
, key, value, expiry, hashCode, 
this
._primitiveAsString);
        }
        
public
 
long
 Decrement(
string
 key)
        {
            
return
 
this
.IncrementOrDecrement(
"
decr
"
, key, 
1L
null
);
        }
        
public
 
long
 Decrement(
string
 key, 
long
 inc)
        {
            
return
 
this
.IncrementOrDecrement(
"
decr
"
, key, inc, 
null
);
        }
        
public
 
long
 Decrement(
string
 key, 
long
 inc, 
int
 hashCode)
        {
            
return
 
this
.IncrementOrDecrement(
"
decr
"
, key, inc, hashCode);
        }
        
public
 
bool
 Delete(
string
 key)
        {
            
return
 
this
.Delete(key, 
null
, DateTime.MaxValue);
        }
        
public
 
bool
 Delete(
string
 key, DateTime expiry)
        {
            
return
 
this
.Delete(key, 
null
, expiry);
        }
        
public
 
bool
 Delete(
string
 key, 
object
 hashCode, DateTime expiry)
        {
            
if
 (key 
==
 
null
)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
null key delete
"
));
                }
                
return
 
false
;
            }
            SockIO sock 
=
 SockIOPool.GetInstance(
this
._poolName).GetSock(key, hashCode);
            
if
 (sock 
!=
 
null
)
            {
                StringBuilder builder 
=
 
new
 StringBuilder(
"
delete 
"
).Append(key);
                
if
 (expiry 
!=
 DateTime.MaxValue)
                {
                    builder.Append(
"
 
"
 
+
 (GetExpirationTime(expiry) 
/
 
0x3e8
));
                }
                builder.Append(
"
\r\n
"
);
                
try
                {
                    sock.Write(Encoding.UTF8.GetBytes(builder.ToString()));
                    sock.Flush();
                    
string
 newValue 
=
 sock.ReadLine();
                    
if
 (
"
DELETED
"
 
==
 newValue)
                    {
                        
bool
 isInfoEnabled 
=
 log.IsInfoEnabled;
                        sock.Close();
                        sock 
=
 
null
;
                        
return
 
true
;
                    }
                    
if
 (
"
NOT_FOUND
"
 
==
 newValue)
                    {
                        
if
 (
!
log.IsInfoEnabled)
                        {
                        }
                    }
                    
else
 
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
delete key error
"
).Replace(
"
$$Key$$
"
, key).Replace(
"
$$Line$$
"
, newValue));
                    }
                }
                
catch
 (IOException exception)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
delete IOException
"
), exception);
                    }
                    
try
                    {
                        sock.TrueClose();
                    }
                    
catch
 (IOException exception2)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, sock.ToString()), exception2);
                        }
                    }
                    sock 
=
 
null
;
                }
                
if
 (sock 
!=
 
null
)
                {
                    sock.Close();
                }
            }
            
return
 
false
;
        }
        
public
 
bool
 FlushAll()
        {
            
return
 
this
.FlushAll(
null
);
        }
        
public
 
bool
 FlushAll(ArrayList servers)
        {
            SockIOPool instance 
=
 SockIOPool.GetInstance(
this
._poolName);
            
if
 (instance 
==
 
null
)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
unable to get socket pool
"
));
                }
                
return
 
false
;
            }
            
if
 (servers 
==
 
null
)
            {
                servers 
=
 instance.Servers;
            }
            
if
 ((servers 
==
 
null
||
 (servers.Count 
<=
 
0
))
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
flushall no servers
"
));
                }
                
return
 
false
;
            }
            
bool
 flag 
=
 
true
;
            
for
 (
int
 i 
=
 
0
; i 
<
 servers.Count; i
++
)
            {
                SockIO connection 
=
 instance.GetConnection((
string
) servers[i]);
                
if
 (connection 
==
 
null
)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
unable to connect
"
).Replace(
"
$$Server$$
"
, servers[i].ToString()));
                    }
                    flag 
=
 
false
;
                }
                
else
                {
                    
string
 s 
=
 
"
flush_all\r\n
"
;
                    
try
                    {
                        connection.Write(Encoding.UTF8.GetBytes(s));
                        connection.Flush();
                        
string
 str2 
=
 connection.ReadLine();
                        flag 
=
 (
"
OK
"
 
==
 str2) 
?
 flag : 
false
;
                    }
                    
catch
 (IOException exception)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
flushall IOException
"
), exception);
                        }
                        
try
                        {
                            connection.TrueClose();
                        }
                        
catch
 (IOException exception2)
                        {
                            
if
 (log.IsErrorEnabled)
                            {
                                log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, connection.ToString()), exception2);
                            }
                        }
                        flag 
=
 
false
;
                        connection 
=
 
null
;
                    }
                    
if
 (connection 
!=
 
null
)
                    {
                        connection.Close();
                    }
                }
            }
            
return
 flag;
        }
        
public
 
object
 Get(
string
 key)
        {
            
return
 
this
.Get(key, 
null
false
);
        }
        
public
 
object
 Get(
string
 key, 
int
 hashCode)
        {
            
return
 
this
.Get(key, hashCode, 
false
);
        }
        
public
 
object
 Get(
string
 key, 
object
 hashCode, 
bool
 asString)
        {
            SockIO sock 
=
 SockIOPool.GetInstance(
this
._poolName).GetSock(key, hashCode);
            
if
 (sock 
!=
 
null
)
            {
                
try
                {
                    
string
 s 
=
 
"
get 
"
 
+
 key 
+
 
"
\r\n
"
;
                    
bool
 isDebugEnabled 
=
 log.IsDebugEnabled;
                    sock.Write(Encoding.UTF8.GetBytes(s));
                    sock.Flush();
                    Hashtable hm 
=
 
new
 Hashtable();
                    
this
.LoadItems(sock, hm, asString);
                    
bool
 flag2 
=
 log.IsDebugEnabled;
                    sock.Close();
                    
return
 hm[key];
                }
                
catch
 (IOException exception)
                { 
                    
//
##监测##
                    
//
exception.Message=无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。
                    
//
原因:memcached重启类造成的连接池无法再通信的错误
                    
//
解决:判断上面的message出现次数几次,就考虑重新建立连接池
                    
if
 (exception.Message.Contains(
"
无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接
"
))
                    {
                       MemcachedSocksMonitor.SockIOErrRestatr();
                    }
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
get IOException
"
).Replace(
"
$$Key$$
"
, key), exception);
                    }
                    
try
                    {
                        sock.TrueClose();
                    }
                    
catch
 (IOException exception2)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, sock.ToString()), exception2);
                        }
                    }
                    sock 
=
 
null
;
                }
                
if
 (sock 
!=
 
null
)
                {
                    sock.Close();
                }
            }
            
return
 
null
;
        }
        
public
 
long
 GetCounter(
string
 key)
        {
            
return
 
this
.GetCounter(key, 
null
);
        }
        
public
 
long
 GetCounter(
string
 key, 
object
 hashCode)
        {
            
if
 (key 
==
 
null
)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
getcounter null key
"
));
                }
                
return
 
-
1L
;
            }
            
long
 num 
=
 
-
1L
;
            
try
            {
                num 
=
 
long
.Parse((
string
this
.Get(key, hashCode, 
true
), 
new
 NumberFormatInfo());
            }
            
catch
 (ArgumentException)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
getcounter counter not found
"
).Replace(
"
$$Key$$
"
, key));
                }
            }
            
return
 num;
        }
        
private
 
static
 
int
 GetExpirationTime(DateTime expiration)
        {
            
if
 (expiration 
<=
 DateTime.Now)
            {
                
return
 
0
;
            }
            TimeSpan span 
=
 
new
 TimeSpan(
0x1d
0x17
0x3b
0x3b
);
            
if
 (expiration.Subtract(DateTime.Now) 
>
 span)
            {
                
return
 (
int
) span.TotalSeconds;
            }
            
return
 (
int
) expiration.Subtract(DateTime.Now).TotalSeconds;
        }
        
private
 
static
 
string
 GetLocalizedString(
string
 key)
        {
            
if
 (key 
!=
 
"
default instance
"
)
            {
                
return
 key;
            }
            
else
            {
                
return
 _resourceManager.GetString(key);
            }
        }
        
public
 Hashtable GetMultiple(
string
[] keys)
        {
            
return
 
this
.GetMultiple(keys, 
null
false
);
        }
        
public
 Hashtable GetMultiple(
string
[] keys, 
int
[] hashCodes)
        {
            
return
 
this
.GetMultiple(keys, hashCodes, 
false
);
        }
        
public
 Hashtable GetMultiple(
string
[] keys, 
int
[] hashCodes, 
bool
 asString)
        {
            
if
 (keys 
==
 
null
)
            {
                
return
 
new
 Hashtable();
            }
            Hashtable hashtable 
=
 
new
 Hashtable();
            
for
 (
int
 i 
=
 
0
; i 
<
 keys.Length; i
++
)
            {
                
object
 hashCode 
=
 
null
;
                
if
 ((hashCodes 
!=
 
null
&&
 (hashCodes.Length 
>
 i))
                {
                    hashCode 
=
 hashCodes[i];
                }
                SockIO sock 
=
 SockIOPool.GetInstance(
this
._poolName).GetSock(keys[i], hashCode);
                
if
 (sock 
!=
 
null
)
                {
                    
if
 (
!
hashtable.ContainsKey(sock.Host))
                    {
                        hashtable[sock.Host] 
=
 
new
 StringBuilder();
                    }
                    ((StringBuilder) hashtable[sock.Host]).Append(
"
 
"
 
+
 keys[i]);
                    sock.Close();
                }
            }
            
bool
 isInfoEnabled 
=
 log.IsInfoEnabled;
            Hashtable hm 
=
 
new
 Hashtable();
            ArrayList list 
=
 
new
 ArrayList();
            
foreach
 (
string
 str 
in
 hashtable.Keys)
            {
                SockIO connection 
=
 SockIOPool.GetInstance(
this
._poolName).GetConnection(str);
                
try
                {
                    
string
 s 
=
 
"
get
"
 
+
 ((StringBuilder) hashtable[str]) 
+
 
"
\r\n
"
;
                    
bool
 flag2 
=
 log.IsDebugEnabled;
                    connection.Write(Encoding.UTF8.GetBytes(s));
                    connection.Flush();
                    
this
.LoadItems(connection, hm, asString);
                }
                
catch
 (IOException exception)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
getmultiple IOException
"
), exception);
                    }
                    list.Add(str);
                    
try
                    {
                        connection.TrueClose();
                    }
                    
catch
 (IOException exception2)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, connection.ToString()), exception2);
                        }
                    }
                    connection 
=
 
null
;
                }
                
if
 (connection 
!=
 
null
)
                {
                    connection.Close();
                }
            }
            
foreach
 (
string
 str3 
in
 list)
            {
                hashtable.Remove(str3);
            }
            
bool
 isDebugEnabled 
=
 log.IsDebugEnabled;
            
return
 hm;
        }
        
public
 
object
[] GetMultipleArray(
string
[] keys)
        {
            
return
 
this
.GetMultipleArray(keys, 
null
false
);
        }
        
public
 
object
[] GetMultipleArray(
string
[] keys, 
int
[] hashCodes)
        {
            
return
 
this
.GetMultipleArray(keys, hashCodes, 
false
);
        }
        
public
 
object
[] GetMultipleArray(
string
[] keys, 
int
[] hashCodes, 
bool
 asString)
        {
            
if
 (keys 
==
 
null
)
            {
                
return
 
new
 
object
[
0
];
            }
            Hashtable hashtable 
=
 
this
.GetMultiple(keys, hashCodes, asString);
            
object
[] objArray 
=
 
new
 
object
[keys.Length];
            
for
 (
int
 i 
=
 
0
; i 
<
 keys.Length; i
++
)
            {
                objArray[i] 
=
 hashtable[keys[i]];
            }
            
return
 objArray;
        }
        
public
 
long
 Increment(
string
 key)
        {
            
return
 
this
.IncrementOrDecrement(
"
incr
"
, key, 
1L
null
);
        }
        
public
 
long
 Increment(
string
 key, 
long
 inc)
        {
            
return
 
this
.IncrementOrDecrement(
"
incr
"
, key, inc, 
null
);
        }
        
public
 
long
 Increment(
string
 key, 
long
 inc, 
int
 hashCode)
        {
            
return
 
this
.IncrementOrDecrement(
"
incr
"
, key, inc, hashCode);
        }
        
private
 
long
 IncrementOrDecrement(
string
 cmdname, 
string
 key, 
long
 inc, 
object
 hashCode)
        {
            SockIO sock 
=
 SockIOPool.GetInstance(
this
._poolName).GetSock(key, hashCode);
            
if
 (sock 
!=
 
null
)
            {
                
try
                {
                    
string
 s 
=
 
string
.Concat(
new
 
object
[] { cmdname, 
"
 
"
, key, 
"
 
"
, inc, 
"
\r\n
"
 });
                    
bool
 isDebugEnabled 
=
 log.IsDebugEnabled;
                    sock.Write(Encoding.UTF8.GetBytes(s));
                    sock.Flush();
                    
string
 input 
=
 sock.ReadLine();
                    
if
 (
new
 Regex(
@"
\d+
"
).Match(input).Success)
                    {
                        sock.Close();
                        
return
 
long
.Parse(input, 
new
 NumberFormatInfo());
                    }
                    
if
 (
"
NOT_FOUND
"
 
==
 input)
                    {
                        
if
 (
!
log.IsInfoEnabled)
                        {
                        }
                    }
                    
else
 
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
incr-decr key error
"
).Replace(
"
$$Key$$
"
, key));
                    }
                }
                
catch
 (IOException exception)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
incr-decr IOException
"
), exception);
                    }
                    
try
                    {
                        sock.TrueClose();
                    }
                    
catch
 (IOException)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, sock.ToString()));
                        }
                    }
                    sock 
=
 
null
;
                }
                
if
 (sock 
!=
 
null
)
                {
                    sock.Close();
                }
            }
            
return
 
-
1L
;
        }
        
private
 
void
 Init()
        {
            
this
._primitiveAsString 
=
 
false
;
            
this
._compressEnable 
=
 
true
;
            
this
._compressThreshold 
=
 
0x7800L
;
            
this
._defaultEncoding 
=
 
"
UTF-8
"
;
            
this
._poolName 
=
 GetLocalizedString(
"
default instance
"
);
        }
        
public
 
bool
 KeyExists(
string
 key)
        {
            
return
 (
this
.Get(key, 
null
true
!=
 
null
);
        }
        
private
 
void
 LoadItems(SockIO sock, Hashtable hm, 
bool
 asString)
        {
            
string
 str;
            
object
 obj2;
        Label_0000:
            str 
=
 sock.ReadLine();
            
bool
 isDebugEnabled 
=
 log.IsDebugEnabled;
            
if
 (
!
str.StartsWith(
"
VALUE
"
))
            {
                
if
 (
"
END
"
 
==
 str)
                {
                    
if
 (log.IsDebugEnabled)
                    {
                    }
                    
return
;
                }
                
goto
 Label_0000;
            }
            
string
[] strArray 
=
 str.Split(
new
 
char
[] { 
'
 
'
 });
            
string
 newValue 
=
 strArray[
1
];
            
int
 num 
=
 
int
.Parse(strArray[
2
], 
new
 NumberFormatInfo());
            
int
 num2 
=
 
int
.Parse(strArray[
3
], 
new
 NumberFormatInfo());
            
bool
 flag2 
=
 log.IsDebugEnabled;
            
byte
[] bytes 
=
 
new
 
byte
[num2];
            sock.Read(bytes);
            sock.ClearEndOfLine();
            
if
 ((num 
&
 
2
!=
 
0
)
            {
                
try
                {
                    
int
 num3;
                    GZipInputStream stream 
=
 
new
 GZipInputStream(
new
 MemoryStream(bytes));
                    MemoryStream stream2 
=
 
new
 MemoryStream(bytes.Length);
                    
byte
[] buffer 
=
 
new
 
byte
[
0x800
];
                    
while
 ((num3 
=
 stream.Read(buffer, 
0
, buffer.Length)) 
>
 
0
)
                    {
                        stream2.Write(buffer, 
0
, num3);
                    }
                    bytes 
=
 stream2.ToArray();
                    stream.Close();
                }
                
catch
 (IOException exception)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
loaditems uncompression IOException
"
).Replace(
"
$$Key$$
"
, newValue), exception);
                    }
                    
throw
 
new
 IOException(GetLocalizedString(
"
loaditems uncompression IOException
"
).Replace(
"
$$Key$$
"
, newValue), exception);
                }
            }
            
if
 ((num 
&
 
8
==
 
0
)
            {
                
if
 (
this
._primitiveAsString 
||
 asString)
                {
                    
bool
 isInfoEnabled 
=
 log.IsInfoEnabled;
                    obj2 
=
 Encoding.GetEncoding(
this
._defaultEncoding).GetString(bytes);
                    
goto
 Label_022A;
                }
                
try
                {
                    obj2 
=
 NativeHandler.Decode(bytes);
                    
goto
 Label_022A;
                }
                
catch
 (Exception exception2)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
loaditems deserialize error
"
).Replace(
"
$$Key$$
"
, newValue), exception2);
                    }
                    
throw
 
new
 IOException(GetLocalizedString(
"
loaditems deserialize error
"
).Replace(
"
$$Key$$
"
, newValue), exception2);
                }
            }
            
try
            {
                MemoryStream serializationStream 
=
 
new
 MemoryStream(bytes);
                obj2 
=
 
new
 BinaryFormatter().Deserialize(serializationStream);
                
bool
 flag4 
=
 log.IsInfoEnabled;
            }
            
catch
 (SerializationException exception3)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
loaditems SerializationException
"
).Replace(
"
$$Key$$
"
, newValue), exception3);
                }
                
throw
 
new
 IOException(GetLocalizedString(
"
loaditems SerializationException
"
).Replace(
"
$$Key$$
"
, newValue), exception3);
            }
        Label_022A:
            hm[newValue] 
=
 obj2;
            
goto
 Label_0000;
        }
        
public
 
bool
 Replace(
string
 key, 
object
 value)
        {
            
return
 
this
.Set(
"
replace
"
, key, value, DateTime.MaxValue, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Replace(
string
 key, 
object
 value, DateTime expiry)
        {
            
return
 
this
.Set(
"
replace
"
, key, value, expiry, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Replace(
string
 key, 
object
 value, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
replace
"
, key, value, DateTime.MaxValue, hashCode, 
this
._primitiveAsString);
        }
        
public
 
bool
 Replace(
string
 key, 
object
 value, DateTime expiry, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
replace
"
, key, value, expiry, hashCode, 
this
._primitiveAsString);
        }
        
public
 
bool
 Set(
string
 key, 
object
 value)
        {
            
return
 
this
.Set(
"
set
"
, key, value, DateTime.MaxValue, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Set(
string
 key, 
object
 value, DateTime expiry)
        {
            
return
 
this
.Set(
"
set
"
, key, value, expiry, 
null
this
._primitiveAsString);
        }
        
public
 
bool
 Set(
string
 key, 
object
 value, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
set
"
, key, value, DateTime.MaxValue, hashCode, 
this
._primitiveAsString);
        }
        
public
 
bool
 Set(
string
 key, 
object
 value, DateTime expiry, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
set
"
, key, value, expiry, hashCode, 
this
._primitiveAsString);
        }
        
private
 
bool
 Set(
string
 cmdname, 
string
 key, 
object
 obj, DateTime expiry, 
object
 hashCode, 
bool
 asString)
        {
            
byte
[] bytes;
            
if
 (expiry 
<
 DateTime.Now)
            {
                
return
 
true
;
            }
            
if
 (((cmdname 
==
 
null
||
 (cmdname.Trim().Length 
==
 
0
)) 
||
 ((key 
==
 
null
||
 (key.Length 
==
 
0
)))
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
set key null
"
));
                }
                
return
 
false
;
            }
            SockIO sock 
=
 SockIOPool.GetInstance(
this
._poolName).GetSock(key, hashCode);
            
if
 (sock 
==
 
null
)
            {
                
return
 
false
;
            }
            
if
 (expiry 
==
 DateTime.MaxValue)
            {
                expiry 
=
 
new
 DateTime(
0L
);
            }
            
int
 num 
=
 
0
;
            
int
 count 
=
 
0
;
            
if
 (NativeHandler.IsHandled(obj))
            {
                
if
 (asString)
                {
                    
if
 (obj 
!=
 
null
)
                    {
                        
bool
 flag1 
=
 log.IsInfoEnabled;
                        
try
                        {
                            bytes 
=
 Encoding.UTF8.GetBytes(obj.ToString());
                            count 
=
 bytes.Length;
                            
goto
 Label_01DF;
                        }
                        
catch
 (ArgumentException exception)
                        {
                            
if
 (log.IsErrorEnabled)
                            {
                                log.Error(GetLocalizedString(
"
set invalid encoding
"
).Replace(
"
$$Encoding$$
"
this
._defaultEncoding), exception);
                            }
                            sock.Close();
                            sock 
=
 
null
;
                            
return
 
false
;
                        }
                    }
                    bytes 
=
 
new
 
byte
[
0
];
                    count 
=
 
0
;
                    
goto
 Label_01DF;
                }
                
bool
 isInfoEnabled 
=
 log.IsInfoEnabled;
                
try
                {
                    bytes 
=
 NativeHandler.Encode(obj);
                    count 
=
 bytes.Length;
                    
goto
 Label_01DF;
                }
                
catch
 (ArgumentException exception2)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
set failed to native handle object
"
), exception2);
                    }
                    sock.Close();
                    sock 
=
 
null
;
                    
return
 
false
;
                }
            }
            
if
 (obj 
!=
 
null
)
            {
                
bool
 flag3 
=
 log.IsInfoEnabled;
                
try
                {
                    MemoryStream serializationStream 
=
 
new
 MemoryStream();
                    
new
 BinaryFormatter().Serialize(serializationStream, obj);
                    bytes 
=
 serializationStream.GetBuffer();
                    count 
=
 (
int
) serializationStream.Length;
                    num 
|=
 
8
;
                    
goto
 Label_01DF;
                }
                
catch
 (IOException exception3)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
set failed to serialize
"
).Replace(
"
$$Object$$
"
, obj.ToString()), exception3);
                    }
                    sock.Close();
                    sock 
=
 
null
;
                    
return
 
false
;
                }
            }
            bytes 
=
 
new
 
byte
[
0
];
            count 
=
 
0
;
        Label_01DF:
            
if
 (
this
._compressEnable 
&&
 (count 
>
 
this
._compressThreshold))
            {
                
bool
 flag4 
=
 log.IsInfoEnabled;
                
try
                {
                    MemoryStream baseOutputStream 
=
 
new
 MemoryStream();
                    GZipOutputStream stream3 
=
 
new
 GZipOutputStream(baseOutputStream);
                    stream3.Write(bytes, 
0
, count);
                    stream3.Finish();
                    bytes 
=
 baseOutputStream.GetBuffer();
                    count 
=
 (
int
) baseOutputStream.Length;
                    num 
|=
 
2
;
                    
bool
 flag5 
=
 log.IsInfoEnabled;
                }
                
catch
 (IOException exception4)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
set compression failure
"
), exception4);
                    }
                }
            }
            
try
            {
                
string
 s 
=
 
string
.Concat(
new
 
object
[] { cmdname, 
"
 
"
, key, 
"
 
"
, num, 
"
 
"
, GetExpirationTime(expiry), 
"
 
"
, count, 
"
\r\n
"
 });
                sock.Write(Encoding.UTF8.GetBytes(s));
                sock.Write(bytes, 
0
, count);
                sock.Write(Encoding.UTF8.GetBytes(
"
\r\n
"
));
                sock.Flush();
                
string
 newValue 
=
 sock.ReadLine();
                
bool
 flag6 
=
 log.IsInfoEnabled;
                
if
 (
"
STORED
"
 
==
 newValue)
                {
                    
bool
 flag7 
=
 log.IsInfoEnabled;
                    sock.Close();
                    sock 
=
 
null
;
                    
return
 
true
;
                }
                
if
 (
"
NOT_STORED
"
 
==
 newValue)
                {
                    
if
 (
!
log.IsInfoEnabled)
                    {
                    }
                }
                
else
 
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
set error
"
).Replace(
"
$$Key$$
"
, key).Replace(
"
$$Size$$
"
, count.ToString(
new
 NumberFormatInfo())).Replace(
"
$$Line$$
"
, newValue));
                }
            }
            
catch
 (IOException exception5)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
set IOException
"
), exception5);
                }
                
//
##监测##
                
//
exception.Message=无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。
                
//
原因:memcached重启类造成的连接池无法再通信的错误
                
//
解决:判断上面的message出现次数几次,就考虑重新建立连接池
                
if
 (exception5.Message.Contains(
"
无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接
"
))
                {
                    MemcachedSocksMonitor.SockIOErrRestatr();
                }
                
try
                {
                    sock.TrueClose();
                }
                
catch
 (IOException exception6)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, sock.ToString()), exception6);
                    }
                }
                sock 
=
 
null
            }
            
if
 (sock 
!=
 
null
)
            {
                sock.Close();
            }
            
return
 
false
;
        }
        
public
 Hashtable Stats()
        {
            
return
 
this
.Stats(
null
);
        }
        
public
 Hashtable Stats(ArrayList servers)
        {
            SockIOPool instance 
=
 SockIOPool.GetInstance(
this
._poolName);
            
if
 (instance 
==
 
null
)
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
unable to get socket pool
"
));
                }
                
return
 
null
;
            }
            
if
 (servers 
==
 
null
)
            {
                servers 
=
 instance.Servers;
            }
            
if
 ((servers 
==
 
null
||
 (servers.Count 
<=
 
0
))
            {
                
if
 (log.IsErrorEnabled)
                {
                    log.Error(GetLocalizedString(
"
stats no servers
"
));
                }
                
return
 
null
;
            }
            Hashtable hashtable 
=
 
new
 Hashtable();
            
for
 (
int
 i 
=
 
0
; i 
<
 servers.Count; i
++
)
            {
                SockIO connection 
=
 instance.GetConnection((
string
) servers[i]);
                
if
 (connection 
==
 
null
)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
unable to connect
"
).Replace(
"
$$Server$$
"
, servers[i].ToString()));
                    }
                    
continue
;
                }
                
string
 s 
=
 
"
stats\r\n
"
;
                
try
                {
                    connection.Write(Encoding.UTF8.GetBytes(s));
                    connection.Flush();
                    Hashtable hashtable2 
=
 
new
 Hashtable();
                    
while
 (
true
)
                    {
                        
string
 str2 
=
 connection.ReadLine();
                        
bool
 isDebugEnabled 
=
 log.IsDebugEnabled;
                        
if
 (str2.StartsWith(
"
STAT
"
))
                        {
                            
string
[] strArray 
=
 str2.Split(
new
 
char
[] { 
'
 
'
 });
                            
string
 str3 
=
 strArray[
1
];
                            
string
 str4 
=
 strArray[
2
];
                            
bool
 flag2 
=
 log.IsDebugEnabled;
                            hashtable2[str3] 
=
 str4;
                        }
                        
else
 
if
 (
"
END
"
 
==
 str2)
                        {
                            
if
 (
!
log.IsDebugEnabled)
                            {
                            }
                            
goto
 Label_01E4;
                        }
                        hashtable[servers[i]] 
=
 hashtable2;
                    }
                }
                
catch
 (IOException exception)
                {
                    
if
 (log.IsErrorEnabled)
                    {
                        log.Error(GetLocalizedString(
"
stats IOException
"
), exception);
                    }
                    
try
                    {
                        connection.TrueClose();
                    }
                    
catch
 (IOException)
                    {
                        
if
 (log.IsErrorEnabled)
                        {
                            log.Error(GetLocalizedString(
"
failed to close some socket
"
).Replace(
"
$$Socket$$
"
, connection.ToString()));
                        }
                    }
                    connection 
=
 
null
;
                }
            Label_01E4:
                
if
 (connection 
!=
 
null
)
                {
                    connection.Close();
                }
            }
            
return
 hashtable;
        }
        
public
 
bool
 StoreCounter(
string
 key, 
long
 counter)
        {
            
return
 
this
.Set(
"
set
"
, key, counter, DateTime.MaxValue, 
null
true
);
        }
        
public
 
bool
 StoreCounter(
string
 key, 
long
 counter, 
int
 hashCode)
        {
            
return
 
this
.Set(
"
set
"
, key, counter, DateTime.MaxValue, hashCode, 
true
);
        }
        
public
 
long
 CompressionThreshold
        {
            
get
            {
                
return
 
this
._compressThreshold;
            }
            
set
            {
                
this
._compressThreshold 
=
 value;
            }
        }
        
public
 
string
 DefaultEncoding
        {
            
get
            {
                
return
 
this
._defaultEncoding;
            }
            
set
            {
                
this
._defaultEncoding 
=
 value;
            }
        }
        
public
 
bool
 EnableCompression
        {
            
get
            {
                
return
 
this
._compressEnable;
            }
            
set
            {
                
this
._compressEnable 
=
 value;
            }
        }
        
public
 
string
 PoolName
        {
            
get
            {
                
return
 
this
._poolName;
            }
            
set
            {
                
this
._poolName 
=
 value;
            }
        }
        
public
 
bool
 PrimitiveAsString
        {
            
get
            {
                
return
 
this
._primitiveAsString;
            }
            
set
            {
                
this
._primitiveAsString 
=
 value;
            }
        }
    }
}

 

 

 

大致就以上内容,修改的地方也不算多,总结发现自己写博文很吃力,平时的缺点很明显,不知道如何去描述一个问题及解决方法,虽然自己都知道,但是就是表达不出来

 

这文章算是靠代码说话了,很惭愧,有兴趣的话就给点意见以及错误的地方

转载于:https://www.cnblogs.com/wyxy2005/archive/2010/08/23/1806785.html

你可能感兴趣的文章
IP_VFR-4-FRAG_TABLE_OVERFLOW【cisco设备报错】碎片***
查看>>
Codeforces Round #256 (Div. 2) D. Multiplication Table 【二分】
查看>>
ARM汇编指令格式
查看>>
HDU-2044-一只小蜜蜂
查看>>
HDU-1394-Minimum Inversion Number
查看>>
df -h 卡住
查看>>
第七天1
查看>>
[转] createObjectURL方法 实现本地图片预览
查看>>
Jquery中的Jquery.extend, Jquery.fn.extend,Jquery.prototype
查看>>
JavaScript—DOM编程核心.
查看>>
JavaScript碎片
查看>>
Bootstrap-下拉菜单
查看>>
soapUi 接口测试
查看>>
【c学习-12】
查看>>
工作中MySql的了解到的小技巧
查看>>
loadrunner-2-12日志解析
查看>>
2013年蓝桥杯省赛C/C++A组真题解析
查看>>
C# Memcached缓存
查看>>
iOS开发NSLayoutConstraint代码自动布局
查看>>
正则表达式
查看>>