一、服务端server的建立 :
以共享使用文件 config.h ,使用结构体较为方便 :
定义一些命令的宏,有兴趣后续可添加其他:
#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
struct Message
{
int type; // 定义标记符号
char data[1024]; //将输入的命令存在这里
char msgbuf[128]; // put 、get文件使用
};
(1) 设置登录账户和密码功能
void ID_and_Key()
{
char *p = NULL;
int key;
p =(char *) malloc(sizeof(char)*128);
printf("Please scanf you ID :");
scanf("%s",p);
printf("Please scanf you Key :");
scanf("%d",&key);
if( (strcmp(p,"lz") == 0) && key == 666)
{
printf("OK!\n");
}
}
(2) 提取命令的类型 :
int option_cmd(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 ) //得到完整命令,如 get config.h
return GET;
if( strstr(cmd,"put")!= NULL ) //得到完整命令
return PUT;
if( strstr(cmd,"cd")!= NULL) //得到完整命令
return CD;
}
粗略讲解strstr函数功能:
定义:strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *str1 = "abcdefghijk";
char *str2 = "efg";
char *p = NULL;
p = (char *)malloc(sizeof(char)*128); //开辟空间
p = strstr(str1,str2);
printf("%s\n",p);
return 0;
}
输出结果:efghijk
(3)分割字符串,调用CD、get、中需要使用
//分割字符串
char *GetDir(char *pcmd)
{
char *p;
p = strtok(pcmd," "); //以空格为标记分割字符串,分割完后为NULL
p = strtok(NULL," "); //以NULL 为标记
return p;
}
粗略讲解strtok:
#include<stdio.h>
#include<string.h>
int main()
{
char buf[20] = "liu,zheng,baba";
char *q[3];
int i = 0;
char *p = buf;
while( (q[i] = strtok(p,",")) != NULL ) // 以逗号 “,” 为标准进行字符串分割
{
i++;
p = NULL;
}
for(i = 0;i<3;i++)
{
printf("q[%d] is : %s\n",i,q[i]);
}
return 0;
}
结果:
q[0] is : liu
q[1] is : zheng
q[2] is : baba
(4)处理客户端发送的指令,以定义 message_handle 函数为例 :
//处理客户端发送的指令
void message_handle(struct Message msg,int c_fd)
{
char cmdbuf[1024] = {0};
char *file = NULL;
int file_fd;
printf("The scanf cmd is : %s\n",msg.data); //服务端显示读取的客户端命令
int Cmd = option_cmd(msg.data); //将读取的命令进行选择,并返回对应指令
switch(Cmd) //对返回的指令进行选择执行
{
case LS:
case PWD: // 将该 ls、pwd 指令进行读取并打开内容
msg.type = 0;
FILE *p = popen(msg.data,"r");
fread(msg.data,sizeof(msg.data),1,p); // 读取数据
write(c_fd,&msg,sizeof(msg)); //将数据发送给客户端,进行打印出来
break;
case QUIT: //客户端输入quit 结束连接
printf("The client always die out!\n");
printf("--------------------------\n");
printf("**************************\n");
exit(-1); //结束整个进程
case CD:
msg.type = 1; //将该指令定位 1 防止和别的指令冲突
char *dir = GetDir(msg.data); //将指令进行分割字符串,得到 cd 后面的指令
printf("The dir is :%s\n",dir);
chdir(dir); //chdir 函数 直接执行 dir 分割出来的指令 例如 ../
break; //不适用system函数打开,是因为system是建立在创建另一个子进
//程上,在子进程上实现,而父进程却没有调用
case GET:
file = GetDir(msg.data); //分割该指令的字符串 例如: get server.c
//则 file = server.c
if(access(file,F_OK) == -1) //判断这个文件存不存在,不存在为 -1
{
strcpy(msg.data,"Sorry,NO this file");
write(c_fd,&msg,sizeof(msg));
}
else
{
msg.type = DOFILE; // 标记方便客户端调用
file_fd = open(file,O_RDWR); // 把文件数据打开
read(file_fd,cmdbuf,sizeof(cmdbuf)); //读入文件数据到数组
close(file_fd);
strcpy(msg.data,cmdbuf); //把数组的文件数据复制到结构体数组中
write(c_fd,&msg,sizeof(msg));//发送数据到客户端
}
break;
case PUT: // 分割得到的字符串,用来打开这个文件,流程和 get 相反
file_fd = open(GetDir(msg.data),O_RDWR|O_CREAT,0666);
write(file_fd,msg.msgbuf,strlen(msg.msgbuf)); // 把这个文件给客户端写数据
close(file_fd); //客户端写完数据发送过来,关闭该文件
break;
}
}
(5)主函数部分 :
int main(int argc , char **argv)
{
int server_fd;
int client_fd;
int n_read;
struct Message msg; //创建结构体对象
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in)); //为新申请内存,初始化结构体
memset(&c_addr,0,sizeof(struct sockaddr_in)); //为新申请内存,初始化结构体
//1.socket
server_fd = socket(AF_INET,SOCK_STREAM,0); //创建服务端socket对象
if(server_fd == -1) //检查是否创建对象成功
{
printf("create socket failed!\n");
exit(-1);
}
//2.bind
s_addr.sin_family = AF_INET; // 建立 socket 对象和IP地址、端口进行绑定
s_addr.sin_port = htons(atoi(argv[2])); // 需要将 argv 里头的字符串转成整型
inet_aton(argv[1],&s_addr.sin_addr); // 把IP地址字符串转换成网络能识别的形式
// 绑定IP地址和端口,注意s_addr需要强转成 struct sockaddr *型
bind(server_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(server_fd,10); //监听信号,设置最多监听队列个数
//4.accept
int len = sizeof(struct sockaddr_in);
ID_and_Key(); //用于连接客户端前进行账号、密码登录
while(1)
{
// 接受客户端信号接入,创建一个新的已连接套接字描述符
client_fd = accept(server_fd,(struct sockaddr *)&c_addr,&len);
if(client_fd == -1) // 确认是否接受客户端成功
{
perror("why accpet failed : ");
exit(-1);
}
// 将 IP地址网络能识别的形式转化成字符串的形式打印
printf("Connect IP address is : %s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0) //当有信号接入的时候,才创建新的进程去跑这个客户端
{
while(1)
{ // 初始化结构体中 data数组内存
memset(msg.data,0,sizeof(msg.data));
n_read = read(client_fd, &msg ,sizeof(msg));// 接受客户端输入的指令
if(n_read == 0) // 客户端没有输入指令
{
printf("The client over!\n");
break;
}
else if(n_read == -1)// 接受数据失败
{
printf("read failed!\n");
exit(-1);
}
else if(n_read > 0) // 接受到来自客户端的指令
{
message_handle(msg,client_fd); //将该指令进行分类处理
}
}
}
}
close(server_fd); //关闭socket对象连接
close(client_fd); //关闭接受客户端连接
return 0;
}
二、客户端client的建立 :
共享文件config.h :
#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
struct Message
{
int type; // 定义标记符号
char data[1024]; //将输入的命令存在这里
char msgbuf[128]; // put 、get文件使用
};
(1)接受指令进行分类选择不同返回值 :
int option_cmd(char *cmd)
{
if( !(strcmp("ls",cmd)) )
return LS;
if( !(strcmp("lls",cmd)) )
return LLS;
if( !(strcmp("pwd",cmd)) )
return PWD;
if( !(strcmp("quit",cmd)) )
return QUIT;
if( strstr(cmd,"get") )
return GET;
if( strstr(cmd,"put") )
return PUT;
if( !strcmp(cmd,"cd") ) // 这里使用strstr 会导致CD 和 LCD读取重复
return CD;
if( !strcmp(cmd,"lcd") ) // 这里使用strstr 会导致CD 和 LCD读取重复
return LCD;
return -1;
}
(2)对指令的字符串进行分割(与服务端有点不同):
char *GetDir(char *cmd) // 分割字符串函数
{
char *p; // strtok函数原理 可参考上面服务端解析
p = strtok(cmd," " ); // 以空格为分割点,进行分割函数
p = strtok(NULL," ");
if(p==NULL) // 判断指令是否有空格,有空格就返回空格后面的内容
{
return cmd;
}
return p;
}
(3)指令的分类执行 :
int CmdHandle_option(struct Message msg,int c_fd)
{
int CMD;
int file_fd;
char *dir = NULL;
char buf[128];
memset(buf,'\0',128); // 初始化buf数组,全设为 '\0'
strcpy(buf,msg.data); //把打入的指令存放在buf数组中
char cmdbuf[1024];
dir = GetDir(buf); //把指令进行字符串分割处理,主要从于LCD、PUT
CMD = option_cmd(buf); //确认指令选择的类型返回值
switch(CMD) // 指令的选择
{
case LS:
case PWD:
msg.type = 0; //服务端那边同样的标记
write(c_fd,&msg,sizeof(msg)); //发送数据
break;
case CD:
msg.type = 1; //服务端那边同样的标记
write(c_fd,&msg,sizeof(msg)); //发送数据
break;
case LLS:
system("ls"); //直接用system打开指令
break;
case LCD:
//dir = GetDir(msg.data);
chdir(dir); //直接执行分割字符串后,返回的指令
break;
case QUIT:
strcpy(msg.data,"quit"); //终止连接命令
write(c_fd,&msg,sizeof(msg));
close(c_fd); //关闭连接
exit(-1);
case GET:
msg.type = 2;
write(c_fd,&msg,sizeof(msg)); //把要得到的文件发送到服务端获取
break;
case PUT:
strcpy(cmdbuf,msg.data); //将要得到的文件指令,存放到数组cmdbuf中
//dir = GetDir(cmdbuf);
if(access(dir,F_OK) == -1) // access函数,判断客户端是否有这个文件
{
printf("Sorry ,The %s file not find!\n",dir);
}
else
{
file_fd = open(dir,O_RDWR); // 打开新的文件
read(file_fd,msg.msgbuf,sizeof(msg.msgbuf));//把想要put的文件数据写入
close(file_fd);// 关闭文件
write(c_fd,&msg,sizeof(msg));// 把数据发送给服务端那边获取该文件
}
break;
}
return CMD; // 返回该次指令,用于打印数据
}
(4)数据的打印处理 :
void message_handle(struct Message msg,int c_fd)
{
int n_read;
struct Message MSG;
int newfile_fd;
n_read = read(c_fd, &MSG, sizeof(MSG)); //接受连接后客户端指令数据
if(n_read == 0) // 判断是否连接好服务器信号
{
printf("The server is die out !\n");
exit(-1); // 结束该进程
}
else if(MSG.type == DOFILE) // 用于 get指令
{
char *file = GetDir(msg.data); // 分割字符,得到文件名称
newfile_fd = open(file,O_RDWR|O_CREAT,0600); //类似打开新文件
write(newfile_fd,MSG.data,strlen(MSG.data)); //往里头发送数据
printf("------------>\n");
fflush(stdout); // 清空printf后缓冲区的数据
}
else
{
printf("=============================\n");
printf("*****************************\n");
printf("\n%s\n",MSG.data); // 打印命令执行结构
printf("*****************************\n");
printf("=============================\n");
fflush(stdout); // 清空printf后缓冲区的数据
}
}
(5)主函数部分 :
int main(int argc , char **argv)
{
int client_fd;
int n_read;
struct Message msg;
//1.socket
client_fd = socket(AF_INET,SOCK_STREAM,0); // 创建客户端socket对象
if(client_fd == -1)
{
printf("create socket failed!\n");
exit(-1);
}
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in)); // 申请内存前初始化
c_addr.sin_family = AF_INET; // 绑定成IPv4 协议
c_addr.sin_port = htons(atoi(argv[2])); // 需要将 argv 里头的字符串转成整型
inet_aton(argv[1],&c_addr.sin_addr); // 将IP地址转换成网络能识别的形式
//2.connect
// 连接服务端监听的信号,接入成功返回值为 0
if( connect(client_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1)
{
printf("The connect failed !\n");
exit(-1);
}
printf("Connect server OK !\n"); //连接成功提示
while(1)
{
memset(msg.data,0,sizeof(msg.data)); //初始化结构体data数组
gets(msg.data); // 输入指令
printf("--->You scanf cmd is : %s\n",msg.data); // 打印指令
int cmd = CmdHandle_option(msg,client_fd); // 把指令进行分类处理
if(cmd > IFGO) // 此时指令 为LCD 、LLS、quit、put
{
printf("------------>");
fflush(stdout); // 清空 printf缓冲区内存数组
continue;
}
if(cmd == -1)
{
printf("The cmd is not find !\n");
fflush(stdout);
continue;
}
message_handle(msg,client_fd); // 把选择好的命令传送
}
return 0;
}
三、以ftpserver.c 和 ftpclient.c 为例子 :
config.h :
#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
struct Message
{
int type;
char data[1024];
char msgbuf[128];
};
ftpserver.c :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
void ID_and_Key()
{
char *p = NULL;
int key;
p =(char *) malloc(sizeof(char)*128);
printf("Please scanf you ID :");
scanf("%s",p);
printf("Please scanf you Key :");
scanf("%d",&key);
if( (strcmp(p,"lz") == 0) && key == 666)
{
printf("OK!\n");
}
}
int option_cmd(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,"put")!= NULL )
return PUT;
if( strstr(cmd,"cd")!= NULL)
return CD;
}
char *GetDir(char *pcmd)
{
char *p;
p = strtok(pcmd," ");
p = strtok(NULL," ");
return p;
}
void message_handle(struct Message msg,int c_fd)
{
char cmdbuf[1024] = {0};
char *file = NULL;
int file_fd;
printf("The scanf cmd is : %s\n",msg.data);
int Cmd = option_cmd(msg.data);
switch(Cmd)
{
case LS:
case PWD:
msg.type = 0;
FILE *p = popen(msg.data,"r");
fread(msg.data,sizeof(msg.data),1,p);
write(c_fd,&msg,sizeof(msg));
break;
case QUIT:
printf("The client always die out!\n");
printf("--------------------------\n");
printf("**************************\n");
exit(-1);
case CD:
msg.type = 1;
char *dir = GetDir(msg.data);
printf("The dir is :%s\n",dir);
chdir(dir);
break;
case GET:
file = GetDir(msg.data);
if(access(file,F_OK) == -1)
{
strcpy(msg.data,"Sorry,NO this file");
write(c_fd,&msg,sizeof(msg));
}
else
{
msg.type = DOFILE;
file_fd = open(file,O_RDWR);
read(file_fd,cmdbuf,sizeof(cmdbuf));
close(file_fd);
strcpy(msg.data,cmdbuf);
write(c_fd,&msg,sizeof(msg));
}
break;
case PUT:
file_fd = open(GetDir(msg.data),O_RDWR|O_CREAT,0666);
write(file_fd,msg.msgbuf,strlen(msg.msgbuf));
close(file_fd);
break;
}
}
int main(int argc , char **argv)
{
int server_fd;
int client_fd;
int n_read;
struct Message msg;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1.socket
server_fd = socket(AF_INET,SOCK_STREAM,0);
if(server_fd == -1)
{
printf("create socket failed!\n");
exit(-1);
}
//2.bind
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(server_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(server_fd,10);
//4.accept
int len = sizeof(struct sockaddr_in);
ID_and_Key();
while(1)
{
client_fd = accept(server_fd,(struct sockaddr *)&c_addr,&len);
if(client_fd == -1)
{
perror("why accpet failed : ");
exit(-1);
}
// IP
printf("Connect IP address is : %s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0)
{
while(1)
{
memset(msg.data,0,sizeof(msg.data));
n_read = read(client_fd, &msg ,sizeof(msg));
if(n_read == 0)
{
printf("The client over!\n");
break;
}
else if(n_read == -1)
{
printf("read failed!\n");
exit(-1);
}
else if(n_read > 0)
{
message_handle(msg,client_fd);
}
}
}
}
close(server_fd);
close(client_fd);
return 0;
}
ftpclient.c :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
int option_cmd(char *cmd)
{
if( !(strcmp("ls",cmd)) )
return LS;
if( !(strcmp("lls",cmd)) )
return LLS;
if( !(strcmp("pwd",cmd)) )
return PWD;
if( !(strcmp("quit",cmd)) )
return QUIT;
if( strstr(cmd,"get") )
return GET;
if( strstr(cmd,"put") )
return PUT;
if( !strcmp(cmd,"cd") )
return CD;
if( !strcmp(cmd,"lcd") )
return LCD;
return -1;
}
char *GetDir(char *cmd)
{
char *p;
p = strtok(cmd," " );
p = strtok(NULL," ");
if(p==NULL)
{
return cmd;
}
return p;
}
int CmdHandle_option(struct Message msg,int c_fd)
{
int CMD;
int file_fd;
char *dir = NULL;
char buf[128];
memset(buf,'\0',128);
strcpy(buf,msg.data);
char cmdbuf[1024];
dir = GetDir(buf);
CMD = option_cmd(buf);
switch(CMD)
{
case LS:
case PWD:
msg.type = 0;
write(c_fd,&msg,sizeof(msg));
break;
case CD:
msg.type = 1;
write(c_fd,&msg,sizeof(msg));
break;
case LLS:
system("ls");
break;
case LCD:
//dir = GetDir(msg.data);
chdir(dir);
break;
case QUIT:
strcpy(msg.data,"quit");
write(c_fd,&msg,sizeof(msg));
close(c_fd);
exit(-1);
case GET:
msg.type = 2;
write(c_fd,&msg,sizeof(msg));
break;
case PUT:
strcpy(cmdbuf,msg.data);
//dir = GetDir(cmdbuf);
if(access(dir,F_OK) == -1)
{
printf("Sorry ,The %s file not find!\n",dir);
}
else
{
file_fd = open(dir,O_RDWR);
read(file_fd,msg.msgbuf,sizeof(msg.msgbuf));
close(file_fd);
write(c_fd,&msg,sizeof(msg));
}
break;
}
return CMD;
}
void message_handle(struct Message msg,int c_fd)
{
int n_read;
struct Message MSG;
int newfile_fd;
n_read = read(c_fd, &MSG, sizeof(MSG));
if(n_read == 0)
{
printf("The server is die out !\n");
exit(-1);
}
else if(MSG.type == DOFILE)
{
char *file = GetDir(msg.data);
newfile_fd = open(file,O_RDWR|O_CREAT,0600);
write(newfile_fd,MSG.data,strlen(MSG.data));
printf("------------>\n");
fflush(stdout);
}
else
{
printf("=============================\n");
printf("*****************************\n");
printf("\n%s\n",MSG.data);
printf("*****************************\n");
printf("=============================\n");
fflush(stdout);
}
}
int main(int argc , char **argv)
{
int client_fd;
int n_read;
struct Message msg;
//1.socket
client_fd = socket(AF_INET,SOCK_STREAM,0);
if(client_fd == -1)
{
printf("create socket failed!\n");
exit(-1);
}
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
//2.connect
if( connect(client_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1)
{
printf("The connect failed !\n");
exit(-1);
}
printf("Connect server OK !\n");
while(1)
{
memset(msg.data,0,sizeof(msg.data));
gets(msg.data);
printf("--->You scanf cmd is : %s\n",msg.data);
int cmd = CmdHandle_option(msg,client_fd);
if(cmd > IFGO)
{
printf("------------>");
fflush(stdout);
continue;
}
if(cmd == -1)
{
printf("The cmd is not find !\n");
fflush(stdout);
continue;
}
message_handle(msg,client_fd);
}
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68481.html