【网络】多线程--NSThread、GCD、NSOperationQueue
2016-02-19 00:39
555 查看
GCD
1.什么是GCD?
GCD是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue 中,GCD就可以生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现,因此可以统一管理,也可以执行任务,这样就比以前的线程更有效率。
用异步函数往并发队列中添加任务
//2.用dispatch_async异步函数往串行队列添加任务
//用同步函数往串行队列添加任务
//4.用dispatch_sync同步函数往并发队列中添加任务
//5.线程异步下载图片 主线程刷新UI
延迟执行
一次性代码
可以用作单例的实现方法
队列组
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一个是实例方法,第二个是类方法
[cpp] view
plain copy
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
2、NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(doSomething:)
object:nil];
[myThread start];
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
threadPriority
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); //
reports whether current thread is main
+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
@property double threadPriority NS_AVAILABLE(10_6, 4_0); //
To be deprecated; use qualityOfService below
下载图片例子
@implementation ViewController
-(void)downloadImage:(NSString *) url{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc]initWithData:data];
if(image == nil){
}else{
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
[thread start];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
线程同步
- (void)run{
while (TRUE) {
// 上锁
// [ticketsCondition lock];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
// [ticketsCondition unlock];
}
}
如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了
线程的顺序执行
[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
tickets = 100;
count = 0;
theLock = [[NSLock alloc] init];
// 锁对象
ticketsCondition = [[NSCondition alloc] init];
ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadone setName:@"Thread-1"];
[ticketsThreadone start];
ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadtwo setName:@"Thread-2"];
[ticketsThreadtwo start];
NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
[ticketsThreadthree setName:@"Thread-3"];
[ticketsThreadthree start];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
-(void)run3{
while (YES) {
[ticketsCondition lock];
[NSThread sleepForTimeInterval:3];
[ticketsCondition signal];
[ticketsCondition unlock];
}
}
- (void)run{
while (TRUE) {
// 上锁
[ticketsCondition lock];
[ticketsCondition wait];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
[ticketsCondition unlock];
}
}
- (void)doSomeThing:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
3.NSOperationQueue
将需要执行的操作封装到NSOperation对象
NSOperation对象放入NSOperationQueue
系统自动queue中取operation
将取出的操作放入新线程执行。
NSOperation是抽象类 不具备封装操作能力,需要使用子类
使用NSOperation子类的方式有三种。
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation实现内部相应的方法
-(void)downLoad
{
NSLog(@"%@",@"逗我呢");
}
//BlockOperation
-(void)testBlockOperation
{
NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"2%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"3%@",[NSThread currentThread]);
}];
[operation start];
//是否开启了新线程 取决于任务的个数。任务=1 主线程 任务>1开启新线程
}
/如果想异步执行任务 则需要queue队列的协助。
-(void)testOperationQueue
{
//1.封装操作
NSInvocationOperation * operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil];
NSInvocationOperation * operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
NSInvocationOperation * operation3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
//2.创建队列
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
//3.将操作添加到队列中
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
-(void)download
{
NSLog(@"%@",@"download");
}
-(void)run
{
NSLog(@"%@",@"runing");
}
operation最大并发数 MaxConcurrentOperationCount = 5以内 2-3为好。
//取消队列的所有操作
[queue cancelAllOperations];
//暂停
[queue setSuspended:YES];
//operation的优先级取值
//NSOpertaion之间可以设置操作依赖。
//如让a执行完之后 才能执行操作B。可以这么写:
[operation1 addDependency:operation2];
可以在不同的operationQueue之间设置依赖关系,但是不能相互依赖。
自定义Operation
创建类继承自NSOperation
然后在.h中定义需要的属性,代理和代理方法。在.m文件中main函数写自己需要的操作。
代码如下。
@implementation CustomOperation
//在main方法中实现操作
-(void)main
{
NSURL * url = [NSURL URLWithString:self.url];
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
if (self.delegate &&
[self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)])
{
[self.delegate downloadOperation:self didFinishDownload:image];
}
}
@end
#import <Foundation/Foundation.h>
@class CustomOperation;
#import <UIKit/UIKit.h>
@protocol CustomOperationDelegate<NSObject>
@optional
-(void)downloadOperation:(CustomOperation *)operation didFinishDownload:(UIImage *)image;
@end
@interface CustomOperation : NSOperation
@property (nonatomic,strong) NSIndexPath *indexpath;
@property (nonatomic,copy) NSString *
url;
@property (nonatomic,assign) id<CustomOperationDelegate>
delegate;
@end
检测网络状态
-(void)testNetStatus
{
//根据用户的网络状态进行处理
/*
wifi /3G自动下载高清图片
低速网络 下载缩略图
没有网络 显示离线缓存数据
苹果官方提供了一个Reachability 可检测网络状态。
*/
//wifi
Reachability * wifi = [Reachability reachabilityForLocalWiFi];
//手机自带网络功能
Reachability * conn= [Reachability reachabilityForInternetConnection];
if ([wifi currentReachabilityStatus ]!= NotReachable)
{
NSLog(@"%@",@"wifi");
}else if ([conn currentReachabilityStatus]
!= NotReachable){
NSLog(@"%@",@"有手机网络");
}else{
NSLog(@"%@",@"没有网络");
}
}
Reachability还可以实时监控网络状态。添加通知,如果网络有问题就通知。
1.什么是GCD?
GCD是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue 中,GCD就可以生成必要的线程并计划执行任务。由于线程管理是作为系统的一部分来实现,因此可以统一管理,也可以执行任务,这样就比以前的线程更有效率。
用异步函数往并发队列中添加任务
-(void)testGlobalQueue { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSLog(@"1%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3%@",[NSThread currentThread]); }); }
//2.用dispatch_async异步函数往串行队列添加任务
-(void)testAsyncQueue { //1.创建串行队列 dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL); //2.添加任务到串行队列中 dispatch_async(queue, ^{ NSLog(@"1%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3%@",[NSThread currentThread]); }); }
//用同步函数往串行队列添加任务
-(void)testSyncQueue { dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL); dispatch_sync(queue, ^{ NSLog(@"1%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3%@",[NSThread currentThread]); }); }
//4.用dispatch_sync同步函数往并发队列中添加任务
<span style="background-color: rgb(255, 255, 255);">-(void)testSyncQueue2 { dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL); dispatch_sync(queue, ^{ NSLog(@"1%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2%@",[NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3%@",[NSThread currentThread]); }); }</span>
//5.线程异步下载图片 主线程刷新UI
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { __block UIImage * image; UIImageView * imgView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 100, 100, 100)]; [self.view addSubview:imgView]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSURL * url = [NSURL URLWithString:@"http://pic80.nipic.com/file/20151013/12964311_203654101785_2.jpg"]; NSData * data = [NSData dataWithContentsOfURL:url]; image = [UIImage imageWithData:data]; NSLog(@"%@",data); dispatch_async(dispatch_get_main_queue(), ^{ imgView.image = image; }); }); }
延迟执行
[NSThread sleepForTimeInterval:3];//这个尽量不要使用,会卡死当前线程。 NSLog(@"%@",@"task"); dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{ NSLog(@"%@",@"task sleep 3s"); });
一次性代码
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ <#code to be executed once#> });
可以用作单例的实现方法
队列组
-(void)testQueueGroup { //组 dispatch_group_t group = dispatch_group_create(); //队列 dispatch_queue_t queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(group, queue, ^{ NSLog(@"1%@",[NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"2%@",[NSThread currentThread]); }); dispatch_group_notify(group, queue, ^{ NSLog(@"%@",@"完成"); }); }2.NSThread
NSThread 有两种直接创建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一个是实例方法,第二个是类方法
[cpp] view
plain copy
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
2、NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(doSomething:)
object:nil];
[myThread start];
参数的意义:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
threadPriority
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); //
reports whether current thread is main
+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
@property double threadPriority NS_AVAILABLE(10_6, 4_0); //
To be deprecated; use qualityOfService below
下载图片例子
@implementation ViewController
-(void)downloadImage:(NSString *) url{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc]initWithData:data];
if(image == nil){
}else{
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
[thread start];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
线程同步
- (void)run{
while (TRUE) {
// 上锁
// [ticketsCondition lock];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
// [ticketsCondition unlock];
}
}
如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了
线程的顺序执行
线程的顺序执行
他们都可以通过[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
tickets = 100;
count = 0;
theLock = [[NSLock alloc] init];
// 锁对象
ticketsCondition = [[NSCondition alloc] init];
ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadone setName:@"Thread-1"];
[ticketsThreadone start];
ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadtwo setName:@"Thread-2"];
[ticketsThreadtwo start];
NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
[ticketsThreadthree setName:@"Thread-3"];
[ticketsThreadthree start];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
-(void)run3{
while (YES) {
[ticketsCondition lock];
[NSThread sleepForTimeInterval:3];
[ticketsCondition signal];
[ticketsCondition unlock];
}
}
- (void)run{
while (TRUE) {
// 上锁
[ticketsCondition lock];
[ticketsCondition wait];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
[ticketsCondition unlock];
}
}
其他同步
我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。- (void)doSomeThing:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
3.NSOperationQueue
将需要执行的操作封装到NSOperation对象
NSOperation对象放入NSOperationQueue
系统自动queue中取operation
将取出的操作放入新线程执行。
NSOperation是抽象类 不具备封装操作能力,需要使用子类
使用NSOperation子类的方式有三种。
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation实现内部相应的方法
-(void)testNSInvocationOperation { //1,创建操作对象 封装要执行的任务 NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad) object:nil]; //2.执行操作 [operation start]; //总结:默认情况下如果操作没有放队列中 那么默认是主线程 }
-(void)downLoad
{
NSLog(@"%@",@"逗我呢");
}
//BlockOperation
-(void)testBlockOperation
{
NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"2%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"3%@",[NSThread currentThread]);
}];
[operation start];
//是否开启了新线程 取决于任务的个数。任务=1 主线程 任务>1开启新线程
}
/如果想异步执行任务 则需要queue队列的协助。
-(void)testOperationQueue
{
//1.封装操作
NSInvocationOperation * operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil];
NSInvocationOperation * operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
NSInvocationOperation * operation3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
//2.创建队列
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
//3.将操作添加到队列中
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
-(void)download
{
NSLog(@"%@",@"download");
}
-(void)run
{
NSLog(@"%@",@"runing");
}
operation最大并发数 MaxConcurrentOperationCount = 5以内 2-3为好。
//取消队列的所有操作
[queue cancelAllOperations];
//暂停
[queue setSuspended:YES];
//operation的优先级取值
//NSOpertaion之间可以设置操作依赖。
//如让a执行完之后 才能执行操作B。可以这么写:
[operation1 addDependency:operation2];
可以在不同的operationQueue之间设置依赖关系,但是不能相互依赖。
自定义Operation
创建类继承自NSOperation
然后在.h中定义需要的属性,代理和代理方法。在.m文件中main函数写自己需要的操作。
代码如下。
@implementation CustomOperation
//在main方法中实现操作
-(void)main
{
NSURL * url = [NSURL URLWithString:self.url];
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
if (self.delegate &&
[self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)])
{
[self.delegate downloadOperation:self didFinishDownload:image];
}
}
@end
#import <Foundation/Foundation.h>
@class CustomOperation;
#import <UIKit/UIKit.h>
@protocol CustomOperationDelegate<NSObject>
@optional
-(void)downloadOperation:(CustomOperation *)operation didFinishDownload:(UIImage *)image;
@end
@interface CustomOperation : NSOperation
@property (nonatomic,strong) NSIndexPath *indexpath;
@property (nonatomic,copy) NSString *
url;
@property (nonatomic,assign) id<CustomOperationDelegate>
delegate;
@end
检测网络状态
-(void)testNetStatus
{
//根据用户的网络状态进行处理
/*
wifi /3G自动下载高清图片
低速网络 下载缩略图
没有网络 显示离线缓存数据
苹果官方提供了一个Reachability 可检测网络状态。
*/
//wifi
Reachability * wifi = [Reachability reachabilityForLocalWiFi];
//手机自带网络功能
Reachability * conn= [Reachability reachabilityForInternetConnection];
if ([wifi currentReachabilityStatus ]!= NotReachable)
{
NSLog(@"%@",@"wifi");
}else if ([conn currentReachabilityStatus]
!= NotReachable){
NSLog(@"%@",@"有手机网络");
}else{
NSLog(@"%@",@"没有网络");
}
}
Reachability还可以实时监控网络状态。添加通知,如果网络有问题就通知。
相关文章推荐
- 开源流媒体服务器EasyDarwin支持epoll网络模型,大大提升流媒体服务器网络并发性能
- 开源流媒体服务器EasyDarwin支持epoll网络模型,大大提升流媒体服务器网络并发性能
- 【Tomcat】HTTP错误代码详细介绍
- iOS 网络请求封装
- 使用Flat Network Provider搭建扁平网络教程
- URL,URLConnection,HttpURLConnection的简单应用
- 厦门巨游网络科技有限公司(HOTPOWER)承接游戏UI外包
- java33.HTTP通信------使用Http的Post方式与网络交互通信
- 黑马程序员——网络编程
- okHttp学习(待完善)
- 蓝懿ios网络请求bock
- Android妙用SPDY协议提高移动端网络请求性能
- 基于HTML5的3D网络拓扑树呈现
- HttpServletRequest和 HttpServletResponse对象的一些使用
- 上下界网络流学习小计
- [bzoj3455]供电网络
- 上下界网络流学习小记
- HttpServletRequest
- 我的博客 http://www.wlheihei.com
- TCP状态