基于TCP的文件服务器

要求:

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

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要实现一个基于 TCP文件传输服务器,你可以按照以下步骤进行: 1. 创建一个 TCP 服务器端程序。你可以使用编程语言(如Python、Java、C++等)提供的网络编程库来实现。在服务器端程序中,你需要创建一个 TCP socket,并绑定到指定的 IP 地址和端口上。 2. 等待客户端的连接请求。使用 socket 的 listen() 函数开始监听来自客户端的连接请求。 3. 接受客户端连接。一旦有客户端发起连接请求,使用 socket 的 accept() 函数接受连接,并返回一个新的 socket 对象用于与客户端进行通信。 4. 接收文件请求。与客户端建立连接后,你可以定义一种协议来传输文件。例如,可以约定客户端发送一个特定的命令来请求文件传输。 5. 打开文件并读取内容。在服务器端,根据客户端请求的文件名,打开相应的文件,并读取文件内容。 6. 将文件内容发送给客户端。使用 socket 的 send() 函数将文件内容逐个数据包发送给客户端。你可以定义合适的数据包大小(如 1024 字节)来进行分包发送。 7. 客户端接收并保存文件内容。在客户端程序中,接收服务器发送的数据包,并将数据包逐个写入文件中,最终组合成完整的文件。 8. 关闭连接。文件传输完成后,关闭与客户端的连接,释放相关资源。 需要注意的是,以上只是一个简单的文件传输服务器的基本流程。实际上,你可能还需要考虑错误处理、并发连接、文件权限等其他方面的问题。此外,为了提高性能和安全性,你还可以对文件传输进行优化和加密处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

傾语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值