18.3 服务器端底层代码
本章的Web QQ是一个比较复杂的项目,下面将首先从它的底层代码开始讲起。这里的底层代码主要包括两类:一类是指独立性很强的通用代码,这些代码稍加修改就可应用于其他项目中;另一类是指这个项目的一些基础类库,如对实体类、工具类的封装等,它们是这个项目的核心代码。本章将分别从服务器端和客户端两个方面详细讲述这些代码的实现。
本节讲述服务器端底层代码的实现。
服务器端的底层代码包括在MyChat类库工程中,主要有两个文件:sql.cs和implement.cs。其中sql.cs只包括一个类的定义Sql,用来操作数据库。Implement.cs包括的类大体包括:消息类、消息基础类BaseMsg、两人消息类Msg、两人消息表类MsgTable、群内单个用户访问时间类RT、群内所有用户访问时间类RTT、群消息表类GroupMsgTable及其扩展类——群类MyGroup;聊天用户类ChatUser;工具类Tools。下面分别作详细介绍。
18.3.1 数据库操作类Sql
数据库操作类的封装是任何工程都必不可少地,本例当然也不例外。Sql类主要包括两类方法:一类用来直接执行SQL语句,另一类用来执行存储过程。其所包括的各种方法的结构如图18.4所示。

图18.4 Sql类的各种方法
其中的数据库连接字符串的数据库路径采用了绝对路径,读者调试程序时应当做相应的更改。Sql类的具体代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace MyChat
{
//数据库操作类
public class Sql
{
private string str = null; //数据库连接字符串
public SqlConnection Con; //sql数据连接组件实例化
public SqlCommand command = new SqlCommand(); //初始化一个SQL命令对象
public Sql() //类初始化,初始化数据连接
{
string path = @"C:\Documents and Settings\Administrator\桌面\tools\
mychat1.0\Chat";
//数据库连接字符串
str="Data Source=.\\SQLEXPRESS;AttachDbFilename=\"" + path +
"\\app_data\\chat.mdf\";Integrated Security=True;User Instance=True";
Con = new SqlConnection(str);
}
#region SQL语句操作
// 执行只读数据信息的提取,返回一个datareader
public SqlDataReader GetReader(string search)
{
SqlDataReader Reader;
if(Con.State != ConnectionState.Open)
Con.Open(); //打开数据库连接
SqlCommand Com = new SqlCommand(search, Con);
Reader = Com.ExecuteReader(); //执行SQL语句
return Reader; //返回一个reader
}
// 输入查询字符串,返回dataset
public DataSet getMyDataSet(string sql)
{
command.Connection = Con; //配置command对象
command.CommandText = sql; //赋予要执行的语句
DataSet dt = new DataSet(); //初始化一个数据返回集合
SqlDataAdapter da = new SqlDataAdapter(command);
Con.Open(); //打开连接
da.Fill(dt); //执行语句
command.Connection.Close(); //关闭连接
return dt;
}
// 执行非查询SQL语句
public void ExecuteSql(string sql)
{
if(Con.State != ConnectionState.Open)
Con.Open(); //如果数据连接关闭,则打开
SqlCommand Com = new SqlCommand(sql, Con);
Com.ExecuteNonQuery(); //执行非查询SQL语句
Con.Close();
}
// 执行非查询数据库操作,是否关闭数据库连接 可以选择
public void ExecuteSql(string sql, bool closeConnection)
{
if(Con.State != ConnectionState.Open)
Con.Open(); //如果未打开连接,则打开
SqlCommand Com = new SqlCommand(sql, Con);
Com.ExecuteNonQuery();
if (closeConnection) Con.Close(); //如果需要关闭,则关闭连接
}
#endregion
#region 执行存储过程的代码
//输入存储过程名称,执行查询存储过程
public DataSet getDataSet(string produreName)
{
command.Connection = Con; //赋予连接对象
//执行的类型为存储过程
command.CommandType = CommandType.StoredProcedure ;
command.CommandText = produreName; //赋予执行的存储过程名字
DataSet dt = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(command);
Con.Open(); //打开连接
da.Fill(dt); //填充数据
command.Connection.Close();
return dt; //返回数据集
}
//输入存储过程名,执行非查询存储过程
public bool exec(string produreName)
{
bool flag = false; //任务是否正确执行,初始化为false
command.Connection = Con; //赋予command对象以数据连接
command.CommandType = CommandType.StoredProcedure;
command.CommandText = produreName; //存储过程名称
try
{
command.ExecuteNonQuery(); //执行存储过程
flag = true; //正确完成任务
}
finally
{
command.Connection.Close(); //关闭连接
}
return flag; //返回成功与否的标志
}
#endregion
}
}
18.3.2 消息基础类BaseMsg
消息是Web QQ的核心任务之一,几乎所有的操作都是围绕消息展开的,所以这里对消息处理进行了实体类封装。消息分两种:两人聊天的消息类和群聊的消息类。它们之间有很多区别,但也有很多相似之处,所以本章定义了一个消息基础类,两人聊天的消息类和群聊的消息类都从基础类继承。与消息直接相关的各类之间的关系如图18.5所示。
消息基础类BaseMsg的代码比较简单,只是封装了几个常用的属性。具体代码如下:
/// <summary>
/// 消息基础类
/// </summary>
public class BaseMsg
{
public BaseMsg(string senderName, string message)
{
msg = message; //消息内容
sendername = senderName; //消息发送者
}
public BaseMsg(string senderName, string message, DateTime sendtime1)
{
msg = message; //消息内容
sendername = senderName; //消息发送者
sendtime = sendtime1; //发送时间
}
public BaseMsg(int id1, string senderName, string message, DateTime
sendtime1)
{
msg = message; //消息内容
sendername = senderName; //消息发送者
id = id1; //消息id
sendtime = sendtime1; //发送时间
}
private int id = 0; //消息的id
public int ID
{
get { return id; }
set { id = value; }
}
private string sendername; //消息的发送者
public string SenderName
{
get
{
return sendername;
}
set
{
sendername = value;
}
}
private string msg; //消息内容
public string Message
{
get
{
return msg;
}
set
{
if(value.Length > 150) //消息不能超过150个字符,否则截断
value = value.Substring(0, 150);
msg = value;
}
}
private DateTime sendtime = DateTime.Now; //发送时间
public DateTime SendTime
{
get
{
return sendtime;
}
set
{
sendtime = value;
}
}
}
18.3.3 两人聊天消息类Msg
两人聊天的消息类Msg直接从BaseMsg继承,在BaseMsg基类上另外添加了两个属性:IfRead和IfInDb。IfRead用来标记这条消息是否已经被接收者阅读过;IfInDb用来标记缓存中的此条消息是否已经在数据库中保存,如果保存了,则要考虑数据的同步问题。Msg的具体代码如下:
/// <summary>
/// 两人聊天时的消息类
/// </summary>
public class Msg : BaseMsg
{
public Msg(string senderName, string message)
: base(senderName, message)
{
}
public Msg(int id1, string senderName, string message, DateTime sendtime1, bool ifread1)
: base(id1, senderName, message, sendtime1)
{
ifread = ifread1; //此条消息是否已经读过
}
private bool ifread = false; //消息初始化未读
public bool IfRead // 是否已经读过
{
get
{
return ifread;
}
set
{
ifread = value;
}
}
private bool ifInDB = false; // 是否在数据库中保存有此条记录
public bool IfInDB
{
get
{
return ifInDB;
}
set
{
ifInDB = value;
}
}
}
18.3.4 两人聊天消息表类MsgTable
消息都要以集合的形式保存,两人聊天的消息表类是MsgTable。每个聊天用户都有一个单独的MsgTable,这个MsgTable记录着发给此用户的所有消息(包括系统消息)。由于内存毕竟是有限的,所以对每个用户的消息数量进行了一定的限制,超过这个数量后,消息将被存储入数据库,并清空该用户的消息表。属性MaxRecord就是实现这个功能的。属性HaveOtherMsg标记的是此用户的未读消息是否已经全部载入了内存。MsgTable定义了两个Add方法,分别用于处理聊天用户类初始化和用户发言操作。具体代码如下:
// 两人聊天的消息表
public class MsgTable
{
private int maxrecord = 30; //消息表中最多存放的记录数目
public int MaxRecord
{
get { return maxrecord; }
set { maxrecord = value; }
}
private ArrayList list; //存放消息的arraylist
private bool haveothermsg = false; //数据库中是否还有未读消息
public bool HaveOtherMsg
{
set { haveothermsg = value; }
get { return haveothermsg; }
}
public ArrayList List //存放消息用
{
get
{
return list;
}
}
public MsgTable()
{
list = new ArrayList(); //类初始化时,初始化一个消息列表存放地
}
public MsgTable(Msg msg1)
{
list = new ArrayList();
this.Add(msg1); //类初始化时,类中便有一条消息
}
//初始化用户类时专用
public void Add(Msg msg1)
{
//内存块已满,首先把已读数据存入数据库,释放部分内存,
//如果内存中的数据都是未读,把所有数据都存入数据库,释放全部内存。
if(list.Count >= MaxRecord)
{
Sql s = new Sql(); //初始化数据库操作类
string insertstr = ""; //插入字符串
string updatestr = ""; //更新字符串
//用户初始化时 只取未读数据,所以内存中的所有已读数据都需要更新为ifread=0,
//或插入数据库。清除内存中已读数据
for(int i = 0; i < MaxRecord; i++)
{
if(((Msg)(list[i])).IfRead) //已读
{
//此条聊天记录存在于数据库中,则更新其为已读状态
if((((Msg)(list[i])).IfInDB))
updatestr += " or id = " + (((Msg)(list[i])).ID.ToString());
else //位在数据库中,则插入数据库
{
insertstr = "insert msg(sendername,receivername,msg, endtime,fread) values('";
insertstr += ((Msg)list[i]).SenderName + "','" + System. Web.HttpContext.Current.User.Identity.Name + "','" + ((Msg)list[i]).Message + "','";
insertstr += ((Msg)list[i]).SendTime + "','" + "0" + "')";
//执行插入操作
s.ExecuteSql(insertstr, false);
}
list.RemoveAt(i); //释放内存
}
}
if(updatestr != "") //如果有需要更改为已读状态的则统一执行更改操作
s.ExecuteSql("update msg set ifread = 0 where 1=2 " + updatestr, false);
//从内存中清除已读消息后,如果内存块仍然满,则把所有消息都存入数据库,清空内存
//块,以待现在聊天用
if(list.Count >= MaxRecord)
{
for(int i = 0; i < MaxRecord; i++)
{
//消息没有在数据库中,则插入数据库
if (!(((Msg)list[i]).IfInDB))
{
insertstr = "insert msg(sendername,receivername,msg, sendtime,ifread) values('";
insertstr += ((Msg)list[i]).SenderName + "','" + System.Web.HttpContext.Current.User.Identity.Name + "','" + ((Msg)list[i]).Message + "','";
insertstr += ((Msg)list[i]).SendTime + "','" + "1" + "')";
s.ExecuteSql(insertstr, false);
}
}
list.Clear(); //清空存放消息的数组
}
s.Con.Close(); //关闭数据库连接
}
list.Add(msg1); //增加一条聊天记录
}
//用户发言时专用
public void Add(string sendername, string message)
{
Add(new Msg(sendername, message));
}
}
18.3.5 群消息表类GroupMsgTable
群消息与两人聊天的消息有所不同。群消息的处理机制是:每个群都包括一个群消息表GroupMsgTable用来记录群内的所有消息,而这个群消息表又包括一个记录群内用户访问时间的属性ReceiveTime。ReceiveTime是用户访问时间表类RTT的一个实例,RTT又是RT的集合。RT、RTT和GroupMsgTable类的实现代码如下:
// 记录群消息中单个用户的访问时间
public class RT
{
private string username; //用户账号
public string UserName
{
set { username = value; }
get { return username; }
}
private DateTime time = DateTime.Now; //用户访问时间
public DateTime Time
{
get { return time; }
set { time = value; }
}
public RT(string un) //初始化时指定账号名
{
username = un;
}
}
/// <summary>
/// 记录一个群中所有用户的访问时间。
/// </summary>
public class RTT : ArrayList
{
public override int Add(object value)
{
return base.Add(value);
}
}
// 单个群的消息表类
public class GroupMsgTable
{
private int maxrecord = 100; //存放群消息的内存块最多存放的消息数目
public int MaxRecord
{
get { return maxrecord; }
set { maxrecord = value; }
}
private int id = 0; //初始化群id
public int ID
{
get { return id; }
set { id = value; }
}
protected ArrayList list; //群消息的arraylist
public ArrayList List
{
get
{
return list;
}
}
private bool haveothermsg = false; //除内存的消息外,是否数据库中还有群消息
public bool HaveOtherMsg
{
set { haveothermsg = value; }
get { return haveothermsg; }
}
public GroupMsgTable() //初始化一个空群消息类
{
list = new ArrayList();
}
public GroupMsgTable(string groupid) //初始化的类指定了群id,主要用于从数据库中取
//出的群消息
{
id = int.Parse(groupid);
list = new ArrayList();
}
//指定群id,并且默认添加一条群消息
public GroupMsgTable(BaseMsg msg1, string groupid)
{
id = int.Parse(groupid);
list = new ArrayList();
this.Add(msg1);
}
private RTT receivetime = new RTT(); //此群中所有用户的访问时间
public RTT ReceiveTime // 群所有用户最近一次接受群消息的时间
{
get
{
return receivetime;
}
set { receivetime = value; }
}
//群消息过期时间
private TimeSpan ts = new TimeSpan(500);
private int askdbnum = 0; //访问数据库的次数
public int AskDbNum
{
get { return askdbnum; }
set { askdbnum = value; }
}
//发布一条群消息
public void Add(BaseMsg msg1)
{
//内存块已满,首先把过期时刻之前的数据存入数据库,释放部分内存,
//如果内存仍满,把所有数据都存入数据库,释放全部内存,IfInDb=true 。
if(list.Count >= MaxRecord) //内存块已经满
{
Sql s = new Sql(); //数据库操作类
string insertstr = ""; //插入字符串
//清除内存中过期数据
for(int i = 0; i < MaxRecord; i++)
{
insertstr = "insert groupmsg(groupid,sendername,sendtime,msg) values(" + id.ToString() + ",'"; //插入字符串
//过期
if(((BaseMsg)(list[i])).SendTime < DateTime.Now - ts)
{
insertstr += ((BaseMsg)list[i]).SenderName + "','" + ((BaseMsg)list[i]).SendTime + "','" + ((BaseMsg)list[i]).Message + "')";
s.ExecuteSql(insertstr, false);
list.RemoveAt(i); //释放内存
}
}
if(list.Count >= MaxRecord) //内存块仍满,所有数据都存入数据库,释放全部
内存,
{
//所有数据存入数据库
for(int i = 0; i < MaxRecord; i++)
{
insertstr = "insert groupmsg(groupid,sendername,sendtime,msg) values(" + id.ToString() + ",'";
insertstr += ((BaseMsg)list[i]).SenderName + "','" + ((BaseMsg)list[i]).SendTime + "','" + ((BaseMsg)list[i]).Message + "')";
s.ExecuteSql(insertstr, false);
}
list.Clear(); //清空内存块
haveothermsg = true; //表明数据库中存有数据
}
s.Con.Close(); //关闭数据库连接
}
list.Add(msg1); //增加消息记录
}
}
18.3.6 群类MyGroup
群类MyGroup继承自GroupMsgTable类,只是类GroupMsgTable基础上添加了一个方法ReceiveMsg,用来接收群消息。接收一条群消息的处理逻辑如图18.6所示。

图18.6 接收群消息的流程图
MyGroup的实现代码如下:
//群的类
public class MyGroup : GroupMsgTable
{
public MyGroup(string groupid)
: base(groupid) //类初始化
{ }
//接收群消息
public GroupMsgTable ReceiveMsg()
{
GroupMsgTable mymsg = new GroupMsgTable();//用于存放接收到的消息
DateTime lt = DateTime.Now.AddMinutes(-3); //上次接收消息的时间
int tempid = -1; //此用户在本群的receivetime中的索引。
//下面得到该用户最近一次访问该群的时间
string usern = System.Web.HttpContext.Current.User.Identity.Name;
//当前用户名
//遍历群中用户访问时间数组,找到自己访问的时间和在数组中的索引
for(int i = 0; i < this.ReceiveTime.Count; i++)
{
if(((RT)ReceiveTime[i]).UserName == usern)//找到本用户
{
lt = ((RT)ReceiveTime[i]).Time;
tempid = i;
break;
}
}
//需要从数据库中取数据
if(this.HaveOtherMsg == true)
{
string str = "select groupid,sendername,sendtime,msg from groupmsg where groupid ="
+this.ID.ToString() + " and sendtime>'" + lt + "'"; //构造字符串
Sql s = new Sql();
SqlDataReader reader = s.GetReader(str); //得到数据
while (reader.Read()) //把数据库中的群消息全部返回给接收者
{
mymsg.Add(new BaseMsg(reader["sendername"].ToString(), reader["msg"].ToString(),
DateTime.Parse(reader["sendtime"].ToString())));
}
reader.Close(); //关闭连接
this.AskDbNum++; //访问数据库的次数增一
//如果超过50次,即认为群中所有人都从数据库中取了一次数据,没有需要从数据库
//中取数据了。
if(this.AskDbNum > 50)
{
this.AskDbNum = 0; //重新计算访问数据库的次数
this.HaveOtherMsg = false;
}
}
//遍历内存块中的数据
for(int i = 0; i < this.list.Count; i++)
{
//如果内存中的群消息的发送时间在自己上次访问之后,并且这条消息不是自己发送的
if(((BaseMsg)list[i]).SendTime >= lt && ((BaseMsg)list[i]).Sender
Name != usern)
{
mymsg.Add((BaseMsg)list[i]); //添加到数组,返回给接收者
}
}
//如果找到了用户在接收消息列表中的索引,则更新接收时间
if(tempid != -1)
((RT)ReceiveTime[tempid]).Time = DateTime.Now;
Else //否则新建接收时间
{
ReceiveTime.Add(new RT(usern));
}
return mymsg; //返回群消息
}
}
18.3.7 聊天用户类ChatUser
每个聊天用户对应一个ChatUser类,当此类初始化时只是取得用户账号和ID,不加载任何相关信息。当类消失时,做一些清理工作,把缓存中的数据存入数据库。清理工作的大致流程是:遍历自己的消息集,如果这条消息在数据库中不存在,则插入数据库;如果在数据库中存在,并且已读状态发生了改变,则更新数据库中的记录。聊天用户类ChatUser的代码如下:
// 聊天程序用户类
public class ChatUser
{
private HttpContext context = HttpContext.Current; //当前的运行上下文
private int userid; //用户id
private string username; //账号名
public int Userid // 用户ID
{
get
{
return userid;
}
}
public string UserName // 账号名
{
get
{
return username;
}
}
//上线与否的过期时间,超过这个时间即认为用户已经离线
private DateTime willtime = DateTime.Now.AddMinutes(1);
public DateTime WillTime
{
get
{
return willtime;
}
set
{
willtime = value;
}
}
//用户消息组,所有发给自己的消息都存储在这里
private MsgTable message = new MsgTable();
public MsgTable Message // 存储别人发给自己的消息
{
get
{
return message;
}
set
{ message = value; }
}
public ChatUser() //初始化时,取得id和name
{
username = System.Web.HttpContext.Current.User.Identity.Name ;
userid = int.Parse(tools.GetUserId(username));
}
//析构函数,本实例消失时把内存中的数据存入数据库
~ChatUser()
{
Sql s = new Sql(); //数据库操作类
for(int i = 0; i < Message.List.Count; i++)
{
string str = "";
//判断此条聊天记录在数据库中是否存在,数据库中没有,则插入数据库
if(((Msg)Message.List[i]).IfInDB == false)
{
str = "insert msg(sendername,receivername,msg,sendtime,ifread)
values('";
string ifread = "1"; //此条记录是否已读,1为未读
//已读
if (((Msg)Message.List[i]).IfRead == true) ifread = "0";
str+=((Msg)Message.List[i]).SenderName
+ "','" + UserName + "','" +
((Msg)Message.List[i]).Message +
"','";
str += ((Msg)Message.List[i]).SendTime + "','" + ifread + "')";
s.ExecuteSql(str); //执行插入操作
}
//数据库中存在这条记录,且内存中的记录由未读变为了已读,则更改数据库中的状态
else if (((Msg)Message.List[i]).IfRead == true)
{
string updatestr = "update msg set ifread=0 where id =" + ((Msg)
Message.List[i]).ID.ToString();
s.ExecuteSql(updatestr);
}
}
}
}
18.3.8 工具类Tools
为了应用程序方便,此处把本项目中常用到的功能封装在了tools类中。本类中的各个方法之间基本上没什么直接联系,可以单独使用,并且绝大部分是静态方法。各个方法的简要说明见表18-8所示。
表18-8 tools类各方法说明
|
方 法 名 |
功 能 |
参 数 说 明 |
返 回 值 |
|
UpdateSelfTime |
更新自己的最终离线时间 |
空 |
|
|
GetUserId |
根据账号得到id |
Username用户账号 |
相应的id |
|
GetMyUserName |
根据id得到账号 |
Userid用户ip |
相应的账号 |
|
SetOnlinStatus |
设置自己在线和隐身的状态 |
Status要设置成的状态 |
空 |
|
CheckMessage |
检测某人是否给自己发送了最新消息 |
Sn要检测者的账号 |
真假值 |
|
GetSysMsgNum |
得到自己的系统消息数量 |
消息数目 |
续表
|
方 法 名 |
功 能 |
参 数 说 明 |
返 回 值 |
|
LoadStr |
加载某类联系人显示的字符串 |
Type联系人类别;ifhavemsg本类联系人中是否有新消息 |
用于客户端显示的字符串 |
|
LoadGroupStr |
加载自己群显示的字符串 |
用于客户端显示的字符串 |
|
|
AddNewUser |
加载一个新的聊天用户类 |
Context当前运行上下文 |
操作是否成功 |
|
Encrypt |
加密 |
strText待加密的字符串;strEncrKey密钥 |
加密后的字符串 |
这里介绍一下LoadStr方法的处理流程。LoadStr用于取得自己某类联系人显示的字符串。它有一个输出参数ifhavemsg,表示此类中是否有新消息。整个方法的处理流程如图18.7所示。

图18.7 LoadStr()方法的流程图
AddNewUser方法是当用户登录时,或者用户在线但用户类的缓存被回收的情况下调用。其处理逻辑大致分为3个步骤,如图18.8所示。

图18.8 AddNewUser方法的流程图
Tools类的实现代码如下:
//工具类,封装一些常用的函数
public class tools
{
Sql s; //数据库操作类
int selfid; //用户id
string selfname; //用户名
public tools() //类实例化时,给变量赋值
{
s = new Sql();
if(System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
{
selfname = System.Web.HttpContext.Current.User.Identity.Name;
selfid = int.Parse(tools.GetUserId(selfname ));
}
}
//更新自己的离线时间, 保持自己的上线状态
public static void UpdateSelfTime()
{
//如果未登录,则返回
if (!System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
return;
HttpContext co = System.Web.HttpContext.Current;
//本用户信息为空
if(co.Cache[System.Web.HttpContext.Current.User.Identity.Name] == null)
{
ChatUser user = new ChatUser();
//增加一个用户聊天类实例
co.Cache.Insert(user.UserName, user);
}
//更新自己的离线时间
((ChatUser)(co.Cache[System.Web.HttpContext.Current.User.Identity.
Name])). WillTime = DateTime.Now.AddSeconds(30);
}
//根据id获得name
public static string GetUserId(string username)
{
string result="";
Sql ms = new Sql();
DataTable dt = ms.getMyDataSet("select userid from userinfo where
username='"+username +"'").Tables[0];
if(dt.Rows.Count > 0)
result = dt.Rows[0][0].ToString();
return result;
}
//根据name获得id
public static string GetMyUserName(string userid)
{
string result = "";
Sql ms = new Sql();
DataTable dt = ms.getDataSet("select username from userinfo where
userid='" + userid + "'").Tables[0];
if(dt.Rows.Count > 0)
result = dt.Rows[0][0].ToString();
return result;
}
// 用户设置自己的上线状态,隐身还是上线
// 上线状态设置 1上线,0隐身
public static void SetOnlineStatus(string status)
{
string user = System.Web.HttpContext.Current.User.Identity.Name;
//用户id
Sql ms = new Sql();
//更新自己的上线状态
ms.ExecuteSql("update userinfo set ifshowonline=" + status + " where
username='" + user+"'");
}
// 判断某用户是否给自己发送了新消息
//sn 发送者姓名
//返回ture 有新消息;false没有消息
public bool CheckMessage(string sn)
{
bool b = false; //默认没有发消息
//内存中存在的聊天记录id 字符串
string temp = "0";
ChatUser my = (ChatUser)(HttpContext.Current.Cache[selfname]); //获
//得聊天用户类
if(my == null)//如果没有了这个用户信息,初始化一个
{
AddNewUser(HttpContext.Current); //添加一个聊天用户信息类
my = (ChatUser)(HttpContext.Current.Cache[selfname]);
}
//遍历自己的信息列表
for(int i = 0; i < my.Message.List.Count; i++)
{
//如果某人给自己发送了消息,并且未读,说明有消息,返回
if(((Msg)(my.Message.List[i])).SenderName==sn && ((Msg)(my.Message.
List[i])).IfRead == false)
{
b = true;
return b;
}
temp += ("," + ((Msg)(my.Message.List[i])).ID); //保存已经检测
//过的消息id
}
if(my.Message.HaveOtherMsg == true) //数据库中还有未读消息
{
Sql q = new Sql(); //构造数据操作类
//数据读取类
SqlDataReader reader = q.GetReader("Select [id] From msg Where
[receivername] ='"
+ selfname + "' and sendername='" + sn + "' and ifread=1 and id
not in (" + temp + ") ");
//有新消息
if(reader.HasRows)
{
 

