一、项目实现功能
-
在客户端对服务端的操作: 1.获取服务器的文件(get) 2.查看服务器当前路径下的所有文件(ls) 3.进入服务器的某个路径(cd) 4.上传文件到服务器(put) 5.查看服务器当前在那个文件夹(pwd) 6.退出 (quit) -
在客户端本地的功能实现: 1.查看客户端本地当前路径有哪些文件(lls) 2.进入客户端的某个路径(lcd) 3.查看客户端当前在那个文件夹下(lpwd) 4.退出连接(quit)
二、项目实现思路
1.创建套接字(socket) 2.将socket与IP地址和端口绑定(bind) 3.监听被绑定的端口(listen) 4.接收连接请求(accept) 5.当有客户端接入时创建子进程对接并处理客户端发来的请求
1.创建套接字(socket) 2.连接指定计算机的端口(connect) 3.接收输入向socket中写入信息(write) 4.获取客户端发送的内容像ls,pwd,get指令,需要进行(read)
ls与pwd:调用popen 函数,执行命令,并获取执行命令后的输出内容,将内容发回到客户端
cd:将cd指令发送到服务器,在服务器端调用chdir 实现路径的切换
get:客户端获取服务器的某个文件,服务器首先通过access 函数判断文件是否存在,存在则将文件的内容发送到客户端,客户端创建文件,并将服务器发送的内容保存至文件中,实现get指令。
put:客户端向服务器发送文件,客户端首先通过access 函数判断文件是否存在,存在则将文件的内容发送到服务器,服务器创建文件,并将客户端发送的内容保存至文件中,实现put指令。
lls,lpwd:调用system 函数即可。
lcd:在客户端直接调用chdir 函数即可
三、项目用到的函数
1.access函数(判断文件是否存在的函数)
int access(const char *pathname, int mode);
- 函数说明:
判断参数中的文件民是否存在 - 参数:
pathname:需要检测的文件路径名 mode:需要测试的操作模式 R_OK 测试读许可权 W_OK 测试写许可权 X_OK 测试执行许可权 F_OK 测试文件是否存在 - 返回值:成功执行时,返回0,失败返回-1,errno被设为以下的某个值
2.chdir函数(进入某个文件夹的函数)
int chdir(const char *path);
- 函数说明:切换到参数所设置的路径
- 参数:所指代的工作目录(即将要进入的工作目录)
- 返回值:成功返回0,失败返回-1,errno为错误代码
3.fgets函数(可以获取空格,且较为安全)
char *fgets(char *s, int size, FILE *stream);
- 函数说明:
虽然用 gets() 时有空格也可以直接输入,但是 gets() 有一个非常大的缺陷,即它不检查预留存储区是否能够容纳实际输入的数据,换句话说,如果输入的字符数目大于数组的长度,gets 无法检测到这个问题,就会发生内存越界,所以编程时建议使用 fgets() 。但是调用次函数会把回车\n也作为字符串的一部分,因此需要将去掉换行符删掉:
if(msg.cmd[strlen(msg.cmd) - 1] == '\n'){
msg.cmd[strlen(msg.cmd) - 1] = '\0';
}
- 参数:
s:代表要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名 size:代表的是读取字符串的长度 stream:表示从何种流中读取,可以是标准输入流 stdin,也可以是文件流,即从某个文件中读取 - 返回值:返回该数组的指针(首地址),如果读完,则返回空指针NULL
四、代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
char *get_cmd_dir(char *cmd)
{
char *p=NULL;
p=strtok(cmd," ");
p=strtok(NULL," ");
return p;
}
int get_cmd_type(char *cmd)
{
if(!strcmp("ls",cmd)) return LS;
if(!strcmp("pwd",cmd)) return PWD;
if(!strcmp("quit",cmd)) return QUIT;
if(strstr(cmd,"get")!=NULL) return GET;
if(strstr(cmd,"cd")!=NULL) return CD;
if(strstr(cmd,"put")!=NULL) return PUT;
return -1;
}
void message_handler(struct Msg msg,int fd)
{
int ret;
char *dir;
char *fileName;
int fdFile;
int getSize;
char *dataBuf;
printf("get cmd: %s\n",msg.cmd);
ret =get_cmd_type(msg.cmd);
switch (ret){
case LS:
case PWD:
msg.type=0;
FILE *fp=popen(msg.cmd,"r");
fread(msg.data,sizeof(msg.data),1,fp);
write(fd,&msg,sizeof(msg));
pclose(fp);
break;
case CD:
msg.type=1;
dir=get_cmd_dir(msg.cmd);
chdir(dir);
break;
case GET:
fileName=get_cmd_dir(msg.cmd);
if(access(fileName,F_OK)==-1){
strcpy(msg.data,"This File is not exist");
write(fd,&msg,sizeof(msg));
}else{
msg.type=DOFILE;
fdFile=open(fileName,O_RDWR);
getSize = lseek(fdFile,0,SEEK_END);
lseek(fdFile,0,SEEK_SET);
read(fdFile,msg.secondBuf,getSize);
close(fdFile);
write(fd,&msg,sizeof(msg));
}
break;
case PUT:
fdFile=open(get_cmd_dir(msg.cmd),O_RDWR|O_CREAT,0666);
write(fdFile,msg.secondBuf,sizeof(msg.secondBuf));
close(fdFile);
break;
case QUIT:
printf("client quit\n");
exit(-1);
}
}
int main(int argc,char * argv[])
{
int socket_fd;
int connect_fd;
int nread;
int clen;
char readBuf[128];
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
struct Msg message;
if(argc != 2){
printf("输入端口号");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr));
memset(&c_addr,0,sizeof(struct sockaddr));
memset(&message,0,sizeof(struct Msg));
socket_fd=socket(AF_INET,SOCK_STREAM,0);
if(socket_fd==-1){
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(atoi(argv[1]));
inet_aton(" 127.0.0.1",&(s_addr.sin_addr));
bind(socket_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
listen(socket_fd,10);
clen=sizeof(struct sockaddr_in);
while(1){
connect_fd=accept(socket_fd,(struct sockaddr*)&c_addr,&clen);
if(connect_fd==-1){
perror("accept");
}
printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));
if(fork()==0){
while(1){
memset(&message,0,sizeof(message));
nread=read(connect_fd,&message,sizeof(message));
if(nread==0){
printf("client out\n");
break;
}else if(nread>0){
message_handler(message,connect_fd);
}
}
}
}
close (connect_fd);
close(socket_fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
char *get_cmd_dir(char *cmd)
{
char *p=NULL;
p=strtok(cmd," ");
p=strtok(NULL," ");
return p;
}
int get_cmd_type(char *cmd)
{
if(strcmp("lls",cmd)==0) return LLS;
if(strstr(cmd,"lcd")!=NULL) return LCD;
if(strcmp("ls",cmd)==0) return LS;
if(strcmp("pwd",cmd)==0) return PWD;
if(strcmp("quit",cmd)==0) return QUIT;
if(strstr(cmd,"cd")!=NULL) return CD;
if(strstr(cmd,"get")!=NULL) return GET;
if(strstr(cmd,"put")!=NULL) return PUT;
if(!strcmp(cmd,"lpwd")) return LPWD;
return -1;
}
int cmd_handler(struct Msg msg,int fd)
{
int ret;
char *dir;
char cmdTemp[128];
int fdFile;
int putSize;
ret=get_cmd_type(msg.cmd);
switch (ret)
{
case LS:
case PWD:
case CD:
case GET:
write(fd,&msg,sizeof(msg));
break;
case PUT:
strcpy(cmdTemp,msg.cmd);
dir=get_cmd_dir(cmdTemp);
printf("cmd :%s\n",msg.cmd);
if(access(dir,F_OK)==-1){
printf("%s this file no exit\n",dir);
}else{
fdFile=open(dir,O_RDWR);
putSize = lseek(fdFile,0,SEEK_END);
lseek(fdFile,0,SEEK_SET);
read(fdFile,msg.secondBuf,putSize);
close(fdFile);
write(fd,&msg,sizeof(msg));
}
break;
case LCD:
dir=get_cmd_dir(msg.cmd);
printf("the dir:%s\n",dir);
chdir(dir);
break;
case LLS:
system("ls");
break;
case QUIT:
strcpy(msg.cmd,"quit");
write(fd,&msg,sizeof(msg));
close(fd);
exit(-1);
case LPWD:
system("pwd");
break;
}
return ret;
}
void c_msg_handler(struct Msg msg,int fd)
{
int n_read;
int filefd;
struct Msg getmsg;
char *filename;
n_read =read(fd,&getmsg,sizeof(getmsg));
if(n_read == 0){
printf("sever is quit\n");
exit(-1);
}
if(getmsg.type == DOFILE){
filename=get_cmd_dir(msg.cmd);
filefd=open(filename,O_RDWR|O_CREAT,0666);
write(filefd,getmsg.secondBuf,strlen(getmsg.secondBuf));
close(filefd);
fflush(stdout);
}
else{
printf("---------------------\n");
printf("%s\n",getmsg.data);
printf("---------------------\n");
}
}
int main(int argc,char *argv[])
{
int client_fd;
int nread;
int ret;
char readBuf[128];
struct sockaddr_in client_addr;
struct Msg msg;
if(argc !=3){
printf("请输入IP地址和端口号\n");
exit(-1);
}
memset(&client_addr,0,sizeof(struct sockaddr));
client_fd=socket(AF_INET,SOCK_STREAM,0);
if(client_fd==-1){
perror("socket");
exit(-1);
}
client_addr.sin_family=AF_INET;
client_addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&(client_addr.sin_addr));
if(connect(client_fd,(struct sockaddr*)&client_addr,sizeof(struct sockaddr))==-1){
perror("connect");
exit(-1);
}
printf("connecting.....\n");
while(1){
memset(&msg,0,sizeof(msg));
putchar('>');
fgets(msg.cmd,1024,stdin);
if(msg.cmd[strlen(msg.cmd) - 1] == '\n') {
msg.cmd[strlen(msg.cmd) - 1] = '\0'; }
ret=cmd_handler(msg,client_fd);
if(ret>IFGO){
continue;
}
if(ret==-1){
printf("cmd error,please put new cmd\n");
continue;
}
c_msg_handler(msg,client_fd);
}
return 0;
}
#define LS 0
#define GET 1
#define PWD 2
#define IFGO 3
#define LCD 4
#define LLS 5
#define CD 6
#define PUT 7
#define QUIT 8
#define DOFILE 9
#define LPWD 10
struct Msg
{
int type;
char cmd[1024];
char data[1024];
char secondBuf[1024];
};
五、项目总结(遇到的问题)
1.在客户端进行put操作时,为防止strtok 将字符串破坏,导致无法获取put的目标文件,需要在引入一个字符串的变量保存。
strcpy(cmdTemp,msg.cmd);
dir=get_cmd_dir(cmdTemp);
2.在进行对输入字符串进行检测的时候,lcd 的检测一定要放在cd 的前面,因为cd 是lcd 中的一个子字符串,所以如果cd 的检测是放在lcd 的前面的话,那么无论是输入的是cd 还是lcd ,都会是返回cd 。
|