前言
跟着上官社长 陈哥花了一个月的时间终于把Linux系统编程学的差不多了,这一个月真的是头疼啊,各种bug,调的真心心累,不过好在问题都解决掉了,在此也感谢一下答疑老师,给我提供了很多的思路,本文章是对前段时间学习Linux,做一个小小的总结,才疏学浅,只学到这个地步,下来继续努力,加油!。
一.基本功能
get + xxx 从服务器获取某个文件到客户端。
put + xxx 把客户端的某个文件上传到服务器。
cd + 路径 切换目录
lls 列出本地文件列表
ls 列出服务端文件列表
lcd +路径 切换本地目录
二.实现思路
1.使用socket先把服务器和客户端建立连接。
2.建立连接后开始信息的交互
客户端输入指令服务器处理指令。
三.具体代码如下
先建立socket连接,如下是服务器的代码。
int main(int argc,char**argv)
{
if(argc !=3 )//判断参数是否输入正确
{
printf("input errror\n");
exit(-1);
}
int s_fd = socket(AF_INET,SOCK_STREAM,0);//创建网络套接字
struct sockaddr_in addr;
struct sockaddr_in addr2;
memset(&addr,0,sizeof(struct sockaddr_in));
memset(&addr2,0,sizeof(struct sockaddr_in));
int n_read;
addr.sin_family = AF_INET;//地址协议族
addr.sin_prot = htons(atoi(argv[2]));//端口号,先使用atoi函数把参数转换成整型,在使用htons转为网络字节序。
inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函数把点分十进制的IP地址,转换为网络字节序。例如,192.168.147.155.
bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
listen(s_fd,10);//监听
int sz = sizeof(struct sockaddr_in);
while(1)//循环卡住不让退出去。
{
int c_fd = accept(s_fd,(struct sockaddr *)&addr2,&sz);//尝试连接
if(c_fd == -1)
{
perror("accept");
exit(-1);
}
printf("get connect : %s\n",inet_nota(addr2.sin_addr));//连接成功打印对方的IP地址。
}
return 0;
}
客服端代码,如下
int main(int argc,char **argv)
{
int c_fd;
struct Msg msg;
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr));
// 1. socket
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1)
{
perror("socket:");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port =htons(atoi(argv[2]));
inet_aton(argv[1], &c_addr.sin_addr);
connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr_in));//请求连接
printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//连接成功打印IP
while(1)
{
}
return 0;
}
上面只是服务器和客户端,建立连接的代码,还不携带参数,下面开始客户端和服务器进行通讯。
四.服务器/客户端通讯
1.服务器和客户端共有的文件
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <fcntl.h>
#define LS 0
#define PWD 1
#define GET 2
#define IFGO 3
#define CD 4
#define PUT 5
#define LLS 6
#define LCD 7
#define LPWD 8
#define QUIT 9
#define DOFILE 10
struct Msg
{
int type;
char data[1024];
char buf[128];
};
2.客户端
int get_cmd_type(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 QUIE;
//在输入的指令字符串里面找,对应的指令
if(strstr(cmd."cd")) return CD;
if(strstr(cmd,"get")) return GET;
if(strstr(cmd,"put")) return PUT;
return -1;//未找到返回错误
}
char *getdir(char *cms)//分割指令,来获取参数
{
char *p = NULL;
p = strtok(cms," ");
p = strtok(NULL," ");
return p;
}
int cmd_handler(struct Msg msg,int fd)
{
int ret;
char buf[100];//临时空间
char *dir = NULL;
int filefd; //文件表示符
ret = get_cmd_type(msg.data);//输入的指令转换成整数
switch(ret)//根据ret的值来选择
{
case PWD:
case LS:
case CD:
msg.type = 0;//标记符
write(fd,msg.data,sizeof(msg));//发送命令
break;
case GET:
msg.type = 2;
write(fd,msg.data,sizeof(msg));//发送命令
break;
case PUT:
strcpy(buf,msg.data);
dir = getdir(buf);
if(access(dir,F_OK) == -1)//判断参数文件是否存在
{
printf("%s not exsit\n",dir);
}
else//如果存在
{
filefd = open(dir,O_RDWR);//打开这个文件
read(filefd,msg.buf,sizeof(msg.buf));//读取这个文件
close(filefd);//关闭这个文件
write(fd,msg,data,sizeof(msg));//向服务器发送命令
}
case QUIT:
strcpy(msg.data,"quit");
write(fd,msg.data,sizeof(msg));
close(fd);//关闭文件
exit(-1);//退出程序
case LLS:
system("ls");
break;
case LCD:
dir = getdir(msg.data);
chdir(dir);
break;
}
return ret;
}
void hand_sever_message(int c_fd,struct Msg msg)
{
struct Msg msgget;
char *dir = NULL;
int n_read;
n_read = read(c_fd,&msgget,sizeof(msgget));//客户端执行到这里时,会阻塞在这,等待服务器写入数据
if(n_read == -1)
{
printf("server out \n");
exit(-1);
}
else if(msg.type == DOFILE)
{
dir = getdir(msg.data);
int filefd = open(dir,O_RDWR|O_CREAT,0666);
write(filefd,msgget.data,strlen(msgget.data));
putchar('>');
fflush(stdout);
}
else
{
printf("============================\n");
printf("\n%s\n",msgget.data);
printf("=============================\n");
putchar('>');
fflush(stdout);
}
}
int main(int argc,char **argv)
{
int c_fd;
int ret;
struct Msg msg;//定义结构体
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr));//初始化结构体里的内容
c_fd = socket(AF_INET,SOCK_STREAM,0);//创建socket
if(c_fd==-1)
{
perror("socket:");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port =htons(atoi(argv[2]));
inet_aton(argv[1], &c_addr.sin_addr);
connect(c_fd,(struct sockaddr*)&c_addr,sizeof(struct sockaddr_in));//请求连接
printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//连接成功打印IP
while(1)
{
memset(msg.data,0,sizeof(msg.data));
scanf("%[\n]",msg.data);//获取客户端指令
if(strlen(msg.data) == 0)
{
if(mark == 1)
{
printf(">");
}
}
ret = cmd_handler(msg,c_fd);//封装一个函数,处理指令
if(ret >IFGO)
{
putchar('>');
fflush(stdout);
continue;
}
if(ret == -1)
{
printf("commend out\n");
printf(">");
fflush(stdout);
}
handler_sever_message(c_fd,msg);//处理客户端返回内容
}
close(c_fd);//关闭文件
return 0;
}
3.服务器文章来源:https://www.toymoban.com/news/detail-524810.html
int get_cmd_type(char *cmd)//把指令转换成整型
{
if(!strcmp("ls",cmd)) return LS;
if(!strcmp("quit",cmd)) return QUIT;
if(!strcmp("pwd",cmd)) return PWD;
if(strstr(cmd,"cd")!=NULL) return CD;
if(strstr(cmd,"get")!=NULL) return GET;
if(strstr(cmd,"put")!=NULL) return PUT;
return -1;
}
char *getdir(char cmd)//分割指令,获取第二个参数
{
char *p = NULL;
p = strtok(cmd," ");
p = strtok(NULL," ");
return p;
}
void msg_handler(struct Msg msg,int fd)
{
int ret;
char *dir;
char *databuf[1024] = {0};//临时空间
int fdfile;//文件描述符
ret = get_cmd_type(msg.data);
switch(ret)
case LS:
case PWD:
msg.type = 0
FILE *r = popen(msg.data,"r");执行该参数,并读取,返回读取文件的指针
fread(msg.data,sizeof(msg.data),1,r);读取到data空间里面,读取一次,读取的文件是上面r指向的文件。
write(fd,msg.data,sizeof(msg));读取完成后写入。
break;
case CD:
dir = getdir(msg.data);//先把指令分割出来,获取参数
printf("dir :%s\n",dir);//打印参数
chdir(dir); 将当前目录改向参数指向的目录。
break;
case GET:
dir = getdir(msg.data);//获取参数文件
if(access(dir,F_OK)== -1)//判断文件存在吗
{
strcpy(msg.data,"NO this file");
}
else//如果存在
{
msg.type = DOFILE; //标记
fdfile = open(dir,O_RDWR);//打开此文件
read(fdfile,databuf,sizeof(databuf));//读取此文件到临时空间databuf里面
close(fdfile);//读取完成,关闭此文件
strcpy(msg.data,databuf);//将databuf拷贝
write(fd,msg.data,sizeof(msg));//写入
}
break;
case PUT:
dir = getdir(msg.data);//分割获取第二个参数
fdfile = open(dir,O_RDWR|O_CREAT,0666);//打开该参数的文件
write(fd,msg.buf,strlen(msg.buf));//将客户端读取的内容写入服务器
close(fdfile);//写完关闭文件
break;
case QUIT:
printf("client quit\n");//打印退出信心
exit(-1);//退出程序
}
int main(int argc,char**argv)
{
if(argc !=3 )//判断参数是否输入正确
{
printf("input errror\n");
exit(-1);
}
int s_fd = socket(AF_INET,SOCK_STREAM,0);//创建网络套接字
struct Msg msg;
struct sockaddr_in addr;
struct sockaddr_in addr2;
memset(&addr,0,sizeof(struct sockaddr_in));
memset(&addr2,0,sizeof(struct sockaddr_in));
int n_read;
addr.sin_family = AF_INET;//地址协议族
addr.sin_prot = htons(atoi(argv[2]));//端口号,先使用atoi函数把参数转换成整型,在使用htons转为网络字节序。
inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函数把点分十进制的IP地址,转换为网络字节序。例如,192.168.147.155.
bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
listen(s_fd,10);//监听
int sz = sizeof(struct sockaddr_in);
while(1)//循环卡住不让退出去。
{
int c_fd = accept(s_fd,(struct sockaddr *)&addr2,&sz);//尝试连接
if(c_fd == -1)
{
perror("accept");
exit(-1);
}
printf("get connect : %s\n",inet_nota(addr2.sin_addr));//连接成功打印对方的IP地址。
if(fork()== 0)//创建子进程来对接,进行通讯
{
memset(msg.data,0,sizeof(msg.date));
n_read =read(c_fd,&msg,sizeof(msg));//读取客户端发过来的消息
if(n_read == 0)//判断读取信息
{
printf("client out\n");
break;
}else (if n_read>0)//如果读取到了
{
msg_hanfler(msg,c_fd);//处理函数
}
}
}
return 0;
}
以上就是我对这段时间学习Linux的理解,希望可以帮助到大家谢谢文章来源地址https://www.toymoban.com/news/detail-524810.html
到了这里,关于Linux系统编程,使用C语言实现简单的FTP(服务器/客户端)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!