- #include "./fun.h"
-
- int main(int argc,const char * argv[])
- {
- //1.判断入参
- if(argc!=3){
- fprintf(stderr,"入参为空,请检查\n");
- return -1;
- }
- //端口号转整型
- int port=atoi(argv[2]);
- //变量声明
- struct sockaddr_in sin;
- int sinLen=sizeof(sin);
- struct sockaddr_in cin;
- int cinLen=sizeof(cin);
- Info_t info;
- int newfd;
- pthread_t tid;
- //2.创建套接字
- int sfd=socket(AF_INET,SOCK_STREAM,0);
- if(sfd==-1){
- PRINT_ERR("socket error");
- }
- //3.快速重用端口号
- int optval=1;
- if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))==-1){
- PRINT_ERR("setsockopt error");
- }
- //3.填充服务器结构体信息
- sin.sin_family=AF_INET;
- sin.sin_addr.s_addr=inet_addr(argv[1]);
- sin.sin_port=htons(port);
- //4.绑定
- if(bind(sfd,(struct sockaddr *)&sin,sinLen)==-1){
- PRINT_ERR("bind error");
- }
- //5.监听
- if(listen(sfd,10)==-1){
- PRINT_ERR("listen error");
- }
- //6.多线程并发
- while(1){
- newfd=accept(sfd,(struct sockaddr *)&cin,&sinLen);
- if(newfd==-1){
- PRINT_ERR("accept error");
- }
- info.newfd=newfd;
- //创建线程,将信息结构体传入线程
- if(pthread_create(&tid,NULL,callBack,&info)==-1){
- PRINT_ERR("pthread_create error");
- }
- }
- //7.关闭套接字
- close(sfd);
- return 0;
- }
- #include "./fun.h"
-
- int main(int argc, const char *argv[])
- {
- // 1.判断入参
- if (argc != 3) {
- fprintf(stderr, "入参为空,请检查\n");
- return -1;
- }
- //变量声明
- struct sockaddr_in sin;
- int sinLen = sizeof(sin);
- buf_t buf;
- char path[128] = "";
- // 2.端口号转整型
- int port = atoi(argv[2]);
- // 3.创建套接字
- int sfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sfd == -1) {
- PRINT_ERR("socket error");
- }
- // 4.填充结构体信息
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = inet_addr(argv[1]);
- sin.sin_port = htons(port);
- // 5.连接服务器
- if (connect(sfd, (struct sockaddr *)&sin, sinLen) == -1) {
- PRINT_ERR("connect error");
- }
- while (1) {
- // 6.打印选项菜单
- puts("*****************************");
- puts("*********1.查看文件***********");
- puts("*********2.下载文件***********");
- puts("*********3.上传文件***********");
- puts("*****************************");
- printf("请输入选项:>>>");
- memset(&buf, 0, sizeof(buf));
- memset(path, 0, sizeof(path));
-
- scanf("%d", &buf.type);
- getchar();
- switch (buf.type) {
- case 1:
- break;
- case 2:
- if (getcwd(path, sizeof(path)) == NULL) {
- PRINT_ERR("getcwd error");
- }
- strcpy(buf.data1, path);
- strcat(buf.data1, "/download/");
- printf("请输入要下载的文件名:>>>");
- if (fgets(buf.data2, sizeof(buf.data2), stdin) == NULL) {
- PRINT_ERR("fgets error");
- }
- buf.data2[strlen(buf.data2) - 1] = '\0';
- strcat(buf.data1, buf.data2);
- break;
- case 3:
- if (getcwd(path, sizeof(path)) == NULL) {
- PRINT_ERR("getcwd error");
- }
- strcpy(buf.data1, path);
- strcat(buf.data1, "/download/");
- printf("请输入要上传的文件名:>>>");
- if (fgets(buf.data2, sizeof(buf.data2), stdin) == NULL) {
- PRINT_ERR("fgets error");
- }
- buf.data2[strlen(buf.data2) - 1] = '\0';
- strcat(buf.data1, buf.data2);
- break;
- default:
- printf("error");
- }
-
- // 7.发送消息
- if (send(sfd, &buf, sizeof(buf), 0) == -1) {
- PRINT_ERR("send error");
- }
- // printf("1\n");
- // 8.接收消息
- while (1) {
- memset(&buf, 0, sizeof(buf));
- if (recv(sfd, &buf, sizeof(buf), 0) == -1) {
- PRINT_ERR("recv error");
- }
- // buf.data2是quit说明服务器读取文件名已经读完,退出循环
- if (strcmp(buf.data2, "quit") == 0)
- break;
- puts(buf.data1);
- if (buf.type == 2 || buf.type == 3)
- break;
- }
- //按任意键继续
- printf("<<请按回车键继续>>");
- getchar();
- }
- // 8.关闭套接字
- close(sfd);
- return 0;
- }
- #ifndef __FUN_H__
- #define __FUN_H__
- #include
- /********共用***********/
- //结构体声明
- //线程信息结构体
- typedef struct{
- int newfd;
- }Info_t;
- //消息收发结构体
- typedef struct{
- int type;
- char data1[256];
- char data2[256];
- }buf_t;
- /********服务器端***********/
- //函数声明
- void *callBack(void *arg);
- //显示文件
- void showFile(int newfd);
- //下载文件
- void downloadFile(int newfd,buf_t buf);\
- //上传文件
- void uploadFile(int newfd,buf_t buf);
-
- /********客户端***********/
-
-
- #endif
- #include "fun.h"
-
- void *callBack(void *arg)
- {
- //转分离态
- pthread_detach(pthread_self());
- Info_t info = *(Info_t *)arg;
- int newfd = info.newfd;
-
- //变量声明
- buf_t buf;
- //循环收发数据
- while (1) {
- if (recv(newfd, &buf, sizeof(buf), 0) == -1) {
- VPRINT_ERR("recv error");
- }
- switch (buf.type) {
- case 1:
- showFile(newfd);
- break;
- case 2:
- downloadFile(newfd, buf);
- break;
- case 3:
- uploadFile(newfd, buf);
- break;
- default:
- printf("error");
- }
- }
-
- //关闭文件描述符
- close(newfd);
- //退出线程
- pthread_exit(0);
- }
- //显示文件
- void showFile(int newfd)
- {
- //变量声明
- DIR *dir = NULL;
- buf_t buf;
- struct dirent *dp = NULL;
- //打开目录
- dir = opendir("./");
- if (NULL == dir) {
- VPRINT_ERR("opendir error");
- }
- while (1) {
- //循环读取目录,直到读完
- dp = readdir(dir);
- if (dp == NULL) {
- if (errno == 0) {
- strcpy(buf.data2, "quit");
- if (send(newfd, &buf, sizeof(buf), 0) == -1) {
- VPRINT_ERR("send error");
- }
- break;
- } else {
- VPRINT_ERR("readdir error");
- }
- }
- memset(&buf, 0, sizeof(buf));
- buf.type = 1;
- strcpy(buf.data1, dp->d_name);
- //循环发送
- if (send(newfd, &buf, sizeof(buf), 0) == -1) {
- VPRINT_ERR("send error");
- }
- }
- //关闭目录,dir指向NULL
- closedir(dir);
- dir = NULL;
- }
- //下载文件
- void downloadFile(int newfd, buf_t buf)
- {
- //变量声明
- char server_path[256] = "./";
- char client_path[256] = "";
- char str[128] = "";
- int ret;
-
- strcpy(client_path, buf.data1);
- strcat(server_path, buf.data2);
- // 1.打开2个文件
- int fdr = open(server_path, O_RDONLY);
- int fdw = open(client_path, O_WRONLY | O_CREAT | O_TRUNC, 0664);
- if (fdr == -1 || fdw == -1) {
- VPRINT_ERR("open error");
- }
- while (1) {
- // 2.循环读取
- ret = read(fdr, str, sizeof(str));
- if (ret == -1) {
- VPRINT_ERR("read error");
- } else if (ret == 0) {
- break;
- }
- // 3.循环写入
- write(fdw, str, ret);
- }
- // 4.发送消息
- memset(&buf, 0, sizeof(buf));
- buf.type = 2;
- strcpy(buf.data1, "下载成功");
- if (send(newfd, &buf, sizeof(buf), 0) == -1) {
- VPRINT_ERR("send error");
- }
- // 5.关闭2个文件
- close(fdr);
- close(fdw);
- }
- //上传文件
- void uploadFile(int newfd, buf_t buf)
- {
- //变量声明
- char server_path[256] = "./";
- char client_path[256] = "";
- char str[128] = "";
- int ret;
-
- strcpy(client_path, buf.data1);
- strcat(server_path, buf.data2);
- // 1.打开2个文件
- int fdr = open(client_path, O_RDONLY);
- int fdw = open(server_path, O_WRONLY | O_CREAT | O_TRUNC, 0664);
- if (fdr == -1 || fdw == -1) {
- VPRINT_ERR("open error");
- }
- while (1) {
- // 2.循环读取
- ret = read(fdr, str, sizeof(str));
- if (ret == -1) {
- VPRINT_ERR("read error");
- } else if (ret == 0) {
- break;
- }
- // 3.循环写入
- write(fdw, str, ret);
- }
- // 4.发送消息
- memset(&buf, 0, sizeof(buf));
- buf.type = 3;
- strcpy(buf.data1, "上传成功");
- if (send(newfd, &buf, sizeof(buf), 0) == -1) {
- VPRINT_ERR("send error");
- }
- // 5.关闭2个文件
- close(fdr);
- close(fdw);
- }
- -include config.mk
- #版本1
- # a.out:$(NAME).o $(FUN).o
- # $(CC) $^ -o $@
- # %.o:%.c
- # $(CC) -c $^ -o $@
-
- # .PHONY:clean
- # clean:
- # rm -rf $(NAME).o $(FUN).o a.out
-
- #版本2(生成动态库版本)
- # a.out:$(NAME).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # lib$(FUN).so:$(FUN).o
- # $(CC) -shared $^ -o $@
- # mv $@ ./lib
- # $(NAME).o:$(NAME).c
- # $(CC) -c $^ -o $@
- # $(FUN).o:$(FUN).c
- # $(CC) -Wall -fPIC -c $^ -o $@
- # .PHONY:clean
- # clean:
- # rm -rf *.o lib/*.so a.out
- #版本3(生成动态库版本+链接线程库版)
- # a.out:$(NAME).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
- # lib$(FUN).so:$(FUN).o
- # $(CC) -shared $^ -o $@
- # mv $@ ./lib
- # $(NAME).o:$(NAME).c
- # $(CC) -c $^ -o $@
- # $(FUN).o:$(FUN).c
- # $(CC) -Wall -fPIC -c $^ -o $@
- # .PHONY:clean
- # clean:
- # rm -rf *.o lib/*.so a.out
- #版本4(生成动态库版本+非父子进程通信版本)
- # .PHONY:all
- # all:F A B
- # A:$(NAMEA).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # B:$(NAMEB).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # F:$(NAMEF).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # lib$(FUN).so:$(FUN).o
- # $(CC) -shared $^ -o $@
- # mv $@ ./lib
- # $(NAMEF).o:$(NAMEF).c
- # $(CC) -c $^ -o $@
- # $(NAMEA).o:$(NAMEA).c
- # $(CC) -c $^ -o $@
- # $(NAMEB).o:$(NAMEB).c
- # $(CC) -c $^ -o $@
- # $(FUN).o:$(FUN).c
- # $(CC) -Wall -fPIC -c $^ -o $@
- # .PHONY:clean
- # clean:
- # rm -rf *.o lib/*.so A B F
- #版本5(生成动态库版本+非父子进程通信版本+链接线程库版本)
- # .PHONY:all
- # all:F A B
- # A:$(NAMEA).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
- # B:$(NAMEB).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
- # F:$(NAMEF).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # lib$(FUN).so:$(FUN).o
- # $(CC) -shared $^ -o $@
- # mv $@ ./lib
- # $(NAMEF).o:$(NAMEF).c
- # $(CC) -c $^ -o $@
- # $(NAMEA).o:$(NAMEA).c
- # $(CC) -c $^ -o $@
- # $(NAMEB).o:$(NAMEB).c
- # $(CC) -c $^ -o $@
- # $(FUN).o:$(FUN).c
- # $(CC) -Wall -fPIC -c $^ -o $@
- # .PHONY:clean
- # clean:
- # rm -rf *.o lib/*.so A B F
- #版本6(生成动态库版本+客户端服务器通信版本)
- # .PHONY:all
- # all:cli ser
- # ser:$(NAMESER).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # cli:$(NAMECLI).o lib$(FUN).so
- # $(CC) $< -L./lib -l$(FUN) -o $@
- # lib$(FUN).so:$(FUN).o
- # $(CC) -shared $^ -o $@
- # mv $@ ./lib
- # $(NAMESER).o:$(NAMESER).c
- # $(CC) -c $^ -o $@
- # $(NAMECLI).o:$(NAMECLI).c
- # $(CC) -c $^ -o $@
- # $(FUN).o:$(FUN).c
- # $(CC) -Wall -fPIC -c $^ -o $@
- # .PHONY:clean
- # clean:
- # rm -rf *.o lib/*.so ser cli
- #版本6(生成动态库版本+客户端服务器通信版本+线程库版本)
- .PHONY:all
- all:cli ser
- ser:$(NAMESER).o lib$(FUN).so
- $(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
- cli:$(NAMECLI).o lib$(FUN).so
- $(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
- lib$(FUN).so:$(FUN).o
- $(CC) -shared $^ -o $@
- mv $@ ./lib
- $(NAMESER).o:$(NAMESER).c
- $(CC) -c $^ -o $@
- $(NAMECLI).o:$(NAMECLI).c
- $(CC) -c $^ -o $@
- $(FUN).o:$(FUN).c
- $(CC) -Wall -fPIC -c $^ -o $@
- .PHONY:clean
- clean:
- rm -rf *.o lib/*.so ser cli
- #对应版本1,2,3的makefile
- # CC=gcc
- # NAME=test
- # FUN=fun
-
- #对应版本4,5的makefile
- # CC=gcc
- # NAMEA=Atest
- # NAMEB=Btest
- # NAMEF=Ftest
- # FUN=fun
-
- #对应版本6的makefile
- CC=gcc
- NAMESER=ser
- NAMECLI=cli
- FUN=fun
编译makefile:
打开服务器和客户端:
上传和下载文件的位置:
选择1查看文件:
选择2下载文件:
另起一个终端客户端,选择3上传文件:
关闭服务器和客户端,diff测试下载以及上传的文件是否和原来的一致: