82.管道实现cgi内存多线程查询
总体思路就是客户端写入要查询的数据到管道中,服务器端从管道读取,然后写入随机文件,再把文件名写入管道,然后客户端再读取文件
服务器端
- 设置缓冲区大写,设置管道名字,以及标识有多少个线程等
1 //设置缓存区大小 2 #define SIZE 4096 3 //最多有多少线程 4 #define MAX_CONNECT 128 5 //一开始有10个线程存在 6 int startthreadnum = 10; 7 //管道名字 8 char pipename[128] = "\\\\.\\Pipe\\cloudpipe";
1 //文件路径 2 #define path "C:\\Program Files\\Apache Software Foundation\\Apache2.2\\cgi-bin\\kaifang.txt" 3 //查询结果存放的路径 4 char randpath[1000] = ""; 5 //全局的二级指针 6 char ** g_pp; 7 //标示有多少行 8 int imax = 15151574;
- 创建句柄结构体
1 //结构体,hpipe存储管道信息,hevent用于给结构体初始化,存放连接管道的信息 2 typedef struct info 3 { 4 HANDLE hthread; 5 HANDLE hpipe; 6 HANDLE hevent; 7 8 }PIPE_ST; 9 10 //创建128个结构体 11 PIPE_ST pipeinst[MAX_CONNECT];
- 随机生成文件名存放查询的结果
1 //随机生成文件名存放查询的结果 2 void run() 3 { 4 time_t ts; 5 srand((unsigned int)time(&ts)); 6 sprintf(randpath, "C:\\Program Files\\Apache Software Foundation\\Apache2.2\\cgi-bin\\%d.txt", rand()); 7 }
- 文件载入内存
1 //载入内存 2 void loadfromfile() 3 { 4 //分配指针数组 5 g_pp = (char **)malloc(sizeof(char*)*imax); 6 //内存清零 7 memset(g_pp, '\0', sizeof(char*)*imax); 8 9 //以读的方式打开文件 10 FILE *pf = fopen(path, "r"); 11 if (pf == NULL) 12 { 13 printf("文件打开失败"); 14 return -1; 15 } 16 else 17 { 18 for (int i = 0; i < imax; i++) 19 { 20 char str[1024] = { 0 }; 21 //按行读取 22 fgets(str, 1024, pf); 23 str[1024 - 1] = '\0'; 24 int strlength = strlen(str); 25 26 //分配内存 27 g_pp[i] = malloc(sizeof(char)*(strlength + 1)); 28 29 //拷贝到分配的内存 30 if (g_pp[i] != NULL) 31 { 32 strcpy(g_pp[i], str); 33 } 34 } 35 fclose(pf);//关闭 36 } 37 }
- 查询函数
1 //查询 2 void search(char *str,char * randpath) 3 { 4 //写的模式打开 5 FILE *pf = fopen(randpath, "w"); 6 if (g_pp != NULL) 7 { 8 9 for (int i = 0; i < imax; i++) 10 { 11 if (g_pp[i] != NULL) 12 { 13 //查询 14 char *p = strstr(g_pp[i], str); 15 if (p != NULL) 16 { 17 fputs(g_pp[i], pf);//输出到文件 18 } 19 } 20 } 21 } 22 fclose(pf); 23 }
- 线程函数,查询结果写入随机文件,文件名再写入管道
1 //线程函数 2 DWORD WINAPI severThread(void *lp) 3 { 4 //读取到的个数 5 DWORD nread = 0; 6 //写入的个数 7 DWORD nwrite = 0; 8 //用于判断IO 9 DWORD dwbyte = 0; 10 //缓存区 11 char szbuf[SIZE] = { 0 }; 12 //获取当前结构体 13 PIPE_ST curpipe = *(PIPE_ST*)lp; 14 //利用event初始化一个结构体 15 OVERLAPPED overlap = { 0, 0, 0, 0, curpipe.hevent }; 16 17 while (1) 18 { 19 //数据清零 20 memset(szbuf, 0, sizeof(szbuf)); 21 //链接管道,信息写入overlap 22 ConnectNamedPipe(curpipe.hpipe, &overlap); 23 //等待连接完成 24 WaitForSingleObject(curpipe.hevent, INFINITE); 25 //检测IO,如果IO错误则退出 26 if (!GetOverlappedResult(curpipe.hpipe, &overlap, &dwbyte, TRUE)) 27 { 28 break; 29 } 30 //读取管道中的数据到szbuf,最多读取SIZE个 31 if (!ReadFile(curpipe.hpipe, szbuf, SIZE, &nread, NULL)) 32 { 33 puts("read fail"); 34 break; 35 } 36 37 char searchstr[100] = { 0 }; 38 //去读查询谁 39 sscanf(szbuf, "%s", searchstr); 40 41 //路径配置 42 run(); 43 //查询 44 search(searchstr, randpath); 45 46 //清零 47 memset(szbuf, 0, sizeof(szbuf)); 48 //把路径写入管道 49 sprintf(szbuf, "%s", randpath); 50 WriteFile(curpipe.hpipe, szbuf, strlen(szbuf), &nwrite, NULL);//写入 51 //断开与管道的连接 52 DisconnectNamedPipe(curpipe.hpipe); 53 } 54 return 0; 55 }
- 初始化结构体并创建线程
1 //初始化结构体并创建线程 2 void start() 3 { 4 for (int i = 0; i < startthreadnum; i++) 5 { 6 //创建管道,如果同名,则操作同一个管道 7 pipeinst[i].hpipe = CreateNamedPipeA( 8 pipename,//管道名称 9 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,//管道读写属性 10 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,//消息模式,读模式,等待模式阻塞 11 10,//最大个数 12 0,//输出缓冲区大小 13 0,//输入缓冲区大小 14 1000,//超时,无限等待 15 NULL); 16 if (pipeinst[i].hpipe == INVALID_HANDLE_VALUE) 17 { 18 printf("\n%d失败", i); 19 return; 20 } 21 //创建事件 22 pipeinst[i].hevent = CreateEventA(NULL, FALSE, FALSE, FALSE);//创建事件 23 //创建线程 24 pipeinst[i].hthread = CreateThread(NULL, 0, severThread, &pipeinst[i], 0, NULL); 25 26 } 27 printf("sever start"); 28 29 }
- 释放内存
1 //释放内存 2 void end() 3 { 4 for (int i = 0; i < 10;i++) 5 { 6 CloseHandle(pipeinst[i].hthread); 7 CloseHandle(pipeinst[i].hevent); 8 CloseHandle(pipeinst[i].hpipe); 9 } 10 }
- 主函数
1 //主函数 2 void main() 3 { 4 //载入内存 5 loadfromfile(); 6 //创建线程 开始查询 7 start(); 8 system("pause"); 9 10 }
客户端
- 设置缓存区,以及管道名字和管道句柄
1 //缓存区大小 2 #define SIZE 4096 3 //管道名字 4 char pipename[128] = "\\\\.\\Pipe\\cloudpipe"; 5 //管道句柄 6 HANDLE m_pipe = NULL;
- CGI编码格式转换到str中
1 //CGI编码格式转换到str中 2 char* change(char *str) 3 { 4 char *tempstr = malloc(strlen(str) + 1); 5 int x = 0, y = 0; 6 char assii_1, assii_2; 7 while (tempstr[x]) 8 { 9 if ((tempstr[x] = str[y]) == '%') 10 { 11 if (str[y + 1] >= 'A') 12 { 13 assii_1 = str[y + 1] - 55; 14 15 } 16 else 17 { 18 assii_1 = str[y + 1] - 48; 19 } 20 if (str[y + 2] >= 'A') 21 { 22 assii_2 = str[y + 2] - 55; 23 } 24 else 25 { 26 assii_2 = str[y + 2] - 48; 27 } 28 tempstr[x] = assii_1 * 16 + assii_2; 29 y += 2; 30 } 31 x++; 32 y++; 33 } 34 tempstr[x] = '\0'; 35 return tempstr; 36 }
- 主函数
1 void main() 2 { 3 printf("Content-type:text/html\n\n");//换行 4 5 system("ipconfig");//服务器不稳定因素,适当中断 6 7 //获取表单信息,并对信息进行处理 8 char szpost[256] = { 0 }; 9 gets(szpost); 10 printf("%s", szpost); 11 12 char*p1 = strchr(szpost, '&'); 13 if (p1 != NULL) 14 { 15 *p1 = '\0'; 16 } 17 printf("<br>%s", szpost + 5); 18 printf("<br>%s", change(szpost + 5)); 19 20 char *p2 = strchr(p1 + 1, '&'); 21 if (p2 != NULL) 22 { 23 *p2 = '\0'; 24 } 25 printf("<br>%s", p1 + 6); 26 printf("<br>%s", change(p1 + 6)); 27 28 //打开管道 29 m_pipe = CreateFileA(pipename, //名称 30 GENERIC_WRITE | GENERIC_READ,//读写 31 0,//共享属性,1独有 32 NULL,//默认安全属性 33 OPEN_EXISTING,//打开已经存在的 34 FILE_ATTRIBUTE_NORMAL, 35 NULL); 36 37 if (m_pipe == INVALID_HANDLE_VALUE) 38 { 39 printf("失败"); 40 return; 41 } 42 43 int nwrite; 44 int nread; 45 46 char winfo[1024] = { 0 }; 47 //打印数据到winfo中 48 sprintf(winfo, "%s", change(szpost + 5)); 49 50 //写入管道 51 WriteFile(m_pipe, winfo, strlen(winfo), &nwrite, NULL); 52 memset(winfo, 0, sizeof(winfo)); 53 //读取管道 54 ReadFile(m_pipe, winfo, 1024, &nread, NULL); 55 ; 56 //打开文件,并读取 57 FILE *pf = fopen(winfo, "r"); 58 while (!feof(pf)) 59 { 60 char ch = fgetc(pf); 61 if (ch=='\n') 62 { 63 puts("<br>"); 64 } 65 else 66 { 67 putchar(ch); 68 } 69 } 70 fclose(pf); 71 72 system("pause"); 73 }
完整代码:
服务器
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<time.h> 4 #include<stdlib.h> 5 #include<Windows.h> 6 7 //设置缓存区大小 8 #define SIZE 4096 9 //最多有多少线程 10 #define MAX_CONNECT 128 11 //一开始有10个线程存在 12 int startthreadnum = 10; 13 //管道名字 14 char pipename[128] = "\\\\.\\Pipe\\cloudpipe"; 15 16 //文件路径 17 #define path "C:\\Program Files\\Apache Software Foundation\\Apache2.2\\cgi-bin\\kaifang.txt" 18 //查询结果存放的路径 19 char randpath[1000] = ""; 20 //全局的二级指针 21 char ** g_pp; 22 //标示有多少行 23 int imax = 15151574; 24 25 //结构体,hpipe存储管道信息,hevent用于给结构体初始化,存放连接管道的信息 26 typedef struct info 27 { 28 HANDLE hthread; 29 HANDLE hpipe; 30 HANDLE hevent; 31 32 }PIPE_ST; 33 34 //创建128个结构体 35 PIPE_ST pipeinst[MAX_CONNECT]; 36 37 //随机生成文件名存放查询的结果 38 void run() 39 { 40 time_t ts; 41 srand((unsigned int)time(&ts)); 42 sprintf(randpath, "C:\\Program Files\\Apache Software Foundation\\Apache2.2\\cgi-bin\\%d.txt", rand()); 43 } 44 45 //载入内存 46 void loadfromfile() 47 { 48 //分配指针数组 49 g_pp = (char **)malloc(sizeof(char*)*imax); 50 //内存清零 51 memset(g_pp, '\0', sizeof(char*)*imax); 52 53 //以读的方式打开文件 54 FILE *pf = fopen(path, "r"); 55 if (pf == NULL) 56 { 57 printf("文件打开失败"); 58 return -1; 59 } 60 else 61 { 62 for (int i = 0; i < imax; i++) 63 { 64 char str[1024] = { 0 }; 65 //按行读取 66 fgets(str, 1024, pf); 67 str[1024 - 1] = '\0'; 68 int strlength = strlen(str); 69 70 //分配内存 71 g_pp[i] = malloc(sizeof(char)*(strlength + 1)); 72 73 //拷贝到分配的内存 74 if (g_pp[i] != NULL) 75 { 76 strcpy(g_pp[i], str); 77 } 78 } 79 fclose(pf);//关闭 80 } 81 } 82 83 //查询 84 void search(char *str,char * randpath) 85 { 86 //写的模式打开 87 FILE *pf = fopen(randpath, "w"); 88 if (g_pp != NULL) 89 { 90 91 for (int i = 0; i < imax; i++) 92 { 93 if (g_pp[i] != NULL) 94 { 95 //查询 96 char *p = strstr(g_pp[i], str); 97 if (p != NULL) 98 { 99 fputs(g_pp[i], pf);//输出到文件 100 } 101 } 102 } 103 } 104 fclose(pf); 105 } 106 107 //线程函数 108 DWORD WINAPI severThread(void *lp) 109 { 110 //读取到的个数 111 DWORD nread = 0; 112 //写入的个数 113 DWORD nwrite = 0; 114 //用于判断IO 115 DWORD dwbyte = 0; 116 //缓存区 117 char szbuf[SIZE] = { 0 }; 118 //获取当前结构体 119 PIPE_ST curpipe = *(PIPE_ST*)lp; 120 //利用event初始化一个结构体 121 OVERLAPPED overlap = { 0, 0, 0, 0, curpipe.hevent }; 122 123 while (1) 124 { 125 //数据清零 126 memset(szbuf, 0, sizeof(szbuf)); 127 //链接管道,信息写入overlap 128 ConnectNamedPipe(curpipe.hpipe, &overlap); 129 //等待连接完成 130 WaitForSingleObject(curpipe.hevent, INFINITE); 131 //检测IO,如果IO错误则退出 132 if (!GetOverlappedResult(curpipe.hpipe, &overlap, &dwbyte, TRUE)) 133 { 134 break; 135 } 136 //读取管道中的数据到szbuf,最多读取SIZE个 137 if (!ReadFile(curpipe.hpipe, szbuf, SIZE, &nread, NULL)) 138 { 139 puts("read fail"); 140 break; 141 } 142 143 char searchstr[100] = { 0 }; 144 //去读查询谁 145 sscanf(szbuf, "%s", searchstr); 146 147 //路径配置 148 run(); 149 //查询 150 search(searchstr, randpath); 151 152 //清零 153 memset(szbuf, 0, sizeof(szbuf)); 154 //把路径写入管道 155 sprintf(szbuf, "%s", randpath); 156 WriteFile(curpipe.hpipe, szbuf, strlen(szbuf), &nwrite, NULL);//写入 157 //断开与管道的连接 158 DisconnectNamedPipe(curpipe.hpipe); 159 } 160 return 0; 161 } 162 163 //初始化结构体并创建线程 164 void start() 165 { 166 for (int i = 0; i < startthreadnum; i++) 167 { 168 //创建管道,如果同名,则操作同一个管道 169 pipeinst[i].hpipe = CreateNamedPipeA( 170 pipename,//管道名称 171 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,//管道读写属性 172 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,//消息模式,读模式,等待模式阻塞 173 10,//最大个数 174 0,//输出缓冲区大小 175 0,//输入缓冲区大小 176 1000,//超时,无限等待 177 NULL); 178 if (pipeinst[i].hpipe == INVALID_HANDLE_VALUE) 179 { 180 printf("\n%d失败", i); 181 return; 182 } 183 //创建事件 184 pipeinst[i].hevent = CreateEventA(NULL, FALSE, FALSE, FALSE);//创建事件 185 //创建线程 186 pipeinst[i].hthread = CreateThread(NULL, 0, severThread, &pipeinst[i], 0, NULL); 187 188 } 189 printf("sever start"); 190 191 } 192 193 //释放内存 194 void end() 195 { 196 for (int i = 0; i < 10;i++) 197 { 198 CloseHandle(pipeinst[i].hthread); 199 CloseHandle(pipeinst[i].hevent); 200 CloseHandle(pipeinst[i].hpipe); 201 } 202 } 203 204 //主函数 205 void main() 206 { 207 //载入内存 208 loadfromfile(); 209 //创建线程 开始查询 210 start(); 211 system("pause"); 212 213 }
客户端
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<time.h> 4 #include<stdlib.h> 5 #include<Windows.h> 6 7 //缓存区大小 8 #define SIZE 4096 9 //管道名字 10 char pipename[128] = "\\\\.\\Pipe\\cloudpipe"; 11 //管道句柄 12 HANDLE m_pipe = NULL; 13 14 //CGI编码格式转换到str中 15 char* change(char *str) 16 { 17 char *tempstr = malloc(strlen(str) + 1); 18 int x = 0, y = 0; 19 char assii_1, assii_2; 20 while (tempstr[x]) 21 { 22 if ((tempstr[x] = str[y]) == '%') 23 { 24 if (str[y + 1] >= 'A') 25 { 26 assii_1 = str[y + 1] - 55; 27 28 } 29 else 30 { 31 assii_1 = str[y + 1] - 48; 32 } 33 if (str[y + 2] >= 'A') 34 { 35 assii_2 = str[y + 2] - 55; 36 } 37 else 38 { 39 assii_2 = str[y + 2] - 48; 40 } 41 tempstr[x] = assii_1 * 16 + assii_2; 42 y += 2; 43 } 44 x++; 45 y++; 46 } 47 tempstr[x] = '\0'; 48 return tempstr; 49 } 50 51 52 void main() 53 { 54 printf("Content-type:text/html\n\n");//换行 55 56 system("ipconfig");//服务器不稳定因素,适当中断 57 58 //获取表单信息,并对信息进行处理 59 char szpost[256] = { 0 }; 60 gets(szpost); 61 printf("%s", szpost); 62 63 char*p1 = strchr(szpost, '&'); 64 if (p1 != NULL) 65 { 66 *p1 = '\0'; 67 } 68 printf("<br>%s", szpost + 5); 69 printf("<br>%s", change(szpost + 5)); 70 71 char *p2 = strchr(p1 + 1, '&'); 72 if (p2 != NULL) 73 { 74 *p2 = '\0'; 75 } 76 printf("<br>%s", p1 + 6); 77 printf("<br>%s", change(p1 + 6)); 78 79 //打开管道 80 m_pipe = CreateFileA(pipename, //名称 81 GENERIC_WRITE | GENERIC_READ,//读写 82 0,//共享属性,1独有 83 NULL,//默认安全属性 84 OPEN_EXISTING,//打开已经存在的 85 FILE_ATTRIBUTE_NORMAL, 86 NULL); 87 88 if (m_pipe == INVALID_HANDLE_VALUE) 89 { 90 printf("失败"); 91 return; 92 } 93 94 int nwrite; 95 int nread; 96 97 char winfo[1024] = { 0 }; 98 //打印数据到winfo中 99 sprintf(winfo, "%s", change(szpost + 5)); 100 101 //写入管道 102 WriteFile(m_pipe, winfo, strlen(winfo), &nwrite, NULL); 103 memset(winfo, 0, sizeof(winfo)); 104 //读取管道 105 ReadFile(m_pipe, winfo, 1024, &nread, NULL); 106 ; 107 //打开文件,并读取 108 FILE *pf = fopen(winfo, "r"); 109 while (!feof(pf)) 110 { 111 char ch = fgetc(pf); 112 if (ch=='\n') 113 { 114 puts("<br>"); 115 } 116 else 117 { 118 putchar(ch); 119 } 120 } 121 fclose(pf); 122 123 system("pause"); 124 }