├── .gitignore ├── README.md ├── client ├── client.c ├── func.h ├── makefile ├── send_file.c └── send_n.c ├── conf └── serverconf.ini ├── login_password.sql └── server ├── child.c ├── func.h ├── main.c ├── makefile ├── mysql_api.c ├── send_fd.c ├── send_file.c └── send_n.c /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixuage/LinuxC_server_mysql_client/6ab1e9baacec171db6ab345aae88d149acf7da3a/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixuage/LinuxC_server_mysql_client/6ab1e9baacec171db6ab345aae88d149acf7da3a/README.md -------------------------------------------------------------------------------- /client/client.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | int sfd; 3 | void sigfunc(int signalnum){ //捕获ctrl+c 信号作为退出机制 4 | train t; 5 | memset(&t,0,sizeof(t)); 6 | t.len=0; //只传递0号命令 7 | send_n(sfd,(char*)&t,sizeof(int)); 8 | close(sfd); 9 | kill(getpid(),SIGKILL); 10 | } 11 | 12 | void judge(ptrain pt,char* buf1,char* buf2){ //输入命令的字符串切割 13 | strcpy(buf1,pt->buf); 14 | strcpy(buf2,pt->buf); 15 | for(int i=0;i0) //只有最后一次结束时发送len=0 的数据包 52 | { 53 | memset(buf,0,sizeof(buf)); 54 | recv_n(sfd,buf,len); 55 | write(fd,buf,len); 56 | 57 | if(l>=check){ 58 | printf("Now Data %8.4f%s\r",(double)l*100/big,"%"); 59 | fflush(stdout); 60 | check +=big/10; 61 | } 62 | }else{ 63 | printf("Now Data %8.4f%s\n",(double)l*100/big,"%"); 64 | printf("load down ok\n"); 65 | break; 66 | } 67 | } 68 | close(fd); 69 | return 0; 70 | } 71 | int judgefile_exit(char *filename){ //判断文件名称是否存在 72 | DIR *dir; 73 | dir=opendir(getcwd(NULL,0)); 74 | struct dirent *entry; 75 | struct stat statbuf; 76 | int flag=-1; //默认文件名称不存在 77 | while((entry=readdir(dir))!=NULL) { 78 | memset(&statbuf,0,sizeof(statbuf)); 79 | stat(entry->d_name,&statbuf); 80 | if(S_ISREG(statbuf.st_mode)){ 81 | if(!strcmp(filename,entry->d_name)) //文件名称已存在 82 | flag=statbuf.st_size; //返回文件大小 83 | } 84 | } 85 | closedir(dir); 86 | return flag; 87 | } 88 | int recivefile_formserver_again(int sfd,char *filename,int need_seek){ 89 | 90 | int len; 91 | char buf[1000]={0}; 92 | recv_n(sfd,(char *)&len,sizeof(len)); 93 | recv_n(sfd,buf,len); //第一次传递文件名称,保存到buf中 94 | int fd=open(buf,O_CREAT|O_WRONLY|O_APPEND,0666); //将server 文件保存到client端,以追加形式写入数据 95 | if(-1==fd) 96 | { 97 | perror("open"); 98 | return -1; 99 | } 100 | //第二次接受文件长度的数据包 101 | recv_n(sfd,(char*)&len,sizeof(len)); 102 | long big; 103 | recv_n(sfd,(char*)&big,sizeof(len)); 104 | printf("file big=%ld\n",big); 105 | 106 | //lseek(fd,need_seek,SEEK_SET); //移动读写指针 107 | 108 | long check=need_seek; 109 | long l=need_seek; //文件长度初始值为 need_seek 110 | while(1) 111 | { 112 | recv_n(sfd,(char *)&len,sizeof(int));//接火车头 113 | l=l+len; 114 | if(len>0) //只有最后一次结束时发送len=0 的数据包 115 | { 116 | memset(buf,0,sizeof(buf)); 117 | recv_n(sfd,buf,len); 118 | write(fd,buf,len); 119 | 120 | if(l>=check){ 121 | printf("Now Data %8.4f%s\r",(double)l*100/big,"%"); 122 | fflush(stdout); 123 | check +=big/10; 124 | } 125 | }else{ 126 | printf("Now Data %8.4f%s\n",(double)l*100/big,"%"); 127 | printf("load down ok--最终文件大小为 %ld\n",l); 128 | break; 129 | } 130 | } 131 | close(fd); 132 | return 0; 133 | } 134 | int main(int argc,char* argv[]) 135 | { 136 | if(argc!=3) 137 | { 138 | printf("error args\n"); 139 | return -1; 140 | } 141 | //int sfd; 142 | sfd=socket(AF_INET,SOCK_STREAM,0); 143 | if(-1==sfd) 144 | { 145 | perror("socket"); 146 | return -1; 147 | } 148 | struct sockaddr_in ser; 149 | memset(&ser,0,sizeof(ser)); 150 | ser.sin_family=AF_INET; 151 | ser.sin_port=htons(atoi(argv[2])); 152 | ser.sin_addr.s_addr=inet_addr(argv[1]); 153 | int ret; 154 | ret=connect(sfd,(struct sockaddr*)&ser,sizeof(ser)); 155 | if(-1==ret) 156 | { 157 | perror("connect"); 158 | return -1; 159 | } 160 | 161 | signal(SIGINT,sigfunc); //异步捕获SIG_INT 162 | 163 | while(1){ 164 | // return 1 登陆成功 return 0注册完成 return -1 登录失败 165 | if(judge_login_singup()>0) {printf("login success! welcome!\n");break;} //注册 or 登陆 166 | } 167 | 168 | train t; 169 | int ret_length; 170 | char buf1[100]={0}; //保存命令 171 | char buf2[100]={0}; //保存命令后面的参数 172 | while(1){ 173 | memset(&t,0,sizeof(t)); 174 | ret_length=read(STDIN_FILENO,t.buf,sizeof(t.buf)); 175 | if(ret_length>0) { 176 | t.buf[strlen(t.buf)-1]='\0'; //删除字符串末尾换行符 177 | memset(buf1,0,sizeof(buf1)); 178 | memset(buf2,0,sizeof(buf2)); 179 | judge(&t,buf1,buf2); 180 | //printf("buf1 %s buf2 %s\n",buf1,buf2); 181 | if(!strcmp(buf1,"cd")){ 182 | t.len=1; 183 | send_n(sfd,(char*)&t,sizeof(int)); 184 | strcpy(t.buf,buf2); //传递cd命令内容 185 | t.len=strlen(t.buf); 186 | send_n(sfd,(char*)&t,sizeof(int)+t.len); 187 | } 188 | else if(!strcmp(buf1,"ls")){ 189 | t.len=2; //只传递ls命令 190 | send_n(sfd,(char*)&t,sizeof(int)); 191 | } 192 | else if(!strcmp(buf1,"puts")){ 193 | printf("uploadfile=%s\n",buf2); 194 | t.len=3; 195 | send_n(sfd,(char*)&t,sizeof(int)); 196 | send_data(sfd,buf2); //上传文件到服务器 197 | printf("puts file ok\n"); 198 | } 199 | else if(!strcmp(buf1,"gets")){ 200 | int exit=judgefile_exit(buf2); //判断文件是否已存在进行断点续传 201 | 202 | if(exit>0){ //文件名称已存在 203 | printf("文件名称已经存在,大小是 %d\n",exit); 204 | t.len=44; 205 | send_n(sfd,(char*)&t,sizeof(int)); //发送44号命令,相当于断点续传命令 206 | strcpy(t.buf,buf2); //发送文件名称 207 | t.len=strlen(t.buf); 208 | send_n(sfd,(char*)&t,sizeof(int)+t.len); 209 | 210 | //发送已存在的文件大小 211 | t.len=exit; 212 | send_n(sfd,(char*)&t,sizeof(int)); 213 | printf("已存在大小 %d\n",exit); 214 | 215 | recivefile_formserver_again(sfd,buf2,exit); //文件再次接收 216 | 217 | } 218 | else if(exit<0){ //不存在此文件名称 219 | t.len=4; 220 | send_n(sfd,(char*)&t,sizeof(int)); 221 | strcpy(t.buf,buf2); //传递gets命令中文件名称 222 | t.len=strlen(t.buf); 223 | send_n(sfd,(char*)&t,sizeof(int)+t.len); 224 | recivefile_formserver(sfd); //文件接收 225 | } 226 | } 227 | else if(!strcmp(buf1,"remove")){ 228 | t.len=5; 229 | send_n(sfd,(char*)&t,sizeof(int)); 230 | strcpy(t.buf,buf2); //传递命令中文件名称 231 | t.len=strlen(t.buf); 232 | send_n(sfd,(char*)&t,sizeof(int)+t.len); 233 | } 234 | else if(!strcmp(buf1,"pwd")){ 235 | t.len=6; 236 | send_n(sfd,(char*)&t,sizeof(int)); 237 | } 238 | else { 239 | printf("please input right command\n"); 240 | } 241 | } 242 | } 243 | 244 | close(sfd); 245 | return 0; 246 | } 247 | int judge_login_singup(){ 248 | // 登陆成功返回1 登录失败返回-1 249 | char judge_check[5]={0}; 250 | int check=0; 251 | int login_num=111; 252 | int signup_num=222; 253 | printf("login or signup? (1/2)\n"); 254 | int z=read(STDIN_FILENO,&judge_check,sizeof(judge_check)); //把换行符去掉!!!!! 255 | judge_check[strlen(judge_check)-1]='\0'; 256 | check=atoi(judge_check); 257 | if(z<=0) {printf("error\n"); return -1;} 258 | if(check==1) { 259 | send_n(sfd,(char*)&login_num,sizeof(int)); 260 | return(client_login()); 261 | } 262 | else if(check==2) { 263 | send_n(sfd,(char*)&signup_num,sizeof(int)); 264 | client_signup(); 265 | return 0; 266 | } 267 | else return -1; 268 | } 269 | int client_login(){ 270 | int len; 271 | char usernamebuf[100]; 272 | char passwordbuf[100]; 273 | char saltbuf[100]; 274 | memset(usernamebuf,0,sizeof(usernamebuf)); 275 | memset(passwordbuf,0,sizeof(passwordbuf)); 276 | memset(saltbuf,0,sizeof(saltbuf)); 277 | 278 | train t; 279 | printf("login username:\n"); 280 | read(STDIN_FILENO,usernamebuf,sizeof(usernamebuf)); 281 | usernamebuf[strlen(usernamebuf)-1]='\0'; //去掉换行符 282 | t.len=strlen(usernamebuf); 283 | strcpy(t.buf,usernamebuf); 284 | send_n(sfd,(char*)&t,sizeof(int)+t.len); //向server发送username 285 | 286 | recv_n(sfd,(char *)&len,sizeof(len)); 287 | if(len>0) recv_n(sfd,saltbuf,len); //保存salt值 288 | if(len==0) { 289 | printf("loginuser not exit!\n"); //server 不存在username 290 | return -1; 291 | } 292 | printf("login password:\n"); 293 | read(STDIN_FILENO,passwordbuf,sizeof(passwordbuf)); 294 | passwordbuf[strlen(passwordbuf)-1]='\0'; 295 | char *encrypted_password=crypt(passwordbuf,saltbuf); 296 | 297 | t.len=strlen(encrypted_password); 298 | strcpy(t.buf,encrypted_password); 299 | send_n(sfd,(char*)&t,sizeof(int)+t.len); //向server发送密文密码 300 | 301 | recv_n(sfd,(char *)&len,sizeof(len)); //获取匹配结果 302 | if(len<0) { printf("Permission deny\n");return -1;} //递归的话会发生 段错误 303 | else if(len>=0) {printf("Permission ok\n"); return 1;} 304 | } 305 | 306 | void get_rand_str(char* saltbuf){ 307 | char s[10]={0}; //获取随机生成的字符串 308 | int num=8; 309 | char *str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; //定义随机生成字符串表 310 | int i,lstr; 311 | char ss[2] = {0}; 312 | lstr = strlen(str); 313 | srand((unsigned int)time((time_t *)NULL));//使用系统时间来初始化随机数发生器 314 | for(i = 0; i < num; i++){ 315 | sprintf(ss,"%c",str[(rand()%lstr)]); //rand()%lstr 316 | strcat(s,ss); //将随机生成的字符串连接到指定数组后面,strcat在dest末尾先覆盖再添加'\0' 317 | } 318 | sprintf(saltbuf,"$6$%s",s); 319 | } 320 | int client_signup(){ 321 | int len; 322 | char usernamebuf[100]; 323 | char passwordbuf[100]; 324 | char saltbuf[100]; 325 | memset(usernamebuf,0,sizeof(usernamebuf)); 326 | memset(passwordbuf,0,sizeof(passwordbuf)); 327 | memset(saltbuf,0,sizeof(saltbuf)); 328 | printf("signup username:\n"); 329 | read(STDIN_FILENO,usernamebuf,sizeof(usernamebuf)); 330 | usernamebuf[strlen(usernamebuf)-1]='\0'; //去掉换行符 331 | printf("signup password:\n"); 332 | read(STDIN_FILENO,passwordbuf,sizeof(passwordbuf)); 333 | passwordbuf[strlen(passwordbuf)-1]='\0'; //去掉换行符 334 | 335 | get_rand_str(saltbuf); //得到盐值 336 | //printf("salt %s\n",saltbuf); 337 | char* encrypted_password=crypt(passwordbuf,saltbuf); //得到密文密码 338 | 339 | train t; 340 | memset(&t,0,sizeof(t)); 341 | t.len=strlen(usernamebuf); 342 | strcpy(t.buf,usernamebuf); 343 | send_n(sfd,(char*)&t,sizeof(int)+t.len); //传递用户名 344 | memset(&t,0,sizeof(t)); 345 | t.len=strlen(saltbuf); 346 | strcpy(t.buf,saltbuf); 347 | send_n(sfd,(char*)&t,sizeof(int)+t.len); //传递盐值 348 | memset(&t,0,sizeof(t)); 349 | t.len=strlen(encrypted_password); 350 | strcpy(t.buf,encrypted_password); 351 | send_n(sfd,(char*)&t,sizeof(int)+t.len); //传递密文密码 352 | return 0; 353 | } 354 | -------------------------------------------------------------------------------- /client/func.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | typedef struct{ 24 | int len; 25 | char buf[1000]; 26 | }train,*ptrain; 27 | 28 | int send_n(int sfd,char* p,int len); 29 | int recv_n(int sfd,char* p,int len); 30 | void send_data(int new_fd,char* FILENAME); 31 | 32 | void judge(ptrain pt,char* buf1,char* buf2); 33 | int recivefile_formserver(int sfd); 34 | void sigfunc(int signalnum); 35 | 36 | int judgefile_exit(char *filename); 37 | int recivefile_formserver_again(int sfd,char *filename,int need_seek); 38 | 39 | int client_login(); 40 | int client_signup(); 41 | int judge_login_singup(); -------------------------------------------------------------------------------- /client/makefile: -------------------------------------------------------------------------------- 1 | client:client.c send_n.c send_file.c 2 | gcc $^ -o $@ 3 | clean: 4 | rm tcp_client 5 | 6 | -------------------------------------------------------------------------------- /client/send_file.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | void send_data(int new_fd,char* FILENAME) 4 | { 5 | train t; 6 | memset(&t,0,sizeof(t)); 7 | strcpy(t.buf,FILENAME); 8 | t.len=strlen(t.buf); 9 | //发送文件名给服务器端 10 | int ret; 11 | ret=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 12 | if(-1==ret) 13 | { 14 | perror("send"); 15 | return; 16 | } 17 | int fd; 18 | fd=open(FILENAME,O_RDONLY); 19 | 20 | //第二次发送文件大小 21 | struct stat st; 22 | memset(&t,0,sizeof(t)); 23 | fstat(fd,&st); 24 | t.len=sizeof(long); 25 | printf("client file big=%ld\n",st.st_size); 26 | strcpy(t.buf,(char*)&st.st_size); 27 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 28 | 29 | //开多趟火车,发文件内容 30 | while(memset(&t,0,sizeof(t)),(t.len=read(fd,t.buf,sizeof(t.buf)))>0) 31 | { 32 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 33 | } 34 | t.len=0; 35 | //发送空火车(只包含int len=0),标示文件已经发送结束 36 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 37 | //close(new_fd); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /client/send_n.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | int send_n(int sfd,char* p,int len) 4 | { 5 | int total=0; 6 | int ret; 7 | //防止接收方速度慢导致数据丢失,循环发送len长度内的数据直到本次len数据发送完毕 8 | while(totald_name,".")&&strcmp(p->d_name,"..")) { 37 | memset(&buf,0,sizeof(buf)); 38 | memset(path,0,sizeof(path)); 39 | memset(result,0,sizeof(result)); 40 | //p是dirent结构指针,&buf是stat结构指针 41 | //拼接目录下文件的路径 42 | sprintf(path,"%s%s%s",getcwd(NULL,0),"/",p->d_name); 43 | ret=stat(path,&buf); 44 | char *time=printdate(result,ctime(&buf.st_mtime)); 45 | printmode(buf.st_mode); 46 | printf(" %d %s %s %5ld %s %s\n",buf.st_nlink,getpwuid(buf.st_uid)->pw_name,getgrgid(buf.st_gid)->gr_name,buf.st_size,time,p->d_name); 47 | } 48 | } 49 | closedir(dir); 50 | return; 51 | } 52 | int recivefile_formclient(int sfd){ 53 | int len; 54 | char buf[1000]={0}; 55 | recv_n(sfd,(char *)&len,sizeof(len)); 56 | recv_n(sfd,buf,len); //第一次传递文件名称,保存到buf中 57 | 58 | insert_commandlog(3,buf); //记录日志 59 | 60 | int fd=open(buf,O_CREAT|O_WRONLY|O_TRUNC,0666); //将server 文件保存到client端 61 | if(-1==fd) 62 | { 63 | perror("open"); 64 | return -1; 65 | } 66 | //第二次接受文件长度的数据包 67 | recv_n(sfd,(char*)&len,sizeof(len)); 68 | long big; 69 | recv_n(sfd,(char*)&big,sizeof(len)); 70 | printf("upload file name=%s big=%ld\n",buf,big); 71 | 72 | long check=big/10; 73 | long l=0; //保存文件的长度 bytes 74 | while(1) 75 | { 76 | recv_n(sfd,(char *)&len,sizeof(int));//接火车头 77 | l=l+len; 78 | if(len>0) //只有最后一次结束时发送len=0 的数据包 79 | { 80 | memset(buf,0,sizeof(buf)); 81 | recv_n(sfd,buf,len); 82 | write(fd,buf,len); 83 | 84 | if(l>=check){ 85 | printf("Now Data %8.4f%s\r",(double)l*100/big,"%"); 86 | fflush(stdout); 87 | check +=big/10; 88 | } 89 | }else{ 90 | printf("Now Data %8.4f%s\n",(double)l*100/big,"%"); 91 | printf("load down ok\n"); 92 | break; 93 | } 94 | } 95 | close(fd); 96 | return 0; 97 | } 98 | 99 | long judge_filesize(char *filename){ 100 | struct stat statbuf; 101 | memset(&statbuf,0,sizeof(statbuf)); 102 | stat(filename,&statbuf); 103 | return statbuf.st_size>1e8?statbuf.st_size:-1; //大于100M返回文件大小 否则返回-1 104 | } 105 | 106 | void insert_commandlog(int command,char* buf){ //记录命令信息 107 | int logfd=open(LogFile,O_CREAT|O_WRONLY|O_APPEND,0666); //O_APPEND 以追加形式打开文件 108 | char buffer[100]={0}; 109 | char cmd[10]={0}; 110 | if(command==1) strcpy(cmd,"cd"); 111 | else if(command==2) strcpy(cmd,"ls"); 112 | else if(command==3) strcpy(cmd,"gets"); 113 | else if(command==4) strcpy(cmd,"puts"); 114 | else if(command==5) strcpy(cmd,"remove"); 115 | else if(command==6) strcpy(cmd,"pwd"); 116 | sprintf(buffer,"[command] %s %s\n",cmd,buf); 117 | //printf("insert_commandlog: %s",buffer); 118 | write(logfd,buffer,strlen(buffer)*sizeof(char)); 119 | close(logfd); 120 | } 121 | 122 | void judge_handle(int command,int new_fd){ 123 | int contentlength; 124 | char buf[100]={0}; 125 | if(command==1){ 126 | memset(buf,0,sizeof(buf)); 127 | recv_n(new_fd,(char*)&contentlength,sizeof(int)); 128 | recv_n(new_fd,(char*)buf,contentlength); 129 | chdir(buf); // cd 目录位置 130 | //printf("working directory: %s\n",getcwd(NULL,0)); 131 | insert_commandlog(command,buf); //记录日志 132 | } 133 | if(command==2){ 134 | memset(buf,0,sizeof(buf)); 135 | ls_l(); 136 | insert_commandlog(command,buf); 137 | } 138 | if(command==3){ 139 | memset(buf,0,sizeof(buf)); 140 | recivefile_formclient(new_fd); //获取客户端上传文件 141 | } 142 | if(command==4){ 143 | memset(buf,0,sizeof(buf)); 144 | recv_n(new_fd,(char*)&contentlength,sizeof(int)); 145 | recv_n(new_fd,(char*)buf,contentlength); //获取下载文件名称 146 | printf("download filename = %s\n",buf); 147 | //send_data(new_fd,buf); 148 | long filesize=judge_filesize(buf); 149 | if(filesize<0) send_data(new_fd,buf); 150 | else if(filesize>0){ //文件大于100M 151 | int src_fd=open(buf,O_RDONLY); 152 | void* src_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, src_fd, 0); 153 | send_mmpdata(new_fd,buf,src_ptr,filesize,0); 154 | } 155 | insert_commandlog(command,buf); 156 | } 157 | if(command==44){ 158 | memset(buf,0,sizeof(buf)); 159 | recv_n(new_fd,(char*)&contentlength,sizeof(int)); 160 | recv_n(new_fd,(char*)buf,contentlength); //获取下载文件名称 161 | recv_n(new_fd,(char*)&contentlength,sizeof(int)); //获取客户端已下载的文件长度 162 | printf("断点下载%s文件已有大小 %d\n",buf,contentlength); 163 | //send_data_again(new_fd,buf,contentlength); 164 | long filesize=judge_filesize(buf); 165 | if(filesize-contentlength<1e8) send_data_again(new_fd,buf,contentlength); 166 | else if(filesize-contentlength>1e8){ 167 | int src_fd=open(buf,O_RDONLY); 168 | //lseek(src_fd,contentlength,SEEK_SET); //移动读写指针 对于mmap无效 169 | //printf("lseek ok %d\n",contentlength); 170 | //void* src_ptr = mmap(NULL, filesize-contentlength, PROT_READ, MAP_PRIVATE, src_fd, 0); //mmap映射已经偏移后的src_fd(无效) 或者最后一个参数即为偏移量被映射对象内容的起点 171 | void* src_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, src_fd, 0); 172 | send_mmpdata(new_fd,buf,src_ptr,filesize,contentlength); //mmap继续下载剩余内容 173 | } 174 | insert_commandlog(command,buf); 175 | } 176 | if(command==5){ 177 | memset(buf,0,sizeof(buf)); 178 | recv_n(new_fd,(char*)&contentlength,sizeof(int)); 179 | recv_n(new_fd,(char*)buf,contentlength); //获取删除文件名称 180 | printf("delete filename = %s\n",buf); 181 | int z=remove(buf); 182 | if(z==0) printf("delete %s ok\n",buf); 183 | insert_commandlog(command,buf); 184 | } 185 | if(command==6){ 186 | memset(buf,0,sizeof(buf)); 187 | printf("working directory: %s\n",getcwd(NULL,0)); 188 | insert_commandlog(command,buf); 189 | } 190 | } 191 | 192 | 193 | void child_handle(int fdr) 194 | { 195 | char flag=1; 196 | int new_fd; 197 | train t; 198 | int command; 199 | while(1) 200 | { 201 | recv_fd(fdr,&new_fd);//从父进程接收任务 //连接只需要接受一次,多次时fdr值已为空 202 | while(1){ 203 | recv_n(new_fd,(char*)&command,sizeof(int)); //不断接受客户端命令 204 | 205 | if(command==0){ //客户端按下ctrl+c 传递给server 0号命令 206 | write(fdr,&flag,sizeof(flag)); 207 | close(new_fd); 208 | break; 209 | } 210 | 211 | judge_handle(command,new_fd); 212 | write(fdr,&flag,sizeof(flag));//通知父进程,完成任务 213 | } 214 | } 215 | } 216 | 217 | void make_child(pchild p,int num) 218 | { 219 | int i; 220 | int fds[2]; 221 | pid_t pid; 222 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #define LogFile "/home/cuixuange/20170714/server/server.log" 25 | 26 | typedef struct{ 27 | pid_t pid;//子进程的pid 28 | int tfds;//通过该管道传递内核控制信息 29 | short busy;//标示进程是否忙碌 30 | }child,*pchild; 31 | typedef struct{ 32 | int len; 33 | char buf[1000]; 34 | }train,*ptrain; 35 | 36 | int send_n(int sfd,char* p,int len); 37 | int recv_n(int sfd,char* p,int len); 38 | void send_data(int new_fd,char* FILENAME); 39 | void make_child(pchild p,int num); 40 | void child_handle(int fdr); 41 | void send_fd(int fdw,int fd); 42 | void recv_fd(int fdr,int* fd); 43 | 44 | void judge_handle(int command,int new_fd); 45 | char* printdate(char *result,char *old); 46 | void printmode(mode_t st_mode); 47 | void ls_l(); 48 | int recivefile_formclient(int sfd); 49 | 50 | void insert_loginlog(); 51 | void insert_commandlog(int command,char* buf); 52 | void send_data_again(int new_fd,char* FILENAME,int need_seek); 53 | long judge_filesize(char *filename); 54 | void send_mmpdata(int new_fd,char* FILENAME,void* src,long filesize,long download_file_size); 55 | 56 | int judge_clientlogin(int new_fd); 57 | int judge_clientSignup(int new_fd); 58 | void query_encrypted_password(char *login_username,char *encrypted_password); 59 | void query_salt(char *login_username,char *salt); 60 | void insert_data(char* login_username,char* login_salt,char* login_password); -------------------------------------------------------------------------------- /server/main.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | int main(int argc,char* argv[]) 4 | { 5 | if(argc!=2) 6 | { 7 | printf("Please INPUT IP PORT PROCESS_NUM\n"); 8 | return -1; 9 | } 10 | 11 | int child_num=0; 12 | //pchild p=(pchild)calloc(child_num,sizeof(child)); 13 | //make_child(p,child_num);//创建子进程并初始化所有的数据结构 14 | 15 | int sfd; 16 | sfd=socket(AF_INET,SOCK_STREAM,0); 17 | if(-1==sfd) 18 | { 19 | perror("socket"); 20 | return -1; 21 | } 22 | struct sockaddr_in ser; 23 | memset(&ser,0,sizeof(ser)); 24 | ser.sin_family=AF_INET; 25 | //ser.sin_port=htons(atoi(argv[2])); 26 | //ser.sin_addr.s_addr=inet_addr(argv[1]); 27 | char conf[100]={0}; 28 | char conf2[100]={0}; //保存conf切割后的数据 29 | int conf_fd=open(argv[1],O_RDONLY); 30 | read(conf_fd,conf,sizeof(conf)); 31 | strcpy(conf2,conf); 32 | //printf("%s\n",conf); 33 | int i=0; 34 | for(i=0;i0) break ; } //用户登录验证 113 | else if(command==222) judge_clientSignup(new_fd); //用户注册 114 | } 115 | 116 | insert_loginlog(); //记录日志信息 117 | for(j=0;j0) printf("child%d is not busy\n",p[j].pid); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | void insert_loginlog(){ 146 | int logfd=open(LogFile,O_CREAT|O_WRONLY|O_APPEND,0666); //O_APPEND 以追加形式打开文件 147 | char nowtime[100]={0}; 148 | time_t timep; 149 | struct tm *p; 150 | time(&timep); 151 | p=localtime(&timep); //取得当地时间 152 | sprintf (nowtime,"[login time] %d-%d-%d %d:%d:%d\n", (1900+p->tm_year),(1+p->tm_mon), p->tm_mday,p->tm_hour, p->tm_min, p->tm_sec); 153 | //printf("nowtime %s",nowtime); 154 | write(logfd,nowtime,strlen(nowtime)*sizeof(char)); 155 | close(logfd); 156 | } 157 | 158 | int judge_clientlogin(int new_fd){ 159 | int len; 160 | char usernamebuf[100]; 161 | char passwordbuf[100]; 162 | train t; 163 | memset(usernamebuf,0,sizeof(usernamebuf)); 164 | memset(passwordbuf,0,sizeof(passwordbuf)); 165 | memset(&t,0,sizeof(t)); 166 | recv_n(new_fd,(char *)&len,sizeof(int)); 167 | recv_n(new_fd,usernamebuf,len); //接受client username 168 | //printf("login username %s\n",usernamebuf); 169 | 170 | char salt[15]={0}; 171 | memset(&t,0,sizeof(t)); 172 | query_salt(usernamebuf,salt); 173 | t.len=strlen(salt); 174 | //printf("salt %d\n",t.len); 175 | if(t.len>0) { 176 | strcpy(t.buf,salt); 177 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); //发送盐值 178 | } 179 | else if(t.len==0) { 180 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); //如果未注册过username,发送空数据包 t.len=0 181 | return -1; 182 | } 183 | 184 | memset(&t,0,sizeof(t)); 185 | recv_n(new_fd,(char *)&len,sizeof(int)); 186 | recv_n(new_fd,passwordbuf,len); //接受密文密码 187 | char encrypted_password[100]={0}; 188 | query_encrypted_password(usernamebuf,encrypted_password); 189 | if(!strcmp(passwordbuf,encrypted_password)) t.len=0; 190 | else t.len=-1; 191 | printf("compare result %d\n",t.len); 192 | send_n(new_fd,(char*)&t,sizeof(int)); //-1 匹配失败 0 匹配成功 193 | 194 | if(t.len<0) return -1; 195 | else return 1; 196 | } 197 | 198 | int judge_clientSignup(int new_fd){ 199 | int len; 200 | char usernamebuf[100]; 201 | char encrypted_passwordbuf[100]; 202 | char saltbuf[100]; 203 | memset(usernamebuf,0,sizeof(usernamebuf)); 204 | memset(encrypted_passwordbuf,0,sizeof(encrypted_passwordbuf)); 205 | memset(saltbuf,0,sizeof(saltbuf)); 206 | recv_n(new_fd,(char *)&len,sizeof(int)); 207 | recv_n(new_fd,usernamebuf,len); //接受用户名 208 | recv_n(new_fd,(char *)&len,sizeof(int)); 209 | recv_n(new_fd,saltbuf,len); //接受盐值 210 | recv_n(new_fd,(char *)&len,sizeof(int)); 211 | recv_n(new_fd,encrypted_passwordbuf,len); //接受密文密码 212 | //printf("username %s\n",usernamebuf); 213 | //printf("salt %s\n",saltbuf); 214 | //printf("password %s\n",encrypted_passwordbuf); 215 | 216 | //插入数据库 217 | insert_data(usernamebuf,saltbuf,encrypted_passwordbuf); 218 | return 0; 219 | } 220 | 221 | 222 | -------------------------------------------------------------------------------- /server/makefile: -------------------------------------------------------------------------------- 1 | server:main.c child.c send_fd.c send_file.c send_n.c mysql_api.c 2 | gcc $^ -o $@ -lcrypt -lmysqlclient 3 | clean: 4 | rm server 5 | 6 | -------------------------------------------------------------------------------- /server/mysql_api.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixuage/LinuxC_server_mysql_client/6ab1e9baacec171db6ab345aae88d149acf7da3a/server/mysql_api.c -------------------------------------------------------------------------------- /server/send_fd.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | void send_fd(int fdw,int fd) 4 | { 5 | struct msghdr msg; 6 | memset(&msg,0,sizeof(msg)); 7 | struct cmsghdr *cmsg; 8 | int len=CMSG_LEN(sizeof(int)); 9 | cmsg=(struct cmsghdr *)calloc(1,len); 10 | cmsg->cmsg_len=len; 11 | cmsg->cmsg_level = SOL_SOCKET; 12 | cmsg->cmsg_type = SCM_RIGHTS; 13 | *(int*)CMSG_DATA(cmsg)=fd; 14 | msg.msg_control=cmsg; 15 | msg.msg_controllen=len; 16 | char buf1[10]="hello"; 17 | char buf2[10]="world"; 18 | struct iovec iov[2]; 19 | iov[0].iov_base=buf1; 20 | iov[0].iov_len=5; 21 | iov[1].iov_base=buf2; 22 | iov[1].iov_len=5; 23 | msg.msg_iov=iov; 24 | msg.msg_iovlen=2; 25 | int ret=sendmsg(fdw,&msg,0); 26 | if(-1==ret) 27 | { 28 | perror("sendmsg"); 29 | return; 30 | } 31 | } 32 | void recv_fd(int fdr,int* fd) 33 | { 34 | struct msghdr msg; 35 | memset(&msg,0,sizeof(msg)); 36 | struct cmsghdr *cmsg; 37 | int len=CMSG_LEN(sizeof(int)); 38 | cmsg=(struct cmsghdr *)calloc(1,len); 39 | cmsg->cmsg_len=len; 40 | cmsg->cmsg_level = SOL_SOCKET; 41 | cmsg->cmsg_type = SCM_RIGHTS; 42 | msg.msg_control=cmsg; 43 | msg.msg_controllen=len; 44 | char buf1[10]="hello"; 45 | char buf2[10]="world"; 46 | struct iovec iov[2]; 47 | iov[0].iov_base=buf1; 48 | iov[0].iov_len=5; 49 | iov[1].iov_base=buf2; 50 | iov[1].iov_len=5; 51 | msg.msg_iov=iov; 52 | msg.msg_iovlen=2; 53 | int ret=recvmsg(fdr,&msg,0); 54 | if(-1==ret) 55 | { 56 | perror("sendmsg"); 57 | return; 58 | } 59 | *fd=*(int*)CMSG_DATA(cmsg); 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /server/send_file.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | void send_mmpdata(int new_fd,char* FILENAME,void* src,long filesize,long download_file_size){ //filesize代表文件大小; rest_of_file_size 断点续传时已下载文件大小 4 | train t; 5 | memset(&t,0,sizeof(t)); 6 | strcpy(t.buf,FILENAME); 7 | t.len=strlen(t.buf); 8 | //发送文件名给对客户端 9 | int ret; 10 | ret=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 11 | if(-1==ret) 12 | { 13 | perror("send"); 14 | return; 15 | } 16 | 17 | t.len=sizeof(long); //发送文件大小 18 | printf("server file big=%ld\n",filesize); 19 | strcpy(t.buf,(char*)&filesize); 20 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 21 | 22 | src +=download_file_size; //偏移mmap指针 23 | filesize -=download_file_size; //计算需要传递的文件大小 24 | 25 | //开多趟火车,发文件内容 26 | while(memset(&t,0,sizeof(t)),filesize>0){ 27 | if(filesize>sizeof(t.buf)){ 28 | memcpy(t.buf,(char*)src,sizeof(t.buf)); 29 | t.len=sizeof(t.buf); 30 | } 31 | else { 32 | memcpy(t.buf,(char*)src,filesize); 33 | t.len=filesize; // strlen只能获取字符串长度 '\0' 34 | } 35 | //printf("final t.buf %d\n",t.len); 36 | //if(t.len>0) printf("t.len %10d\n",t.len); 37 | src +=sizeof(t.buf); 38 | filesize -=sizeof(t.buf); 39 | //printf("filesize %ld\n",filesize); 40 | 41 | int check=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 42 | if(check<0) {printf("send file break ok\n");return;} 43 | 44 | } 45 | t.len=0; 46 | //发送空火车(只包含int len=0),标示文件已经发送结束 47 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 48 | //close(new_fd); 49 | } 50 | 51 | 52 | void send_data(int new_fd,char* FILENAME) 53 | { 54 | train t; 55 | memset(&t,0,sizeof(t)); 56 | strcpy(t.buf,FILENAME); 57 | t.len=strlen(t.buf); 58 | //发送文件名给对客户端 59 | int ret; 60 | ret=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 61 | if(-1==ret) 62 | { 63 | perror("send"); 64 | return; 65 | } 66 | int fd; 67 | fd=open(FILENAME,O_RDONLY); 68 | struct stat st; 69 | memset(&t,0,sizeof(t)); 70 | fstat(fd,&st); 71 | t.len=sizeof(long); 72 | printf("server file big=%ld\n",st.st_size); 73 | strcpy(t.buf,(char*)&st.st_size); 74 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 75 | 76 | //开多趟火车,发文件内容 77 | while(memset(&t,0,sizeof(t)),(t.len=read(fd,t.buf,sizeof(t.buf)))>0) 78 | { 79 | int check=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 80 | if(check<0) {printf("send file break ok\n");return;} //当客户端断开连接时此处break 81 | } 82 | t.len=0; 83 | //发送空火车(只包含int len=0),标示文件已经发送结束 84 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 85 | //close(new_fd); 86 | } 87 | 88 | void send_data_again(int new_fd,char* FILENAME,int need_seek){ 89 | train t; 90 | memset(&t,0,sizeof(t)); 91 | strcpy(t.buf,FILENAME); 92 | t.len=strlen(t.buf); 93 | //发送文件名给对客户端 94 | int ret; 95 | ret=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 96 | if(-1==ret) 97 | { 98 | perror("send"); 99 | return; 100 | } 101 | int fd; 102 | fd=open(FILENAME,O_RDONLY); 103 | struct stat st; 104 | memset(&t,0,sizeof(t)); 105 | fstat(fd,&st); 106 | t.len=sizeof(long); //额外获取文件大小,便于客户端百分比显示 107 | printf("server file big=%ld\n",st.st_size); 108 | strcpy(t.buf,(char*)&st.st_size); 109 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 110 | 111 | printf("server file seek=%d\n",need_seek); 112 | lseek(fd,need_seek,SEEK_SET); //移动读写指针 113 | 114 | //开多趟火车,发文件内容 115 | while(memset(&t,0,sizeof(t)),(t.len=read(fd,t.buf,sizeof(t.buf)))>0) 116 | { 117 | int check=send_n(new_fd,(char*)&t,sizeof(int)+t.len); 118 | if(check<0) {printf("send file break ok\n");return;} 119 | } 120 | t.len=0; 121 | //发送空火车(只包含int len=0),标示文件已经发送结束 122 | send_n(new_fd,(char*)&t,sizeof(int)+t.len); 123 | //close(new_fd); 124 | } 125 | 126 | -------------------------------------------------------------------------------- /server/send_n.c: -------------------------------------------------------------------------------- 1 | #include "func.h" 2 | 3 | int send_n(int sfd,char* p,int len) 4 | { 5 | int total=0; 6 | int ret; 7 | //防止接收方速度慢导致数据丢失,循环发送len长度内的数据直到本次len数据发送完毕 8 | while(total