大学生网络协议分析课实验:文件传输程序设计

  • Post author:
  • Post category:其他

网络协议分析课实验:文件传输程序设计

要求:
  设计一个控制台应用程序,基于流式套接字完成文件传输的功能。具体功能如下:

  1.将任意类型的文件从客户端传送到服务器,传送前提示用户输入完整的文件名(含路径和扩展名);

  2.必须可以传送大文件(50MB以上,大文件不用发给我,我自己找文件测试);

  3.必须有文件传送进度提示。
 
  4. 程序完成后,删除Debug,ipch文件夹,以及sdf,suo,opensdf等中间文件。
    
    然后压缩,压缩文件命名为3117000999张三_实验4.zip(rar/7z等),然后发送到老师的交作业平台。

一、server服务器的源文件cpp文件代码:

#include "stdio.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
#define SERVERIP "127.0.0.1"
#define SERVERPORT 3333
#define SIZE 4096//4096
#define BUFSIZE 4096

int RecvFile(SOCKET sock);
int main(void)
{
	int ret,len;
	WSADATA data;
	SOCKET sockListen,sockTx;
	struct sockaddr_in addrServer;

	ret=WSAStartup(MAKEWORD(2,2),&data);
	if (SOCKET_ERROR==ret)
	{
		return -1;
	}

	sockListen=socket(AF_INET,SOCK_STREAM,0);
	if (INVALID_SOCKET==sockListen)
	{
		WSACleanup();
		return -2;
	}

	memset(&addrServer,0,sizeof(struct sockaddr_in));
	addrServer.sin_family=AF_INET;
	addrServer.sin_addr.S_un.S_addr=inet_addr(SERVERIP);
	addrServer.sin_port=htons(SERVERPORT);

	len=sizeof(struct sockaddr);
	ret=bind(sockListen,(struct sockaddr*)&addrServer,len);
	if (SOCKET_ERROR==ret)
	{
		closesocket(sockListen);
		WSACleanup();
		return -3;
	}

	ret=listen(sockListen,1);
	if (SOCKET_ERROR==ret)
	{
		closesocket(sockListen);
		WSACleanup();
		return -4;
	}

	len=sizeof(struct sockaddr);
	sockTx=accept(sockListen,NULL,&len);
	if (INVALID_SOCKET==sockTx)
	{
		closesocket(sockListen);
		WSACleanup();
		return -5;
	}

	printf("接收到客户端的连接\n");

	RecvFile(sockTx);

	closesocket(sockListen);
	closesocket(sockTx);
	WSACleanup();
	system("pause");
	return 0;
}

int RecvFile(SOCKET sock)
{
	int ret;
	FILE *fp;
	char sendBuf[BUFSIZE],recvBuf[BUFSIZE],filename[512];

	
	memset(recvBuf,0,sizeof(recvBuf));
	ret=recv(sock,recvBuf,sizeof(recvBuf),0);
	if (SOCKET_ERROR==ret)
	{
		return -1;
	}

	printf("成功接收客户端发来的文件名: %s\n",recvBuf);

	memset(sendBuf,0,sizeof(sendBuf));
	strcpy(sendBuf,recvBuf);
	ret=send(sock,sendBuf,strlen(sendBuf),0);
	if (SOCKET_ERROR==ret)
	{
		return -2;
	}

	printf("请输入你希望保存的文件名(带扩展名)\n");
	scanf("%s",filename);
    fp=fopen(filename,"wb");
	if (NULL==fp)
	{
		return -3;
	}

	memset(recvBuf,0,sizeof(recvBuf));
	ret=recv(sock,recvBuf,sizeof(recvBuf),0);
	if (SOCKET_ERROR==ret)
	{
		return -4;
	}
    int fileSize = 0;
	memcpy(&fileSize,recvBuf,sizeof(int));//将缓冲区的内容复制到fileSize
	fileSize = atoi(recvBuf);
	printf("成功接收客户端发来的文件长度: %s\n",recvBuf);

	memset(sendBuf,0,sizeof(sendBuf));
	strcpy(sendBuf,recvBuf);
	ret=send(sock,sendBuf,strlen(sendBuf),0);//回复
	if (SOCKET_ERROR==ret)
	{
		return -5;
	}
	//接收文件包
	int recvedFilelen = 1;
	float progress = 0;
	float finish = 0;

	while(recvedFilelen)
	{
		recvedFilelen = 0;
		recvedFilelen = recv(sock,recvBuf,SIZE,0);
		if (SOCKET_ERROR==recvedFilelen)
		{
			return -6;
		} 
		fwrite(recvBuf,recvedFilelen,1,fp);
		//计算进度
		finish += recvedFilelen;
		progress = 100 * (finish / (float)fileSize);
		printf("\r\n进度:%.2f%",progress);
	}
	


	//fwrite(pRecvFileData,recvedFilelen,1,fp);
	fclose(fp);
	return 0;	
}

