1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > TCP协议实现文件传输

TCP协议实现文件传输

时间:2021-06-25 16:00:26

相关推荐

TCP协议实现文件传输

使用TCP协议实现传输文件

程序分为发送端和接收端。首先在传输文件数据之前,发送端会把将装有文件名称和文件长度等

信息的数据包发送至接收端。接收端收到文件名称和文件长度信息后会创建好空白文件。接着开始传输

文件数据。下面介绍实现功能的主要过程:

1.创建套接字、绑定、监听、连接、接受连接

//创建TCP协议的套接字

m_Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(SOCKET_ERROR==m_Socket)

AfxMessageBox("CreateSocketError!",0,0);

//绑定与监听

SOCKADDR_INaddrSrv;

addrSrv.sin_addr.s_addr=inet_addr(sIP);

addrSrv.sin_family=AF_INET;

addrSrv.sin_port=htons(Port);

intret=bind(m_Socket,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

if(ret==SOCKET_ERROR)

AfxMessageBox("BindSocketError!",0,0);

//连接

SOCKADDR_INServerAddr;

ServerAddr.sin_addr.s_addr=inet_addr(ServerAddr_in);

ServerAddr.sin_family=AF_INET;

ServerAddr.sin_port=htons(ServerPort);

intResult=connect(m_Socket,(structsockaddr*)&ServerAddr,sizeof(structsockaddr));

if(SOCKET_ERROR==Result)

AfxMessageBox("ConnetFailed!");

//接受连接

SOCKADDR_INClientAddr;

intlen=sizeof(SOCKADDR_IN);

SOCKETClientSock=accept(m_Socket,(structsockaddr*)&ClientAddr,&len);

if(SOCKET_ERROR==ClientSock)

AfxMessageBox("AcceptFailed!");

2.声明宏和结构体

声明套接字缓冲区和一次发送文件数据的缓冲区大小

#defineSOCKET_BUFF80000//套接字缓冲区大小

#definePACK_BUFF50000//数据包缓冲区大小

声明文件I/O缓冲区和最大文件路径长度

#defineFILE_NAME_MAX100//文件路径最大长度

#defineFILE_IO_BUFFPACK_BUFF//文件IO缓冲区

//文件信息

typedefstruct_FileInfor

{

u_longulFileLen;

charsFileName[FILE_NAME_MAX];

}_FileInfor;

//数据包

typedefstruct_DataPack

{

charcType;//'D'为数据'M'为文件信息

intnPackLen;

charsContent[PACK_BUFF];//数据包缓冲区

u_longnPosition;//数据在文件中的位置

intnContentLen;//数据字节数

_FileInforFileInfor;//文件信息

}_DataPack;

3.发送端

//发送线程需要的全局变量

charsPath[FILE_NAME_MAX];//文件地址

u_longFileByteCount;//文件大小

SOCKETClientSocket;//

(1)设置套接字发送缓冲区大小,在32位WindowsXP环境下,系统为每个套接字分配的默认发送数据缓

冲区为8192字节。由于传输的文件很大,可能几十兆,或者更大。那么系统为每个套接字分配的默认

缓冲区显然过小。为此在创建套接字之后,需要修改套接字发送数据缓冲尺寸。在这里我修改为80k,

差不多可以够用了。

//设置套接字发送缓冲区

intnBuf=SOCKET_BUFF;

intnBufLen=sizeof(nBuf);

intnRe=setsockopt(ClientSock,SOL_SOCKET,SO_SNDBUF,(char*)&nBuf,nBufLen);

if(SOCKET_ERROR==nRe)

AfxMessageBox("setsockopterror!");

//检查缓冲区是否设置成功

nRe=getsockopt(ClientSock,SOL_SOCKET,SO_SNDBUF,(char*)&nBuf,&nBufLen);

if(SOCKET_BUFF!=nBuf)

AfxMessageBox("检查缓冲区:setsockopterror!");

(2)测量文件大小并发送文件大小和名称给客户端

首先使用C库函数对源文件进行测量

//得到文件地址

LPTSTRlpPath=m_sPath.GetBuffer(m_sPath.GetLength());

//打开文件

FILE*File=fopen(lpPath,"rb");

if(NULL==File)

AfxMessageBox("打开文件失败!");

//测量文件大小

charBuff[PACK_BUFF];

u_longulFaceReadByte;

FileByteCount=0;

fseek(File,0,SEEK_SET);

while(!feof(File))

{

ulFaceReadByte=fread(Buff,1,1,File);

FileByteCount+=ulFaceReadByte;

}

//关闭文件

intnRe=fclose(File);

if(nRe)

AfxMessageBox("关闭文件失败!");

此时以获取源文件的长度,我们将文件长度和文件名称放到数据包中,设置数据包为'M'类型。

//打包

_DataPackPack;

Pack.cType='M';

Pack.nPackLen=sizeof(Pack);

//取得文件名

ZeroMemory(Pack.FileInfor.sFileName,FILE_NAME_MAX);

GetFIieNameFromPath(lpPath,Pack.FileInfor.sFileName);

Pack.FileInfor.ulFileLen=FileByteCount;

接着使用send()将打包完成的数据包发送给接收端,把发送线程的全局变量初始化,并创建发送线

程,文件数据将由发送线程负责发送

//发送数据包文件大小和名称

nRe=send(m_ClientSockFd.fd_array[0],(char*)&Pack,Pack.nPackLen,0);

if(SOCKET_ERROR==nRe)

AfxMessageBox("SendFileSizeFailed!");

//线程准备全局变量

strcpy(sPath,m_sPath);

ClientSocket=m_ClientSockFd.fd_array[0];

//启动线程发送文件

DWORDID;

m_hSendThread=CreateThread(0,0,SendDataThrad,0,0,&ID);

(3)发送文件数据线程。先打开源文件,为了一次读取大量数据将文件缓冲区设置为FILE_IO_BUFF大小,

然后将读取的数据打包并发送。这样不断地读、不断地发送,直到将整个文件发送完为止。

DWORD__stdcallCServerDlg::SendDataThrad(LPVOIDLpP)

{

//打开文件

FILE*File=fopen(sPath,"rb");

if(NULL==File)

{

AfxMessageBox("SendDataThrad中打开文件失败!");

return1;

}

//设置文件缓冲区

intnBuff=FILE_IO_BUFF;

if(setvbuf(File,(char*)&nBuff,_IOFBF,sizeof(nBuff)))

AfxMessageBox("设置文件缓冲区失败!");

//读取文件数据并发送

u_longulFlagCount=0;//记录读了多少数据

u_longFaceReadByte=0;//一次实际读取的字节数

charsBuff[PACK_BUFF];

ZeroMemory(sBuff,PACK_BUFF);

fseek(File,0,SEEK_SET);

while(!feof(File))

{

FaceReadByte=fread(sBuff,1,PACK_BUFF,File);

//打包

_DataPackDataPack;

DataPack.cType='D';

DataPack.nPackLen=sizeof(DataPack);

DataPack.nContentLen=FaceReadByte;

CopyMemory(DataPack.sContent,sBuff,FaceReadByte);

DataPack.nPosition=ulFlagCount;

//发送

intnResult=send(ClientSocket,(char*)&DataPack,DataPack.nPackLen,0);

if(SOCKET_ERROR==nResult)

{

AfxMessageBox("SendDataThrad中发送数据失败!");

}else

ulFlagCount+=FaceReadByte;//记录发送字节数

}

AfxMessageBox("发送结束");

//关闭

intnRe=fclose(File);

if(nRe)

AfxMessageBox("SendDataThrad中关闭文件失败!");

return0;

}

4.接收端

//接收线程用的全局变量

_FileInforFileInfor;//文件信息

u_longulWriteByte;//记录总共写入的字节

charlpPath[FILE_NAME_MAX];//文件路径

charsFilePathAndName[FILE_NAME_MAX];//完整的文件路径

(1)设置套接字接收缓冲区大小。

//设置套接字接收缓冲区

intnBuf=SOCKET_BUFF;

intnBufLen=sizeof(nBuf);

SOCKETClientSock=m_Sock.GetSocket();

intnRe=setsockopt(ClientSock,SOL_SOCKET,SO_RCVBUF,(char*)&nBuf,nBufLen);

if(SOCKET_ERROR==nRe)

AfxMessageBox("setsockopterror!");

//检查缓冲区是否设置成功

nRe=getsockopt(ClientSock,SOL_SOCKET,SO_RCVBUF,(char*)&nBuf,&nBufLen);

if(SOCKET_BUFF!=nBuf)

AfxMessageBox("检查缓冲区:setsockopterror!");

(2)接收文件信息和文件数据线程。先判断数据包是属于文件信息还是文件类型,如果是文件信息就根

据信息创建空文件,如果是文件数据就将数据已追加的方式写进目的文件中。

DWORD__stdcallCClientDlg::ReceiveDataPro(LPVOIDLpP)

{

CSocket_Win32*pCSock=(CSocket_Win32*)LpP;

u_longulWriteByteCount=0;

while(1)

{

_DataPackDataPack;

ZeroMemory(&DataPack,sizeof(DataPack));

if(!(*pCSock).Receive(&DataPack,sizeof(DataPack)))

{

AfxMessageBox("ReceiveDataPackFailed!");

}

//判断数据包类型

if('M'==DataPack.cType)//包为文件信息

{

//接收文件信息

FileInfor.ulFileLen=DataPack.FileInfor.ulFileLen;//获取文件长度

strcpy(FileInfor.sFileName,DataPack.FileInfor.sFileName);//获取文件名称

//得到文件目录

charsFilePath[FILE_NAME_MAX];

ZeroMemory(sFilePath,FILE_NAME_MAX);

strcpy(sFilePath,lpPath);

strcat(sFilePath,FileInfor.sFileName);

strcat(sFilePathAndName,sFilePath);//保存完整的文件路径

//创建文件

SECURITY_ATTRIBUTESattr;

attr.nLength=FileInfor.ulFileLen;

attr.lpSecurityDescriptor=NULL;

HANDLEhRe=CreateFile(sFilePath,GENERIC_WRITE,FILE_SHARE_WRITE,&attr,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);

if(INVALID_HANDLE_VALUE==hRe)

AfxMessageBox("创建文件失败!");

boolbRe=::CloseHandle(hRe);

//可以开始接受文件

bIsStartReceive=true;

}elseif('D'==DataPack.cType)//包为文件数据

{

//打开文件

charsPath[FILE_NAME_MAX];

strcpy(sPath,sFilePathAndName);

FILE*File=fopen(sPath,"ab");

if(0==File)

AfxMessageBox("打开文件失败!");

//设置文件缓冲区

intnBuff=FILE_IO_BUFF;

if(setvbuf(File,(char*)&nBuff,_IOFBF,sizeof(nBuff)))

AfxMessageBox("设置文件缓冲区失败!");

//定位文件

u_longnPosition=DataPack.nPosition;

intnRe=fseek(File,nPosition,SEEK_SET);

if(nRe)

AfxMessageBox("SendDataThrad中定位失败!");

//写文件

u_longnNumberOfBytesWritten=fwrite(&DataPack.sContent,1,DataPack.nContentLen,File);

if(DataPack.nContentLen!=nNumberOfBytesWritten)

AfxMessageBox("写文件失败!");

else

{

ulWriteByteCount+=nNumberOfBytesWritten;

}

fflush(File);//清除文件缓冲区

//关闭文件

nRe=fclose(File);

if(nRe)

AfxMessageBox("关闭文件失败!");

if(ulWriteByteCount>=FileInfor.ulFileLen)

{

AfxMessageBox("接收结束");

break;

}

}

}

return0;

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。