Linux网络异常处理(6.12)
来源:互联网 发布:优质小麦基因组数据库 编辑:程序博客网 时间:2024/05/16 13:46
[1] 网络异常处理
1. 客户端出了问题(死机、重启了、网络断了...)
2. 服务端出了问题(死机、重启了、网络断了、内存耗尽、...)
3. 网络不正常
解决办法: 心跳包
心跳包的实现方法:
1. 利用TCP协议的KeepAlive(TCP协议实现的心跳包)
见《tcp_keepalive》的服务端
2. 设置接收超时检测心跳,对端需要定时发送
heart_beat程序只在接收端实现了如何(利用阻塞超时)检测超时
3. 如何实现应用程序的定时发送和超时检测?
alarm
总结: 利用实现心跳包
[2] 广播
[3] 组播
1. 分组
每个D类IP地址就是一个组,组播实现原理:
接收 -- 加入一个组
发送 -- 向一个组(目标IP地址为组播地址)发送数据包
2. 组播地址(IP地址和网卡地址)
IP地址: D类地址 ,高位固定为1110,范围: 224.0.0.0-239.255.255.255
网卡地址: 前24bit固定为01-00-5e, 最后23bit是D类IP地址的后23bit直接映射下来 -- 仅仅正对于以太网
3. 接收流程
[3] unix域套接字--流式 1. 头文件
#include <sys/un.h>
2. 数据结构
struct sockaddr_un {
sa_family_t sun_family;
// __SOCKADDR_COMMON (sun_);
// #define __SOCKADDR_COMMON(sa_prefix) \
// sa_family_t sa_prefix##family
// 替换原理,带参数的宏,实参替换形参(整个宏中所有的)
char sun_path[108]; // 字符串(unix域套接字文件的名)
};
3. 服务端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2. 绑定地址到socket
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 设置为监听模式
ret = listen(sockfd, 10);
4. 接收请求
clientfd = accept(sockfd, NULL, NULL);
5. 接收数据
ret = recv(clientfd, buf, sizeof(buf), 0);
6. 发送数据
ret = send(clientfd, buf, len, 0);
7. 关闭套接字
close(clientfd);
close(sockfd);
4. 客户端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2. 连接服务器
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 发送数据
ret = send(clientfd, buf, len, 0);
4. 接收数据
ret = recv(clientfd, buf, sizeof(buf), 0);
5. 关闭套接字
close(sockfd);
[3] unix域套接字--报文
1. 客户端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
2. 绑定(自己)地址
struct sockaddr_un self_addr;
self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "client_addr");
ret = bind(sockfd, (struct sockaddr *)&self_addr, sizeof(self_addr));
3. 发送/接收
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "server_addr");
ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
// 接收
struct sockaddr_un peer_addr;
socklen_t addrlen = sizeof(peer_addr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
4. 关闭套接字
close(sockfd);
unlink("client_addr");
2. 服务端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
2. 绑定(自己)地址
struct sockaddr_un self_addr;
self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "server_addr");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 接收
struct sockaddr_un peer_addr;
socklen_t addrlen = sizeof(peer_addr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
4. 发送
ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));
5. 关闭
close(sockfd);
unlink("server_addr");
1. 客户端出了问题(死机、重启了、网络断了...)
2. 服务端出了问题(死机、重启了、网络断了、内存耗尽、...)
3. 网络不正常
解决办法: 心跳包
心跳包的实现方法:
1. 利用TCP协议的KeepAlive(TCP协议实现的心跳包)
见《tcp_keepalive》的服务端
2. 设置接收超时检测心跳,对端需要定时发送
heart_beat程序只在接收端实现了如何(利用阻塞超时)检测超时
3. 如何实现应用程序的定时发送和超时检测?
alarm
总结: 利用实现心跳包
[2] 广播
1. 接收端流程
// (1) 创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); // (2) 绑定IP和端口到socket struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); // addr.sin_addr.s_addr = INADDR_ANY; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); // (3) 接收 struct sockaddr_in peer_addr; socklen_t addrlen = sizeof(peer_addr); ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen); // (3) 关闭 close(sockfd);2. 发送端流程
// (1) 创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); // (2) 设置套接字,使能广播 int on = 1; ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); if (-1 == set){ } SOL_SOCKET: //设置的选项在socket层 SO_BROADCAST: //设置是否允许广播 0 - 不能 1-可以 // (3) 通过广播地址发送广播 struct sockaddr_in broad_addr; bzero(&broad_addr, sizeof(broad_addr)); broad_addr.sin_family = AF_INET; broad_addr.sin_port = htons(port); broad_addr.sin_addr.s_addr = inet_addr//(一定填广播(192.168.0.255)); ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr)); // (4) 关闭 clos(sockfd);
[3] 组播
1. 分组
每个D类IP地址就是一个组,组播实现原理:
接收 -- 加入一个组
发送 -- 向一个组(目标IP地址为组播地址)发送数据包
2. 组播地址(IP地址和网卡地址)
IP地址: D类地址 ,高位固定为1110,范围: 224.0.0.0-239.255.255.255
网卡地址: 前24bit固定为01-00-5e, 最后23bit是D类IP地址的后23bit直接映射下来 -- 仅仅正对于以太网
3. 接收流程
// (1) 创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); // (2) 加入组 struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); // "224.10.10.1" mreq.imr_interface.s_addr = INADDR_ANY; ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); // (3) 绑定IP地址和端口 struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); // addr.sin_addr.s_addr = INADDR_ANY; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); // (4) 接收 struct sockaddr_in peer_addr; socklen_t addrlen = sizeof(peer_addr); ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen); // (3) 关闭 close(sockfd);4. 发送流程
// (1) 创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); // (2) 发送 struct sockaddr_in muticast_addr; bzero(&muticast_addr, sizeof(muticast_addr)); muticast_addr.sin_family = AF_INET; muticast_addr.sin_port = htons(port); muticast_addr.sin_addr.s_addr = inet_addr//(一定填多播(224.10.10.1)); ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr)); // (3) 关闭 close(sockfd);
send.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>// ./send 192.168.0.255 8888int main(int argc, const char *argv[]){int ret;int sockfd;int on = 1;char packet[1024];struct sockaddr_in broad_addr;if (argc < 3){fprintf(stderr, "Usage: %s <broadcast ip> <port>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建报文套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 设置套接字广播属性 ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); if (-1 == ret){ perror("Fail to setsockopt."); exit(EXIT_FAILURE); } // 3. 通过广播地址发送数据包到指定端口bzero(&broad_addr, sizeof(broad_addr));broad_addr.sin_family = AF_INET;broad_addr.sin_port = htons(atoi(argv[2]));broad_addr.sin_addr.s_addr = inet_addr(argv[1]);while (1){putchar('\n');putchar('>');fgets(packet, sizeof(packet), stdin);packet[strlen(packet) - 1] = '\0';ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&broad_addr, sizeof(broad_addr));if (-1 == ret){perror("Fail to sendto."); break;}if (strcmp(packet, "quit") == 0){break;}}// 4. 关闭套接字close(sockfd);return 0;}recv.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>// ./recv 192.168.2.255 8888int main(int argc, const char *argv[]){int ret;int sockfd;char packet[1024];struct sockaddr_in broad_addr;struct sockaddr_in peer_addr;socklen_t addrlen = sizeof(peer_addr);if (argc < 3){fprintf(stderr, "Usage: %s <broadcast ip> <port>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建报文套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定广播地址和端口bzero(&broad_addr, sizeof(broad_addr));broad_addr.sin_family = AF_INET;broad_addr.sin_port = htons(atoi(argv[2]));// broad_addr.sin_addr.s_addr = inet_addr(argv[1]);broad_addr.sin_addr.s_addr = INADDR_ANY;ret = bind(sockfd, (struct sockaddr *)&broad_addr, sizeof(broad_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);}while (1){// 3. 接收广播ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);if (-1 == ret){perror("Fail to recvfrom.");break;}packet[ret] = '\0';printf("---------------------------------------\n");printf("ip : %s\n", inet_ntoa(peer_addr.sin_addr));printf("port : %d\n", ntohs(peer_addr.sin_port));printf("recv(%d) : %s\n", ret, packet);printf("---------------------------------------\n");if (strcmp(packet, "quit") == 0){break;}}// 4. 关闭套接字close(sockfd);return 0;}
[3] unix域套接字--流式 1. 头文件
#include <sys/un.h>
2. 数据结构
struct sockaddr_un {
sa_family_t sun_family;
// __SOCKADDR_COMMON (sun_);
// #define __SOCKADDR_COMMON(sa_prefix) \
// sa_family_t sa_prefix##family
// 替换原理,带参数的宏,实参替换形参(整个宏中所有的)
char sun_path[108]; // 字符串(unix域套接字文件的名)
};
3. 服务端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2. 绑定地址到socket
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 设置为监听模式
ret = listen(sockfd, 10);
4. 接收请求
clientfd = accept(sockfd, NULL, NULL);
5. 接收数据
ret = recv(clientfd, buf, sizeof(buf), 0);
6. 发送数据
ret = send(clientfd, buf, len, 0);
7. 关闭套接字
close(clientfd);
close(sockfd);
4. 客户端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
server.c
/* * 实现目标: * UNIX域套接字通讯 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <pthread.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>void *handler(void *arg){int ret = 0;int clientfd = (int)(long int)arg;char packet[1024];while (1){// 5. 接收数据ret = recv(clientfd, packet, sizeof(packet), 0);if (-1 == ret){perror("Fail to accept.");break;}packet[ret] = '\0';printf("--------------------------------\n");printf("recv(%d): %s\n", ret, packet);printf("--------------------------------\n");if (strcmp(packet, "quit") == 0){break;}}// 6. 关闭套接字close(clientfd);return (void *)0;}// ./server mypathint main(int argc, const char *argv[]){int ret;int sockfd;int clientfd;pthread_t tid;char packet[1024];struct sockaddr_un server_addr;if (argc < 2){fprintf(stderr, "Usage: %s <path>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_STREAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定地址server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);}// 3. 设置为监听模式ret = listen(sockfd, 10);if (-1 == ret){perror("Fail to listen.");exit(EXIT_FAILURE);}while (1){// 4. 接收连接请求clientfd = accept(sockfd, NULL, NULL);if (-1 == clientfd){perror("Fail to accept.");exit(EXIT_FAILURE);}printf("--------------------------------\n");printf("accept a client\n");printf("--------------------------------\n"); pthread_create(&tid, NULL, handler, (void *)(long int)clientfd); pthread_detach(tid);}// 6. 关闭套接字close(sockfd);unlink(argv[1]);return 0;}client.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./client "mypath"int main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr;if (argc < 2){fprintf(stderr, "Usage: %s <path>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建监听socketsockfd = socket(AF_UNIX, SOCK_STREAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 连接服务端(connect)server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[1]);ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}while (1){putchar('\n');putchar('>');fgets(packet, sizeof(packet), stdin);packet[strlen(packet) - 1] = '\0';// 3. 发送(写)ret = send(sockfd, packet, strlen(packet), 0);if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}/* 4. 接收(读)ret = recv(sockfd, packet, sizeof(packet), 0);if (-1 == ret){perror("Fail to connect.");exit(EXIT_FAILURE);}packet[ret] = '\0';printf("--------------------------------\n");printf("recv(%d) : %s\n", ret, packet);printf("--------------------------------\n");*/if (strcmp(packet, "quit") == 0) break;}// 5. 关闭套接字close(sockfd);return 0;}
2. 连接服务器
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "mypath");
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 发送数据
ret = send(clientfd, buf, len, 0);
4. 接收数据
ret = recv(clientfd, buf, sizeof(buf), 0);
5. 关闭套接字
close(sockfd);
[3] unix域套接字--报文
1. 客户端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
2. 绑定(自己)地址
struct sockaddr_un self_addr;
self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "client_addr");
ret = bind(sockfd, (struct sockaddr *)&self_addr, sizeof(self_addr));
3. 发送/接收
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "server_addr");
ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
// 接收
struct sockaddr_un peer_addr;
socklen_t addrlen = sizeof(peer_addr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
4. 关闭套接字
close(sockfd);
unlink("client_addr");
2. 服务端流程
1. 创建套接字
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
2. 绑定(自己)地址
struct sockaddr_un self_addr;
self_addr.sun_family = AF_UNIX;
strcpy(self_addr.sun_path, "server_addr");
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
3. 接收
struct sockaddr_un peer_addr;
socklen_t addrlen = sizeof(peer_addr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &addrlen);
4. 发送
ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));
5. 关闭
close(sockfd);
unlink("server_addr");
client.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./server client_addr server_addrint main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr;struct sockaddr_un peer_addr;socklen_t addrlen = sizeof(server_addr);if (argc < 3){fprintf(stderr, "Usage: %s <client addr> <server addr>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket");exit(EXIT_FAILURE);} // 2. 绑定(自己)地址peer_addr.sun_family = AF_UNIX;strcpy(peer_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&peer_addr, sizeof(peer_addr));if (-1 == ret){perror("Fail to bind");exit(EXIT_FAILURE);}server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, argv[2]); while (1){ putchar('\n'); putchar('>'); fgets(packet, sizeof(packet), stdin); packet[strlen(packet) - 1] = '\0'; // 3. 发送(写) ret = sendto(sockfd, packet, strlen(packet), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (-1 == ret){ perror("Fail to sendto."); break; } printf("-----------------------------\n"); printf("send : %s\n", packet); printf("-----------------------------\n"); // 4. 接收(读) ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&server_addr, &addrlen); if (-1 == ret){ perror("Fail to recvfrom."); break; } packet[ret] = '\0'; printf("-----------------------------\n");printf("recv(%d): %s\n", ret, packet);printf("-----------------------------\n"); if (strcmp(packet, "quit") == 0){ break; }} // 5. 关闭 close(sockfd); unlink(argv[1]);return 0;}server.c
#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <strings.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>// ./server server_addrint main(int argc, const char *argv[]){int ret = 0;int sockfd;char packet[1024];struct sockaddr_un server_addr; struct sockaddr_un peer_addr;socklen_t addrlen = sizeof(peer_addr);if (argc < 2){fprintf(stderr, "Usage: %s <src addr>\n", argv[0]);exit(EXIT_FAILURE);}// 1. 创建套接字sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);if (-1 == sockfd){perror("Fail to socket.");exit(EXIT_FAILURE);}// 2. 绑定(自己)地址server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, argv[1]);ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));if (-1 == ret){perror("Fail to bind.");exit(EXIT_FAILURE);} while (1){// 3. 接收数据包ret = recvfrom(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)&peer_addr, &addrlen);if (-1 == ret){perror("Fail to recvfrom.");break;}packet[ret] = '\0';printf("-----------------------------\n");printf("from : %s\n", peer_addr.sun_path);printf("recv(%d): %s\n", ret, packet);printf("-----------------------------\n");// 4. 发送数据包ret = sendto(sockfd, packet, ret, 0, (struct sockaddr *)&peer_addr, sizeof(peer_addr));if (-1 == ret){perror("Fail to sendto.");break;}if (strcmp(packet, "quit") == 0){break;}}// 5. 关闭close(sockfd);unlink(argv[1]);return 0;}
0 0
- Linux网络异常处理(6.12)
- Python网络爬虫(四)-----异常处理
- 网络异常处理
- 网络环境异常处理
- linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)
- jquery 网络请求处理异常
- 网络爬虫异常文件处理
- linux中断(与异常)处理过程
- Linux异常处理体系结构
- linux异常处理
- linux异常处理体系结构
- linux异常处理体系结构
- Linux页面异常处理
- Linux异常关闭处理
- linux网络编程常见异常
- Linux内核分析-异常处理
- Linux内核异常处理体系结构
- Linux内核异常处理体系结构
- 引用library之——带有自定义属性的自定义控件的library包
- android开发步步为营之63:webview常用用法
- iOS学习之Socket使用简明教程- AsyncSocket
- 黑马程序员--文件操作知识总结
- 让服务器iis支持.apk文件下载的设置方法
- Linux网络异常处理(6.12)
- Git
- 如何领导技术团队
- APAC Day of Coderetreat 2015
- GDI+
- 使用JDBC连接MySQL数据库--典型案例分析(九)----财务帐号的DAO设计及其实现
- 用swift实现navigation bar的完全透明 & navigation bar中button的字体大小调整
- 第一章 初识JAVA学习总结(15-6-16)
- 【华为OJ】求int型数据在内存中存储时1的个数