1、AsyncSocket

  • 基于 CFSocket、GCD 进行的封装(OC)。

  • 支持 TCP 和 UDP。

  • 完整的回调函数(用于处理各种回调事件,连接成功,断开连接,收到数据等)。

  • 需要注意的问题:

    • 1、Socekt 连接成功回调方法中主动调用:[self.socket readDataWithTimeout:-1 tag:0];,相当于主动添加一个读取请求,不然不会执行读取信息回调方法。
    • 2、读取信息回调方法中,读取完信息后,主动调用一下 [self.socket readDataWithTimeout:-1 tag:0];,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。

2、基本使用

2.1 Client 客户端

  • TCP 客户端

        #import "GCDAsyncSocket.h"@interface ViewController () <GCDAsyncSocketDelegate>@property (weak, nonatomic) IBOutlet UITextField *addrTF;@property (weak, nonatomic) IBOutlet UITextField *portTF;@property (weak, nonatomic) IBOutlet UITextField *msgTF;@property (weak, nonatomic) IBOutlet UITextView *logTV;@property (nonatomic, strong) GCDAsyncSocket *clientSockfd;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// 创建 Socket,在主队列中处理,所有的回执都在主队列中执行。self.clientSockfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];}- (IBAction)connectBtnClick:(id)sender {NSError *error = nil;// Socket 连接if (![self.clientSockfd isConnected]) {[self.clientSockfd connectToHost:_addrTF.text onPort:_portTF.text.intValue error:&error];}if (error != nil) {[self showLogMessage:@"连接失败..."];}}#pragma mark - GCDAsyncSocketDelegate 协议方法// 连接成功,协议方法- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {// 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法[self.clientSockfd readDataWithTimeout:-1 tag:0];[self showLogMessage:[NSString stringWithFormat:@"连接服务器地址:%@, 端口:%d 成功", host, port]];[self showLogMessage:[NSString stringWithFormat:@"本地地址:%@, 端口:%d", sock.localHost, sock.localPort]];}// 已经断开链接,协议方法- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {[self showLogMessage:@"socket 断开连接..."];}// 读取到数据,协议方法- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {// 注意:要想长连接,必须还要在 DidReceiveData 的 delegate 中再写一次 [_udpSocket receiveOnce:&error]// 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。[self.clientSockfd readDataWithTimeout:-1 tag:0];NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];[self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];}#pragma mark - 发送数据- (IBAction)sendBtnClick:(id)sender {// Socket 发送数据[self.clientSockfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];[self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];}// 显示信息- (void)showLogMessage:(NSString *)msg {_logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];}// 键盘回收- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];}@end

