佛山电商网站制作,南软科技网站开发,手机兼职赚钱正规平台,wordpress网页游戏主题http://www.cnblogs.com/wunaozai/p/3891062.html 接上一小节#xff0c;这次增加另外的两张表#xff0c;用于记录用户是保存那些文件。增加传上来的文件的文件指纹#xff0c;使用MD5表示。 两张表如下定义: 1 create table files(2 fid int,3 filename varchar(64),4 md… http://www.cnblogs.com/wunaozai/p/3891062.html 接上一小节这次增加另外的两张表用于记录用户是保存那些文件。增加传上来的文件的文件指纹使用MD5表示。 两张表如下定义: 1 create table files(2 fid int,3 filename varchar(64),4 md5 varchar(64)5 );6 7 create table relations(8 uid int,9 fid int
10 ); 表与表之间的关系如下: client.cpp 在上一小节基础上增加了一个md5的功能传输给服务器用于作为文件的唯一标识 ... 42 struct File43 {44 int uid;45 char filename[64];46 char md5[64];47 };48 struct FileList49 {50 char list[1024];51 };52 53 void print_time(char *ch);//打印时间54 int file_push(struct Addr addr,struct User user,char *filenames);55 int check_login(struct Addr addr,struct User * user);56 int md5sum(char *filename,unsigned char *md5);57 int file_pull(struct Addr addr,struct User user,char *filenames);58 59 60 int main(int argc,char *argv[])61 {...
131 return 0;
132 }
133
134 //验证成功时返回大于0的uid号码错误返回-1
135 int check_login(struct Addr addr,struct User * user)
136 {...186 }
187
188 int file_push(struct Addr addr,struct User user,char *filenames)
189 {... ...
193 struct File file;//文件指纹
194 int sockfd;
195 FILE *fp;
196 char md5[64];
197 unsigned char md5tmp[64];
198 ... ...220 //计算MD5
221 memset(md5,0,sizeof(md5));
222 md5sum(filenames,md5tmp);
223 printf(计算得到的MD5:);
224 for(int i0;i16;i)
225 {
226 sprintf(md5[i*2],%02X,md5tmp[i]);
227 }
228 printf(%s\n,md5);
229
230 //打开文件
231 if((fpfopen(filenames,rb))NULL)
232 {
233 perror(文件打开失败);
234 exit(-1);
235 }
236 //这里传输控制信号
237 control.controlFILE_PUSH;
238 control.uiduser.uid;
239 if(send(sockfd,(char *)control,sizeof(struct Control),0)0)
240 {
241 perror(控制信号发送失败);
242 exit(-1);
243 }
244 //发送文件指纹
245 strcpy(file.filename,filenames);
246 strcpy(file.md5,md5);
247 file.uiduser.uid;
248 if(send(sockfd,(char *)file,sizeof(struct File),0)0)
249 {
250 perror(文件指纹发送失败);
251 exit(-1);
252 }
253 char buffer[BUFFER_SIZE];
254 bzero(buffer,BUFFER_SIZE);
255 printf(正在传输文件);
256 int len0;
257 //不断的读取文件直到文件结束
258 while((lenfread(buffer,1,BUFFER_SIZE,fp))0)
259 {
260 if(send(sockfd,buffer,len,0)0)
261 {
262 perror(发送数据失败);
263 exit(-1);
264 }
265 bzero(buffer,BUFFER_SIZE);
266 printf(.);//1K打印一个点//如果要实现百分比就要计算文件大小然后再处理即可
267 }
268
269 printf(传输完毕\n);
270 fclose(fp);//关闭文件流
271 close(sockfd);//关闭socket连接
272
273 return 0;
274 }
275
276 int md5sum(char *filename,unsigned char *md5)
277 {
278 MD5_CTX ctx;
279 char buffer[1024];
280 unsigned char outmd[16];
281 int len0;
282 int i;
283 FILE *fpNULL;
284 memset(outmd,0,sizeof(outmd));
285 memset(buffer,0,sizeof(buffer));
286 fpfopen(filename,rb);
287 if(fpNULL)
288 {
289 perror(打开文件失败);
290 }
291 MD5_Init(ctx);
292 while((lenfread(buffer,1,sizeof(buffer),fp))0)
293 {
294 MD5_Update(ctx,buffer,len);
295 memset(buffer,0,sizeof(buffer));
296 }
297 MD5_Final(outmd,ctx);
298 for(i0;i16;i)
299 {
300 md5[i]outmd[i];
301 }
302 fclose(fp);
303 return 0;
304 }
305 server.cpp ... ... 40 struct File41 {42 int uid;43 char filename[64];44 char md5[64];45 };46 struct FileList47 {48 char list[1024];49 };50 51 void print_time(char *ch);//打印时间52 int MAX(int a,int b);53 int mysql_check_login(struct User user);54 int mysql_file_in(struct File file);55 56 int mysql_get_max_fid()57 {58 MYSQL conn;59 MYSQL_RES *res_ptr;60 MYSQL_ROW result_row;61 int res;int row;int column;int mfid;62 char sql[256];63 strcpy(sql,select max(fid) from files;);64 mfid0;65 mysql_init(conn);66 if(mysql_real_connect(conn,localhost,root,,filetranslate,0,NULL,CLIENT_FOUND_ROWS))67 {68 resmysql_query(conn,sql);69 if(res)70 {71 perror(SELECT SQL ERROR!);72 exit(-1);73 }74 else75 {76 res_ptrmysql_store_result(conn);77 if(res_ptr)78 {79 columnmysql_num_fields(res_ptr);80 rowmysql_num_rows(res_ptr)1;81 if(row1)82 {83 ;//没有数据84 }85 else86 {87 result_rowmysql_fetch_row(res_ptr);88 printf(最大的fid是:%s\n,result_row[0]);89 if(result_row[0]NULL)90 mfid0;91 else92 mfidatoi(result_row[0]);93 }94 }95 else96 {97 printf(没有查询到匹配的数据\n);98 }99 }
100 }
101 else
102 {
103 perror(Connect Failed!);
104 exit(-1);
105 }
106 mysql_close(conn);
107 return mfid;
108 }
109
110 int mysql_file_in(struct File file)
111 {
112 int mfid;
113 MYSQL conn;
114 int res;
115 char sql[256];
116 char tmp[32];
117 mfidmysql_get_max_fid()1;
118 printf(获取到的最大fid为:%d\n,mfid);
119 mysql_init(conn);
120 if(mysql_real_connect(conn,localhost,root,,filetranslate,0,NULL,CLIENT_FOUND_ROWS))
121 {
122 //insert into files values(mfid,file.filename,file.md5);
123 //insert into files values(file.uid,mfid);
124 memset(sql,0,sizeof(sql));
125 strcpy(sql,insert into files values();
126 sprintf(tmp,%d,mfid);
127 strcat(sql,tmp);
128 strcat(sql,,);
129 strcat(sql,file.filename);
130 strcat(sql,,);
131 strcat(sql,file.md5);
132 strcat(sql,););
133 printf(插入的sql语句: %s\n,sql);
134 resmysql_query(conn,sql);
135 if(res)
136 printf(Insert Error!\n);
137 else
138 printf(Insert Success!\n);
139
140 memset(sql,0,sizeof(sql));
141 strcpy(sql,insert into relations values();
142 sprintf(tmp,%d,file.uid);
143 strcat(sql,tmp);
144 strcat(sql,,);
145 sprintf(tmp,%d,mfid);
146 strcat(sql,tmp);
147 strcat(sql,););
148 printf(插入的sql语句: %s\n,sql);
149 resmysql_query(conn,sql);
150 if(res)
151 printf(Insert Error!\n);
152 else
153 printf(Insert Success!\n);
154 }
155 else
156 {
157 perror(Connect Failed!);
158 exit(-1);
159 }
160 return 0;
161 }
162
163
164 int main(int argc,char *argv[])
165 {...
201 while(1)
202 {
203 clientfdaccept(sockfd,(struct sockaddr *)client_addr,length);
204 if(clientfd-1)
205 {
206 perror(accept 失败);
207 continue;
208 }
209 printf(%s:%d 连接成功当前所在的ID(fd)号: %d \n,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),clientfd);
210 print_time(ch);
211 printf(加入的时间是:%s\n,ch);
212
213 //来一个连接就创建一个进程进行处理
214 pidfork();
215 if(pid0)
216 {
217 perror(fork error);
218 }
219 else if(pid0)
220 {
221 recv(clientfd,(char *)control,sizeof(struct Control),0);
222 printf(用户 %d 使用命令 %d\n,control.uid,control.control);
223 switch(control.control)
224 {
225 case USER_CHECK_LOGIN:
226 {
227 //身份验证处理... ...239 break;
240 }
241 case FILE_PUSH:
242 {
243 char buffer[BUFFER_SIZE];
244 int data_len;
245 FILE * fpNULL;
246 struct File file;
247 //获取文件指纹
248 recv(clientfd,(char *)file,sizeof(struct File),0);
249 printf(获取到的用户名ID: %d 文件名:%s MD5:%s\n,file.uid,file.filename,file.md5);
250 bzero(buffer,BUFFER_SIZE);
251 if((fpfopen(data,wb))NULL)
252 {
253 perror(文件打开失败);
254 exit(-1);
255 }
256 //循环接收数据
257 int size0;//表示有多少个块
258 while(data_lenrecv(clientfd,buffer,BUFFER_SIZE,0))
259 {... ...278 }
279 if(size0)
280 {
281 printf(\n%s:%d的文件传送完毕\n,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
282 //如果文件传输成功那么就可以写入数据库了
283 mysql_file_in(file);
284 }
285 else
286 printf(\n%s:%d的文件传送失败\n,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
287 fclose(fp);
288 rename(data,file.md5);//这里可以修改文件的名字
289 exit(0);
290 break;
291 }
292 case FILE_PULL:
293 {
294 break;
295 }
296 case FILE_LIST:
297 {
298 break;
299 }
300 case FILE_DELECT:
301 {
302 break;
303 }
304 default:
305 {
306 break;
307 }
308 }
309 close(clientfd);//短连接结束
310 exit(0);//退出子进程
311 }
312 }
313
314 return 0;
315 }
316
317
318 //函数定义
319 int mysql_check_login(struct User user)
320 {... ...377 }
378 ... ... 上面已经介绍了如何计算MD5值并写入数据库接下来要做的事就是如何判断要上传的文件是否在服务器中已经存在如果存在就可以不用上传而是在relations表中记录写入uid-fid关系这样就可以实现网盘的秒传功能了。而如何区分文件是否相同我这里使用的是以MD5作为文件指纹。话说秒传功能也不过如此吧。所以现在应该知道为什么有的文件可以秒传有的不可以了吧。关于具体的解释可以参考杜鑫先生在知乎中的回到。传送门在第一小节中有。 已加入验证和秒传功能的网盘程序 client.cpp修改如下 ... ...
188 int file_push(struct Addr addr,struct User user,char *filenames)
189 {... ...238 //发送文件指纹
239 strcpy(file.filename,filenames);
240 strcpy(file.md5,md5);
241 file.uiduser.uid;
242 if(send(sockfd,(char *)file,sizeof(struct File),0)0)
243 {
244 perror(文件指纹发送失败);
245 exit(-1);
246 }
247 char ch[64];
248 if(recv(sockfd,ch,64,0)0)
249 {
250 perror(error);
251 }
252 if(ch[0]y)//表示已经存在
253 {
254 printf(该文件在服务器中存在正使用秒传功能。\n);
255 printf(传输完毕\n);
256 return 0;
257 }
258 //打开文件
259 if((fpfopen(filenames,rb))NULL)
260 {
261 perror(文件打开失败);
262 exit(-1);
263 }
264 char buffer[BUFFER_SIZE];
265 bzero(buffer,BUFFER_SIZE);
266 printf(正在传输文件);
267 int len0;
268 //不断的读取文件直到文件结束
269 while((lenfread(buffer,1,BUFFER_SIZE,fp))0)
270 {
271 if(send(sockfd,buffer,len,0)0)
272 {
273 perror(发送数据失败);
274 exit(-1);
275 }
276 bzero(buffer,BUFFER_SIZE);
277 printf(.);//1K打印一个点//如果要实现百分比就要计算文件大小然后再处理即可
278 }
279
280 printf(传输完毕\n);
281 fclose(fp);//关闭文件流
282 close(sockfd);//关闭socket连接
283
284 return 0;
285 }
286 ... ... server.cpp修改如下 ......61 int main(int argc,char *argv[])62 {......
110 //来一个连接就创建一个进程进行处理
111 pidfork();
112 if(pid0)
113 {
114 perror(fork error);
115 }
116 else if(pid0)
117 {
118 recv(clientfd,(char *)control,sizeof(struct Control),0);
119 printf(用户 %d 使用命令 %d\n,control.uid,control.control);
120 switch(control.control)
121 {
122 case USER_CHECK_LOGIN:... ...138 case FILE_PUSH:
139 {
140 char buffer[BUFFER_SIZE];
141 int data_len;
142 FILE * fpNULL;
143 struct File file;
144 //获取文件指纹
145 recv(clientfd,(char *)file,sizeof(struct File),0);
146 printf(获取到的用户名ID: %d 文件名:%s MD5:%s\n,file.uid,file.filename,file.md5);
147 //对文件进行验证如果文件已经存在就不用进行接收了
148 int tmysql_check_md5(file);
149 char ch[64]{0};
150 printf(t%d\n,t);
151 if(t!0)
152 {
153 printf(该文件存在,使用秒传功能\n);
154 strcpy(ch,yes);
155 send(clientfd,ch,64,0);
156 mysql_file_in(file.uid,t);
157 continue;
158 }
159 strcpy(ch,no);
160 send(clientfd,ch,64,0);
161 printf(md5验证后得到的fid:%d\n,t);
162 bzero(buffer,BUFFER_SIZE);... ... ...202 break;
203 }... ...220 }
221 close(clientfd);//短连接结束
222 exit(0);//退出子进程
223 }
224 }
225
226 return 0;
227 }
228
229
230 //函数定义
231 int mysql_check_md5(struct File file)
232 {
233 MYSQL conn;
234 MYSQL_RES * res_ptr;
235 MYSQL_ROW result_row;
236 int res;int row;int column;int value0;
237 char sql[256]{0};
238 strcpy(sql,select fid from files where md5);
239 strcat(sql,file.md5);
240 strcat(sql,;);
241 printf(查询的sql:%s\n,sql);
242
243 mysql_init(conn);
244 if(mysql_real_connect(conn,localhost,root,,filetranslate,0,NULL,CLIENT_FOUND_ROWS))
245 {
246 resmysql_query(conn,sql);
247 if(res)
248 {
249 perror(Select Sql Error!);
250 exit(-1);
251 }
252 else
253 {
254 res_ptrmysql_store_result(conn);
255 if(res_ptr)
256 {
257 columnmysql_num_fields(res_ptr);
258 rowmysql_num_rows(res_ptr)1;
259 if(row1)
260 {
261 ;
262 }
263 else
264 {
265 result_rowmysql_fetch_row(res_ptr);
266 valueatoi(result_row[0]);
267 }
268 }
269 else
270 {
271 printf(没有查询到匹配的数据\n);
272 }
273 }
274 }
275 else
276 {
277 perror(Connect Failed!);
278 exit(-1);
279 }
280 mysql_close(conn);
281 return value;//返回fid
282 }
283
284 int mysql_file_in(int uid,int fid)
285 {
286 MYSQL conn;
287 int res;
288 char sql[256];
289 char tmp[32];
290 mysql_init(conn);
291 if(mysql_real_connect(conn,localhost,root,,filetranslate,0,NULL,CLIENT_FOUND_ROWS))
292 {
293 //insert into files values(uid,fid);
294 memset(sql,0,sizeof(sql));
295 strcpy(sql,insert into relations values();
296 sprintf(tmp,%d,uid);
297 strcat(sql,tmp);
298 strcat(sql,,);
299 sprintf(tmp,%d,fid);
300 strcat(sql,tmp);
301 strcat(sql,););
302 printf(插入的sql语句: %s\n,sql);
303 resmysql_query(conn,sql);
304 if(res)
305 printf(Insert Error!\n);
306 else
307 printf(Insert Success!\n);
308 }
309 else
310 {
311 perror(Connect Failed!);
312 exit(-1);
313 }
314 return 0;
315 }
316 ... ... 运行时的截图 由上图可以看出如果该文件在服务器中存在的话那么下一次上传同一个文件的话就会跳过上传的步骤而是把数据库中的标识号给用户uid即可。具体关系可以看下面数据库数据。 好了现在的上传功能已经很完善了。下一节将实现下载功能了。 本文地址: http://www.cnblogs.com/wunaozai/p/3891062.html