當(dāng)前位置:首頁 > 芯聞號 > 充電吧
[導(dǎo)讀]c++ 使用socket實現(xiàn)C/S端文件的下載傳輸首先是服務(wù)器端,大致說下流程:服務(wù)器創(chuàng)建線程去處理應(yīng)答accept(),當(dāng)接受到客戶端連接請求時,首先獲取要發(fā)送的指定的文件數(shù)據(jù)總大小給客戶端,接著就

c++ 使用socket實現(xiàn)C/S端文件的下載傳輸
首先是服務(wù)器端,大致說下流程:服務(wù)器創(chuàng)建線程去處理應(yīng)答accept(),當(dāng)接受到客戶端連接請求時,首先獲取要發(fā)送的指定的文件數(shù)據(jù)總大小給客戶端,接著就是循環(huán)讀取要發(fā)送的文件數(shù)據(jù)流向客戶端發(fā)送文件數(shù)據(jù),每次都判斷循環(huán)讀取到的數(shù)據(jù)實際大小,當(dāng)實際讀取到的數(shù)據(jù)總大小為0時,表示文件發(fā)送結(jié)束。下面是服務(wù)器server端實現(xiàn):

聲明部分:


public:
??? afx_msg void OnBnClickedButton1();
public:
??? BOOL InitSocket();??? //初始化并創(chuàng)建套接字

??? static DWORD WINAPI ThreadProc(LPVOID lpParameter);??? //創(chuàng)建線程去執(zhí)行服務(wù)器accept()
實現(xiàn)部分:


void CSendFileServerDlg::OnBnClickedButton1()
{
??? // TODO: 在此添加控件通知處理程序代碼
??? if (InitSocket())
??? {
??????? GetDlgItem(IDC_EDIT1)->SetWindowText(_T("服務(wù)器開啟監(jiān)聽。。。 rn"));

??????? //創(chuàng)建線程
??????? HANDLE hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
??????? //關(guān)閉該接收線程句柄,釋放引用計數(shù)
??????? CloseHandle(hThread);
??? }
}

BOOL CSendFileServerDlg::InitSocket()
{
??? //加載套接字庫
??? WORD wVersionRequested;
??? WSADATA wsaData;
??? int err;
??? wVersionRequested = MAKEWORD( 1, 1 );
??? err = WSAStartup( wVersionRequested, &wsaData );
??? if ( err != 0 )
??? {
??????? return FALSE;
??? }

??? if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
??? {
??????????? WSACleanup( );
??????????? return FALSE;
??? }

??? //創(chuàng)建套接字
??? //SOCKET m_socket=socket(AF_INET,SOCK_STREAM,0);
??? m_socket=socket(AF_INET,SOCK_STREAM,0);
??? if (m_socket == INVALID_SOCKET)
??? {
??????? AfxMessageBox(_T("套接字創(chuàng)建失敗!"));
??????? return FALSE;
??? }

??? SOCKADDR_IN addrSrv;
??? addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
??? addrSrv.sin_family=AF_INET;
??? addrSrv.sin_port=htons(8099);

??? err = bind(m_socket,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));??? //綁定本地端口
??? if (err==SOCKET_ERROR)
??? {
??????? closesocket(m_socket);
??????? AfxMessageBox(_T("綁定失敗!"));
??????? return FALSE;
??? }
??? listen(m_socket,5);//開啟監(jiān)聽

??? return TRUE;

}

DWORD WINAPI CSendFileServerDlg::ThreadProc(LPVOID lpParameter)
{
??? SOCKADDR_IN addrClient;
??? int len = sizeof(SOCKADDR);

??? while (true)
??? {
??????? SOCKET sockConn=accept(m_socket,(SOCKADDR*)&addrClient,&len);

??????? CString filename = _T("E:\test.zip");
??????? HANDLE hFile;
??????? unsigned long long file_size = 0;

??????? char Buffer[1024];
??????? DWORD dwNumberOfBytesRead;

??????? hFile = CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
??????? file_size = GetFileSize(hFile,NULL);
??????? send(sockConn,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

??????? do
??????? {
??????????? ::ReadFile(hFile,Buffer,sizeof(Buffer),&dwNumberOfBytesRead,NULL);
??????????? ::send(sockConn,Buffer,dwNumberOfBytesRead,0);
??????? } while (dwNumberOfBytesRead);


??????? CloseHandle(hFile);
??? }

??? return 0;
}
如代碼所述? 每次發(fā)送單位是unsigned char[1024]大小(程序是char 應(yīng)該為unsigned char[1024])所以就不存在網(wǎng)絡(luò)字節(jié)序問題也不用考慮大端小端什么的。

服務(wù)器端暫時不支持多客戶端并發(fā)訪問,后續(xù)可能會加上。。。

-------------------------------------------

下面是客戶端,同樣也大致說下客戶端流程,客戶端增加手動填寫Ip地址和端口號功能(端口號暫為8099)。以及下載傳輸文件數(shù)據(jù)進(jìn)度條的顯示,和下面簡單的一些狀態(tài)顯示。客觀端由填寫的IP地址進(jìn)行連接服務(wù)器操作,如果客戶端連接服務(wù)器成功的話直接就會獲取服務(wù)器端發(fā)送的要發(fā)送的文件數(shù)據(jù)的總大小,如果獲取文件總大小>0 則會循環(huán)往指定的路徑寫數(shù)據(jù)啦。此處循環(huán)寫文件結(jié)束標(biāo)志,我是用每次實際寫的累加如果累計值等于從服務(wù)器端獲取的文件總大小的話表示下載文件數(shù)據(jù)成功,結(jié)束循環(huán)。大致是這樣一個過程。代碼實現(xiàn):

客戶端聲明部分:

?public:
??? afx_msg void OnBnClickedButton1();
?
??? BOOL InitSocket();
??? void ConnectServer();
??? void ConnectRecvFileData(DWORD ip,int port);
?
private:
??? CProgressCtrl *m_progress; //進(jìn)度條

?進(jìn)度條在OnInitDialog()里初始化:

按 Ctrl+C 復(fù)制代碼
BOOL CRecvFileClientDlg::OnInitDialog()
{
??? CDialog::OnInitDialog();

??? // 將“關(guān)于...”菜單項添加到系統(tǒng)菜單中。

??? // IDM_ABOUTBOX 必須在系統(tǒng)命令范圍內(nèi)。
??? ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
??? ASSERT(IDM_ABOUTBOX < 0xF000);

??? CMenu* pSysMenu = GetSystemMenu(FALSE);
??? if (pSysMenu != NULL)
??? {
??????? CString strAboutMenu;
??????? strAboutMenu.LoadString(IDS_ABOUTBOX);
??????? if (!strAboutMenu.IsEmpty())
??????? {
??????????? pSysMenu->AppendMenu(MF_SEPARATOR);
??????????? pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
??????? }
??? }

??? // 設(shè)置此對話框的圖標(biāo)。當(dāng)應(yīng)用程序主窗口不是對話框時,框架將自動
??? //? 執(zhí)行此操作
??? SetIcon(m_hIcon, TRUE);??????????? // 設(shè)置大圖標(biāo)
??? SetIcon(m_hIcon, FALSE);??????? // 設(shè)置小圖標(biāo)

??? // TODO: 在此添加額外的初始化代碼

??? m_progress = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
??? m_progress->SetPos(0);

??? return TRUE;? // 除非將焦點設(shè)置到控件,否則返回 TRUE
}
按 Ctrl+C 復(fù)制代碼
客戶端具體實現(xiàn)部分:

按 Ctrl+C 復(fù)制代碼
void CRecvFileClientDlg::OnBnClickedButton1()
{
??? // TODO: 在此添加控件通知處理程序代碼
??? ConnectServer();
???
}


BOOL CRecvFileClientDlg::InitSocket()
{
??? //加載套接字庫
??? WORD wVersionRequested;
??? WSADATA wsaData;
??? int err;
??? wVersionRequested = MAKEWORD( 1, 1 );
??? err = WSAStartup( wVersionRequested, &wsaData );
??? if ( err != 0 )
??? {
??????? return FALSE;
??? }

??? if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
??? {
??????? WSACleanup( );
??????? return FALSE;
??? }

??? return TRUE;

}

void CRecvFileClientDlg::ConnectRecvFileData(DWORD ip,int port)
{
???
??? unsigned long long file_size=0;
??? SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);
??? SOCKADDR_IN addrSrv;
??? addrSrv.sin_addr.S_un.S_addr=htonl(ip);
??? addrSrv.sin_port=ntohs(port);
??? addrSrv.sin_family = AF_INET;
??? //connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
??? //recv(sockClient,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

??? if (!connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))
??? {
??????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
??????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("連接服務(wù)器成功!rn"));

???????

??????? recv(sockClient,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

??????? unsigned short maxvalue = file_size;??? //此處不太穩(wěn)妥 當(dāng)數(shù)據(jù)很大時可能會出現(xiàn)異常
??????? m_progress->SetRange(0,maxvalue);

??????? if (file_size>0)
??????? {
??????????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
??????????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("文件下載到本地 d:\test.zip rn"));

??????????? DWORD dwNumberOfBytesRecv=0;
??????????? DWORD dwCountOfBytesRecv=0;
??????????? char Buffer[1024];
??????????? CString filename = _T("d:\test.zip");
??????????? HANDLE hFile;
??????????? hFile = CreateFile(filename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

??????????? do
??????????? {
??????????????? m_progress->SetPos(dwCountOfBytesRecv);//更新進(jìn)度條

??????????????? dwNumberOfBytesRecv = ::recv(sockClient,Buffer,sizeof(Buffer),0);
??????????????? ::WriteFile(hFile,Buffer,dwNumberOfBytesRecv,&dwNumberOfBytesRecv,NULL);
??????????????? dwCountOfBytesRecv += dwNumberOfBytesRecv;???????????????
??????????? } while (file_size - dwCountOfBytesRecv);


??????????? CloseHandle(hFile);
???????????
??????????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
??????????? GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("文件接收完畢!rn"));
??????????? AfxMessageBox(_T("文件接收完畢!"));//醒目可以注釋
??????? }else
??????? {
??????????? AfxMessageBox(_T("獲取文件總大小失??!"));
??????? }
??? }else
??? {
??????? AfxMessageBox(_T("連接服務(wù)器失敗、請確認(rèn)IP地址或端口號!"));
??? }
???
???

??? closesocket(sockClient);//關(guān)閉套接字


}

void CRecvFileClientDlg::ConnectServer()
{
??? if (InitSocket())
??? {
??????? DWORD strIp =NULL;
??????? CString strPort = _T("");

??????? ((CIPAddressCtrl*)GetDlgItem(IDC_IP))->GetAddress(strIp);
??????? GetDlgItem(IDC_PORT)->GetWindowText(strPort);

??????? if (strIp==NULL||strPort=="")
??????? {
??????????? AfxMessageBox(_T("Ip地址或Port端口號不能為空!"));

??????? }else
??????? {
??????????? int port = atoi(strPort.GetBuffer(1));
??????????? ConnectRecvFileData(strIp,port);
???????????
??????? }
???????
??? }
???

}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