前言
跟著上官社長 陳哥花了一個月的時間終于把Linux系統(tǒng)編程學的差不多了,這一個月真的是頭疼啊,各種bug,調(diào)的真心心累,不過好在問題都解決掉了,在此也感謝一下答疑老師,給我提供了很多的思路,本文章是對前段時間學習Linux,做一個小小的總結(jié),才疏學淺,只學到這個地步,下來繼續(xù)努力,加油!。
一.基本功能
get + xxx 從服務器獲取某個文件到客戶端。
put + xxx 把客戶端的某個文件上傳到服務器。
cd + 路徑 切換目錄
lls 列出本地文件列表
ls 列出服務端文件列表
lcd +路徑 切換本地目錄
二.實現(xiàn)思路
1.使用socket先把服務器和客戶端建立連接。

2.建立連接后開始信息的交互
客戶端輸入指令服務器處理指令。
三.具體代碼如下
先建立socket連接,如下是服務器的代碼。
int main(int argc,char**argv)
{
? ? if(argc !=3 )//判斷參數(shù)是否輸入正確
? ? {
? ? ? ? printf("input errror\n");? ?
? ? ? ? exit(-1);
? ? }
? ? int s_fd = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建網(wǎng)絡套接字
? ? 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;//地址協(xié)議族
? ? addr.sin_prot = htons(atoi(argv[2]));//端口號,先使用atoi函數(shù)把參數(shù)轉(zhuǎn)換成整型,在使用htons轉(zhuǎn)為網(wǎng)絡字節(jié)序。
? ? inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函數(shù)把點分十進制的IP地址,轉(zhuǎn)換為網(wǎng)絡字節(jié)序。例如,192.168.147.155.
? ? bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
? ? listen(s_fd,10);//監(jiān)聽
? ? int sz = sizeof(struct sockaddr_in);
? ? while(1)//循環(huán)卡住不讓退出去。
? ? {
? ? ? ? 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;
}
上面只是服務器和客戶端,建立連接的代碼,還不攜帶參數(shù),下面開始客戶端和服務器進行通訊。
四.服務器/客戶端通訊
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)//分割指令,來獲取參數(shù)
{
? ? 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);//輸入的指令轉(zhuǎn)換成整數(shù)
? ? switch(ret)//根據(jù)ret的值來選擇
? ? {
case PWD:
? ? ? ? case LS:
? ? ? ? case CD:
? ?? ? ? ? ? ? msg.type = 0;//標記符
? ? ? ? ? ? ? ? write(fd,msg.data,sizeof(msg));//發(fā)送命令
? ? ? ? ? ? ? ? break;
? ? ? ?
? ? ? ? case GET:
? ? ? ? ? ? ? ? msg.type = 2;
? ? ? ? ? ? ? ? write(fd,msg.data,sizeof(msg));//發(fā)送命令
? ? ? ? ? ? ? ? break;
? ? ? ? case PUT:
? ? ? ? ? ? ? ? strcpy(buf,msg.data);
? ? ? ? ? ? ? ? dir = getdir(buf);
? ? ? ? ? ? ? ? if(access(dir,F_OK) == -1)//判斷參數(shù)文件是否存在
? ? ? ? ? ? ? ? ?{? ?
? ? ? ? ? ? ? ? ? ? ? ? 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));//向服務器發(fā)送命令
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?
? ? ? ? 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));//客戶端執(zhí)行到這里時,會阻塞在這,等待服務器寫入數(shù)據(jù)
? ? 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;//定義結(jié)構體
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr));//初始化結(jié)構體里的內(nèi)容
c_fd = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建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);//封裝一個函數(shù),處理指令
? ? ? ?
? ? if(ret >IFGO)
? ? ? ? {
? ? ? ? ? ? putchar('>');
? ? ? ? ? ? fflush(stdout);
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? if(ret == -1)
? ? ? ? {
? ? ? ? ? ? printf("commend out\n");
? ? ? ? ? ? printf(">");
? ? ? ? ? ? fflush(stdout);
? ? ? ? }
? ? ? handler_sever_message(c_fd,msg);//處理客戶端返回內(nèi)容
}
? ? close(c_fd);//關閉文件
return 0;
}
3.服務器文章來源:http://www.zghlxwxcb.cn/news/detail-524810.html
int get_cmd_type(char *cmd)//把指令轉(zhuǎn)換成整型
{
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)//分割指令,獲取第二個參數(shù)
{
? ? 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");執(zhí)行該參數(shù),并讀取,返回讀取文件的指針
? ? ? ? ? ? ? ? ? ? fread(msg.data,sizeof(msg.data),1,r);讀取到data空間里面,讀取一次,讀取的文件是上面r指向的文件。
? ? ? ? ? ? ? ? ? ? write(fd,msg.data,sizeof(msg));讀取完成后寫入。
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case CD:
? ? ? ? ? ? ? ? ? ?dir = getdir(msg.data);//先把指令分割出來,獲取參數(shù)
? ? ? ? ? ? ? ? ? ? printf("dir :%s\n",dir);//打印參數(shù)
? ? ? ? ? ? ? ? ? ? chdir(dir); 將當前目錄改向參數(shù)指向的目錄。
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case GET:
? ? ? ? ? ? ? ? ? ? dir = getdir(msg.data);//獲取參數(shù)文件
? ? ? ? ? ? ? ? ? ? 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);//分割獲取第二個參數(shù)
? ? ? ? ? ? ? ? ? ?fdfile = open(dir,O_RDWR|O_CREAT,0666);//打開該參數(shù)的文件
? ? ? ? ? ? ? ? ? ? write(fd,msg.buf,strlen(msg.buf));//將客戶端讀取的內(nèi)容寫入服務器
? ? ? ? ? ? ? ? ? ? close(fdfile);//寫完關閉文件
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case QUIT:
? ? ? ? ? ? ? ? ? ? printf("client quit\n");//打印退出信心
? ? ? ? ? ? ? ? ? ? exit(-1);//退出程序
}
int main(int argc,char**argv)
{
if(argc !=3 )//判斷參數(shù)是否輸入正確
{
printf("input errror\n");
exit(-1);
}
int s_fd = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建網(wǎng)絡套接字
? ? 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;//地址協(xié)議族
addr.sin_prot = htons(atoi(argv[2]));//端口號,先使用atoi函數(shù)把參數(shù)轉(zhuǎn)換成整型,在使用htons轉(zhuǎn)為網(wǎng)絡字節(jié)序。
inet_aton(argv[1], &s_addr.sin_addr);//IP地址,使用inet_aton函數(shù)把點分十進制的IP地址,轉(zhuǎn)換為網(wǎng)絡字節(jié)序。例如,192.168.147.155.
bind(s_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in));
listen(s_fd,10);//監(jiān)聽
int sz = sizeof(struct sockaddr_in);
while(1)//循環(huán)卡住不讓退出去。
{
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)//創(chuàng)建子進程來對接,進行通訊
? ? ? ? {
? ? ? ? ? ? ? ? memset(msg.data,0,sizeof(msg.date));
? ? ? ? ? ? ? ? n_read =read(c_fd,&msg,sizeof(msg));//讀取客戶端發(fā)過來的消息
? ? ? ? ? ? ? ? if(n_read == 0)//判斷讀取信息
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? printf("client out\n");
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }else (if n_read>0)//如果讀取到了
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? msg_hanfler(msg,c_fd);//處理函數(shù)
? ? ? ? ? ? ? ? }
? ? ? ? }
}
return 0;
}
以上就是我對這段時間學習Linux的理解,希望可以幫助到大家謝謝文章來源地址http://www.zghlxwxcb.cn/news/detail-524810.html
到了這里,關于Linux系統(tǒng)編程,使用C語言實現(xiàn)簡單的FTP(服務器/客戶端)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!