set { _info = value; } }
public Friend[] Fri {
get { return _friend; } set { _friend = value; } }
public int Fn {
get { return _fn; } set { _fn = value; } }
public string Fg {
get { return _fg; } set { _fg = value; } }
}
由于MESSAGE.CS与UMESSAGE.CS类似,在此不再详述。
服务器和客户端都可以通过相同的代码对UMESSAGE赋值,再通过XmlSerializer方法进行将UMESSAGE序列化为XML文档,最后将XML文档转化为网络流进行传输。代码如下:
#region 将登录信息转为UMessage private void Traslator() { _message.Accounts=this.TextBox1.Text; _message.Nickname=\ _message.Password=this.TextBox2.Text; _message.Email=\ _message.Info=1; _message.Fri=null; }
#endregion
4.1.2 数据结构FriendStruct
服务器如果保存和传递用户的好友信息是难点之一。数据库的设计和信息的传递辨别都是比较难实现的。
在数据库方面,每个用户拥有各自的好友分组信息(UserFav),分组中间使用“,”分隔,在TCP_FriendInfo表中则分别保存了用户ID和好友ID,使用一个
第 12 页 共 28 页
INT字段保存分组信息。数据库以用户ID为标准对好友ID和分组信息进行内连接查询,就可以得到基本的好友信息了。代码如下:
select * from TCP_UserInfo join TCP_FriendInfo on TCP_FriendInfo.UserID='\+ \
在好友信息的传输方面,首先定义一个FriendStruct数据结构(当然也可以用枚举完成)如下:
using System;
using System.Collections.Generic; using System.Text; namespace TCP {
public class FriendStruct {
public struct FileInfo {
public int filere;//接收和拒绝信息,1为接收,2为拒绝,3为取消 public string filename; public long filelength; } }
public struct Friend {
public string account; public string nickname; public string IP;
public string status;
public string fg;//好友分组 } }
在MESSAGE.CS或者UMESSAGE.CS中,我们则定义了FriendStruct的数组。在C#中使用DATAREADER语句可以逐句读取数据库查询的结果,再依次将结果赋值FriendStruct数组元素,就得到了便于发送和读取的存放好友信息的数组。赋值代码如下:
while (getf.Read()) //getf即是以上的数据库查询的datareader语句 {
ff[i].account=getf[\ ff[i].IP = getf[\
ff[i].nickname = getf[\ ff[i].status = getf[\ ff[i].fg = getf[\ i++; }
第 13 页 共 28 页
getf.Close();
4.2 数据库连接类
实现一个快捷简单的数据库连接的相关代码是非常有必要的。实现的途径也多种多样,鉴于安全性和复杂性的需求不同,实现方法有简有繁。本设计使用了一个简单的类(UserData.CS)实现了简单快捷的数据库连接和读取。主要代码如下:
public static SqlConnection connStr = new
SqlConnection(\
public static SqlDataReader SqlReader(string sql, SqlConnection connstr) {
SqlDataReader sqldr = null;
SqlCommand cmd = new SqlCommand(sql, connstr);
if (cmd.Connection.State.ToString() == \ try {
sqldr = cmd.ExecuteReader(); }
catch (Exception e) {
if (e != null) sqldr = null; }
return sqldr; }
//数据库操作连接
public static string SqlCmd(string sql, SqlConnection connstr) {
string errorstr = null;
SqlCommand sqlcmd = new SqlCommand(sql, connstr); if (sqlcmd.Connection.State.ToString() == \sqlcmd.Connection.Close();
sqlcmd.Connection.Open(); try {
sqlcmd.ExecuteNonQuery(); }
catch (Exception e) {
if (e != null) errorstr = e.ToString(); }
sqlcmd.Connection.Close(); return errorstr;
}
在UserData.CS的基础上,主程序可以更方便地实现数据库连接操作,对数据库进行读写和更新,在此不再详述。
第 14 页 共 28 页
4.3 服务器端
服务器端的界面设计是基于便于测试的目的而实现的。如下图:
这里显示已连入的连接
这里显示传入的原始信息
图4 服务器端界面
4.3.1 同步套接字网络监听
基于同步套接字的网络监听器对服务器来说并不是最好的解决方案,但是仍然可行并且实现简单。主要代码如下:
开启监听端口:
public void Serve() {
int port = 8888;
ServerIPEP = new IPEndPoint(IPAddress.Any, port);
s = new Socket(ServerIPEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Bind((EndPoint)ServerIPEP); s.Listen(10);
alSock = new ArrayList();
以下代码读取连入的连接,依次将连接加入可变长数组alsock,并且读取传入的信息,进行反串行化:
while (true) {
try {
uc = s.Accept(); alSock.Add(uc);
this.tb_states.AppendText(System.Convert.ToString(uc)); byte[] data = new byte[2048]; int rect = uc.Receive(data); byte[] chat = new byte[rect];
Buffer.BlockCopy(data, 0, chat, 0, rect);
UMessage umessage = (UMessage)_translator.Deserialize(new
第 15 页 共 28 页
MemoryStream(chat));
int info = umessage.Info;
对反串行化后的信息进行处理,通过info参数辨认客户端行为(注册或者登录),对注册的信息进行数据库查询,注册信息可插入,则将用户信息插入数据库,否则返回客户端“注册出错”的信息:
#region 处理用户注册信息
if (info==0)//分辨出用户发送的是注册信息 {
string Accounts = umessage.Accounts;
SqlDataReader usdr = FPara.SqlReader(\TCP_UserInfo where UserAccount='\ if (usdr != null) {
if (usdr.Read()) {
#region 此处写入返回注册失败的代码
Socket sc = (Socket)alSock[alSock.IndexOf(uc, 0)]; sc.Send(chat); #endregion } else {
#region 此处写入插入数据库用户注册信息的代码 Stream ms = new MemoryStream();
Socket sc = (Socket)alSock[alSock.IndexOf(uc, 0)]; if (FPara.SqlCmd(\(UserAccount,UserNickname,UserEmail,JoinDate,UserIP,UserPassword) values('%umessage.Accounts + \System.DateTime.Now.ToString() + \
((IPEndPoint)uc.RemoteEndPoint).Address.ToString() + \+ umessage.Password + \FPara.connStr) == null)
{
umessage.Info = 1;
_translator.Serialize(ms, umessage); byte[] d = new byte[ms.Length]; ms.Seek(0, SeekOrigin.Begin); ms.Read(d, 0, d.Length); sc.Send(d); } else {
umessage.Info = 2;
_translator.Serialize(ms, umessage); byte[] d = new byte[ms.Length]; ms.Seek(0, SeekOrigin.Begin); ms.Read(d, 0, d.Length);
第 16 页 共 28 页
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库基于TCP协议的简单即时通信软件的设计与实现(4)在线全文阅读。
相关推荐: