C/S + HTML 桌面网络软件的实现

来源:互联网 发布:高姿护肤品怎么样知乎 编辑:程序博客网 时间:2024/06/10 20:01

C/S + HTML 桌面网络软件的实现

作者:陈明

Emailqmroom@126.com

Blog: http://blog.csdn.net/qmroom

(转载请注明出处)

 

环境:VC8+SERVER2003/XP

关键字:C/SHTML、网络

 

摘要:

B/S的软件系统在系统实时性、桌面功能拓展性上有很大的不足;纯C/S的软件系统虽然实时性强、功能拓展强,但在界面美观和开发效率上远不如B/S软件。有没有一种更完美的解决方案呢,既能解决界面美观性、开发高效性,又有很强的实时性和很好的拓展性?解决方案当然有好多种,如Web+控件、C/S +界面控件+其他基础控件库、C/S +Flash+控件库……,我们今天要讨论的是另一种实现模式:C/S + HTML

C/S + HTML的实现思路(我们以VC为例):服务器端用VC实现服务程序。客户端在VC中嵌入IE控件,以VC为框架HTML为交换界面。这样做有诸多优点:页面开发高效、界面修改方便、实时性高、功能可拓展性强、可在网页里嵌入其他控件、利用js控制MS OFFICE行为实现vba等。而VC部分只需要关注数据的处理,便于功能划分。

 

下面我们以竞价系统为例说明:

 

页面展示:

 

 

中间是网页,利用js接口或页面元素和vc通信。

 

VC从服务器端取得数据,绘制折线图。

 

 

 

 

利用js技术显示word文档,可以打开并操作word文档。

 

实现:

 

新建一个vc对话框工程,在对话框中加入LABEL,修改id为:IDC_BROWSER

 

定义浏览器类:

class CBrowserView : public CHtmlView {

     DECLARE_DYNCREATE(CBrowserView)

     DECLARE_MESSAGE_MAP()

     DECLARE_DISPATCH_MAP() // 构建dispatch映射表以暴露方法或属性

public:

     // 当在一个窗体上创建时(当作窗体的一个控件)可以指定一个控件ID按指定的控件大小位置

     BOOL CreateFromStatic(UINT nID, CWnd* pParent);

     // 调用JS函数

     BOOL CallJScript(LPCTSTR strFunc, const CStringArray& paramArray, _variant_t* pVarResult = NULL);

     // 修改网页元素的内容

     BOOL PutElementHtml(LPCTSTR lpElemID, LPCTSTR lpHtml);

     // 取表单元素的值

     BOOL GetElementValue(LPCTSTR lpElemID, CString &Value);

     // 设置元素的值

     BOOL PutElementValue(LPCTSTR lpElemID, LPCTSTR lpValue);

}

 

在对话框中定义浏览器对象

CBrowserView m_Browser;

在对话框初始化时,创建浏览器 Browser.CreateFromStatic(IDC_BROWSER, this);

指定其实页Browser.Navigate2(webs/index.html);

 

 

JS接口部分:

在类CBrowserView中实现js接口:

 

BEGIN_DISPATCH_MAP(CBrowserView, CBrowserView)

     DISP_FUNCTION(CBrowserView, "CloseWin", CloseWin, VT_EMPTY, VTS_NONE)

     DISP_FUNCTION(CBrowserView, "ShowWin", ShowWin, VT_EMPTY, VTS_NONE)

     DISP_FUNCTION(CBrowserView, "HideWin", HideWin, VT_EMPTY, VTS_NONE)

END_DISPATCH_MAP()

 

BrowserView.h头文件声明:

     //常用操作

     void CloseWin();                 //关闭窗口

     void ShowWin();                      //显示窗口

     void HideWin();                      //隐藏窗口

 

BrowserView.cpp实现

 

void CBrowserView::CloseWin()

{

     GetMainDlg()->PostMessage(WM_CLOSE);

}

void CBrowserView::ShowWin()

{

     GetMainDlg()->ShowWindow(SW_SHOW);

     GetMainDlg()->UpdateWindow();

}

void CBrowserView::HideWin()

{

     GetMainDlg()->ShowWindow(SW_HIDE);

     GetMainDlg()->UpdateWindow();

}

 

 

同时可以触发JS事件:

 

     //JS事件函数,由C++框架调用

    function GetMessage(type)

    {

         do

         {

              if('1' == type) //最高价更新了

              {

                   //你需要更新页面显示

                   //同时,若在延时阶段,你需要重置延时结束时间为GetProjYs()秒,更新页面倒计时钟

                   alert("最高价更新了");

                   break;

              }

             

              if('2' == type) //开始竞价

              {

                   alert("开始竞价");

                   break;

              }

             

              if('3' == type) //正常竞价结束,进入延时竞价

              {

                   alert("正常竞价结束,进入延时竞价");

                   break;

              }

             

              if('4' == type) //竞价结束

              {

                   alert("竞价结束");

                   break;

              }

             

              if('7' == type) //报价成功【服务器接受了报价】

              {

                   alert("报价成功");

                   break;

              }

             

              if('8' == type) //报价失败【服务器没有接受报价】,失败原因可以通过GetLastErrMsg()获取

              {

                   alert("报价失败:" + external.GetLastErrMsg());

                   break;

              }

        

         }while(false);

    }

 

