首    页 界面/窗口 网络/通讯 数据库 组件开发 图像/多媒体 NET/Web 其它技术 源码下载 资料下载 软件共享 软件外包 曲艺杂谈
栏目导航:  首    页  |  网络/通讯  |  P2P   


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


原作者:bat603    源出处:CSDN    发布者:施昌权    发布类型:转载    发布日期:2008-08-27

         
        在局域网内实现图像的实时传输(实现环境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();
        }
        //---------------------------------------------------------------------------
        //---------------------------------------------------------------------------
        服务器端较简单,不做介绍。

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

 

关于我们 版权声明 广告服务 联系我们 友情链接 加入收藏
站长:施昌权    Email:scq2099yt@163.com    MSN:scq2099yt@live.cn    QQ:14046300    本站QQ群:67202409
Copyright © 2008     卓为VC(www.joyvc.cn)    All Rights Reserved    建议分辨率 1024×768
本站由施昌权制作维护
京ICP备09012297号