在局域网内实现图像的实时传输

作者:bat603

网址:http://blog.csdn.net/bat603/(本文可以随意转载及修改并可用于任何用处,但须注明作者和网址)

在局域网内实现图像的实时传输(实现环境bcb6.0+MSSQL)

     本来要去睡觉的,但是为了整理一下该文档,还是坐在了电脑旁。明天睡个大头觉。  

     之所以使用bcb6.0,是因为用它开发速度快。但是一个前辈曾经给我说过,bcb开发的软件没有商业价值,当然他说的有点偏颇,不过

也反映了bcb的境遇。不过如果开发较小的项目,使用它的优势还是明显的。     转入正题,在网络传输信息,有两种模型:C/S、P2P。C/S模式需要在网络内有个服务器,客户端传输信息都要通过服务器进行转发。当传

输信息量较小的文本信息时,采用该方法因为其实现较简单,方便控制信息的传输,所以可以使用,以前的QQ就是采用这个方法,但是如果传

输信息量较大的图像信息时,显然当客户端较多时,服务器的负担会呈级数增加,显然是不合适的。只有使用P2P模式,即节点之间传输,这样

可以把负载平衡到各个节点,效率很高。但是它的缺点也是很明显的,每个节点都要负责维护其他节点的状态信息,实现起来比较复杂。这个

也是现在的研究热点,并有成品出现,但是也是应用于较小的网络。  在做这个网络协作系统时,由于人力资源较弱,所以我采用了这种的方法。就是把这两者结合,在图像信息传输的时候采用P2P模式,

但是需要在网络内运行一个服务器来负责维护各个节点的状态信息。这样可以极大的减少服务器的负荷,同时节点间传输的实现也比较容易。         实现方法:服务器运行,监视各个节点的状态。当一个节点登陆网络时,需要向服务器报告自己的状态,并请求得到它希望传输图像

信息的状态信息。当得到信息时,便不再与服务器进行交互,而是自己把图像向节点传输。当该节点退出网络时要向服务器报告。可见服务器

的工作就是一个索引服务器,而负载已经平衡到了各个节点。         应用背景:在网络协作学习系统中实时协作学习电子白板  系统中的电子白板是一个虚拟公共学习区域,在问题求解的过程中它作为主要的问题解决方案编辑的协作空间,而不同于聊天室只承

担组内成员沟通和情感维系的工作,以及与教师就学习问题互动的渠道。  • 实时协作学习电子白板的功能  ①基本的书写的功能,可以对文字进行协作编辑  ②对文字可以进行重点标示,以及擦除。  ③对协作动作进行控制,即在操作前必须首先控制申请,操作结束后解除控制。  ④可以对文字和标记进行点对点的传输,亦可在组内广播。

         代码实现:节点与服务器的交互采用C/S模式,使用控件ClientSocket/ServerSocket,节点间传输信息,由于需要实现接收和发送两

个功能,所以在每个节点都要有两个控件,一个用来接收,一个用来发送,该系统中使用了NMStrm/NMStrmServ控件。数据库采用MSSQL,当然要

存放在服务器上。有必要强调的是,要把图像的BMP格式转化为JPG格式在进行传输,这样可以大大缩小传输的信息量。

       该方法的 缺点:在传输图像时,采用的是传输整个图像方法。虽然经过格式优化,但是还是有很大的信息量,较好的方法是传输在白板上的动作信息,比如画线动作,可以采集关键部位的坐标和画笔颜色信息传输,这样更能减少信息量的传输(仲日给提的建议),但是实现起来较麻烦,考虑到时间问题,没有实现。           部分源代码:(部分代码参考csdn的bcb版和www.ccrun.com)  节点端  //---------------------------------------------------------------------------

#include <vcl.h> #pragma hdrstop

#include "board.h" #include "Unit7.h" #include "Unit1.h" #include <jpeg.hpp> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TWhiteBoard *WhiteBoard; //--------------------------------------------------------------------------- __fastcall TWhiteBoard::TWhiteBoard(TComponent* Owner)     : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TWhiteBoard::FormCreate(TObject *Sender) {     //禁用关闭按钮     EnableMenuItem(GetSystemMenu(Handle,false), SC_CLOSE,         MF_DISABLED | MF_BYCOMMAND | MF_GRAYED);

    Button3->Enabled = false;

    Timer1->Enabled = false;     m_npenFlag = 0;//初始化画笔的功能     Image->Parent->DoubleBuffered = true;     void *dsdc;     void *dxwnd;

    dxwnd=GetDesktopWindow();//取得桌面句柄     dsdc=GetDC(dxwnd);     BitBlt(Image->Canvas->Handle,0,0,NULL,NULL,dsdc,0,0,SRCCOPY);     ReleaseDC(dxwnd,dsdc); } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::ImageMouseMove(TObject *Sender,       TShiftState Shift, int X, int Y) {     //m_oldCursor =  Screen->Cursor;     if (m_npenFlag == 1)//输入文本     {

        if (Shift.Contains(ssCtrl))//按下ctrl,要改变文本大小         {             int xstart,ystart;

            Screen->Cursor =  crSizeNWSE;             xstart = myMemo->Left;             ystart = myMemo->Top;             myMemo->Width = X - xstart;             myMemo->Height = Y - ystart;

        }         else         {             Screen->Cursor = crCross;         }

    }

if (m_npenFlag == 2)//画笔 {      if(Shift.Contains(ssLeft))      {         if(x1==-1&&y1==-1)         {             x1=X;             y1=Y;             //Image->Canvas->Pen->Color=clRed;             Image->Canvas->Pen->Width=3;             Image->Canvas->MoveTo(x1,y1);             Image->Canvas->LineTo(X,Y);         }         else         {             //Image->Canvas->Pen->Color=clRed;             Image->Canvas->Pen->Width=3;             Image->Canvas->MoveTo(x1,y1);             Image->Canvas->LineTo(X,Y);             x1=X;             y1=Y;         }     } }     if (m_npenFlag == 3)//橡皮     {         if(Shift.Contains(ssLeft))         {         if(x1==-1&&y1==-1)         {             x1=X;             y1=Y;             //Image->Canvas->Pen->Color=clRed;             Image->Canvas->MoveTo(x1,y1);             Image->Canvas->LineTo(X,Y);         }         else         {             //Image->Canvas->Pen->Color=clRed;             Image->Canvas->MoveTo(x1,y1);             Image->Canvas->LineTo(X,Y);             x1=X;             y1=Y;         }         }     }

 

} //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::ImageMouseUp(TObject *Sender,       TMouseButton Button, TShiftState Shift, int X, int Y) {      if(Button==mbLeft)     {         x1=-1;         y1=-1;     }

} //---------------------------------------------------------------------------

 

void __fastcall TWhiteBoard::BitBtn2Click(TObject *Sender) {     m_npenFlag = 2;     if (ColorDialog->Execute())         Image->Canvas->Pen->Color = ColorDialog->Color; } //---------------------------------------------------------------------------

//产生输入文本框 void __fastcall TWhiteBoard::ImageMouseDown(TObject *Sender,       TMouseButton Button, TShiftState Shift, int X, int Y) {     if (m_npenFlag == 1)     {

        if (Button==mbLeft )         {             if (myMemo != NULL)             {                 delete myMemo;                 myMemo = NULL;             }             myMemo = new TMemo(Owner);             myMemo->Parent = Panel1;             myMemo->Left = X;             myMemo->Top = Y;             myMemo->Width = 500;             myMemo->Height = 20;             myMemo->Ctl3D = false;             myMemo->OnMouseMove = Memo1MouseMove;         }     }     else         if (m_npenFlag == 2)         {             x1 = X;             y1 = Y;         }

        if (m_npenFlag == 3)         {             Image->Canvas->Pen->Color =  clCaptionText;             Image->Canvas->Pen->Width = 13;             Image->Canvas->Rectangle(X-1, Y-1, X, Y);

 

        } } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::BitBtn1Click(TObject *Sender) {     m_npenFlag = 1; } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::Panel1MouseMove(TObject *Sender,       TShiftState Shift, int X, int Y) {     if (m_npenFlag == 1)     {         if(X<0||X>Panel1->Width||Y<0||Y>Panel1->Height)         {                 ReleaseCapture();                 Screen->Cursor = crArrow;                // Label1->Caption="Leave";//鼠标离开事件         }         else         {                 if(Panel1->Handle!=GetCapture())                 {                         SetCapture(Panel1->Handle);                         Screen->Cursor = crCross;                        // Label1->Caption="Enter";//鼠标进入事件                 }         }     }     if (m_npenFlag == 2)     {         if(X<0||X>Panel1->Width||Y<0||Y>Panel1->Height)         {                 ReleaseCapture();                 Screen->Cursor = crArrow;                // Label1->Caption="Leave";//鼠标离开事件         }         else         {                 if(Panel1->Handle!=GetCapture())                 {                         SetCapture(Panel1->Handle);                         Screen->Cursor = crHandPoint;                        // Label1->Caption="Enter";//鼠标进入事件                 }         }     }

     Label1->Caption = IntToStr(X)+","+IntToStr(Y);

} //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::Memo1MouseMove(TObject *Sender,       TShiftState Shift, int X, int Y) {     //if (Shift.Contains(ssCtrl)    // {     Label1->Caption = IntToStr(X)+","+IntToStr(Y);      Screen->Cursor = crIBeam;

} //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::FormMouseMove(TObject *Sender,       TShiftState Shift, int X, int Y) {

    Screen->Cursor = crArrow; } //---------------------------------------------------------------------------

 