2.2 Server 服务端

  • TCP 服务端

        #import <arpa/inet.h>#import <ifaddrs.h>#import "GCDAsyncSocket.h"@interface ViewController () <GCDAsyncSocketDelegate>@property (weak, nonatomic) IBOutlet UITextField *addrTF;@property (weak, nonatomic) IBOutlet UITextField *portTF;@property (weak, nonatomic) IBOutlet UITextField *msgTF;@property (weak, nonatomic) IBOutlet UITextView *logTV;@property (nonatomic, strong) GCDAsyncSocket *serverSocketfd;@property (nonatomic, strong) GCDAsyncSocket *clientSocketfd;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];NSString *ip_addr = [self getIPAddress];_addrTF.text = ip_addr;// 创建 Socket,在主队列中处理,所有的回执都在主队列中执行。self.serverSocketfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];}- (IBAction)listenBtnClick:(id)sender {NSError *error = nil;// Socket 监听[self.serverSocketfd acceptOnPort:_portTF.text.intValue error:&error];if (error != nil) {NSLog(@"监听出错:%@", error);} else{[self showLogMessage:@"正在监听..."];}}#pragma mark - GCDAsyncSocketDelegate 协议方法// 接收到连接请求,协议方法- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {// 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法[newSocket readDataWithTimeout:-1 tag:0];[self showLogMessage:@"收到客户端连接...."];[self showLogMessage:[NSString stringWithFormat:@"客户端地址:%@, 端口:%d", newSocket.connectedHost, newSocket.connectedPort]];self.clientSocketfd = newSocket;}// 已经断开链接,协议方法- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {[self showLogMessage:@"socket 断开连接..."];}// 读取到数据,协议方法- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {// 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。[sock readDataWithTimeout:-1 tag:0];NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];[self showLogMessage:[NSString stringWithFormat:@"recv:%@",strMsg]];}#pragma mark - 发送数据- (IBAction)sendBtnClick:(id)sender {// Socket 发送数据[self.clientSocketfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];[self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];}#pragma mark - 获取本地 IP 地址- (NSString *)getIPAddress {NSString *address = @"error";struct ifaddrs *interfaces = NULL;struct ifaddrs *temp_addr = NULL;int success = 0;// retrieve the current interfaces - returns 0 on successsuccess = getifaddrs(&interfaces);if (success == 0) {// Loop through linked list of interfacestemp_addr = interfaces;while (temp_addr != NULL) {if (temp_addr->ifa_addr->sa_family == AF_INET) {// Check if interface is en0 which is the wifi connection on the iPhoneif ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {// Get NSString from C Stringaddress = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];}}temp_addr = temp_addr->ifa_next;}}// Free memoryfreeifaddrs(interfaces);return address;}// 显示信息- (void)showLogMessage:(NSString *)msg {_logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];}// 键盘回收- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];}@end

2.3 UDP 通信

  • UDP 通信

        #import <arpa/inet.h>#import <ifaddrs.h>#import "GCDAsyncUdpSocket.h"@interface ViewController () <GCDAsyncUdpSocketDelegate>@property (weak, nonatomic) IBOutlet UITextField *desAddrTF;@property (weak, nonatomic) IBOutlet UITextField *desPortTF;@property (weak, nonatomic) IBOutlet UITextField *locAddrTF;@property (weak, nonatomic) IBOutlet UITextField *locPortTF;@property (weak, nonatomic) IBOutlet UITextField *msgTF;@property (weak, nonatomic) IBOutlet UITextView *logTV;@property (nonatomic, strong) GCDAsyncUdpSocket *udpSocketfd;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];NSString *ip_addr = [self getIPAddress];_locAddrTF.text = ip_addr;// 创建 Socket,在主队列中处理,所有的回执都在主队列中执行self.udpSocketfd = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];}- (IBAction)connectBtnClick:(id)sender {NSError *error = nil;// 绑定端口[self.udpSocketfd bindToPort:_locPortTF.text.intValue error:&error];if (error != nil) {NSLog(@"绑定端口出错:%@", error);return;} else{[self showLogMessage:[NSString stringWithFormat:@"绑定端口 %d 成功...", _locPortTF.text.intValue]];}// 开始接收数据[self.udpSocketfd beginReceiving:&error];if (error != nil) {NSLog(@"开始接收数据出错:%@", error);} else{[self showLogMessage:@"开始接收数据..."];}}#pragma mark - GCDAsyncUdpSocketDelegate 协议方法// 接收到的数据,协议方法- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)datafromAddress:(NSData *)addresswithFilterContext:(id)filterContext {NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];[self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];}#pragma mark - 发送数据- (IBAction)sendBtnClick:(id)sender {// Socket 发送数据[self.udpSocketfd sendData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]toHost:_desAddrTF.textport:_desPortTF.text.intValuewithTimeout:30 tag:0];[self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];}#pragma mark - 获取本地 IP 地址- (NSString *)getIPAddress {NSString *address = @"error";struct ifaddrs *interfaces = NULL;struct ifaddrs *temp_addr = NULL;int success = 0;// retrieve the current interfaces - returns 0 on successsuccess = getifaddrs(&interfaces);if (success == 0) {// Loop through linked list of interfacestemp_addr = interfaces;while (temp_addr != NULL) {if (temp_addr->ifa_addr->sa_family == AF_INET) {// Check if interface is en0 which is the wifi connection on the iPhoneif ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {// Get NSString from C Stringaddress = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];}}temp_addr = temp_addr->ifa_next;}}// Free memoryfreeifaddrs(interfaces);return address;}// 显示信息- (void)showLogMessage:(NSString *)msg {_logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];}// 键盘回收- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];}@end

