网络协议分析课实验:文件传输程序设计
要求:
设计一个控制台应用程序,基于流式套接字完成文件传输的功能。具体功能如下:
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 版权协议,转载请附上原文出处链接和本声明。