Socket网络编程--小小网盘程序(2)
这一节将不会介绍太多的技术的问题,这节主要是搭建一个小小的框架,为了方便接下来的继续编写扩展程序。本次会在上一小节的基础上加上一个身份验证的功能。
因为网盘程序不像聊天程序,网盘是属于主动向服务器拉取信息,而聊天程序有可能要被动获取信息,所以为了减轻服务器压力,每次要向服务器获取服务就建立一个短连接,而不像聊天程序一样的长连接,微信的公众平台,输入指令获取服务,就是这个样子了。具体看一下代码就知道了。
还有为了方便处理,我增加了一个控制信号,这个控制信号在以前的聊天程序中讲到过,但是当时为了简单就没有实现,现在就简单实现一些,方便以后可以参考。
还有就是这次的网盘程序我将尽量实现下面的这些功能:
(1) file push filename //用户上传文件到服务器上
(2) file pull filename //用户下载文件到本地上
(3) file list //列出用户在服务器中的所有文件
(4) file sendto filename username //共享文件给其他用户
(5) file delete filename //删除服务器中的文件
(6) 用户登录,自动完成
本次数据库名为filetranslate,目前有表user
create table user
(
uid int;
username varchar(64);
password varchar(64);
);
修改后的client.cpp
#include <netinet/in.h> // sockaddr_in
#include <sys/types.h> //socket
#include <sys/socket.h> //socket
#include <netdb.h> //gethostbyname
#include <unistd.h> //close
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h> //inet_addr #define SERVVER_PORT 12138
#define LISTEN_QUEUE 20
#define BUFFER_SIZE 1024 //传输控制信号宏定义
//struct Control中control的取值
#define USER_CHECK_LOGIN 1
#define FILE_PUSH 2
#define FILE_PULL 3
#define FILE_LIST 4
#define FILE_SENDTO 5
#define FILE_DELECT 6 struct Addr
{
char host[];
int port;
};
struct User
{
int uid;
char username[];
char password[];
};
struct Control
{
int uid;
int control;
}; void print_time(char *ch);//打印时间
int file_push(struct Addr addr,struct User user,char *filenames);
int check_login(struct Addr addr,struct User * user); int main(int argc,char *argv[])
{
char orderbuf[BUFFER_SIZE];
struct Addr addr;
char arg1[],arg2[],arg3[],arg4[];
struct User user; if(argc!=)
{
perror("usage: ./client [serverhost] [serverport] [username] [password]");
exit(-);
}
strcpy(addr.host,argv[]);
addr.port=atoi(argv[]);
strcpy(user.username,argv[]);
strcpy(user.password,argv[]);
int uid=check_login(addr,&user);
if(uid<=)
{
perror("用户验证失败");
exit(-);
}
printf("验证登陆成功\n");
while()
{
printf("\n请输入操作指令:");
fgets(orderbuf,BUFFER_SIZE,stdin);
memset(arg1,,sizeof(arg1));
memset(arg2,,sizeof(arg2));
memset(arg3,,sizeof(arg3));
memset(arg4,,sizeof(arg4));
sscanf(orderbuf,"%s%s%s%s",arg1,arg2,arg3,arg4);
if(strcmp(arg1,"file")==)
{
if(strcmp(arg2,"push")==)
{
strcpy(orderbuf,arg3);
file_push(addr,user,orderbuf);
}
else if(strcmp(arg2,"pull")==)
{
;
}
else if(strcmp(arg2,"list")==)
{
;
}
else if(strcmp(arg2,"sendto")==)
{
;
}
else if(strcmp(arg2,"delect")==)
{
;
}
else
{
printf("该命令不支持\n");
}
}
else
{
printf("该命令不支持\n");
}
} return ;
} //验证成功时返回大于0的uid号码,错误返回-1
int check_login(struct Addr addr,struct User * user)
{
struct sockaddr_in servAddr;
struct hostent * host;
struct Control control;
int sockfd; host=gethostbyname(addr.host);
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
//servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
servAddr.sin_port=htons(addr.port);
if(host==NULL)
{
perror("获取IP地址失败");
exit(-);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("socket创建失败");
exit(-);
}
if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
exit(-);
} control.control=USER_CHECK_LOGIN;
control.uid=;
if(send(sockfd,(char *)&control,sizeof(struct Control),)<)
{
perror("发送数据失败");
exit(-);
} if(send(sockfd,(char *)user,sizeof(struct User),)<)
{
perror("发送数据失败");
exit(-);
}
bzero(user,sizeof(struct User));
if(recv(sockfd,(char *)user,sizeof(struct User),)<)
{
perror("接收数据失败");
exit(-);
}
printf("获取后用户名:%s 密码:%s ID号:%d\n",user->username,user->password,user->uid); close(sockfd);//关闭socket连接
return user->uid;
} int file_push(struct Addr addr,struct User user,char *filenames)
{
struct sockaddr_in servAddr;
struct hostent * host;
struct Control control;
int sockfd;
FILE *fp; host=gethostbyname(addr.host);
servAddr.sin_family=AF_INET;
servAddr.sin_addr=*((struct in_addr *)host->h_addr);
//servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
servAddr.sin_port=htons(addr.port);
if(host==NULL)
{
perror("获取IP地址失败");
exit(-);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-)
{
perror("socket创建失败");
exit(-);
} if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-)
{
perror("connect 失败");
exit(-);
} //打开文件
if((fp=fopen(filenames,"rb"))==NULL)
{
perror("文件打开失败");
exit(-);
}
//这里传输控制信号
control.control=FILE_PUSH;
control.uid=user.uid;
if(send(sockfd,(char *)&control,sizeof(struct Control),)<)
{
perror("控制信号发送失败");
exit(-);
}
char buffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);
printf("正在传输文件");
int len=;
//不断的读取文件直到文件结束
while((len=fread(buffer,,BUFFER_SIZE,fp))>)
{
if(send(sockfd,buffer,len,)<)
{
perror("发送数据失败");
exit(-);
}
bzero(buffer,BUFFER_SIZE);
printf(".");//1K打印一个点//如果要实现百分比,就要计算文件大小,然后再处理即可
} printf("传输完毕\n");
fclose(fp);//关闭文件流
close(sockfd);//关闭socket连接 return ;
} void print_time(char *ch)
{
time_t now;
struct tm * stm;
time(&now);
stm=localtime(&now);
sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec);
return ;
}
下面这个是server.cpp
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h> //inet_ntoa
#include <mysql.h> #define SERVER_PORT 12138
#define LISTEN_QUEUE 20
#define BACKLOG 200
#define BUFFER_SIZE 1024 //传输控制信号宏定义
//struct Control中control的取值
#define USER_CHECK_LOGIN 1
#define FILE_PUSH 2
#define FILE_PULL 3
#define FILE_LIST 4
#define FILE_SENDTO 5
#define FILE_DELECT 6 struct User
{
int uid;
char username[];
char password[];
}; struct Control
{
int uid;
int control;
}; void print_time(char *ch);//打印时间
int MAX(int a,int b);
int mysql_check_login(struct User user); int main(int argc,char *argv[])
{
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct User user;
struct Control control;
char ch[];
int clientfd;
pid_t pid;
socklen_t length;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htons(INADDR_ANY);
server_addr.sin_port=htons(SERVER_PORT); //创建套接字
int sockfd=socket(AF_INET,SOCK_STREAM,);
if(sockfd<)
{
perror("创建套接字失败");
exit(-);
} if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-)
{
perror("bind 失败");
exit(-);
} if(listen(sockfd,LISTEN_QUEUE))
{
perror("listen 失败");
exit(-);
} length=sizeof(struct sockaddr); while()
{
clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&length);
if(clientfd==-)
{
perror("accept 失败");
continue;
}
printf(">>>>>%s:%d 连接成功,当前所在的ID(fd)号: %d \n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),clientfd);
print_time(ch);
printf("加入的时间是:%s\n",ch); //来一个连接就创建一个进程进行处理
pid=fork();
if(pid<)
{
perror("fork error");
}
else if(pid==)
{
recv(clientfd,(char *)&control,sizeof(struct Control),);
printf("用户 %d 使用命令 %d\n",control.uid,control.control);
switch(control.control)
{
case USER_CHECK_LOGIN:
{
//身份验证处理
recv(clientfd,(char *)&user,sizeof(struct User),);
printf("客户端发送过来的用户名是:%s,密码:%s\n",user.username,user.password);
if((user.uid=mysql_check_login(user))>)
{
printf("验证成功\n");
}
else
{
printf("验证失败\n");
}
send(clientfd,(char *)&user,sizeof(struct User),);
break;
}
case FILE_PUSH:
{
char buffer[BUFFER_SIZE];
int data_len;
FILE * fp=NULL;
bzero(buffer,BUFFER_SIZE);
if((fp=fopen("data","wb"))==NULL)
{
perror("文件打开失败");
exit(-);
}
//循环接收数据
int size=;//表示有多少个块
while(data_len=recv(clientfd,buffer,BUFFER_SIZE,))
{
if(data_len<)
{
perror("接收数据错误");
exit(-);
}
size++;
if(size==)
printf("正在接收来自%s:%d的文件\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
else
printf(".");
//向文件中写入
int write_len=fwrite(buffer,sizeof(char),data_len,fp);
if(write_len>data_len)
{
perror("写入数据错误");
exit(-);
}
bzero(buffer,BUFFER_SIZE);
}
if(size>)
printf("\n%s:%d的文件传送完毕\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
else
printf("\n%s:%d的文件传送失败\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
fclose(fp);
//rename("data","asdf");//这里可以修改文件的名字
exit();
break;
}
case FILE_PULL:
{
break;
}
case FILE_LIST:
{
break;
}
case FILE_DELECT:
{
break;
}
default:
{
break;
}
}
close(clientfd);//短连接结束
exit();//退出子进程
}
} return ;
} //函数定义
int mysql_check_login(struct User user)
{
MYSQL conn;
MYSQL_RES *res_ptr;
MYSQL_ROW result_row;
int res;
int row;
int column;
int uid;
char sql[]={};
strcpy(sql,"select uid from users where username=\"");
strcat(sql,user.username);
strcat(sql,"\" and password=\"");
strcat(sql,user.password);
strcat(sql,"\";");
printf("查询的sql:%s\n",sql);
uid=-;
mysql_init(&conn);
if(mysql_real_connect(&conn,"localhost","root","","filetranslate",,NULL,CLIENT_FOUND_ROWS))
{
res=mysql_query(&conn,sql);
if(res)
{
perror("Select SQL ERROR!");
exit(-);
}
else
{
res_ptr=mysql_store_result(&conn);
if(res_ptr)
{
column=mysql_num_fields(res_ptr);//获取列数
row=mysql_num_rows(res_ptr)+;//获取行数,加1表示还有第一行字段名
if(row<=)
{
;//验证失败
}
else
{
//这里先假定username是唯一
result_row=mysql_fetch_row(res_ptr);
printf("获取到的uid是:%s\n",result_row[]);
uid=atoi(result_row[]);
}
}
else
{
printf("没有查询到匹配的数据\n");
}
}
}
else
{
perror("Connect Failed!\n");
exit(-);
}
mysql_close(&conn);
return uid;
} void print_time(char *ch)
{
time_t now;
struct tm * stm;
time(&now);
stm=localtime(&now);
sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec);
return ;
} int MAX(int a,int b)
{
if(a>b)
return a;
return b;
}
下面给张运行时的截图

关于c语言调用mysql: http://www.cnblogs.com/wunaozai/p/3876134.html
本文地址: http://www.cnblogs.com/wunaozai/p/3887728.html
Socket网络编程--小小网盘程序(2)的更多相关文章
- Socket网络编程--小小网盘程序(5)
各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友. 列出用户在服务器中的文件 ...
- Socket网络编程--小小网盘程序(4)
在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 cli ...
- Socket网络编程--小小网盘程序(3)
接上一小节,这次增加另外的两张表,用于记录用户是保存那些文件.增加传上来的文件的文件指纹,使用MD5表示. 两张表如下定义: create table files( fid int, filename ...
- Socket网络编程--小小网盘程序(1)
这个系列是准备讲基于Linux Socket进行文件传输.简单的文件传输就是客户端可以上传文件,可以从服务器端下载文件.就这么两个功能如果再加上身份验证,就成了FTP服务器了,如果对用户的操作再加上一 ...
- linux下C语言socket网络编程简例
原创文章,转载请注明转载字样和出处,谢谢! 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到client的连接后,发送数据给client:clie ...
- 5.3linux下C语言socket网络编程简例
原创文章,转载请注明转载字样和出处,谢谢! 这里给出在Linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后 ...
- Socket网络编程--聊天程序(9)
这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也 ...
- Socket网络编程系列教程序
C语言的用途相当多,可以用在数据结构.数据库.网络.嵌入式等方面,历经40多年不衰,真是厉害!最近一直想从某一应用方面写一个系列教程,好好地把某一方面讲深讲透. 正好博主对网络方面的编 ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
随机推荐
- 第六章|网络编程-socket开发
1.计算机基础 作为应用开发程序员,我们开发的软件都是应用软件,而应用软件必须运行于操作系统之上,操作系统则运行于硬件之上,应用软件是无法直接操作硬件的,应用软件对硬件的操作必须调用操作系统的接口,由 ...
- (转)python中调用R语言通过rpy2 进行交互安装配置详解
python中调用R语言通过rpy2 进行交互安装配置详解(R_USER.R_HOME配置) 2018年11月08日 10:00:11 luqin_ 阅读数:753 python中调用R语言通过r ...
- moodle3.15+,mysql完全的Unicode支持配置
https://docs.moodle.org/dev/Releases,moodle个版本升级的主要内容和改动 在windows是mysql.ini linux 下是mysql.cnf 因为MyS ...
- Python Django 学习 (二) 【Django 模型】
注: 由于自己排版确实很难看,本文开始使用markdown编辑,希望有所改善 官方定义 A model is the single, definitive source of information ...
- 利用zabbix监控oracle数据库
一.概述 zabbix是一款非常强大,同时也是应用最为广泛的开源监控软件,本文将给大家介绍如何利用zabbix监控oracle数据库. 二.环境介绍 以下是我安装的环境,实际部署时并不需要跟我的环境一 ...
- 实现分布式服务注册及简易的netty聊天
现在很多地方都会用到zookeeper, 用到它的地方就是为了实现分布式.用到的场景就是服务注册,比如一个集群服务器,需要知道哪些服务器在线,哪些服务器不在线. ZK有一个功能,就是创建临时节点,当机 ...
- 8.10 正睿暑期集训营 Day7
目录 2018.8.10 正睿暑期集训营 Day7 总结 A 花园(思路) B 归来(Tarjan 拓扑) C 机场(凸函数 点分治) 考试代码 A B C 2018.8.10 正睿暑期集训营 Day ...
- #1075 : 开锁魔法III
描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...
- Java虚拟机详解----常用JVM配置参数
本文主要内容: Trace跟踪参数 堆的分配参数 栈的分配参数 零.在IDE的后台打印GC日志: 既然学习JVM,阅读GC日志是处理Java虚拟机内存问题的基础技能,它只是一些人为确定的规则,没有太多 ...
- python中的zip、lambda、map操作
python 中有几个比较酷炫的操作,比如:zip.lambda.map 一.zip操作 zip字面意思:拉链.这么来记,把几个东西扔到一个包里,拉上拉链,就算打包好了.通俗点讲,就是把第1个参数.与 ...