最近需要做網路傳輸的專案,需要實現較大檔案的傳輸。在網上收集了不少資料,但是各有各的做法,尤其是關於檔案自動接收這一塊不太清楚。 經過圖書館查閱後還是找到了一種解決辦法,雖然做的不太專業,但是思路比較精簡、清晰,也希望能給大家尤其是剛學習socket套接字的人一些啟示。
對於套接字socket我其實也不太懂,並且一般資料都可以查詢到,所以不交易累贅了,直接說如何實現檔案的傳輸吧。
對於傳送檔案,有三步:傳送檔案長度,傳送檔名,傳送檔案內容。
關於傳送檔案內容,又可以根據檔案大小進行直接傳輸和分塊傳輸,如果是分塊傳輸還需要多執行緒,否則會容易使程式失去響應。 在這裡其實我也有乙個疑惑,就是通過cfiledialog類getfilename函式獲取檔名,一般沒有問題,但是當檔名很長(如大於60)時不能完整讀取,導致接收方無法判別檔案型別。 所以保險起見,我就從getfilepath中截取出了檔名。
[cpp]view plain
copy
print?
void cchatdlg::onsend()
cfiledialog dlg(true);
dlg.m_ofn.lpstrtitle="選擇";
dlg.m_ofn.lpstrfilter="all files";
cstring path="";
cstring name="";
if(dlg.domodal()==idok)
if(path=="")
return ;//表示沒有選擇任何元素
//不直接讀取檔名,而是從路徑名中擷取
int pos=0,start=0;
while(1)
name=path.right(path.getlength()-start-1);
file.open(path,cfile::moderead);//開啟檔案
dwlen=file.getlength();//獲取檔案長度
m_se.setrange32(0,dwlen);
cstring te;
te.format("%d",dwlen);
if(flag==0)//傳送資料
send(m_accept, te.getbuffer(0), 10, 0);//傳送檔案的長度
if(flag==1)
send(m_local, te.getbuffer(0), 10, 0);
sleep(500);//延時
if(flag==0)//傳送資料
send(m_accept, name.getbuffer(0), name.getlength(), 0);//傳送檔案的名
if(flag==1)
send(m_local, name.getbuffer(0), name.getlength(), 0);
sleep(500);//延時
if(dwlen<=1024*1024)//如果小於1m就直接傳輸
date=new
char[dwlen];//開闢neicun
memset(date,0,dwlen);//初始化
file.read(date,dwlen);//讀取檔案
file.close();
int n=0;
if(flag==0)//傳送資料
n=send(m_accept, date, dwlen, 0);
if(flag==1)
n=send(m_local, date, dwlen, 0);
m_se.setpos(n);
cstring ss;
ss.format("%d %d",dwlen,n);
ss+="傳送完成";
messagebox(ss);
delete date;
date=null;
} else
}
上面一段已經說明了,也希望大家更好的解決方法。其中flag的值時表示是服務端還是客戶端,0-服務端,1-客戶端,集合在了乙個程式中。
注意::: 其中的sleep(500)的延時是因為為了讓接受方有足夠多的時間獲取檔案長度和檔名關鍵資訊,如果不延時,接收方會先接受到檔案內容後接收到檔案長度和檔名,順序是相反的,具體原因我也沒弄清楚,希望大家指教。
最後是關於乙個執行緒的函式,具體如下:
[cpp]view plain
copy
print?
uint send(lpvoid pthreadparam)//執行緒函式
int total=0,len=0;
while(total//直到全部傳送完成
else
sleep(1);
total+=len;//累計已經傳送的資料
dlg->m_se.setpos(total);
delete date;
date=null; //**記憶體空間
} file.close();
cstring ss;
ss.format("%d",total);
ss+="傳送完成";
messagebox(dlg->m_hwnd,ss,"提示",mb_ok);
dword exit=0;
bool ret=getexitcodethread(dlg->p_thread->m_hthread,&exit);//獲取執行緒退出**
if(exit==still_active) //如果程序仍在進行
return 0;
}
執行緒的好處是不會讓程式失去響應,而且對於大型檔案傳輸來說這是必須的。
其次,關於檔案的接受,就是乙個註冊的onsocket中的fd_read,通過這個方式設定wsaasyncselect模型的。
[cpp]view plain
copy
print?
int nret = wsaasyncselect(m_local, m_hwnd, wm_socket, fd_accept|fd_connect|fd_read|fd_write|fd_close);
if (nret != 0)
關於onsocket 函式完整如下,處理fd_read|fd_connect|fd_accept等訊息
[cpp]view plain
copy
print?
void cchatdlg::onsocket(wparam wparam,lparam lparam)
case fd_read: //接收資料
temp=new
char[1024*56];//開闢乙個記憶體
memset(temp,0,1024*56);
x=recv(sock,temp,1024*56,0);
f.write(temp,x);
total+=x;
m_get.setpos(total);
delete temp;
temp=null;
if(total>=m_length)//表示接受完成
break;
} }
break;
case fd_close:
case fd_connect: //連線網路事件
break;
} }
}
其中接受就在fd_read訊息中,flag1-1接受檔案長度,flag1-2接受檔名,flag1-3接受檔案內容。
當然整個函式太長了,本來應該一些語句應該設定成一些函式的,那樣也更直觀。
這基本上是這個工程的全部了,還是比較簡潔的。在同一臺電腦上測試結果是:732577734位元組共耗時114秒,平均6.12m/s,也不是體太慢。
整個專案還是有不少弊端的,有疑惑的可以相互交流討論。
**:
Windows Socket 程式設計
伺服器端 客戶端 在 http fayaa.com code 處理的高亮顯示效果 c 語言 臨時自用 include include void main if lobyte wsadata wversion 1 hibyte wsadata wversion 1 socket socksrv soc...
Windows Socket程式設計
windows下socket程式設計主要包括以下幾部分 服務端1 初始化windows socket庫。2 建立socket。3 繫結socket。4 監聽。5 accept。6 接收 傳送資料。客戶端1 初始化windows socket庫。2 建立socket。3 連線socket。4 接收 傳...
Windows Socket程式設計
1 初始化windows socket庫。2 建立socket。3 繫結socket。4 監聽。5 accept。6 接收 傳送資料。1 初始化windows socket庫。2 建立socket。3 連線socket。4 接收 傳送資料。服務端每接收到乙個客戶端的socket,則建立乙個執行緒。滿...