這一節将不會介紹太多的技術的問題,這節主要是搭建一個小小的架構,為了友善接下來的繼續編寫擴充程式。本次會在上一小節的基礎上加上一個身份驗證的功能。
因為網盤程式不像聊天程式,網盤是屬于主動向伺服器拉取資訊,而聊天程式有可能要被動擷取資訊,是以為了減輕伺服器壓力,每次要向伺服器擷取服務就建立一個短連接配接,而不像聊天程式一樣的長連接配接,微信的公衆平台,輸入指令擷取服務,就是這個樣子了。具體看一下代碼就知道了。
還有為了友善處理,我增加了一個控制信号,這個控制信号在以前的聊天程式中講到過,但是當時為了簡單就沒有實作,現在就簡單實作一些,友善以後可以參考。
還有就是這次的網盤程式我将盡量實作下面的這些功能:
(1) file push filename //使用者上傳檔案到伺服器上
(2) file pull filename //使用者下載下傳檔案到本地上
(3) file list //列出使用者在伺服器中的所有檔案
(4) file sendto filename username //共享檔案給其他使用者
(5) file delete filename //删除伺服器中的檔案
(6) 使用者登入,自動完成
本次資料庫名為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
本文位址: http://www.cnblogs.com/wunaozai/p/3887728.html
作者:無腦仔的小明 出處:http://www.cnblogs.com/wunaozai/ 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。 如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。有需要溝通的,可以站内私信,文章留言,或者關注“無腦仔的小明”公衆号私信我。一定盡力回答。 |