`
ihuashao
  • 浏览: 4791861 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

一个消息提示托盘程序的开发历程(采用socket技术,附源代码)一

阅读更多

在我的一个J2EE项目中,当一个人的某一任务到来时,我们在一个jsp页面显示这个到来的任务,提示用户需要处理该任务。
我们是通过轮询数据库来实现对任务的实时监控的。表USER_MESSAGE存储用户的任务。表结构如下:
create table USER_MESSAGE
(
MESSAGE_ID NUMBER(9) not null,
TASK_ID VARCHAR2(100),
USER_CODE VARCHAR2(10),
TASK_NAME VARCHAR2(50),
IS_READ VARCHAR2(1),
CREATE_TIME DATE,
TASK_STATE VARCHAR2(10),
CREATE_MAN VARCHAR2(10),
SEND_MAN VARCHAR2(10),
PRE_TASK_NAME VARCHAR2(50),
SERIAL_CODE NUMBER(11),
MESSAGE_TITLE VARCHAR2(200)
)
当IS_READ=‘F’时,则是新任务。
这个方案有以下弊病:
1:必须打开页面才可以看到任务;
2:每个客户端都需要轮询,当用户多时数据库负荷过大;
于是我做了一个辅助的消息提示工具,当任务到来时发出提示,在系统托盘区发出提示信息,类似QQ。
方案如下:
利用套接字(socket)技术,编写客户端、服务端程序。服务端作为消息服务器,采用每隔一段时间轮询数据库的方式实时监控USER_MESSAGE表。
把新任务消息发送到客户端;客户端识别该消息是否是“我的”消息,如果是“我的消息”,则在系统托盘区闪烁,用户点击闪烁图标,则可以看到消息标题,点击消息标题下
的箭头图案,则可以打开页面进入J2EE系统。
好了,现在就来一步一步的用C++builder做这个小东东吧:
需要准备的知识如下:
一:采用自己的消息通讯协议
二:socket编程
三:如何实现系统托盘
四:数据库中的一条记录,如何打包发送到客户端?
我们一点一点的逐一解决:
一:消息通讯协议如下
Msg.h
/*
* Create Date: 2004-12-01
* Create By: 李春雷
* purpose: 协议用自定义消息结构:
* MESSAGEINFO:任务消息
* MsgType消息头:0xA登陆成功,0xB登陆失败,0xC工作消息,0xD任务结束标识
* LoginInfo:登陆消息
*/

//------------------------------------------------------------------------------

struct MESSAGEINFO{ //消息结构
int MsgType; //消息头:0xA登陆成功,0xB登陆失败,0xC工作消息,0xD任务结束标识
char MessageID[10]; //任务序号
char UsrCode[10]; //用户帐号
//char TastName[50]; //任务名称
char TastName[200]; //任务名称
char CreatTime[20]; //时间
};

struct LoginInfo{ //登陆信息
char pwd[20]; //用户密码
char userID[30]; //用户ID
};
//------------------------------------------------------------------------------
服务端发送的消息只采用的是一个结构体MESSAGEINFO(确认是否登陆成功和发出任务消息),客户端只发送一次登陆信息(LoginInfo)
给服务端,其他时间只是接受服务端发来的消息。

二:socket编程
如果没有用过socket编程,没关系,现在赶快学习:
C++ Builder提供了Internet套件,其中的TClientSocket和TServerSocket组件封装了Windows的有关API,大大简化了WinSock编程。
要通过Internet传输数据,至少需要一对Socket,一个Socket在客户端,另一个Socket在服务器端。其实TClientSocket、TServerSocket组件并不是Socket对象,
其属性Socket将返回各自的Socket对象。TClientSocket用来处理客户端到服务器端之间的socket连接,TServerSocket用来处理由客户端发来的socket连接,
一旦客户端和服务器端都接通了socket,客户端和服务器端就可以相互通信了。
我们做一个小例子:
---- 建立一新项目,创建应用程序的用户界面:
---- 1.将组件页切换到Internet页,放一个TServerSocket组件和一个TClientSocket组件到窗体上,这样应用程序既可以是TCP/IP服务器,也可以是TCP/IP客户。
将Port属性都设为同一个值(如1000),确定Socket之间的连接类型为NonBlocking(非阻塞方式)。
---- 2.放两个TMemo组件到窗体上,用来分别显示双方的谈话内容,将Memo2的ReadOnly属性设为True。
---- 3.在窗体的顶部放上一个Panel组件,在其上放三个按钮:监听(btnlisten)、连接(btnconnect)、断开(btndisconnect),用来启动相应的操作。
---- 4.在窗体底部放一个StatusBar组件,将其SimplePanel属性设为True,在相应的事件处理程序中改变状态条信息,让用户随时了解连接状态。
---- 打开头文件,在窗体类的Private段添加两个私有成员: bool IsServer;String Server。双方通信时需同时运行Chat程序,IsServer用来确定哪个
Chat程序处于服务器端,Server用来存放服务器的主机名。建立窗体类的构造器如下:
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
IsServer=false;
Server="localhost";
}
---- 这里Server被缺省设为localhost,这样程序可以在没有连入Internet的单机上进行调试。在Windows子目录下你可以找到hosts.sam文件中,在该文件
中已经将本机IP地址127.0.0.1定义了主机名:localhost。
void __fastcall TForm1::FormCreate(TObject *Sender)
{
btndisconnect- >Enabled=false;
}
---- 程序运行后,如果用户按下"监听"钮,则将该程序设为服务器端,这时应将TServerSocket的Active属性设为True,使服务器自动进入监听状态。
void __fastcall TForm1::btnlistenClick(TObject *Sender)
{
ClientSocket1- >Active=false;
ServerSocket1- >Active=true;
StatusBar1- >SimpleText="正在监听...";
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
}

---- 当用户按下"连接"钮后,程序会弹出一个询问框,要求用户输入要连接的服务器的主机名,然后建立连接。
void __fastcall TForm1::btnconnectClick(TObject *Sender)
{
if(InputQuery("连接到服务器","输入服务器地址:",Server)){
if(Server.Length() >0){
ClientSocket1- >Host=Server;
ClientSocket1- >Active=true;
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
btndisconnect- >Enabled=true;
}
}
}

---- 当用户提出连接请求后,客户端会触发OnCreate事件,程序先在状态条中显示连接信息,然后将显示对方谈话内容的Memo2清空,准备开始交谈。
void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="连接到:"+Server;
Memo2- >Lines- >Clear();
}
---- 在服务器接受了客户的请求后会触发OnAccept事件,在这个事件处理程序中将标志服务器端的变量IsServer设为True,并准备开始交谈。
void __fastcall TForm1::ServerSocket1Accept(
TObject *Sender,
TCustomWinSocket *Socket)
{
Memo2- >Lines- >Clear();
IsServer=true;
StatusBar1- >SimpleText="连接到:"
+Socket- >RemoteAddress;
}
---- 在建立连接后,双方就可以在Memo1中输入谈话内容开始进行交谈了,按下Enter键后,将所在行的文本发送出去。服务器端的Socket的Connections
属性返回一个数组,该数组由服务器当前活动的连接组成。
void __fastcall TForm1::Memo1KeyDown(
TObject *Sender, WORD &Key,
TShiftState Shift)
{
if(Key==VK_RETURN){
if(IsServer)
ServerSocket1- >Socket- >Connections[0]- >SendText(
Memo1- >Lines- >Strings[Memo1- >Lines- >Count-1]);
else
ClientSocket1- >Socket- >SendText(
Memo1- >Lines- >Strings[Memo1- >Lines- >Count-1]);
}
}

---- 在本例中我们采用非阻塞传输方式,当其中的一方进行写操作时,另一方会触发OnRead事件(客户端)或OnClientRead事件(服务器端),这两个事件的处理程序只是将接收到的内容添加到Memo2的后面。
Memo2- >Lines- >Add(Socket- >ReceiveText());

---- 如果在用户建立连接后单击"断开"钮,将断开客户端与服务器的连接,服务器端将触发OnClientDisconnect事件,而客户端则会触发OnDisconnect事件,这时服务器端应回到监听状态,等待用户的连接;而客户端将返回到连接前的状态,等待用户再次建立连接,如果有不止一个服务器的话,可以选择连接到其他的服务器上。
void __fastcall TForm1::btndisconnectClick(
TObject *Sender)
{
ClientSocket1- >Close();
}
void __fastcall TForm1::ServerSocket1ClientDisconnect(
TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="正在监听...";
}
void __fastcall TForm1::ClientSocket1Disconnect(
TObject *Sender, TCustomWinSocket *Socket)
{
btnlisten- >Enabled=true;
btnconnect- >Enabled=true;
btndisconnect- >Enabled=false;
StatusBar1- >SimpleText="";
}
---- 此外在客户端还应该增加错误捕获机制,当用户输入无效的服务器名或服务器端没有处于监听状态时能够及时给用户反馈信息。
void __fastcall TForm1::ClientSocke
t1Error(TObject *Sender,
TCustomWinSocket *Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
StatusBar1- >SimpleText="无法连接到:
"+Socket- >RemoteHost;
ErrorCode=0;
}
以上步骤完成后,socket就可以run了。是不是没有想象中的困难?

三:关于托盘,bcb给出了很简单的实现方法:
下面让我们来编一个简单的Tary程序:
1、新建工程,添加一个TrayIcon组件、一个PopupMenu组件和一个ImageList组件。它们的Name属性都用默认的名字:TrayIcon1、
PopupMenu1、ImageList1。
2、设置TrayIcon1的属性,如下:
属性 值
Animate true
AnimateInterva 1000
Hide true
Hint Tary演示程序
IconIndex 0
Icons ImageList1
Name TrayIcon1
PopupMenu PopupMenu1
PopupMenuOn imRightClickUp
RestoreOn imDoubleClick
Visible true
3、双击PopupMenu1,弹出菜单设计器,随意地加入几个菜单项。
4、双击ImageList1,加入支持的图片(*.ico、*.bmp)。
  到此,不用编写一句程序代码,一个简单的Tary程序就做好了。按F9编译运行,将鼠标移动到Tary上面就会出现“Tary演示程序”的提示信息;
在Tary上单击鼠标右键弹出菜单Popmenu1;按下程序窗口的最小化按钮,程序最小化后隐藏任务栏上的标题栏;双击Tary将会恢复程序最小化;
而且,Tary图标以1000毫秒(1秒)的速度变换。够简单了吧?!

四:数据库中的一条记录,如何打包发送到客户端?
我们把数据库中的一条记录,放在一个结构体中,然后把该结构体send出去。
下面是一个简单的例子:
.h
struct TUSERINFO
{
int NO; //用户组别
char UsrID[20]; //用户帐号
};

.cpp
void __fastcall TForm1::Button1Click(TObject *Sender)
{ TUSERINFO *tst = new TUSERINFO[2];
tst[0].NO=1;
tst[1].NO=2;
String tmp = "正常";
memcpy(tst[0].UsrID,tmp.c_str(),tmp.Length()+1);
tmp = "不正常";
memcpy(tst[1].UsrID,tmp.c_str(),tmp.Length()+1);
ClientSocket1->Socket->SendBuf(tst,24);
delete tst;}
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
TUSERINFO *tst = new TUSERINFO[2];
Socket->ReceiveBuf(tst,24);
ShowMessage(tst[0].UsrID);
ShowMessage(tst[1].UsrID);
}
上面的例子很简单,可以实现struct的发送,但存在一个小问题:
如果要传2条记录,必须SendBuf(tst,24*2);那么接受的时候必须ReceiveBuf(tst,24*2);
而我发的条数是不确定的,时多时少,有什么办法可以我发多少,客户就接多少?
其实也简单解决:
每次只发一个struct,用for循环发出去就可以了。

通过了以上的一二三四的技术准备,消息提示工具的具体实现就很明朗了,只是工作量的问题了。
在消息提示工具中,我采用ADO访问数据库。
另外,为了到客户那实施起来方便,我采用了配置文件,程序先读取配置文件,然后运行。

分享到:
评论

相关推荐

    一个托盘程序C++源代码

    标题中的“一个托盘程序C++源代码”指的是使用C++编程语言编写的系统托盘应用程序。这种程序通常会在电脑任务栏的右下角图标区域显示一个小图标,用户可以通过单击或右键点击该图标来执行各种操作。这类程序常用于...

    C#做的托盘程序,源代码

    【标题】:“C#制作的托盘程序源代码解析” 在编程领域,托盘程序通常指的是那些在操作系统任务栏通知区域(通常称为“系统托盘”或“通知区域”)运行的应用程序。C#作为微软.NET框架的一部分,提供了一种简单而...

    27.如何制作托盘程序?(Visual C++编程 源代码)

    27.如何制作托盘程序?(Visual C++编程 源代码)27.如何制作托盘程序?(Visual C++编程 源代码)27.如何制作托盘程序?(Visual C++编程 源代码)27.如何制作托盘程序?(Visual C++编程 源代码)27.如何制作托盘...

    托盘程序源码(VC)

    【描述】:“一个简单的对话框托盘程序源码.” 这意味着源代码实现的是一个基础版的托盘程序,它可能包含一个对话框界面,用户可以通过右键点击托盘图标来访问各种功能或设置。对话框是Windows应用程序中常见的一种...

    C#日志托盘提示程序+源代码

    总的来说,这个项目提供了一个学习C#系统托盘程序和日志处理实践的好机会,不仅涉及到基础的编程技术,还有实际开发中的问题处理和资源管理。通过分析和理解源代码,开发者能够增强自己的C#编程能力,特别是对于系统...

    Windows托盘冒泡消息提示(源码).zip_PB开发windows托盘程序_PB提醒

    综上所述,这个压缩包提供的是一份使用PowerBuilder 9开发的Windows系统托盘程序的源代码示例,用户可以根据自己的需求修改和定制提示消息。通过学习和理解这段代码,开发者可以掌握如何在PowerBuilder中实现托盘...

    winfrom 托盘程序,Socket监听

    在本项目中,"winfrom 托盘程序,Socket监听"是一个利用WinForms技术开发的小型应用,该程序能够在系统托盘区运行,提供Socket通信功能,用于监听和接收特定的命令,执行如关机、重启或更新设备上的程序等操作。...

    mfc 最小化到托盘程序源代码

    在这个场景中,"mfc最小化到托盘程序源代码"是指一个使用MFC编写的应用程序,该程序可以在用户选择最小化时,将窗口隐藏到系统托盘区,而不是传统地最小化到任务栏。 系统托盘,也称为通知区域,位于Windows桌面右...

    托盘TRaY源程序

    从标签“动画”、“托盘”、“源程序”可以看出,该程序是一个包含动态效果的系统托盘程序,其源代码是公开的。这对于想要深入学习MFC编程以及Windows应用程序开发的人员来说是一个宝贵的学习资源。开发者可以通过...

    vc++一个小巧的时间提示程序源代码(托盘和serial系列化).rar

    这是一个基于VC++开发的小型时间提醒程序,包含了托盘图标功能和序列化处理。源代码提供了丰富的学习资源,让我们深入探讨一下其中涉及的关键知识点。 1. **MFC框架**: 这个程序使用了Microsoft Foundation ...

    给一个应用程序关联一个托盘程序

    8. **源代码文件**:"tray"可能是一个源代码文件,比如在C#中可能是".cs"文件,包含了托盘程序的核心逻辑。具体实现可能包括定义托盘图标、菜单项以及与之相关的事件处理函数。 结合这些知识点,要实现"给一个应用...

    VB编程源代码 24运行时设置系统托盘图标及提示

    VB编程源代码 24运行时设置系统托盘图标及提示VB编程源代码 24运行时设置系统托盘图标及提示VB编程源代码 24运行时设置系统托盘图标及提示VB编程源代码 24运行时设置系统托盘图标及提示VB编程源代码 24运行时设置...

    C# 托盘程序 托盘程序

    本文将深入探讨如何使用C#来创建一个简单的托盘程序。 首先,我们需要了解C#中的System.Windows.Forms命名空间,它提供了创建图形用户界面(GUI)所需的各种控件和类。在这个命名空间中,`NotifyIcon`类是实现托盘...

    完整的VB托盘气泡提示模块源代码

    【标题】"完整的VB托盘气泡提示模块源代码"涉及的是Visual Basic(VB)编程中的一个特定功能,即托盘区域的气泡提示。在VB应用程序中,托盘图标通常用于最小化程序到系统托盘,而气泡提示则是一种非侵入性的通知方式...

    托盘效果源代码 托盘效果源代码

    在IT领域,"托盘效果源代码"通常指的是在软件开发中,应用程序如何在系统托盘(也称为通知区域)中实现图标和交互功能的源代码。系统托盘是操作系统界面的一部分,位于任务栏的右下角,允许程序在后台运行并提供快捷...

    VB编程源代码 50在系统托盘中增加一个光驱按钮

    VB编程源代码 50在系统托盘中增加一个光驱按钮VB编程源代码 50在系统托盘中增加一个光驱按钮VB编程源代码 50在系统托盘中增加一个光驱按钮VB编程源代码 50在系统托盘中增加一个光驱按钮VB编程源代码 50在系统托盘中...

    VB编程源代码 39在系统托盘中设置动画图标

    VB编程源代码 39在系统托盘中设置动画图标VB编程源代码 39在系统托盘中设置动画图标VB编程源代码 39在系统托盘中设置动画图标VB编程源代码 39在系统托盘中设置动画图标VB编程源代码 39在系统托盘中设置动画图标VB...

    win7托盘管理程序源代码

    标题中的“win7托盘管理程序源代码”指的是一个针对Windows 7操作系统的应用程序,它的主要功能是管理和控制系统任务栏右下角的托盘区域。这个托盘区域通常显示各种程序的小图标,如网络连接、音量控制、时钟等。...

    获取关机、休眠消息托盘程序

    这个“获取关机、休眠消息托盘程序”就是一个这样的工具,它允许开发者捕获并处理系统的关机和休眠事件,以便在这些操作发生前或发生后执行自定义的功能。 首先,我们来理解“截获关机、休眠消息”这一概念。在...

Global site tag (gtag.js) - Google Analytics