select 函数实现 三种拓扑结构 n个客户端的异步通信 (完全图+线性链表+无环图)
2016-06-13 09:57
267 查看
http://blog.csdn.net/u011239443/article/details/51655257
一、这里只介绍简单的三个客户端异步通信(完全图拓扑结构)
1 1 //建立管道2 2 mkfifo 12 13 21 23 31 32open顺序:cl1 读 , cl2 cl3 向 cl1写cl2 读 , cl1 cl3 向 cl2写cl3 读 , cl1 cl2 向 cl3写顺序的规律就是 第i个 客户端读 其他各个客户端 ,其他的各个客户端 向 i 写 ,i 从 1 到 3.cl1 代码:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<string.h>4 #include<unistd.h>5 #include<sys/stat.h>6 #include<sys/types.h>7 #include<fcntl.h>8 #include <sys/time.h>9 #include<sys/select.h>10 #include <sys/select.h>1112 /* According to earlier standards */13 #include <sys/time.h>14 #include <sys/types.h>15 #include <unistd.h>1617 int main(int argc, char* argv[])//2118 {1920 int fd21, fd31,fd12,fd13 ;21 fd21 = open("21", O_RDONLY);22 fd31 = open("31", O_RDONLY);2324 fd12 = open("12",O_WRONLY);2526 fd13 = open("13",O_WRONLY);27 printf("OK!\n");282930 printf("OK!\n");31 fd_set read_sets ;32 fd_set write_sets ;33 int iret,iwrt ;34 char buf[1024] ;35 struct timeval tm ;36 while(1)37 {3839 tm.tv_sec = 1 ;40 tm.tv_usec = 0 ;41 FD_ZERO(&read_sets);42 FD_ZERO(&write_sets);4344 FD_SET(fd21, &read_sets);45 FD_SET(fd31, &read_sets);46 FD_SET( 0, &write_sets);47 //FD_SET(fd12, &write_sets);48 //FD_SET(fd13, &write_sets);4950 iret = select(10, &read_sets, NULL, NULL, &tm);51 iwrt = select(10,&write_sets,NULL,NULL,&tm);5253 //读54 if(iret != 0)55 {56 printf("active: %d\n", iret);5758 if(FD_ISSET(fd21, &read_sets))59 {60 memset(buf, 0, 1024);61 read(fd21, buf, 1023);62 printf("from 2: %s\n", buf);63 }64 if(FD_ISSET(fd31, &read_sets))65 {66 memset(buf, 0, 1024);67 read(fd31, buf, 1023);68 printf("from 3: %s\n", buf);69 }70 }717273 // write74 if(iwrt != 0)75 {76 printf("active: %d\n", iwrt);77 if(FD_ISSET( 0 /*fd12*/, &write_sets))78 {79 memset(buf, 0, 128);80 read(0, buf, 127) ;81 write(fd12, buf, strlen(buf));82 write(fd13, buf, strlen(buf));83 }84 /*if(FD_ISSET(fd13, &write_sets))85 {86 memset(buf, 0, 128);87 read(0, buf, 127) ;88 write(fd13, buf, strlen(buf));89 }*/90 }9192 }93 return 0 ;94 }cl2 代码:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<string.h>4 #include<unistd.h>5 #include<sys/stat.h>6 #include<sys/types.h>7 #include<fcntl.h>8 #include<sys/select.h>9 int main(int argc, char* argv[])//2110 {11 int fd12, fd32,fd21,fd23 ;12 fd21 = open("21",O_WRONLY);1314 fd12 = open("12", O_RDONLY);15 fd32 = open("32", O_RDONLY);1617 fd23 = open("23",O_WRONLY);181920 fd_set read_sets ,write_sets ;21 int iret ,iwrt;22 char buf[1024] ;23 struct timeval tm ;24 while(1)25 {2627 tm.tv_sec = 1 ;28 tm.tv_usec = 0 ;29 FD_ZERO(&read_sets);30 FD_ZERO(&write_sets);31 FD_SET(fd12, &read_sets);32 FD_SET(fd32, &read_sets);33 FD_SET( 0, &write_sets);34 //FD_SET(fd21,&write_sets);35 //FD_SET(fd23,&write_sets);3637 iret = select(10, &read_sets, NULL, NULL, &tm);38 iwrt = select(10,&write_sets,NULL,NULL,&tm);3940 if(iret != 0)41 {42 printf("active: %d\n", iret);4344 if(FD_ISSET(fd12, &read_sets))45 {46 memset(buf, 0, 1024);47 read(fd12, buf, 1023);48 printf("from 1: %s\n", buf);49 }50 if(FD_ISSET(fd32, &read_sets))51 {52 memset(buf, 0, 1024);53 read(fd32, buf, 1023);54 printf("from 3: %s\n", buf);55 }56 }575859 // write60 if(iwrt != 0)61 {62 printf("active: %d\n", iwrt);63 if(FD_ISSET( 0 , &write_sets))64 {65 memset(buf, 0, 128);66 read(0, buf, 127) ;67 write(fd21, buf, strlen(buf));68 write(fd23, buf, strlen(buf));69 }70 /* if(FD_ISSET(fd23, &write_sets))71 {72 memset(buf, 0, 128);73 read(0, buf, 127) ;74 write(fd23, buf, strlen(buf));75 }*/76 }7778 }79 return 0 ;80 }cl3 代码:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<string.h>4 #include<unistd.h>5 #include<sys/stat.h>6 #include<sys/types.h>7 #include<fcntl.h>8 #include<sys/select.h>9 int main(int argc, char* argv[])//3110 {11 int fd13, fd23,fd31,fd32 ;12 fd31 = open("31",O_WRONLY);1314 fd32 = open("32",O_WRONLY);1516 fd13 = open("13", O_RDONLY);17 fd23 = open("23", O_RDONLY);1819 printf("OK!\n");20 fd_set read_sets ,write_sets ;21 int iret,iwrt ;22 char buf[1024] ;23 struct timeval tm ;24 while(1)25 {2627 tm.tv_sec = 1 ;28 tm.tv_usec = 0 ;29 FD_ZERO(&read_sets);30 FD_ZERO(&write_sets);31 FD_SET(fd13, &read_sets);32 FD_SET(fd23, &read_sets);33 //FD_SET(fd31,&write_sets);34 //FD_SET(fd32,&write_sets);35 FD_SET( 0, &write_sets);3637 iret = select(10, &read_sets, NULL, NULL, &tm);38 iwrt = select(10,&write_sets,NULL,NULL,&tm);3940 //读41 if(iret != 0)42 {43 printf("active: %d\n", iret);4445 if(FD_ISSET(fd13, &read_sets))46 {47 memset(buf, 0, 1024);48 read(fd13, buf, 1023);49 printf("from 1: %s\n", buf);50 }51 if(FD_ISSET(fd23, &read_sets))52 {53 memset(buf, 0, 1024);54 read(fd23, buf, 1023);55 printf("from 2: %s\n", buf);56 }57 }585960 // write61 if(iwrt != 0)62 {63 printf("active: %d\n", iwrt);64 if(FD_ISSET( 0 , &write_sets))65 {66 memset(buf, 0, 128);67 read(0, buf, 127) ;68 write(fd31, buf, strlen(buf));69 write(fd32, buf, strlen(buf));70 }71 /*if(FD_ISSET(fd32, &write_sets))72 {73 memset(buf, 0, 128);74 read(0, buf, 127) ;75 write(fd32, buf, strlen(buf));76 }*/77 }78 }7980 return 0 ;81 }
二 、n个客户端异步通信 (线性链表的拓扑结构)
很显然的,如果用上述的方法需要每个客户端和其他客户端都直接相邻,即完全图。建立n个客户端通信,需要 2*((n-1)+(n-2)+(n-3)+……3+2+1) = 2*(n-1 + 1)*(n -1)/2 =n * (n-1) 根管道,这么多的管道连接会使得代码实现变得非常冗杂、而且系统浪费资源管道。这里,用线性链表的拓扑结构,可以解决这个问题:1、 客户端以线性存储2、 当 pre 发来数据时, 打印出来,并且转发给next(若next存在)。3、 当 next 发来数据时, 打印出来,并且转发给pre(若pre存在)。4、 当键盘发来数据时,转发给next(若next存在),转发给pre(若pre存在)。例子:1、客户端拓扑结构为 1——3——2——4
在文件存储如下:2、我还编写一个读取topo.txt 文件 ,自动生成管道的代码:
BuildFIFO.cpp 如下:1 #include<stdio.h>2 #include<stdlib.h>3 #include<string.h>4 #include<string>5 #include<unistd.h>6 #include<sys/stat.h>7 #include<sys/types.h>8 #include<fcntl.h>9 #include <sys/time.h>10 #include<sys/select.h>11 using namespace std;12 int main(int argc, char* argv[])//2113 {1415 FILE* topu = fopen("topo.txt","r");16 int fir = 1;17 char dir[5],DIR[11];18 string str1,str2,str ;19 while(!feof(topu))20 {21 fscanf(topu ,"%s\n",dir);22 str1 = dir;23 if(fir)24 {25 fir =0 ;26 str2=str1;27 continue;28 }29 str=str1+"T"+str2;30 strcpy(DIR,str.c_str());31 mkfifo(DIR,0777);3233 str=str2+"T"+str1;34 strcpy(DIR,str.c_str());35 mkfifo(DIR,0777);36 str2 = str1;37 }3839 fclose(topu);4041 return 0;42 }
3、从客户端3键盘输入数据后,发送到各个客户端:
4、这里也有个 open 的 顺序的问题,但其实这种拓扑结构很好解决这个问题:
只需要每个相邻的客户端 读写顺序相反就能解决了如下:1 if(count & 1== 1) //判断节点的位置是奇数 还是 偶数 ,如果是 奇数 就 先读后写2 {3 if(strcmp("-1",pre->val)!=0)4 {56 fdReadFromPre = My_Open(pre->val,p->val,0);7 fdWriteToPre = My_Open(p->val,pre->val,1);8 }910 if(p->next!=NULL)11 {12 fdReadFromNext = My_Open(p->next->val,p->val,0);13 fdWriteToNext = My_Open(p->val,p->next->val,1);14 }15 }16 else //如果是偶数,先写后读17 {18 if(strcmp("-1",pre->val)!=0)19 {20 fdWriteToPre = My_Open(p->val,pre->val,1);21 fdReadFromPre = My_Open(pre->val,p->val,0);22 }2324 if(p->next!=NULL)25 {26 fdWriteToNext = My_Open(p->val,p->next->val,1);27 fdReadFromNext = My_Open(p->next->val,p->val,0);28 }2930 }
5、各客户端代码:
这里只发 cl1.cpp(其他客户端就是1 while( strcmp("1",p->val)!=0)
1 char tembuf[1024] = "Form1 :";这两句代码不一样而已)如下:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<string.h>4 #include<unistd.h>5 #include<sys/stat.h>6 #include<sys/types.h>7 #include<fcntl.h>8 #include <sys/time.h>9 #include<sys/select.h>101112 #define fdNULL -99991314 struct node15 {16 char val[5];17 node* next;18 };1920 int My_Open(char A[],char B[],int type)21 {22 char Cstr[11];23 memset( Cstr, '\0', sizeof(Cstr) );24 strcat(Cstr,A);25 strcat(Cstr,"T");26 strcat(Cstr,B);27 if(type == 0) return open(Cstr, O_RDONLY);28 else return open(Cstr, O_WRONLY);29 }303132 int main(int argc, char* argv[])//2133 {3435 FILE* topu = fopen("/home/soso/Desktop/1-30/LineSelect/topo.txt","r");36 char a[5];3738 node* L = (node*)calloc(1, sizeof(node)); //save topo39 strcpy(L->val,"-1");40 L->next = NULL;41 node* tem , *p ,*pre;42 p=L;43 while(!feof(topu))44 {45 fscanf(topu ,"%s\n",a);46 tem= (node*)calloc(1, sizeof(node));47 strcpy(tem->val,a);48 tem->next = NULL;49 p->next=tem;50 p=p->next;51 }52 fclose(topu);5354 pre=L;55 p= L->next;56 int count = 1;57 while( strcmp("1",p->val)!=0)58 {59 p=p->next;60 pre=pre->next;61 ++count;62 }6364 int fdReadFromPre,fdReadFromNext,fdWriteToPre,fdWriteToNext ;65 fdReadFromPre=fdReadFromNext=fdWriteToPre=fdWriteToNext=fdNULL;66 if(count & 1== 1) //判断节点的位置是奇数 还是 偶数 ,如果是 奇数 就 先读后写67 {68 if(strcmp("-1",pre->val)!=0)69 {7071 fdReadFromPre = My_Open(pre->val,p->val,0);72 fdWriteToPre = My_Open(p->val,pre->val,1);73 }7475 if(p->next!=NULL)76 {77 fdReadFromNext = My_Open(p->next->val,p->val,0);78 fdWriteToNext = My_Open(p->val,p->next->val,1);79 }80 }81 else //如果是偶数,先写后读82 {83 if(strcmp("-1",pre->val)!=0)84 {85 fdWriteToPre = My_Open(p->val,pre->val,1);86 fdReadFromPre = My_Open(pre->val,p->val,0);87 }8889 if(p->next!=NULL)90 {91 fdWriteToNext = My_Open(p->val,p->next->val,1);92 fdReadFromNext = My_Open(p->next->val,p->val,0);93 }9495 }9697 printf("OK!\n");9899 fd_set read_sets ;100 fd_set write_sets ;101 int iret,iwrt ;102 char buf[1024] ;103 struct timeval tm ;104 while(1)105 {106107 tm.tv_sec = 1 ;108 tm.tv_usec = 0 ;109 FD_ZERO(&read_sets);110 FD_ZERO(&write_sets);111 if(fdReadFromPre != fdNULL)112 FD_SET(fdReadFromPre, &read_sets);113 if(fdReadFromNext != fdNULL)114 FD_SET(fdReadFromNext, &read_sets);115 FD_SET( 0, &write_sets);116117118 iret = select(10, &read_sets, NULL, NULL, &tm);119 iwrt = select(10,&write_sets,NULL,NULL,&tm);120121 //读122 if(iret != 0)123 {124125 if(FD_ISSET(fdReadFromPre, &read_sets))126 {127 memset(buf, 0, 1024);128 read(fdReadFromPre, buf, 1023);129 if(fdWriteToNext!=fdNULL) //把从pre读过来的数据转发到next去130 write(fdWriteToNext, buf, strlen(buf));131 printf("%s\n" ,buf);132 }133 if(FD_ISSET(fdReadFromNext, &read_sets))134 {135 memset(buf, 0, 1024);136 read(fdReadFromNext, buf, 1023);137 if(fdWriteToPre!=fdNULL) //把从next读过来的数据转发到pre去138 write(fdWriteToPre, buf, strlen(buf));139 printf("%s\n", buf);140 }141 }142143144 // write145 if(iwrt != 0)146 {147148 if(FD_ISSET( 0 , &write_sets))149 {150 memset(buf, 0, 128);151 read(0, buf, 127) ;152 char tembuf[1024] = "Form1 :";153 strcat(tembuf,buf);154 if(fdWriteToNext!=fdNULL) //把从键盘输入的数据向next、pre 转发155 write(fdWriteToNext, tembuf, strlen(tembuf));156 if(fdWriteToPre!=fdNULL)157 write(fdWriteToPre, tembuf, strlen(tembuf));158 }159 }160161 }162 return 0;163 }
6、添加的客户端
1、在topo.txt 添加 客户名 再 换行2、再按一下 已经生成的 BuildFIFO 可执行文件,及自动生成所需的管道3、vim 出客户端,代码只需 改动两处(见5) 便可以完成客户端的添加。三 、n个客户端异步通信 (无环图的拓扑结构)
线性拓扑结构有个很大的缺陷如图:客户端1 发送消息,要经过 3、2 的转发才能到达 4。当客户端数量很大时,链表前部和后部之间的通信的延迟会很大。如果改进,用树形拓扑机构就会很大的缓解这个问题。1、 《计算机网络》的OSPF路由算法里面提到的泛洪法+无环图拓扑结构
如图 为Zhu客户端键盘输入数据:2、存储结构
在文件topo.txt 中以类似于邻接的方式存储:topo文件格式为:顶点 节点个数 节点1 节点2 ……如图:客户端读取文件后的邻接表存储代码:1 map<string,bool> visit;23 struct TreeLine4 {5 vector<string> TreeNode;6 int level; //层号7 };8910 map<string,TreeLine> Tree;
1 FILE* topu = fopen("topo.txt","r");2 int fir = 1;3 int i,j;4 char strtem[5],strtem2[5],tem,Lval[5];5 int num;6 while(!feof(topu))7 {8 fscanf(topu ,"%s %d",strtem,&num);9 if(fir) //记录第一个客户端的名称10 {11 fir = 0;12 strcpy(Lval,strtem);13 }141516 TreeLine TemLine;17 for(int i =0 ;i< num;i++)18 {19 fscanf(topu," %s",strtem2);20 TemLine.TreeNode.push_back(strtem2);21 }22 fgetc(topu);2324 Tree[strtem]=TemLine;25 visit[strtem] = false; //初始化访问位26 }27 fclose(topu);3、DFS来标注奇偶层号,判断open顺序(只要奇偶层顺序相反)
1 void DFS(string val,int level)2 {3 visit[val] = true ;4 Tree[val].level = level;5 //cout<<val<<":"<<level<<" "<<Tree[val].TreeNode.size()<<endl;6 int i;7 for(i = 0;i<Tree[val].TreeNode.size();++i)8 {9 if(visit[Tree[val].TreeNode[i]] == false)10 DFS(Tree[val].TreeNode[i],level+1);11 }12 }
1 int level = 1;2 DFS(Lval,level);34 vector<int> fdReadOpen,fdWriteOpen;567 string TemString;8 if(Tree[UserName].level & 1 == 1) //判断层号 奇数先读后写9 {10 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)11 {12 TemString=Tree[UserName].TreeNode[i]+"TO"+UserName;13 fdReadOpen.push_back(open(TemString.c_str(), O_RDONLY));14 }1516 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)17 {18 TemString = UserName;19 TemString+="TO"+Tree[UserName].TreeNode[i];20 fdWriteOpen.push_back(open(TemString.c_str(),O_WRONLY));21 }2223 }24 else //判断层号 偶数数先写后读25 {26 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)27 {28 TemString = UserName;29 TemString+="TO"+Tree[UserName].TreeNode[i];30 fdWriteOpen.push_back(open(TemString.c_str(),O_WRONLY));31 }3233 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)34 {35 TemString=Tree[UserName].TreeNode[i]+"TO"+UserName;36 fdReadOpen.push_back(open(TemString.c_str(), O_RDONLY));37 }38 }
3、各客户端代码:
这次用了宏定义,每个客户端只需修改:1 #define UserName "Ye"其他代码都相同。这里分析客户端 Ye 的代码:
1 #include <vector>2 #include<map>3 #include<string>4 #include<iostream>5 #include<stdio.h>6 #include<stdlib.h>7 #include<string.h>8 #include<unistd.h>9 #include<sys/stat.h>10 #include<sys/types.h>11 #include<fcntl.h>12 #include <sys/time.h>13 #include<sys/select.h>14 using namespace std;1516 #define MaxSize 100001718 #define UserName "Ye"1920 map<string,bool> visit;2122 struct TreeLine23 {24 vector<string> TreeNode;25 int level; //层号26 };272829 map<string,TreeLine> Tree;3031 void DFS(string val,int level)32 {33 visit[val] = true ;34 Tree[val].level = level;35 //cout<<val<<":"<<level<<" "<<Tree[val].TreeNode.size()<<endl;36 int i;37 for(i = 0;i<Tree[val].TreeNode.size();++i)38 {39 if(visit[Tree[val].TreeNode[i]] == false)40 DFS(Tree[val].TreeNode[i],level+1);41 }42 }43444546 int main(int argc, char* argv[])47 {4849 FILE* topu = fopen("topo.txt","r");50 int fir = 1;51 int i,j;52 char strtem[5],strtem2[5],tem,Lval[5];53 int num;54 while(!feof(topu))55 {56 fscanf(topu ,"%s %d",strtem,&num);57 if(fir) //记录第一个客户端的名称58 {59 fir = 0;60 strcpy(Lval,strtem);61 }626364 TreeLine TemLine;65 for(int i =0 ;i< num;i++)66 {67 fscanf(topu," %s",strtem2);68 TemLine.TreeNode.push_back(strtem2);69 }70 fgetc(topu);7172 Tree[strtem]=TemLine;73 visit[strtem] = false; //初始化访问位74 }75 fclose(topu);7677 int level = 1;78 DFS(Lval,level);7980 vector<int> fdReadOpen,fdWriteOpen;818283 string TemString;84 if(Tree[UserName].level & 1 == 1) //判断层号 奇数先读后写85 {86 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)87 {88 TemString=Tree[UserName].TreeNode[i]+"TO"+UserName;89 fdReadOpen.push_back(open(TemString.c_str(), O_RDONLY));90 }9192 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)93 {94 TemString = UserName;95 TemString+="TO"+Tree[UserName].TreeNode[i];96 fdWriteOpen.push_back(open(TemString.c_str(),O_WRONLY));97 }9899 }100 else //判断层号 偶数数先写后读101 {102 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)103 {104 TemString = UserName;105 TemString+="TO"+Tree[UserName].TreeNode[i];106 fdWriteOpen.push_back(open(TemString.c_str(),O_WRONLY));107 }108109 for(i= 0 ;i<Tree[UserName].TreeNode.size();++i)110 {111 TemString=Tree[UserName].TreeNode[i]+"TO"+UserName;112 fdReadOpen.push_back(open(TemString.c_str(), O_RDONLY));113 }114 }115116117118119 printf("OK!\n");120121 fd_set read_sets ;122 fd_set write_sets ;123 int iret,iwrt ;124 char buf[1024] ;125 struct timeval tm ;126 while(1)127 {128129 tm.tv_sec = 1 ;130 tm.tv_usec = 0 ;131 FD_ZERO(&read_sets);132 FD_ZERO(&write_sets);133 for(i=0;i<fdReadOpen.size();i++)134 FD_SET(fdReadOpen[i], &read_sets);135 FD_SET( 0, &write_sets);136137 iret = select(1023, &read_sets, NULL, NULL, &tm);138 iwrt = select(1023,&write_sets,NULL,NULL,&tm);139140 //读141 if(iret != 0)142 {143144 for(i=0;i<fdReadOpen.size();i++) //遍历ReadOpen145 {146 if(FD_ISSET(fdReadOpen[i], &read_sets)) //当收到ReadOpen[i]时147 {148 memset(buf, 0, 1024);149 read(fdReadOpen[i], buf, 1023);150 printf("%s\n" ,buf); //打印出来151 for(j=0;j<fdWriteOpen.size();j++) //向其他客户端转发152 {153 if(j != i) //AtoB 和 BtoA 的fdOpen存储位置是对应的154 write(fdWriteOpen[j], buf, strlen(buf));155 }156 }157 }158 }159160161 // write162 if(iwrt != 0)163 {164 if(FD_ISSET( 0 , &write_sets))165 {166 memset(buf, 0, 128);167 read(0, buf, 127) ;168 char tembuf[1024] = UserName;169 strcat(tembuf," :");170 strcat(tembuf,buf);171 for(i =0 ;i< fdWriteOpen.size();i++)172 write(fdWriteOpen[i], tembuf, strlen(tembuf));173 }174 }175176 }177178179 return 0;180 }
4、添加的客户端
1、按照输入格式在topo.txt 添加2、再按一下 已经生成的 BuildFIFO 可执行文件,及自动生成所需的管道3、vim 出客户端,代码只需 改动一处(见3) 便可以完成客户端的添加。相关文章推荐
- C#项目中发生PInvokeStackImbalance异常,堆栈不对称异常
- 诺基亚衰落的原因及其如何走去困境
- Android 中的回调函数揭秘
- [LeetCode][12]Integer to Roman解析 int转罗马字符时间复杂度为常数的实现-Java实现
- Maven导入时,Cannot change version of project facet Dynamic Web Module to 3.0.
- ThreadLocal
- 职场笔录-1
- 如何在WebService中重载方法
- 《直到最后一句》,人物:高晨
- RF-微信文章
- 解决Eclipse交叉编译环境下出现Symbol"NULL" could not be resolved
- 计算器(delphi)
- CentOS 下 Codeblocks 的 安装 + 汉化 以及 基本使用介绍
- 关于阿里如何吸引大学生用户理财的一些个人看法
- 余额宝个人用户体验
- 谷歌到底有没有为了希拉里而“作恶”?
- 学生信息管理系统(C实现)
- CRC的校验原理
- git add -A使用说明
- Greenplum client Tools使用