#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指向NULLclosedir(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测试下载以及上传的文件是否和原来的一致: