這一節將不會介紹太多的技術的問題,這節主要是搭建一個小小的框架,爲了方便接下來的繼續編寫擴展程序。本次會在上一小節的基礎上加上一個身份驗證的功能。html
由於網盤程序不像聊天程序,網盤是屬於主動向服務器拉取信息,而聊天程序有可能要被動獲取信息,因此爲了減輕服務器壓力,每次要向服務器獲取服務就創建一個短鏈接,而不像聊天程序同樣的長鏈接,微信的公衆平臺,輸入指令獲取服務,就是這個樣子了。具體看一下代碼就知道了。mysql
還有爲了方便處理,我增長了一個控制信號,這個控制信號在之前的聊天程序中講到過,可是當時爲了簡單就沒有實現,如今就簡單實現一些,方便之後能夠參考。sql
還有就是此次的網盤程序我將盡可能實現下面的這些功能:數據庫
(1) file push filename //用戶上傳文件到服務器上服務器
(2) file pull filename //用戶下載文件到本地上微信
(3) file list //列出用戶在服務器中的全部文件框架
(4) file sendto filename username //共享文件給其餘用戶socket
(5) file delete filename //刪除服務器中的文件函數
(6) 用戶登陸,自動完成fetch
本次數據庫名爲filetranslate,目前有表user
1 create table user 2 ( 3 uid int; 4 username varchar(64); 5 password varchar(64); 6 );
修改後的client.cpp
1 #include <netinet/in.h> // sockaddr_in 2 #include <sys/types.h> //socket 3 #include <sys/socket.h> //socket 4 #include <netdb.h> //gethostbyname 5 #include <unistd.h> //close 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <time.h> 10 #include <arpa/inet.h> //inet_addr 11 12 #define SERVVER_PORT 12138 13 #define LISTEN_QUEUE 20 14 #define BUFFER_SIZE 1024 15 16 //傳輸控制信號宏定義 17 //struct Control中control的取值 18 #define USER_CHECK_LOGIN 1 19 #define FILE_PUSH 2 20 #define FILE_PULL 3 21 #define FILE_LIST 4 22 #define FILE_SENDTO 5 23 #define FILE_DELECT 6 24 25 struct Addr 26 { 27 char host[64]; 28 int port; 29 }; 30 struct User 31 { 32 int uid; 33 char username[64]; 34 char password[64]; 35 }; 36 struct Control 37 { 38 int uid; 39 int control; 40 }; 41 42 void print_time(char *ch);//打印時間 43 int file_push(struct Addr addr,struct User user,char *filenames); 44 int check_login(struct Addr addr,struct User * user); 45 46 47 int main(int argc,char *argv[]) 48 { 49 char orderbuf[BUFFER_SIZE]; 50 struct Addr addr; 51 char arg1[32],arg2[32],arg3[32],arg4[32]; 52 struct User user; 53 54 if(argc!=5) 55 { 56 perror("usage: ./client [serverhost] [serverport] [username] [password]"); 57 exit(-1); 58 } 59 strcpy(addr.host,argv[1]); 60 addr.port=atoi(argv[2]); 61 strcpy(user.username,argv[3]); 62 strcpy(user.password,argv[4]); 63 int uid=check_login(addr,&user); 64 if(uid<=0) 65 { 66 perror("用戶驗證失敗"); 67 exit(-1); 68 } 69 printf("驗證登錄成功\n"); 70 while(1) 71 { 72 printf("\n請輸入操做指令:"); 73 fgets(orderbuf,BUFFER_SIZE,stdin); 74 memset(arg1,0,sizeof(arg1)); 75 memset(arg2,0,sizeof(arg2)); 76 memset(arg3,0,sizeof(arg3)); 77 memset(arg4,0,sizeof(arg4)); 78 sscanf(orderbuf,"%s%s%s%s",arg1,arg2,arg3,arg4); 79 if(strcmp(arg1,"file")==0) 80 { 81 if(strcmp(arg2,"push")==0) 82 { 83 strcpy(orderbuf,arg3); 84 file_push(addr,user,orderbuf); 85 } 86 else if(strcmp(arg2,"pull")==0) 87 { 88 ; 89 } 90 else if(strcmp(arg2,"list")==0) 91 { 92 ; 93 } 94 else if(strcmp(arg2,"sendto")==0) 95 { 96 ; 97 } 98 else if(strcmp(arg2,"delect")==0) 99 { 100 ; 101 } 102 else 103 { 104 printf("該命令不支持\n"); 105 } 106 } 107 else 108 { 109 printf("該命令不支持\n"); 110 } 111 } 112 113 114 return 0; 115 } 116 117 //驗證成功時返回大於0的uid號碼,錯誤返回-1 118 int check_login(struct Addr addr,struct User * user) 119 { 120 struct sockaddr_in servAddr; 121 struct hostent * host; 122 struct Control control; 123 int sockfd; 124 125 host=gethostbyname(addr.host); 126 servAddr.sin_family=AF_INET; 127 servAddr.sin_addr=*((struct in_addr *)host->h_addr); 128 //servAddr.sin_addr.s_addr=inet_addr("127.0.0.1"); 129 servAddr.sin_port=htons(addr.port); 130 if(host==NULL) 131 { 132 perror("獲取IP地址失敗"); 133 exit(-1); 134 } 135 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 136 { 137 perror("socket建立失敗"); 138 exit(-1); 139 } 140 if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1) 141 { 142 perror("connect 失敗"); 143 exit(-1); 144 } 145 146 control.control=USER_CHECK_LOGIN; 147 control.uid=0; 148 if(send(sockfd,(char *)&control,sizeof(struct Control),0)<0) 149 { 150 perror("發送數據失敗"); 151 exit(-1); 152 } 153 154 if(send(sockfd,(char *)user,sizeof(struct User),0)<0) 155 { 156 perror("發送數據失敗"); 157 exit(-1); 158 } 159 bzero(user,sizeof(struct User)); 160 if(recv(sockfd,(char *)user,sizeof(struct User),0)<0) 161 { 162 perror("接收數據失敗"); 163 exit(-1); 164 } 165 printf("獲取後用戶名:%s 密碼:%s ID號:%d\n",user->username,user->password,user->uid); 166 167 close(sockfd);//關閉socket鏈接 168 return user->uid; 169 } 170 171 int file_push(struct Addr addr,struct User user,char *filenames) 172 { 173 struct sockaddr_in servAddr; 174 struct hostent * host; 175 struct Control control; 176 int sockfd; 177 FILE *fp; 178 179 host=gethostbyname(addr.host); 180 servAddr.sin_family=AF_INET; 181 servAddr.sin_addr=*((struct in_addr *)host->h_addr); 182 //servAddr.sin_addr.s_addr=inet_addr("127.0.0.1"); 183 servAddr.sin_port=htons(addr.port); 184 if(host==NULL) 185 { 186 perror("獲取IP地址失敗"); 187 exit(-1); 188 } 189 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 190 { 191 perror("socket建立失敗"); 192 exit(-1); 193 } 194 195 if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1) 196 { 197 perror("connect 失敗"); 198 exit(-1); 199 } 200 201 //打開文件 202 if((fp=fopen(filenames,"rb"))==NULL) 203 { 204 perror("文件打開失敗"); 205 exit(-1); 206 } 207 //這裏傳輸控制信號 208 control.control=FILE_PUSH; 209 control.uid=user.uid; 210 if(send(sockfd,(char *)&control,sizeof(struct Control),0)<0) 211 { 212 perror("控制信號發送失敗"); 213 exit(-1); 214 } 215 char buffer[BUFFER_SIZE]; 216 bzero(buffer,BUFFER_SIZE); 217 printf("正在傳輸文件"); 218 int len=0; 219 //不斷的讀取文件直到文件結束 220 while((len=fread(buffer,1,BUFFER_SIZE,fp))>0) 221 { 222 if(send(sockfd,buffer,len,0)<0) 223 { 224 perror("發送數據失敗"); 225 exit(-1); 226 } 227 bzero(buffer,BUFFER_SIZE); 228 printf(".");//1K打印一個點//若是要實現百分比,就要計算文件大小,而後再處理便可 229 } 230 231 printf("傳輸完畢\n"); 232 fclose(fp);//關閉文件流 233 close(sockfd);//關閉socket鏈接 234 235 return 0; 236 } 237 238 void print_time(char *ch) 239 { 240 time_t now; 241 struct tm * stm; 242 time(&now); 243 stm=localtime(&now); 244 sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec); 245 return ; 246 }
下面這個是server.cpp
1 #include <netinet/in.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <sys/select.h> 5 #include <netdb.h> 6 #include <stdlib.h> 7 #include <time.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <stdio.h> 11 #include <arpa/inet.h> //inet_ntoa 12 #include <mysql.h> 13 14 #define SERVER_PORT 12138 15 #define LISTEN_QUEUE 20 16 #define BACKLOG 200 17 #define BUFFER_SIZE 1024 18 19 //傳輸控制信號宏定義 20 //struct Control中control的取值 21 #define USER_CHECK_LOGIN 1 22 #define FILE_PUSH 2 23 #define FILE_PULL 3 24 #define FILE_LIST 4 25 #define FILE_SENDTO 5 26 #define FILE_DELECT 6 27 28 struct User 29 { 30 int uid; 31 char username[64]; 32 char password[64]; 33 }; 34 35 struct Control 36 { 37 int uid; 38 int control; 39 }; 40 41 void print_time(char *ch);//打印時間 42 int MAX(int a,int b); 43 int mysql_check_login(struct User user); 44 45 46 int main(int argc,char *argv[]) 47 { 48 struct sockaddr_in server_addr; 49 struct sockaddr_in client_addr; 50 struct User user; 51 struct Control control; 52 char ch[64]; 53 int clientfd; 54 pid_t pid; 55 socklen_t length; 56 bzero(&server_addr,sizeof(server_addr)); 57 server_addr.sin_family=AF_INET; 58 server_addr.sin_addr.s_addr=htons(INADDR_ANY); 59 server_addr.sin_port=htons(SERVER_PORT); 60 61 //建立套接字 62 int sockfd=socket(AF_INET,SOCK_STREAM,0); 63 if(sockfd<0) 64 { 65 perror("建立套接字失敗"); 66 exit(-1); 67 } 68 69 if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1) 70 { 71 perror("bind 失敗"); 72 exit(-1); 73 } 74 75 if(listen(sockfd,LISTEN_QUEUE)) 76 { 77 perror("listen 失敗"); 78 exit(-1); 79 } 80 81 length=sizeof(struct sockaddr); 82 83 while(1) 84 { 85 clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&length); 86 if(clientfd==-1) 87 { 88 perror("accept 失敗"); 89 continue; 90 } 91 printf(">>>>>%s:%d 鏈接成功,當前所在的ID(fd)號: %d \n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),clientfd); 92 print_time(ch); 93 printf("加入的時間是:%s\n",ch); 94 95 //來一個鏈接就建立一個進程進行處理 96 pid=fork(); 97 if(pid<0) 98 { 99 perror("fork error"); 100 } 101 else if(pid==0) 102 { 103 recv(clientfd,(char *)&control,sizeof(struct Control),0); 104 printf("用戶 %d 使用命令 %d\n",control.uid,control.control); 105 switch(control.control) 106 { 107 case USER_CHECK_LOGIN: 108 { 109 //身份驗證處理 110 recv(clientfd,(char *)&user,sizeof(struct User),0); 111 printf("客戶端發送過來的用戶名是:%s,密碼:%s\n",user.username,user.password); 112 if((user.uid=mysql_check_login(user))>0) 113 { 114 printf("驗證成功\n"); 115 } 116 else 117 { 118 printf("驗證失敗\n"); 119 } 120 send(clientfd,(char *)&user,sizeof(struct User),0); 121 break; 122 } 123 case FILE_PUSH: 124 { 125 char buffer[BUFFER_SIZE]; 126 int data_len; 127 FILE * fp=NULL; 128 bzero(buffer,BUFFER_SIZE); 129 if((fp=fopen("data","wb"))==NULL) 130 { 131 perror("文件打開失敗"); 132 exit(-1); 133 } 134 //循環接收數據 135 int size=0;//表示有多少個塊 136 while(data_len=recv(clientfd,buffer,BUFFER_SIZE,0)) 137 { 138 if(data_len<0) 139 { 140 perror("接收數據錯誤"); 141 exit(-1); 142 } 143 size++; 144 if(size==1) 145 printf("正在接收來自%s:%d的文件\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); 146 else 147 printf("."); 148 //向文件中寫入 149 int write_len=fwrite(buffer,sizeof(char),data_len,fp); 150 if(write_len>data_len) 151 { 152 perror("寫入數據錯誤"); 153 exit(-1); 154 } 155 bzero(buffer,BUFFER_SIZE); 156 } 157 if(size>0) 158 printf("\n%s:%d的文件傳送完畢\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); 159 else 160 printf("\n%s:%d的文件傳送失敗\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port)); 161 fclose(fp); 162 //rename("data","asdf");//這裏能夠修改文件的名字 163 exit(0); 164 break; 165 } 166 case FILE_PULL: 167 { 168 break; 169 } 170 case FILE_LIST: 171 { 172 break; 173 } 174 case FILE_DELECT: 175 { 176 break; 177 } 178 default: 179 { 180 break; 181 } 182 } 183 close(clientfd);//短鏈接結束 184 exit(0);//退出子進程 185 } 186 } 187 188 return 0; 189 } 190 191 192 //函數定義 193 int mysql_check_login(struct User user) 194 { 195 MYSQL conn; 196 MYSQL_RES *res_ptr; 197 MYSQL_ROW result_row; 198 int res; 199 int row; 200 int column; 201 int uid; 202 char sql[256]={0}; 203 strcpy(sql,"select uid from users where username=\""); 204 strcat(sql,user.username); 205 strcat(sql,"\" and password=\""); 206 strcat(sql,user.password); 207 strcat(sql,"\";"); 208 printf("查詢的sql:%s\n",sql); 209 uid=-1; 210 mysql_init(&conn); 211 if(mysql_real_connect(&conn,"localhost","root","","filetranslate",0,NULL,CLIENT_FOUND_ROWS)) 212 { 213 res=mysql_query(&conn,sql); 214 if(res) 215 { 216 perror("Select SQL ERROR!"); 217 exit(-1); 218 } 219 else 220 { 221 res_ptr=mysql_store_result(&conn); 222 if(res_ptr) 223 { 224 column=mysql_num_fields(res_ptr);//獲取列數 225 row=mysql_num_rows(res_ptr)+1;//獲取行數,加1表示還有第一行字段名 226 if(row<=1) 227 { 228 ;//驗證失敗 229 } 230 else 231 { 232 //這裏先假定username是惟一 233 result_row=mysql_fetch_row(res_ptr); 234 printf("獲取到的uid是:%s\n",result_row[0]); 235 uid=atoi(result_row[0]); 236 } 237 } 238 else 239 { 240 printf("沒有查詢到匹配的數據\n"); 241 } 242 } 243 } 244 else 245 { 246 perror("Connect Failed!\n"); 247 exit(-1); 248 } 249 mysql_close(&conn); 250 return uid; 251 } 252 253 void print_time(char *ch) 254 { 255 time_t now; 256 struct tm * stm; 257 time(&now); 258 stm=localtime(&now); 259 sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec); 260 return ; 261 } 262 263 int MAX(int a,int b) 264 { 265 if(a>b) 266 return a; 267 return b; 268 }
下面給張運行時的截圖
關於c語言調用mysql: http://www.cnblogs.com/wunaozai/p/3876134.html