void __fastcall TWhiteBoard::BitBtn3Click(TObject *Sender) {     Image->Canvas->TextOutA(myMemo->Left,myMemo->Top,myMemo->Text);     if (myMemo != NULL)     {         delete myMemo;         myMemo = NULL;     } } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::BitBtn4Click(TObject *Sender) {     Screen->Cursor = crNoDrop;     m_npenFlag = 3; } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::NMStrmServ1MSG(TComponent *Sender,       const AnsiString sFrom, TStream *strm) {     TMemoryStream *ImageStream;     ImageStream = new TMemoryStream;     strm->Seek(0,soFromBeginning);     TJPEGImage *jpeg;  // 定义JPEG图象     try     {         jpeg = new TJPEGImage;  // 分配内存         // 从数据流中载入图象         jpeg->LoadFromStream(strm);         // 显示图象         Image->Picture->Bitmap->Assign(jpeg);         //MessageBeep(MB_OK);  // 发出提示声音     }     __finally {         delete jpeg;  // 释放资源     }     delete ImageStream;     ImageStream = NULL; } //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::Button2Click(TObject *Sender) {     WorkRoom->ClientSocket->Socket->SendText("4:"+NBCL->m_sUserID+":Request");//申请白板控制权     Button2->Enabled = false;     Button3->Enabled = true; } //---------------------------------------------------------------------------

//定时传输图像,以达到实时传输目的 void __fastcall TWhiteBoard::Timer1Timer(TObject *Sender) {

        TMemoryStream  *imgstream;         imgstream = new TMemoryStream;         Graphics::TBitmap *bBitmap;  // 定义位图变量      try {       bBitmap = new Graphics::TBitmap(); // 创建位图

      // 拷贝屏幕的指定区域到位图             bBitmap->Assign(Image->Picture->Bitmap);    TJPEGImage *jpeg;    try {     jpeg = new TJPEGImage;  // 创建JPEG图象     jpeg->Assign(bBitmap);  // 将位图转化为JPEG格式     jpeg->SaveToStream(imgstream);  // 保存JPEG图象信息    }     __finally {     delete jpeg;  // 释放资源    }    }  __finally {   delete bBitmap;  // 释放资源  }     //向服务器发送图像信息    /* AnsiString shostName = WorkRoom->ClientSocket->Socket->RemoteHost;     try     {   imgstream->Position = 0;         NMStrm1->Host=shostName; //指定主机名         NMStrm1->PostIt(imgstream); //发送的文件     }     catch(...){}  */

    //找到其他组成员     vFindOtherHost();     for (int i=0; i<m_nHostNum; i++)     try     {   imgstream->Position = 0;         NMStrm1->Host=m_sOtherHost[i]; //指定主机名         NMStrm1->PostIt(imgstream); //发送的文件     }     catch(...){}    delete imgstream;    imgstream = NULL;

} //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::Button3Click(TObject *Sender) {     WorkRoom->ClientSocket->Socket->SendText("4:"+NBCL->m_sUserID+":Giveup");//放弃白板控制权     Button2->Enabled = true;     Button3->Enabled = false;     Timer1->Enabled = false;     WorkRoom->Memo->Lines->Add("我放弃了白板控制权");

} //---------------------------------------------------------------------------

void __fastcall TWhiteBoard::FormHide(TObject *Sender) {     Timer1->Enabled = false;     if (Button3->Enabled)         WorkRoom->ClientSocket->Socket->SendText("4:"+NBCL->m_sUserID+":Giveup");//放弃白板控制权     if (WorkRoom->Showing)         WorkRoom->Hide(); } //---------------------------------------------------------------------------

//得到其他节点状态 void TWhiteBoard::vFindOtherHost() {     //TODO: Add your source code here     //找到同组在线人的计算机名称

                    //读取本组在线成员信息表     AnsiString SQL;     AnsiString sUserID,sUserName;     AnsiString sHost,sIP;     SQL = "  declare @teamid int ";     SQL += " select @teamid=TeamID from StudentGroupInfo where UserID='"+NBCL->m_sUserID+"'";     SQL += " select R.UserID,UserName,O.Host,O.IP from StudentRegisterInfo as R inner join StudentGroupInfo as G on

R.UserID=G.UserID and G.TeamID=@teamid inner join OnlineInfo as O on O.UserID=G.UserID";     NBCL->MainQuery->Close();     NBCL->MainQuery->SQL->Clear();     NBCL->MainQuery->SQL->Add(SQL);     NBCL->MainQuery->Open();     m_nHostNum = 0;     while (!NBCL->MainQuery->Eof)     {         sUserID = NBCL->MainQuery->FieldByName("UserID")->AsString;         if (sUserID != NBCL->m_sUserID)         {             sUserName = NBCL->MainQuery->FieldByName("UserName")->AsString;             sHost = NBCL->MainQuery->FieldByName("Host")->AsString;             sIP = NBCL->MainQuery->FieldByName("IP")->AsString;

            m_sOtherHost[m_nHostNum++] = sHost;         }         NBCL->MainQuery->Next();     }     //m_nHostNum--;//保存本组主机名的个数 } void __fastcall TWhiteBoard::Button1Click(TObject *Sender) {     if (Button3->Enabled)     {         ShowMessage("请放弃控制白板控制后再关闭该窗口");         return;     }

    Hide(); } //---------------------------------------------------------------------------

} //---------------------------------------------------------------------------         服务器端较简单,不做介绍。

若有不妥之处,敬请指点。

 

 

更多技术文章请参看施昌权的个人网站: http://www.joyvc.cn

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值