日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TCP协议实现文件传输

發布時間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP协议实现文件传输 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?使用TCP協議實現傳輸文件
????程序分為發送端和接收端。首先在傳輸文件數據之前,發送端會把將裝有文件名稱和文件長度等
信息的數據包發送至接收端。接收端收到文件名稱和文件長度信息后會創建好空白文件。接著開始傳輸
文件數據。下面介紹實現功能的主要過程:

1.創建套接字、綁定、監聽、連接、接受連接
//創建TCP協議的套接字
????m_Socket?=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);
????
if(SOCKET_ERROR?==?m_Socket)
????????AfxMessageBox(
"Create?Socket?Error!?",?0,?0);

//綁定與監聽
????SOCKADDR_IN???addrSrv;???
????addrSrv.sin_addr.s_addr?
=?inet_addr(sIP);
????addrSrv.sin_family???
=???AF_INET;???
????addrSrv.sin_port???
=???htons(Port);???
????
int???ret???=???bind(m_Socket,???(SOCKADDR???*)&addrSrv,???sizeof(SOCKADDR));???
????
if(ret==SOCKET_ERROR)???
????????AfxMessageBox(
"Bind?Socket?Error!",?0,?0);

//連接
????SOCKADDR_IN?ServerAddr;
????ServerAddr.sin_addr.s_addr?
=?inet_addr(ServerAddr_in);
????ServerAddr.sin_family?
=?AF_INET;
????ServerAddr.sin_port?
=?htons(ServerPort);
????
int?Result?=?connect(m_Socket,?(struct?sockaddr*)&ServerAddr,?sizeof(struct?sockaddr));
????
if(SOCKET_ERROR?==?Result)
????????AfxMessageBox(
"Connet?Failed!");

//接受連接
????SOCKADDR_IN?ClientAddr;
????
int?len?=?sizeof(SOCKADDR_IN);
????SOCKET?ClientSock?
=?accept(m_Socket,?(struct?sockaddr*)&ClientAddr,?&len);
????
if(SOCKET_ERROR?==?ClientSock)
????????AfxMessageBox(
"Accept?Failed!");

2.聲明宏和結構體
聲明套接字緩沖區和一次發送文件數據的緩沖區大小
#define?SOCKET_BUFF?80000????//套接字緩沖區大小
#define?PACK_BUFF?50000????????//數據包緩沖區大小


聲明文件I
/O緩沖區和最大文件路徑長度
#define?FILE_NAME_MAX?100???????//文件路徑最大長度
#define?FILE_IO_BUFF?PACK_BUFF????//文件IO緩沖區????


//文件信息
typedef?struct?_FileInfor????
{
????u_long?ulFileLen;
????
char?sFileName[?FILE_NAME_MAX?];
}_FileInfor;

//數據包
typedef?struct?_DataPack
{
????
char?cType;????????//'D'為數據??'M'為文件信息
????int?nPackLen;
????
char?sContent[?PACK_BUFF?];????????????//數據包緩沖區
????u_long?nPosition;????????????????//數據在文件中的位置
????int?nContentLen;????????????????//數據字節數
????_FileInfor????FileInfor;????????//文件信息
}_DataPack;



3.發送端
//發送線程需要的全局變量
char?sPath[FILE_NAME_MAX];????????//文件地址
u_long?FileByteCount;????????????//文件大小
SOCKET?ClientSocket;????????????//


(
1)設置套接字發送緩沖區大小,在32位Windows?XP環境下,系統為每個套接字分配的默認發送數據緩
沖區為8192字節。由于傳輸的文件很大,可能幾十兆,或者更大。那么系統為每個套接字分配的默認
緩沖區顯然過小。為此在創建套接字之后,需要修改套接字發送數據緩沖尺寸。在這里我修改為80k,
差不多可以夠用了。
????
//設置套接字發送緩沖區
????int?nBuf?=?SOCKET_BUFF;
????
int?nBufLen?=?sizeof(nBuf);
????
int?nRe?=?setsockopt(ClientSock,?SOL_SOCKET,?SO_SNDBUF,?(char*)&nBuf,?nBufLen);
????
if(SOCKET_ERROR?==?nRe)
????????AfxMessageBox(
"setsockopt?error!");????
????
//檢查緩沖區是否設置成功
????nRe?=?getsockopt(ClientSock,?SOL_SOCKET,?SO_SNDBUF,?(char*)&nBuf,?&nBufLen);
????
if(SOCKET_BUFF?!=?nBuf)
????????AfxMessageBox(
"檢查緩沖區:setsockopt?error!");

(
2)測量文件大小并發送文件大小和名稱給客戶端

????首先使用C庫函數對源文件進行測量
????
//得到文件地址
????LPTSTR?lpPath?=?????m_sPath.GetBuffer(????m_sPath.GetLength?());
????
//打開文件
????FILE?*File?=?fopen(lpPath,?"rb");?
????
if(NULL?==?File)
????????AfxMessageBox(
"打開文件失敗!");
????
//測量文件大小
????char?Buff[PACK_BUFF];
????u_long?ulFaceReadByte;
????FileByteCount?
=?0;
????fseek(File,?
0,?SEEK_SET);
????
while(!feof(File))
????{
????????ulFaceReadByte?
=?fread(Buff,?1,?1,?File);
????????FileByteCount?
+=?ulFaceReadByte;
????}
????
//關閉文件
????int?nRe?=?fclose(File);
????
if(nRe)
????????AfxMessageBox(
"關閉文件失敗!");
????????
????此時以獲取源文件的長度,我們將文件長度和文件名稱放到數據包中,設置數據包為
'M'類型。
????
//打包
????_DataPack?Pack;
????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(
"Send?File?Size?Failed!");
????
//線程準備全局變量
????strcpy(sPath,?m_sPath);
????ClientSocket?
=?m_ClientSockFd.fd_array[0];
????
//啟動線程發送文件
????DWORD?ID;
????m_hSendThread?
=?CreateThread(0,?0,?SendDataThrad,?0,?0,?&ID);


(
3)發送文件數據線程。先打開源文件,為了一次讀取大量數據將文件緩沖區設置為FILE_IO_BUFF大小,
然后將讀取的數據打包并發送。這樣不斷地讀、不斷地發送,直到將整個文件發送完為止。

DWORD?__stdcall?CServerDlg::SendDataThrad(LPVOID?LpP)
{
????
//打開文件
????FILE?*File?=?fopen(sPath,?"rb");
????
if(NULL?==?File)
????{
????????AfxMessageBox(
"SendDataThrad中打開文件失敗!");
????????
return?1;
????}
????
//設置文件緩沖區
????int?nBuff?=?FILE_IO_BUFF;
????
if(setvbuf(File,?(char*)&nBuff,?_IOFBF,?sizeof(nBuff)))
????????AfxMessageBox(
"設置文件緩沖區失敗!");
????
//讀取文件數據并發送
????u_long?ulFlagCount?=?0;????????????//記錄讀了多少數據
????u_long?FaceReadByte?=?0;????//一次實際讀取的字節數
????char?sBuff[PACK_BUFF];????
????ZeroMemory(sBuff,?PACK_BUFF);
????fseek(File,?
0,?SEEK_SET);
????
while?(!feof(File))
????{
????????FaceReadByte?
=?fread(sBuff,?1,?PACK_BUFF,?File);
????????
//打包
????????_DataPack?DataPack;
????????DataPack.cType?
=?'D';
????????DataPack.nPackLen?
=?sizeof(DataPack);
????????DataPack.nContentLen?
=?FaceReadByte;
????????CopyMemory(DataPack.sContent,?sBuff,?FaceReadByte);
????????DataPack.nPosition?
=?ulFlagCount;
????????
//發送
????????int?nResult?=?send(ClientSocket,?(char*)&DataPack,?DataPack.nPackLen,?0);
????????
if?(SOCKET_ERROR?==?nResult)
????????{
????????????AfxMessageBox(
"SendDataThrad中發送數據失敗!");
????????}
else
????????????ulFlagCount?
+=?FaceReadByte;????????//記錄發送字節數
????}
????AfxMessageBox(
"發送結束");
????
//關閉
????int?nRe?=?fclose(File);
????
if(nRe)
????????AfxMessageBox(
"SendDataThrad中關閉文件失敗!");
????
return?0;
}

4.接收端
//接收線程用的全局變量
_FileInfor?FileInfor;????????//文件信息
u_long?ulWriteByte;????????????//記錄總共寫入的字節
char?lpPath[FILE_NAME_MAX];????//文件路徑
char?sFilePathAndName[FILE_NAME_MAX];????????//完整的文件路徑

(
1)設置套接字接收緩沖區大小。
//設置套接字接收緩沖區
????int?nBuf?=?SOCKET_BUFF;
????
int?nBufLen?=?sizeof(nBuf);
????SOCKET?ClientSock?
=?m_Sock.GetSocket();
????
int?nRe?=?setsockopt(ClientSock,?SOL_SOCKET,?SO_RCVBUF,?(char*)&nBuf,?nBufLen);
????
if(SOCKET_ERROR?==?nRe)
????????????AfxMessageBox(
"setsockopt?error!");
????
//檢查緩沖區是否設置成功
????nRe?=?getsockopt(ClientSock,?SOL_SOCKET,?SO_RCVBUF,?(char*)&nBuf,?&nBufLen);
????
if(SOCKET_BUFF?!=?nBuf)
????????AfxMessageBox(
"檢查緩沖區:setsockopt?error!");
????????
(
2)接收文件信息和文件數據線程。先判斷數據包是屬于文件信息還是文件類型,如果是文件信息就根
據信息創建空文件,如果是文件數據就將數據已追加的方式寫進目的文件中。

DWORD?__stdcall?CClientDlg::ReceiveDataPro(LPVOID?LpP)
{
????CSocket_Win32?
*pCSock?=?(CSocket_Win32*)LpP;
????u_long?ulWriteByteCount?
=?0;
????
while?(1)
????{
????????_DataPack?DataPack;
????????ZeroMemory(
&DataPack,?sizeof(DataPack));
????????
if(!(*pCSock).Receive(&DataPack,?sizeof(DataPack)))
????????{
????????????AfxMessageBox(
"Receive?DataPack?Failed!");
????????}
????????
//判斷數據包類型
????????if('M'?==?DataPack.cType)????//包為文件信息
????????{
????????????
//接收文件信息
????????????FileInfor.ulFileLen?=?DataPack.FileInfor.ulFileLen;??//獲取文件長度
????????????strcpy(FileInfor.sFileName,?DataPack.FileInfor.sFileName);?//獲取文件名稱
????????????
//得到文件目錄
????????????char?sFilePath[FILE_NAME_MAX];
????????????ZeroMemory(sFilePath,?FILE_NAME_MAX);
????????????strcpy(sFilePath,?lpPath);
????????????strcat(sFilePath,?FileInfor.sFileName);
????????????strcat(sFilePathAndName,?sFilePath);????
//保存完整的文件路徑
????????????
//創建文件
????????????SECURITY_ATTRIBUTES?attr;
????????????attr.nLength?
=?FileInfor.ulFileLen;
????????????attr.lpSecurityDescriptor?
=?NULL;
????????????HANDLE?hRe?
=?CreateFile(sFilePath,?GENERIC_WRITE,?FILE_SHARE_WRITE,?&attr,?CREATE_ALWAYS,?FILE_ATTRIBUTE_NORMAL,?0);
????????????
if(INVALID_HANDLE_VALUE?==?hRe)
????????????????AfxMessageBox(
"創建文件失敗!");
????????????
bool?bRe?=?::CloseHandle(hRe);
????????????
//可以開始接受文件
????????????bIsStartReceive?=?true;
????????}
else?if('D'?==?DataPack.cType)????????//包為文件數據
????????{
????????????
//打開文件
????????????char?sPath[FILE_NAME_MAX];
????????????strcpy(sPath,?sFilePathAndName);
????????????FILE?
*File?=?fopen(sPath,?"ab");
????????????
if(0?==?File)
????????????????AfxMessageBox(
"打開文件失敗!");
????????????
//設置文件緩沖區
????????????int?nBuff?=?FILE_IO_BUFF;
????????????
if(setvbuf(File,?(char*)&nBuff,?_IOFBF,?sizeof(nBuff)))
????????????????AfxMessageBox(
"設置文件緩沖區失敗!");
????????????
//定位文件
????????????u_long?nPosition?=?DataPack.nPosition;
????????????
int?nRe?=?fseek(File,?nPosition,?SEEK_SET);
????????????
if(nRe)
????????????????AfxMessageBox(
"SendDataThrad中定位失敗!");
????????????
//寫文件
????????????u_long?nNumberOfBytesWritten?=?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;
????????????}????
????????}
????}
????
return?0;
}

?

?

?

轉載于:https://www.cnblogs.com/yunboy4/archive/2009/08/04/1538865.html

總結

以上是生活随笔為你收集整理的TCP协议实现文件传输的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。