本例是通過截取桌面圖象,壓縮並以廣播數據報形式發送到各個機子。以便老師的演示可以讓每個同學都可以看到。
為將數據以較快的速度從網絡上發送出去,須使用Socket的異步通訊方式.異步方式在命令計算機將數據報發送出去後就立即返回,不用等數據發完,當數據發送完後計算機能自動產生一個消息,通知程序可以發送下一個數據報.該方式要求用戶必須自己用CAsyncSocket類派生出一個新類,並且要重寫OnSend函數,以便響應FD_WRITE網絡事件,該事件在數據報已經全部從網絡發送出去後產生,並會讓計算機自動執行OnSend函數.因此在該函數中要有發送下一個數據報的命令.為了讓對方收到數據報後知道這是第幾個數據報,可在數據報首用一個數字標記編號,每次發送數據前采用JPEG無損壓縮算法壓縮數據,以提高傳送速度。當一屏信息發送完後,就再截取下一屏信息發送.
發送程序:
發送程序先要在C++下用MFC AppWizard 建立一個基於dialog的目標工作空間,工程名為Netss在第二部必須選取Windows Socket支持.
用MFC AppWizard建立基於dialog的目標工作空間後,在CNetssDlg派生類中加入以下程序,其中OnCreate的函數框架用ClassWizard響應WM_CREATE消息生成,裡邊做一些初始化操作,目的是當用戶剛開始運行程序時能自動設置好環境,提高接收速度。
int i=0,ii,iii,xx,yy,b=1,pa=1000,bl=3840,eee=8192,bb;
short aa[350000];LPVOID pbit0=&aa[1000];
CDC wdc;CBitmap bmp1;CDC* pdc;char frame[5000];POINT pp;LPPOINT ppp=&pp;
void* pbuf=(void*)(&frame[0]);int *paa=(int*)pbuf;char *pf;short *pfi;
class mysocket:public CAsyncSocket //用CAsyncSocket類派生出新類mysocket
{public: void OnSend(int nErrorCode) //當上一個數據報已經發送完後自動執行該函數
{if(pa>307200) //如果發送完一屏信息,則截取下一屏信息
{pa=1000;
wdc.BitBlt(0,0,640,480,pdc,0,0,SRCCOPY); //把桌面圖像復制到wdc的bmp1中
bmp1.GetBitmapBits(614400,pbit0); //獲取圖像信息
GetCursorPos(ppp); //獲取鼠標位置
xx=ppp->x; yy=ppp->y;
for(ii=0;ii<10&&xx<640&&yy<480;ii++) //顯示鼠標指針
for(iii=0;iii aa[(yy+ii)*640+iii+xx+1000]=31744;
}
pf=&frame[4];
pfi=(short*)(pf+1);
*paa=pa;
for(;pf<&frame[3836];) //JPEG壓縮一個數據報
{*pf=0x00;
for(i=0;i<8;i=i+2)
{ if(aa[pa]==aa[pa-1]) //JPEG壓縮
*pf=*pf|(0x40>>i);
else if(aa[pa]==aa[pa-640])
*pf=*pf|(0x80>>i);
else if(aa[pa]==aa[pa-641])
*pf=*pf|(0xc0>>i);
else
{*pfi=aa[pa];
pfi++;
}
pa++;
}
pf=(char*)pfi;
pfi=(short*)(pf+1);
}
CAsyncSocket::AsyncSelect(FD_WRITE); //允許對象socks繼續響應FD_WRITE事件
CAsyncSocket::SendTo(pbuf,bl,1050,NULL,0); //把該段信息發送出去,發送bl=3840字節
}
};
mysocket socks;
int CNetssDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
socks.Create(2001,SOCK_DGRAM,FD_WRITE,NULL); //建立數據報Socket,端口號2001
socks.SetSockOpt(SO_BROADCAST,&b,sizeof(BOOL),SOL_SOCKET); //選擇廣播數據報
socks.SetSockOpt(SO_DONTROUTE,&b,sizeof(BOOL),SOL_SOCKET);
socks.SetSockOpt(SO_SNDBUF,&eee,sizeof(int),SOL_SOCKET); //設置發送緩沖區長度eee
socks.AsyncSelect(FD_WRITE); //允許對象socks響應FD_WRITE事件
static CWindowDC ddc(GetDesktopWindow()); //引用桌面窗口指針定義對象ddc
pdc=&ddc; //將指針pdc指向ddc
wdc.CreateCompatibleDC(pdc); //建立與ddc兼容的device context,
bmp1.CreateCompatibleBitmap(pdc,640,480); //建立與ddc兼容的位圖
wdc.SelectObject(&bmp1); //選擇bmp1
return 0;
}
接收程序:
則要在C++下用MFC AppWizard建立一個單文檔目標工作空間,也要使用Windows Socket支持.同樣,為以較快的速度從網絡上接收數據報,也要用異步方式.處理方法與發送程序相似,但要注意此時要響應的是FD_READ事件,該事件在網絡上有數據報到達時發生,因此要重寫的是OnReceive函數,該函數中要有從網絡接收數據報的命令,並能根據數據報最後的數字編號判斷這是第幾個數據報,將收到的信息放到合適的地方.
當把保存一屏信息的數據報全部收完後,就可用來把圖像再現到屏幕上.處理方法與發送程序類似,不過我們一般希望再現的圖像顯示在用戶窗口中,因此引用用戶窗口指針定義CClIEntDC類對象sdc,代替發送程序中的ddc,再現時的處理與發送時相反,把從網絡上收到的數據用bmp2的成員函數SetBitmapBits復制到位圖bmp2中,再用sdc的成員函數BitBlt把bmp2中的圖像顯示在用戶窗口中.
接收程序代碼: (設目標工作空間名為Netcc)
用MFC AppWizard建立單文檔目標工作空間後,在CNetccVIEw派生類中加入以下程序,其中OnCreate函數框架用ClassWizard響應WM_CREATE消息生成,裡邊做一些初始化操作。
int i=0,a,b=1,bl=3840,eee=8192;short aa[350000],ff;LPVOID pbit0=&aa[1000];
DWord dw=0;UINT nport=1050;CString name;char frame[5000];
void* pbuf=(void*)(&frame[0]);int *paa=(int*)pbuf;char *pf;short *pfi;
CDC wdc;CBitmap bmp2;CDC* pdc;
class mysocket:public CAsyncSocket //用CAsyncSocket類派生出新類mysocket
{public: void OnReceive(int nErrorCode) //當收到數據報後自動執行該函數
{CAsyncSocket::ReceiveFrom(pbuf,bl,name,nport,0); //從網絡接收信息,接收bl=3840字節
pf=&frame[4];
pfi=(short*)(pf+1);
for(;pf<&frame[3836];) //JPEG解壓縮一個數據報
{for(i=0;i<8;i=i+2)
{ff=(*pf)&(0xc0>>i); //JPEG解壓縮
if(ff==(0x40>>i))
aa[*paa]=aa[(*paa)-1];
else if(ff==(0x80>>i))
aa[*paa]=aa[(*paa)-640];
else if(ff==(0xc0>>i))
aa[*paa]=aa[(*paa)-641];
else
{aa[*paa]=*pfi;
pfi++;
}
(*paa)++;
}
pf=(char*)pfi;
pfi=(short*)(pf+1);
}
if(*paa>307200) //重現圖像
{bmp2.SetBitmapBits(614400,pbit0); //把pbit0指向的內存數據復制到bmp2中
pdc->BitBlt(0,0,640,480,&wdc,0,0,SRCCOPY); //把bmp2中圖像復制到用戶窗口中
}
}
};
mysocket sockc; //定義mysocket類對象sockc
int CNetccVIEw::OnCreate(LPCREATESTRUCT lpCreateStruct)
{ if (CVIEw::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
sockc.Create(1050,SOCK_DGRAM,FD_READ,NULL); //建立數據報Socket,端口號2001
sockc.SetSockOpt(SO_BROADCAST,&b,sizeof(BOOL),SOL_SOCKET);
sockc.SetSockOpt(SO_DONTROUTE,&b,sizeof(BOOL),SOL_SOCKET);
sockc.SetSockOpt(SO_RCVBUF,&eee,sizeof(int),SOL_SOCKET); //設置接收緩沖區長度eee
sockc.AsyncSelect(FD_READ); //允許對象sockc響應FD_READ事件
static CClIEntDC ddc(this);pdc=&ddc; //引用用戶窗口指針定義對象ddc
wdc.CreateCompatibleDC(pdc); //建立與ddc兼容的device context
bmp2.CreateCompatibleBitmap(pdc,640,480); //建立與ddc兼容的位圖
wdc.SelectObject(&bmp2);
*paa=1000;
return 0;
}
使用方法,只需老師運行發送程序,學生運行接收程序就可以工作。