二、client客户端的源文件cpp文件代码:

#include "stdio.h"
#include "stdlib.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
#define SERVERIP "127.0.0.1"
#define SERVERPORT 3333
#define SIZE 4096//4096
#define BUFSIZE 4096

int SendFile(SOCKET sock,char filename[512]);
int main(void)
{
	int ret,len;
	WSADATA data;
	SOCKET sockClient;
	struct sockaddr_in addrServer;
	char fname[512];

	ret=WSAStartup(MAKEWORD(2,2),&data);
	if (SOCKET_ERROR==ret)
	{
		return -1;
	}

	sockClient=socket(AF_INET,SOCK_STREAM,0);
	if (INVALID_SOCKET==sockClient)
	{
		WSACleanup();
		return -2;
	}

	memset(&addrServer,0,sizeof(struct sockaddr_in));
	addrServer.sin_family=AF_INET;
	addrServer.sin_addr.S_un.S_addr=inet_addr(SERVERIP);
	addrServer.sin_port=htons(SERVERPORT);

	len=sizeof(struct sockaddr);
	ret=connect(sockClient,(sockaddr*)&addrServer,len);
	if (SOCKET_ERROR==ret)
	{
		closesocket(sockClient);
		WSACleanup();
		return -3;
	}

	printf("连接服务器成功\n");

	printf("请输入你需要传送的文件名,带路径扩展名\n");
	scanf("%s",fname);
	SendFile(sockClient,fname);
	
	
	closesocket(sockClient);
	WSACleanup();

	system("pause");
	return 0;
}

int SendFile(SOCKET sock,char filename[512])
{
	int ret,cnt,len1,lenlast;
	char sendBuf[BUFSIZE],recvBuf[BUFSIZE];
	FILE *fp;
	int totlen;
	fp=fopen(filename,"rb");//获得文件的指针
	if (NULL==fp)
	{
		printf("open file error\n");
		return -1;
	}

    fseek(fp,0,SEEK_END);//指针指向文件尾巴
	totlen=ftell(fp);
	printf("文件%s的长度为%d字节\n",filename,totlen);//获取文件名字和大小

	memset(sendBuf,0,sizeof(sendBuf));
	strcpy(sendBuf,filename);

	ret=send(sock,sendBuf,strlen(sendBuf)+1,0);//发送文件名
	if (SOCKET_ERROR==ret)
	{
		return -2;
	}

	memset(recvBuf,0,sizeof(recvBuf));
	ret=recv(sock,recvBuf,sizeof(recvBuf),0);//服务器接收到了文件名
	if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) )
	{
		return -3;
	} 

	printf("向服务器发送文件名成功\n");

	memset(sendBuf,0,sizeof(sendBuf));
	itoa(totlen,sendBuf,10);//整数转成字符串 被转换的数字 目标字符串 10进制
	ret=send(sock,sendBuf,strlen(sendBuf)+1,0);//发送文件长度
	if (SOCKET_ERROR==ret)
	{
		return -4;
	}	

	memset(recvBuf,0,sizeof(recvBuf));
	ret=recv(sock,recvBuf,sizeof(recvBuf),0);
	if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) )
	{
		return -5;
	} 

	printf("向服务器发送文件长度成功\n");
	

	rewind(fp);//指向文件头
	float progress = 0;
	float finish = 0;
	int nCount = 1;
	memset(sendBuf,0,sizeof(sendBuf));
	while(!feof(fp))//判断是否到达文件尾 是则返回0 否则返回非0值
	{	
		nCount = fread(sendBuf,1,SIZE,fp);
		//目标缓冲区,每次读取多少字节,读取1次,文件指针		
		ret=send(sock,sendBuf,nCount,0);
		if (SOCKET_ERROR==ret)
		{
			return -6;
		}
		//计算进度
		finish += ret;
		if(totlen<SIZE) finish = totlen;
		progress = 100 * (finish / (float)totlen);
		printf("\r\n进度:%.2f%",progress);
	}

	
	fclose(fp);
	return 0;
}

三、执行运行过程如下:

(1)首先先运行server的cpp文件,然后再运行client的cpp文件;

(2)根据提示在client窗口输入你要传送的那个文件的路径名称,并且要带后缀名,然后按回车就可以啦


版权声明:本文为weixin_45586870原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。