网络通信实现部分,可采用异步多线程通信:

监听

bool CNet::Listen(int port)

{

     if(IsListening())

         StopListen();

 

     sockaddr_in   addr;

     SOCKET        sock;

 

     sock = socket(AF_INET, SOCK_STREAM, 0);            // Create socket

 

     addr.sin_family = AF_INET;                         // Address family Internet

     addr.sin_port = htons(port);                       // Assign port 'port' to this socket

     addr.sin_addr.s_addr = htonl(INADDR_ANY);      // No destination

 

     if(bind(sock,(LPSOCKADDR) &addr, sizeof(addr)) == SOCKET_ERROR)

     {

         closesocket(sock);

         long err = WSAGetLastError();

         CNet::SetLastError(err);

         return false;

     }

 

     if(listen(sock, BACKLOG) == SOCKET_ERROR)

     {

         closesocket(sock);

         long err = WSAGetLastError();

         CNet::SetLastError(err);

         return false;

     }

 

     m_sync.Enter();

     m_socket = sock;

     m_addr = addr;

     m_sync.Leave();

 

     hAcceptThread = CreateThread(NULL,

                                       0,

                                      (LPTHREAD_START_ROUTINE) AcceptThread,

                                       this,

                                       0,

                                      (LPDWORD) &dwAcceptThreadID);

     if(!hAcceptThread)

     {

         StopListen();

         return false;

     }

 

     return true;

}

 

int CNet::AcceptWait()

{

     int           addr_size = sizeof(sockaddr_in);

 

     SOCKET        lsock;

     SOCKET        csock = INVALID_SOCKET;

     sockaddr_in   caddr = { 0 };

 

     m_sync.Enter();

     lsock = m_socket;

     m_sync.Leave();

 

     while(IsListening())

     {

         m_sync.Enter();

         bool bRightSock =(lsock == m_socket);

         m_sync.Leave();

         if(!bRightSock) return 1;

 

         csock = accept(lsock,(LPSOCKADDR) &caddr, &addr_size); // accept a connection

         if(csock == INVALID_SOCKET)

         {

              int aErr = WSAGetLastError();

              if(aErr == WSAEINTR)

              {

                   StopListen();

                   return 1;

              }

              else

              {

                   //   error: could not accept

                   long err = WSAGetLastError();

                   CNet::SetLastError(err);

 

                   StopListen();

                   return 1;

              }

         }

         else

         {

              CConnection* cAccepted = new CConnection();

              cAccepted->m_socket = csock;

              cAccepted->m_addr = caddr;

 

              cAccepted->hRecvThread = CreateThread(NULL,

                                                           0,

                                                          (LPTHREAD_START_ROUTINE) cAccepted->RecvThread,

                                                           cAccepted,

                                                           0,

                                                          (LPDWORD) &cAccepted->dwRecvThreadID);

 

              if(cAccepted->hRecvThread == NULL)

              {

                   cAccepted->Disconnect();

                   CNet::SetLastError(1002);

              }

              else

              {

                   m_sync.Enter();

                   m_accepted.Add(cAccepted);

 

                   HANDLE hEvent = hAcceptEvent;

                   CALLBACKFUNC fncCallback = hAcceptFunc;

                   m_sync.Leave();

 

                   if(hEvent) SetEvent(hEvent);                   //   if an event was given, pulse the event

                   if(fncCallback)(fncCallback)((DWORD) this);    //   if a function ptr was given, call the function

              }

         }

     }

 

     return 0;

}

 

int CNet::AcceptThread(void* pThis)

{

     return((CNet*)(pThis))->AcceptWait();

}

 

连接:

bool CCon::Connect(const char* host, unsigned short port)

{

     Disconnect();

 

     sockaddr_in   addr;

     SOCKET        sock;

 

     sock = socket(AF_INET, SOCK_STREAM, 0);        // create socket

     addr.sin_family = AF_INET;                     // address family Internet

     addr.sin_port = htons(port);                   // set serverport number

     addr.sin_addr.s_addr = inet_addr(host);        // set serverIP

 

     if(connect(sock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)

     {

         long err = WSAGetLastError();

         CConnection::SetLastError(err);

         return false;

     }

 

     linger lg;

     lg.l_onoff = 1;

     lg.l_linger = 10;

     setsockopt(sock, SOL_SOCKET, SO_LINGER, reinterpret_cast <const char*>(&lg), sizeof(linger));

 

     hRecvThread = CreateThread(NULL

         , 0

         , (LPTHREAD_START_ROUTINE) RecvThread

         , this

         , 0

         , (LPDWORD) &dwRecvThreadID);

 

     if(hRecvThread == NULL)

     {

         CConnection::SetLastError(1002);

         closesocket(sock);

         return false;

     }

 

     m_sync.Enter();

     m_socket = sock;

     m_addr = addr;

     m_sync.Leave();

 

     return true;

}

 

至此,C/S + HTML的框架已经搭建完成,剩下的就你们自由发挥了。J

对于这个框架,当然也有缺点,缺点就是需要在客户端安装一个程序。

由于本人水平有限,本文难免有错误疏漏之处,欢迎来信交流指正:qmroom@126.com