要求:
1.编写客户端和服务器程序
2.客户端可以查看服务器端目录中的文件名
3.客户端可以从服务器中下载文件
4.客户端可以从服务器中上传文件
服务器代码:
(1)头文件
#ifndef __FANC_H__
#define __FANC_H__
#define ERRMSG(msg) do{\
fprintf(stderr,"__%d__", __LINE__);\
perror(msg);\
exit(1);\
}while(0)
#define PORT 8888
#define IP "192.168.1.10"
#define N 256 //接收信息容量大小
//从客户端接收请求(查看、上传、下载)
void recive_message(int newfd);
//发送当前目录下的所有文件名
void send_list(int newfd);
//发送信息给客户端
void send_massage(int newfd, char* buff, int len);
//发送客户端要下载的文件
void download(int newfd);
//接收客户端上传的文件
void upload(int newfd);
#endif
(2)功能函数
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "./func.h"
//从客户端接收请求(查看、上传、下载)
void recive_message(int newfd)
{
char buff[N]="";
while(1)
{
bzero(buff, sizeof(buff));
if(-1 == recv(newfd, buff, sizeof(buff), 0))
{
ERRMSG("recv");
}
//查看是什么请求
short n = ntohs(*(short*)buff);
switch(n)
{
case 1: send_list(newfd); break;//客户端要查看列表
case 2: download(newfd); break;//客户端要下载文件
case 3: upload(newfd); break;//客户端要上传文件
}
}
}
//发送当前目录下的所有文件名
void send_list(int newfd)
{
//打开服务器所在目录
DIR* fp = opendir("./");
if(NULL == fp)
{
ERRMSG("opendir");
}
//循环发送目录下的文件名或目录名
char buff[N]="";
struct dirent *dir = readdir(fp);
while(NULL != dir)
{
strcpy(buff, dir->d_name);
if(buff[0] != '.') //隐藏文件不发送
{
send_massage(newfd, buff, sizeof(buff));
}
bzero(buff, sizeof(buff));
dir = readdir(fp);
}
//发送完成发送finish提示客户端已经发送完成
strcpy(buff, "finish");
send_massage(newfd, buff, sizeof(buff));
//关闭文件
closedir(fp);
}
//发送信息给客户端
void send_massage(int newfd, char* buff, int len)
{
if(-1 == send(newfd, buff, len, 0))
{
ERRMSG("send");
}
}
//发送客户端要下载的文件
void download(int newfd)
{
//接收文件名
char name[N]="";//接收文件名
char buff[N]="";//接收信息
int res = 0;
if(-1 == recv(newfd, name, sizeof(name), 0))
{
ERRMSG("recv");
}
//如果有该文件,只读打开文件,无则发送错误信息
int fd = open(name, O_RDONLY);
if(-1 == fd)//打开文件失败,发送文件名字
{
send_massage(newfd, name, sizeof(name));
return;
}else //有该文件反馈信息不为文件名即可
{
send_massage(newfd, buff, sizeof(buff));
}
//循环读取并发送给客户端
while(1)
{
bzero(buff, sizeof(buff));
res = read(fd, buff,sizeof(buff));
send_massage(newfd, buff, res);
if(res < N)//最后一次发送
{
printf("\n发送完成\n");
break;
}
}
//关闭文件
close(fd);
}
//接收客户端上传的文件
void upload(int newfd)
{
//接收文件名
char name[N]="";
if(-1 == recv(newfd, name, sizeof(name), 0))
{
ERRMSG("recv");
}
//创建或打开这个文件
int fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
if(fd == -1)
{
ERRMSG("open");
}
//循环接收并写入文件
char buff[N]="";
int res = 0;
while(1)
{
res = recv(newfd, buff, sizeof(buff), 0);
if(res == -1)
{
ERRMSG("recv");
}
//写入
write(fd, buff, res);
if(res < N)
{
printf("上传结束\n");
break;
}
}
//关闭文件
close(fd);
}
(3)主函数
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "./func.h"
int main(int argc, const char *argv[])
{
//创建数据流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == sfd)
{
ERRMSG("socket");
}
//填充自身IP地址和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//绑定地址信息
if(-1 == bind(sfd,(struct sockaddr*)&sin, sizeof(sin)))
{
ERRMSG("bind");
}
//设置成被动监听状态
if(-1 == listen(sfd, 20))
{
ERRMSG("lisent");
}
//定义接收地址信息结构体变量
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
//获取连接成功后的套接字
int newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
if(-1 == newfd)
{
ERRMSG("accept");
}
//接收客户端请求(查看、上传、下载)
recive_message(newfd);
//关闭套接字
close(newfd);
close(sfd);
return 0;
}
客户端代码:
(1)头文件
#ifndef __FANC_H__
#define __FANC_H__
#define ERRMSG(msg) do{\
fprintf(stderr,"__%d__", __LINE__);\
perror(msg);\
exit(1);\
}while(0)
#define PORT 8888
#define IP "192.168.1.10"
#define N 256 //接收信息容量大小
//系统菜单返回选项
short menu();
//接收服务器服务器发送的文件列表
void list(int sfd);
//发送信息给服务器
void send_massage(int sfd, char* buff, int len);
//下载文件
void download(int sfd);
//上传文件
void upload(int sfd);
#endif
(2)功能函数
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "./func.h"
//系统菜单返回选项
short menu()
{
short n = 0;
printf("**********TCP服务器**********\n");
printf("*********1:查看文件*********\n");
printf("*********2:下载文件*********\n");
printf("*********3:上传文件*********\n");
printf("*********0:退出系统*********\n");
printf("请输入选项>>>>>> ");
scanf("%hd", &n);
return n;
}
//接收服务器服务器发送的文件列表
void list(int sfd)
{
//发送查看文件列表请求
short n = htons(1);
send_massage(sfd, (char*)&n, sizeof(n));
//接收列表
char buff[N]=""; //N=N
ssize_t res = 0; //接收到的字节数
printf("********list*******\n");
while(1)
{
bzero(buff, sizeof(buff));//字符串清空避免干扰
res = recv(sfd, buff, sizeof(buff), 0);//接收信息,服务器会发送finish提示列表全部发送完成
if(-1 == res)
{
ERRMSG("recv");
}
if(0 == strcmp(buff, "finish"))//如果服务器发送完了跳出循环
{
printf("*******finish******\n");
break;
}
printf("%s\n", buff);//没有接收完直接打印接收到的文件或者目录名
}
}
//下载文件
void download(int sfd)
{
//发送下载请求
short n = htons(2);
send_massage(sfd, (char*)&n, sizeof(n));
//发送文件名
char name[N]="";
printf("请输入文件名>>> ");
getchar();//吸收垃圾字符
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0';
//发送文件名,等待服务器查看是否有该文件
send_massage(sfd, name, sizeof(name));
// 接收回馈信息,如果服务器没有该文件会将该文件名发送回来,
char buff[N]="";//接收信息
if(-1 == recv(sfd, buff, sizeof(buff), 0))
{
ERRMSG("recv");
}
if(0 == strcmp(name, buff))
{
printf("服务器中没有 %s 这个文件\n", name);
return;
}
//准备接收文件,打开或创建同名文件
int fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
if(-1 == fd)
{
ERRMSG("open");
}
//接收文件
int res = 0;
while(1)
{
bzero(buff, sizeof(buff));
res = recv(sfd, buff, sizeof(buff), 0);
if(-1 == res)
{
ERRMSG("recv");
}
//将接收到的文件内容写入文件中
write(fd, buff, res);
if(res < N)//最后一次发送的字节数必然小于N,等于N表示没有发送完成
{
printf("\n下载完成\n");
break;
}
}
//关闭文件
close(fd);
}
//发送信息给服务器,将buff里的内容发送给服务器
void send_massage(int sfd, char* buff, int len)
{
if(-1 == send(sfd, buff, len, 0))
{
ERRMSG("send");
}
}
//上传文件
void upload(int sfd)
{
//发送上传请求
short n = htons(3);
send_massage(sfd, (char*)&n, sizeof(n));
//获取文件名
char name[N]="";
printf("请输入文件名>>> ");
getchar();//吸收垃圾字符
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0';
//打开文件
int fd = open(name, O_RDONLY);
if(-1 == fd)
{
printf("没有 %s 这个文件,上传失败\n", name);
return;
}
//发送文件名给服务器,让它准备创建或更新这个文件
send_massage(sfd, name, sizeof(name));
//循环读取并发送给服务器
char buff[N]="";
int res = 0;
while(1)
{
res = read(fd, buff, sizeof(buff));
if(-1 == res)
{
ERRMSG("res");
}
//发送文件
send_massage(sfd, buff, res);
if(res < N)//最后一次发送的字节数必然小于N
{
printf("上传完成\n");
break;
}
}
//关闭文件
close(fd);
}
(3)主函数
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "./func.h"
int main(int argc, const char *argv[])
{
//创建数据流式套接字
int sfd = socket(AF_INET, SOCK_STREAM,0);
if(-1 == sfd)
{
ERRMSG("socket");
}
//填充服务器IP地址和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
socklen_t addrlen = sizeof(sin);
//连接服务器
if(-1 == connect(sfd, (struct sockaddr*)&sin, sizeof(sin)))
{
ERRMSG("connect");
}
//发送需求给服务器
while(1)
{
short n = menu();
switch(n)
{
case 1: list(sfd); break;//查看文件列表
case 2: download(sfd); break;//下载文件
case 3: upload(sfd); break;//上传文件
case 0: exit(0); break;//退出系统
default: printf("请重新输入\n"); break;
}
}
//关闭套接字
close(sfd);
return 0;
}
测试结果:
客户端:
ubuntu@ubuntu:client$ ls
client.c client.o func.c func.h func.o makefile
ubuntu@ubuntu:client$ make
ubuntu@ubuntu:client$ ./client
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 1
********list*******
func.h
serve.o
makefile
serve.c
serve
func.c
func.o
*******finish******
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 2
请输入文件名>>> serve.c
下载完成
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 3
请输入文件名>>> client.c
上传完成
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 2
请输入文件名>>> aaaa
服务器中没有 aaaa 这个文件
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 3
请输入文件名>>> 44444
没有 44444 这个文件,上传失败
**********TCP服务器**********
*********1:查看文件*********
*********2:下载文件*********
*********3:上传文件*********
*********0:退出系统*********
请输入选项>>>>>> 0
ubuntu@ubuntu:client$ ls -l serve.c
-rw-rw-r-- 1 ubuntu ubuntu 1160 八月 14 11:42 serve.c
ubuntu@ubuntu:client$ ls -l
总用量 48
-rwxrwxr-x 1 ubuntu ubuntu 13584 八月 14 11:41 client
-rw-rw-r-- 1 ubuntu ubuntu 1103 八月 14 10:09 client.c
-rw-rw-r-- 1 ubuntu ubuntu 2800 八月 14 10:57 client.o
-rw-rw-r-- 1 ubuntu ubuntu 3689 八月 14 11:39 func.c
-rw-rw-r-- 1 ubuntu ubuntu 494 八月 14 10:59 func.h
-rw-rw-r-- 1 ubuntu ubuntu 7240 八月 14 11:41 func.o
-rw-rw-r-- 1 ubuntu ubuntu 153 八月 14 10:57 makefile
-rw-rw-r-- 1 ubuntu ubuntu 1160 八月 14 11:42 serve.c
服务器:
ubuntu@ubuntu:serve$ ls
func.c func.h func.o makefile serve.c serve.o
ubuntu@ubuntu:serve$ make
ubuntu@ubuntu:serve$ ./serve
发送完成
上传结束
__135__open: No such file or directory
ubuntu@ubuntu:serve$ ls -l serve.c
-rw-rw-r-- 1 ubuntu ubuntu 1160 八月 14 11:21 serve.c
ubuntu@ubuntu:serve$ ls -l
总用量 48
-rw-rw-r-- 1 ubuntu ubuntu 1103 八月 14 11:42 client.c
-rw-rw-r-- 1 ubuntu ubuntu 2944 八月 14 11:40 func.c
-rw-rw-r-- 1 ubuntu ubuntu 593 八月 14 11:20 func.h
-rw-rw-r-- 1 ubuntu ubuntu 6056 八月 14 11:41 func.o
-rw-rw-r-- 1 ubuntu ubuntu 151 八月 14 11:22 makefile
-rwxrwxr-x 1 ubuntu ubuntu 13616 八月 14 11:41 serve
-rw-rw-r-- 1 ubuntu ubuntu 1160 八月 14 11:21 serve.c
-rw-rw-r-- 1 ubuntu ubuntu 3184 八月 14 11:22 serve.o
ubuntu@ubuntu:serve$ diff client.c ../client/client.c
ubuntu@ubuntu:serve$ diff serve.c ../client/serve.c
服务器makefile
Target:=serve
Objs:=serve.o
Objs+=func.o
CC:=gcc
LAN:=-c -o
$(Target):$(Objs)
@gcc $^ -o $@
%.o:%.c
@$(CC) $< $(LAN) $@
clear:
@rm $(Target) *.o
客户端makefile
Target:=client
Objs:=client.o
Objs+=func.o
CC:=gcc
LAN:=-c -o
$(Target):$(Objs)
@gcc $^ -o $@
%.o:%.c
@$(CC) $< $(LAN) $@
clear:
@rm $(Target) *.o