2.4 Socket 长连接

  • PublicTool.h

        @interface PublicTool : NSObject// 字典转换成 JSON 字符串+ (NSString *)JSONStringWithDic:(NSDictionary *)dic;// JSON 字符串转换成字典+ (NSDictionary *)dictionaryWithJSON:(NSString *)json;@end
  • PublicTool.m

        @implementation PublicTool// 字典转成成 JSON 字符串+ (NSString *)JSONStringWithDic:(NSDictionary *)dic {NSError *error = nil;NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dicoptions:0error:&error];if (jsonData == nil) {NSLog(@"fail to get JSON from dictionary: %@, error: %@", self, error);return nil;}NSString *jsonString = [[NSString alloc] initWithData:jsonDataencoding:NSUTF8StringEncoding];return jsonString;}// JSON 字符串转换成字典+ (NSDictionary *)dictionaryWithJSON:(NSString *)json {NSError *error = nil;NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonDataoptions:NSJSONReadingMutableContainers |NSJSONReadingAllowFragmentserror:&error];if (jsonDict == nil) {NSLog(@"fail to get dictioanry from JSON: %@, error: %@", json, error);return nil;}return jsonDict;}@end
  • SocketSingleTon.h

        @interface SocketSingleTon : NSObject@property (nonatomic, copy) NSString *hostAddr;@property (nonatomic, copy) NSString *port;@property (nonatomic, copy) void(^msgLog)(NSString *);+ (instancetype)shareInstance;// 连接到服务器- (void)connectToServer;// 断开连接- (void)cutOffSocket;// 发送数据到服务器- (void)sendDataToServer:(NSData*)data;@end
  • SocketSingleTon.m

        #import "GCDAsyncSocket.h"#import <netdb.h>#import <arpa/inet.h>#import "PublicTool.h"typedef NS_ENUM(NSInteger, SocketOffline) {SocketOfflineByServer,SocketOfflineByUser};@interface SocketSingleTon () <GCDAsyncSocketDelegate>@property (nonatomic, strong) GCDAsyncSocket *socket;@property (nonatomic, strong) NSTimer *beatTimer;@end@implementation SocketSingleTon+ (instancetype)shareInstance {static SocketSingleTon *shareInstance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{shareInstance = [[self alloc] init];});return shareInstance;}// 连接到服务器- (void)connectToServer {NSError *error = nil;if (self.socket != nil) {if ([self.socket isConnected]) {// 断开后再连接self.socket.userData = @(SocketOfflineByUser);[self cutOffSocket];[self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];} else {[self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];}} else {self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];[self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];}if (error != nil) {NSLog(@"socket 连接失败:%@", error);} else {NSLog(@"socket 连接成功");}}// 断开连接- (void)cutOffSocket {self.socket.userData = @(SocketOfflineByUser);[self.socket disconnect];}#pragma mark  - GCDAsyncSocketDelegate 协议方法// 连接成功,协议方法- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {[sock readDataWithTimeout:-1 tag:0];NSString *logStr = [NSString stringWithFormat:@"连接主机:%@:%d 成功\n", host, port];NSLog(@"%@", logStr);if (self.msgLog) {self.msgLog(logStr);}// 创建定时器,定时发送 beat 包self.beatTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(longConnectToServer) userInfo:nil repeats:YES];}// 连接断开,协议方法- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {self.socket = nil;[self.beatTimer invalidate];self.beatTimer = nil;if ([sock.userData  isEqual: @(SocketOfflineByUser)]) {NSLog(@"the socket have been cutted off by user");if (self.msgLog) {self.msgLog(@"the socket have been cutted off by user");}} else if (sock.userData == SocketOfflineByServer) {NSLog(@"the socket have been cutted off by server");if (self.msgLog) {self.msgLog(@"the socket have been cutted off by server");}// reconnect[self connectToServer];} else {NSLog(@"%@", err.localizedDescription);if (self.msgLog) {self.msgLog([NSString stringWithFormat:@"%@", err.localizedDescription]);}[self connectToServer];}}// 收到消息,协议方法- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {[sock readDataWithTimeout:-1 tag:0];char buf[1024];[data getBytes:buf length:1024];NSString *receivedData = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];NSLog(@"receivedData:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);if (receivedData.length > 0) {NSDictionary *dataDic = [PublicTool dictionaryWithJSON:receivedData];if ([dataDic[@"msgType"] isEqualToString:@"beta"]) {NSString *strMsg = [NSString stringWithFormat:@"收到心跳确认的数据:%@\n", receivedData];if (self.msgLog) {self.msgLog(strMsg);}} else if ([dataDic[@"msgType"] isEqualToString:@"normal"]) {NSString *strMsg = [NSString stringWithFormat:@"收到正常的数据:%@\n", receivedData];if (self.msgLog) {self.msgLog(strMsg);}} else if ([dataDic[@"msgType"] isEqualToString:@"exit"]) {NSString *strMsg = [NSString stringWithFormat:@"收到关闭的数据:%@\n", receivedData];if (self.msgLog) {self.msgLog(strMsg);}[self cutOffSocket];}}}// 发送数据- (void)longConnectToServer {[self sendDataToServer:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];}// 发送数据到服务器- (void)sendDataToServer:(NSData*)data {NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];if ([dataStr isEqualToString:@"hello"]) {[dicParams setValue:dataStr forKey:@"msg"];[dicParams setValue:@"beta" forKey:@"msgType"];} else {[dicParams setValue:dataStr forKey:@"msg"];[dicParams setValue:@"normal" forKey:@"msgType"];}NSData *sendData = [[PublicTool JSONStringWithDic:dicParams] dataUsingEncoding:NSUTF8StringEncoding];NSString *strMsg = [NSString stringWithFormat:@"发送数据: %@\n", [PublicTool JSONStringWithDic:dicParams]];if (self.msgLog) {self.msgLog(strMsg);}[self.socket writeData:sendData withTimeout:30 tag:0];}@end
  • ViewController.m

        #import "SocketSingleTon.h"#import "PublicTool.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UITextField *addressTF;@property (weak, nonatomic) IBOutlet UITextField *portTF;@property (weak, nonatomic) IBOutlet UITextField *msgTF;@property (weak, nonatomic) IBOutlet UITextView *logTV;@end@implementation ViewController- (IBAction)connectToServer:(id)sender {// 创建 SocketSocketSingleTon *socketInstance = [SocketSingleTon shareInstance];socketInstance.hostAddr = _addressTF.text;socketInstance.port = _portTF.text;__weak __typeof (self)weakSelf = self;socketInstance.msgLog = ^(NSString *log){dispatch_async(dispatch_get_main_queue(), ^{weakSelf.logTV.text = [weakSelf.logTV.text stringByAppendingString:log];});};// 连接到服务器[socketInstance connectToServer];}- (IBAction)cutOffConnect:(id)sender {SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];// 断开连接[socketInstance cutOffSocket];}- (IBAction)sendDataToServer:(id)sender {SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];// 发送数据到服务器[socketInstance sendDataToServer:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]];}- (IBAction)sendBetaDataToServer:(id)sender {SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];[dicParams setValue:@"beta" forKey:@"msgType"];[dicParams setValue:@"hello" forKey:@"msg"];NSString *strMsg = [PublicTool JSONStringWithDic:dicParams];// 发送心跳数据到服务器[socketInstance sendDataToServer:[strMsg dataUsingEncoding:NSUTF8StringEncoding]];}- (IBAction)clearLog:(id)sender {_logTV.text = nil;}// 键盘回收- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.view endEditing:YES];}@end

转载于:https://www.cnblogs.com/QianChia/p/6392265.html

iOS - AsyncSocket 的使用相关推荐

  1. iOS - Socket 网络套接字

    1.Socket 套接字 所谓 Socket,通常称为 "套接字",网络应用程序通过套接字向网络发送请求或者应答网络请求.Socket 通常用于描述 IP 地址和端口,是应⽤层与 ...

  2. iOS学习之Socket使用简明教程- AsyncSocket

    2019独角兽企业重金招聘Python工程师标准>>> 如果需要在项目中像QQ微信一样做到即时通讯,必须使用socket通讯,本人也是刚学习,分享一下,有什么不对的地方希望大家指正 ...

  3. iOS之Socket的使用-AsyncSocket

    iOS有原生的socket,但AsyncSocket这个第三方库,对socket的封装比较好,本文就是基于AsyncSocket的使用介绍. 环境 下载AsyncSocket https://gith ...

  4. IOS socket编程--Asyncsocket

    iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写, ...

  5. iOS端Socket连接、发送数据(一)

    一.Socket的应用 IM即时通讯是通过Socket的方式实现长连接,可运用于 (1)直播聊天室.礼物 (2)微信.QQ等即时聊天 (3)游戏对话.技能等 二.SOCKET原理 套接字(socket ...

  6. ios 即时聊天轻松搞定

    使用技术: CocoaAsyncSocket + Apache MINA(ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java ...

  7. 关于IOS开发知识的总结

    IOS开发特别备注: IOS 7 UI适配方法 http://blog.sina.com.cn/s/blog_6fd90b5b0101cy50.html http://forum.bee-framew ...

  8. (转)直接拿来用!最火的iOS开源项目(一)

    2019独角兽企业重金招聘Python工程师标准>>> 1. AFNetworking 在众多iOS开源项目中,AFNetworking可以称得上是最受开发者欢迎的库项目.AFNet ...

  9. iOS各种小理论知识

    Objective-C 部分 1. 你如何理解 OC 的内存管理 OC 内存管理是基于引用计数.谁想使用某个对象 B,就要把对象 B 的计数器+1,如果不 使用这个对象了,那么就把对象 B 计数器-1 ...

最新文章

  1. ESP8266-iot-2
  2. 动态规划练习1--Unique Paths
  3. 企业互联网应用高性能解决之道
  4. 埃洛等级分系统【转自百度百科】
  5. 【数值分析】微分求积:复化梯形、复化辛浦生
  6. will not add file alias already exists in index(git上传代码出错)
  7. LOJ#2542. 「PKUWC2018」随机游走
  8. 数据结构中的树 --- 红黑树
  9. pyinstaller打包流程
  10. 如何使用移动硬盘加密
  11. python定时器 是线程吗_定时器中断线程python
  12. 让jquery构造出类
  13. 删除分卷php逻辑,Linux LVM(逻辑卷管理)删除详解
  14. DeNA/上海纵游通过使用AWS大量缩短新款游戏和服务的上线时间
  15. 使用ffmpeg转换webm格式到MP4格式
  16. 实验室信息化建设助力医药研发
  17. adobe xd 白屏闪退 终极拯救方法
  18. QtDesigner视频手把手教程制作一个弹性,自适应大小的页面布局
  19. 计算机网络物联网论文,物联网技术及其应用_计算机网络论文.doc
  20. 在系统里放一只“猴子”,阿里疯了吗?

热门文章

  1. 云电脑是什么_云电脑为什么发布新1代5G无影?带你了解PC
  2. html中collapse代码怎么写,面试题: 手写collapse(折叠组件)的css/html部分
  3. 插入模板_现场组装楼梯踏步模板施工支设细节
  4. android新闻管理,Android资讯新闻类App(头条、网易等),频道管理集成之数据库存储...
  5. uvm 形式验证_验证平台自动化篇之二:UVM Framework
  6. ecmall支持php5.3,在PHP5.3以上版本运行ecshop和ecmall出现的问题及解决方案
  7. centos部署python个人博客项目
  8. liferay 如何添加css或者js
  9. 带超时的system
  10. 微信小程序之坦克大战学习