TCP服务器与客户端软件word文档良心出品.docx
- 文档编号:27058065
- 上传时间:2023-06-26
- 格式:DOCX
- 页数:30
- 大小:234.73KB
TCP服务器与客户端软件word文档良心出品.docx
《TCP服务器与客户端软件word文档良心出品.docx》由会员分享,可在线阅读,更多相关《TCP服务器与客户端软件word文档良心出品.docx(30页珍藏版)》请在冰豆网上搜索。
TCP服务器与客户端软件word文档良心出品
1实验目的
1.理解和掌握软件工程的设计理念与设计方法。
2.掌握某种数据库管理以及可视化编程环境,掌握基于某种编程语言的信息系统或网络通信软件或某种通用总线接口的通信软件的开发设计方法。
2实验题目及要求
题目:
TCP服务器与客户端软件
本题目要求使用TCP协议实现若干台电脑之间的通信。
1.任何一台电脑都具有收发信息功能。
2.具有记录查询通信纪录的功能。
3.有图形化界面。
4.服务器可同时与多个客户端通信。
分别实现服务器和客户端的程序。
3实验系统设计
3.1需求分析:
本次实验的题目是TCP服务器与客户端软件,本题目要求使用TCP协议实现若干台电脑之间的通信。
软件针对局域网内部用户,实现用户间的即时通信。
需要分别实现服务器端和客户端的软件设计,并有图形化界面。
服务器端负责监听用户连接请求,负责连接数据库存储用户信息,负责发送给用户好友信息,负责发送心跳报文检查用户在线状态并即时让用户更新好友在新信息。
客户端发起主动连接,向服务器请求登录或者注册。
客户端可以修改昵称,可以加已知用户为好友(类似于MSN的好友添加功能)。
客户端之间可以发起P2P模式的聊天,可以传送文件。
3.2主要理论依据:
1.TCP——传输控制协议:
TCP协议提供的是可靠的、面向连接的传输控制协议,即在传输数据前要先建立逻辑连接,然后再传输数据,最后释放连接3个过程。
TCP提供端到端、全双工通信;采用字节流方式,如果字节流太长,将其分段;提供紧急数据传送功能。
TCP要求在发送数据之前必须打开连接。
服务器应用程序必须执行一个称作被动打开(passiveopen)的操作,以利用一个已知的端口号创建一个链接,这是,服务器并不是对网络进行呼叫,而是侦听并等待引入的请求。
客户应用程序必须执行一个主动打开(activeopen),为此,它向服务器应用程序发送一个同步序列号(SYN)以标识连接。
客户应用程序可以将动态端口号作为本地端口使用。
服务器必须向客户发送一个确认(ACK)以及服务器的序列号(SYN)。
随后,客户回复一个ACK,这样就建立了链接。
现在可以发送和接收消息了。
接收消息后,总是返回ACK消息。
如果在收到ACK之前发送方已经超时,则消息将被放到重发队列中以再次发送。
由于它的握手机制,所以TCP协议比较复杂并且费时,但此协议在处理数据时对数据包的传送有保障,从而使得在应用程序协议中不需要再包括该功能。
2.套接字:
套接字这个术语并没有定义某个协议:
它具有两层含义,但两者都与一个协议相关。
第一个含义是套接字编程API,它最初由伯克利大学为BSDUNIX而创建。
BSD套接字在经过修改后被用作Windows环境的编程接口(并且被命名为WinSock)。
WinSockAPI被包装在System.Net.sockets命名空间的.NET类中。
WindowsSockets是一个独立于协议的编程接口,用于编写网络应用程序。
套接字的第二层含义表示一个用于在进程间进行通信的终端。
在TCP/IP中,每个终端都与一个IP地址和一个端口号绑定。
我们必须对流式套接字和数据报套接字这两种类型进行区分。
流失套接字用TCP/IP协议来使用面向连接的通信;另一方面,数据报套接字用UDP/IP来使用无连接通信。
3.C/S模型:
客户机/服务器模型,又称为Client/Server模型,简称C/S架构。
C/S计算技术在信息产业当中占有重要的地位。
这种客户机/服务器模型是一种非对称式编程模式。
该模式的基本思想是把集中在一起的应用划分成为功能不同的两个部分,分别在不同的计算机上运行,通过它们之间的分工合作来实现一个完整的功能。
对于这种模式而言其中一部分需要作为服务器,用来响应并为客户提供固定的服务;另一部分则作为客户机程序用来向服务器提出请求或要求某种服务。
在此“服务器”是指能在网络上提供服务的任何程序。
服务器接受网络上的请求,完成服务后将结果返回给申请者。
对于简单的服务,把每个请求用一个IP数据报发给服务器,服务器用另一个数据报返回响应。
客户机和服务器都是独立的计算机。
当一台连入网络的计算机向其他计算机提供各种网络服务(如数据、文件的共享等)时,它就被叫做服务器。
而那些用于访问服务器资料的计算机则被叫做客户机。
严格说来,客户机/服务器模型并不是从物理分布的角度来定义,它所体现的是一种网络数据访问的实现方式。
采用这种结构的系统目前应用非常广泛。
如宾馆、酒店的客房登记、结算系统,超市的POS系统,银行、邮电的网络系统等。
各种网络服务器基本都遵循同样的算法:
创建一个端口(Port),接受从网络上来的客户服务请求,完成计算后把结果返回给客户,如此反复。
3.3系统基本构架:
基于C/S架构的即时通信软件便于对用户信息进行统一管理和保存,面向特定的用户,对信息的安全控制能力很强。
为了减轻服务器负担,客户端之间的信息传递是采用P2P模式的,服务器只负责用户的注册,登录和用户在线状态的检验。
基本结构如图:
3.4功能模块设计:
CLIENT:
1.注册:
(1)可以完成客户端注册,客户端可以通过填写信息进行注册,信息被发送到服务器端。
2.登录:
(1)客户可以输入账号和密码进行登录,客户端会发送登录信息等待服务器响应,登录成功后会发出登录成功信息并刷新好友列表。
3.修改:
(1)密码修改:
应该有密码修改功能
(2)信息修改:
可以更改一些注册信息
4.通信:
(1)即时聊天模块:
客户端与客户端之间建立线程进行即时聊天,也包含有简单的对称加密算法功能。
(2)好友列表:
可以对好友列表进行添加删除等动作
5.文件传输:
(1)文件传输:
文件传输功能
SERVER:
1.注册回应:
对客户端传送的注册信息进行判断。
(1)HASH加密:
对用户的账号和密码信息进行HASH加密
(2)重复用户检查:
将加密后信息与已存在账号进行比较,检查是否账号已存在,如果存在就返回错误信息
(3)注册成功:
将可成功注册的用户账号和密码写入数据库内,并向客户端返回成功信息
2.修改回应:
(1)对密码和信息修改请求进行判断,执行和返回修改成功信息
3.登录回应:
(1)对登录的账号和密码进行加密检查后发回正确或错误情况,并记录上线信息
(2)好友列表发送:
给成功登录的账号发送好友列表及好友上线信息
(3)上线信息发送:
给成功登录的账号的好友发送在线信息(包括IP,端口等等信息)
4.在线情况:
(1)对登录,在线,离线的用户情况进行统计,记录和通知
(2)心跳测试:
每隔一段时间发送报文测试用户是否因意外原因离线
(3)情况记录:
将用户登录时间,IP,下线时间等信息记录入数据库
3.5逻辑图:
具体逻辑图如下图所示:
3.6数据库设计:
服务器是作为记录和读取数据库信息的载体,与客户端关系并不复杂,这里需要重点考虑客户端之间的关系。
用户与用户之间的关系是较为特殊的递归关系,即描述发生在两个相同实体上的关系。
E-R图如下:
数据库包含两个表,分别为记录用户信息的TCP_Userinfo和记录用户好友信息的TCP_Friendinfo。
详细设计见下面两表:
表1用户信息表TCP_UserInfo
TCP_Userinfo
列(属性)名
类型
主键
宽度
是否允许为空
备注
UserID
numeric
Y
9
NOTNULL
自增长
UserAccount
nchar
N
20
NOTNULL
用户帐号
UserNickname
nchar
N
20
NOTNULL
用户昵称,可重复
UserEmail
nchar
N
20
NOTNULL
用户EMAIL
JoinDate
nchar
N
35
NOTNULL
注册日期
LastLogin
nchar
Y
20
NOTNULL
最后登录IP
UserIP
nchar
Y
20
NOTNULL
用户IP
UserFav
varchar
N
100
NOTNULL
用户好友分组,有默认值
UserQuestion
nchar
Y
20
NOTNULL
密码问题
UserAnswer
nchar
Y
20
NOTNULL
密码答案
UserPassword
nchar
N
20
NOTNULL
用户密码
UserOnline
int
N
4
NOTNULL
在线状态,1在,0不在
表2用户好友表TCP_FriendInfo
TCP_Userinfo
列(属性)名
类型
主键
宽度
是否允许为空
备注
InfoID
numeric
Y
9
NOTNULL
自增长
UserID
nchar
N
20
NOTNULL
用户ID
FriendID
nchar
N
20
NOTNULL
用户好友ID
FriendGroup
nchar
N
20
NOTNULL
用户好友分组
4系统实现
4.1使用XML定义的即时通信协议:
信息结构MESSAGE.CS&UMESSAGE.CS
这两个C#类定义了包括服务器信息,状态信息,注册信息,登录信息,聊天信息或者请求文件传输信息的函数,服务器和客户端通过将它们实例化和序列化再转换成流在网络上进行传输。
UMESSAGE.CS主要代码如下:
[Serializable]
publicclassUMessage
{
publicUMessage(){}
privatestring_nickname;
privatestring_password;
privatestring_accounts;
privatestring_email;
privateint_info;//表示注册或者登录信息,客户端信息0为注册,1为登录;服务器返回信息0为用户已存在,1为注册成功,2为服务器未知错误,3为CLIENT在线检查,10为登录失败,11为登录成功
privateFriend[]_friend;
privateint_fn;
privatestring_fg;
publicstringNickname
{
get{return_nickname;}
set{_nickname=value;}
}
publicstringPassword
{
get{return_password;}
set{_password=value;}
}
publicstringAccounts
{
get{return_accounts;}
set{_accounts=value;}
}
publicstringEmail
{
get{return_email;}
set{_email=value;}
}
publicintInfo
{
get{return_info;}
set{_info=value;}
}
publicFriend[]Fri
{
get{return_friend;}
set{_friend=value;}
}
publicintFn
{
get{return_fn;}
set{_fn=value;}
}
publicstringFg
{
get{return_fg;}
set{_fg=value;}
}
}
由于MESSAGE.CS与UMESSAGE.CS类似,在此不再详述。
服务器和客户端都可以通过相同的代码对UMESSAGE赋值,再通过XmlSerializer方法进行将UMESSAGE序列化为XML文档,最后将XML文档转化为网络流进行传输。
代码如下:
#region将登录信息转为UMessage
privatevoidTraslator()
{
_message.Accounts=this.TextBox1.Text;
_message.Nickname="";
_message.Password=this.TextBox2.Text;
_message.Email="";
_message.Info=1;
_message.Fri=null;
}
#endregion
4.2数据结构FriendStruct:
服务器如果保存和传递用户的好友信息是难点之一。
数据库的设计和信息的传递辨别都是比较难实现的。
在数据库方面,每个用户拥有各自的好友分组信息(UserFav),分组中间使用“,”分隔,在TCP_FriendInfo表中则分别保存了用户ID和好友ID,使用一个INT字段保存分组信息。
数据库以用户ID为标准对好友ID和分组信息进行内连接查询,就可以得到基本的好友信息了。
在好友信息的传输方面,首先定义一个FriendStruct数据结构(当然也可以用枚举完成)如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceTCP
{
publicclassFriendStruct
{
publicstructFileInfo
{
publicintfilere;//接收和拒绝信息,1为接收,2为拒绝,3为取消
publicstringfilename;
publiclongfilelength;
}
}
publicstructFriend
{
publicstringaccount;
publicstringnickname;
publicstringIP;
publicstringstatus;
publicstringfg;//好友分组
}
}
在MESSAGE.CS或者UMESSAGE.CS中,我们则定义了FriendStruct的数组。
在C#中使用DATAREADER语句可以逐句读取数据库查询的结果,再依次将结果赋值FriendStruct数组元素,就得到了便于发送和读取的存放好友信息的数组。
赋值代码如下:
while(getf.Read())//getf即是以上的数据库查询的datareader语句
{
ff[i].account=getf["UserAccount"].ToString();
ff[i].IP=getf["UserIP"].ToString();
ff[i].nickname=getf["UserNickname"].ToString();
ff[i].status=getf["UserOnline"].ToString();
ff[i].fg=getf["FriendGroup"].ToString();
i++;
}
getf.Close();
4.3数据库连接类:
实现一个快捷简单的数据库连接的相关代码是非常有必要的。
实现的途径也多种多样,鉴于安全性和复杂性的需求不同,实现方法有简有繁。
本设计使用了一个简单的类(UserData.CS)实现了简单快捷的数据库连接和读取。
主要代码如下:
publicstaticSqlConnectionconnStr=newSqlConnection("Server=D96B85DD938A465.;uid=sa;pwd=change;database=TCPDB");
publicstaticSqlDataReaderSqlReader(stringsql,SqlConnectionconnstr)
{
SqlDataReadersqldr=null;
SqlCommandcmd=newSqlCommand(sql,connstr);
if(cmd.Connection.State.ToString()=="Closed")cmd.Connection.Open();
try
{
sqldr=cmd.ExecuteReader();
}
catch(Exceptione)
{
if(e!
=null)sqldr=null;
}
returnsqldr;
}
//数据库操作连接
publicstaticstringSqlCmd(stringsql,SqlConnectionconnstr)
{
stringerrorstr=null;
SqlCommandsqlcmd=newSqlCommand(sql,connstr);
if(sqlcmd.Connection.State.ToString()=="Open")sqlcmd.Connection.Close();
sqlcmd.Connection.Open();
try
{
sqlcmd.ExecuteNonQuery();
}
catch(Exceptione)
{
if(e!
=null)errorstr=e.ToString();
}
sqlcmd.Connection.Close();
returnerrorstr;
}
在UserData.CS的基础上,主程序可以更方便地实现数据库连接操作,对数据库进行读写和更新,在此不再详述。
4.4服务器端:
服务器端的界面设计是基于便于测试的目的而实现的。
如下图:
1.同步套接字网络监听
基于同步套接字的网络监听器对服务器来说并不是最好的解决方案,但是仍然可行并且实现简单。
主要代码如下:
开启监听端口:
publicvoidServe()
{
intport=8888;
ServerIPEP=newIPEndPoint(IPAddress.Any,port);
s=newSocket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);
s.Bind((EndPoint)ServerIPEP);
s.Listen(10);
alSock=newArrayList();
以下代码读取连入的连接,依次将连接加入可变长数组alsock,并且读取传入的信息,进行反串行化:
while(true)
{
try
{
uc=s.Accept();
alSock.Add(uc);
this.tb_states.AppendText(System.Convert.ToString(uc));
byte[]data=newbyte[2048];
intrect=uc.Receive(data);
byte[]chat=newbyte[rect];
Buffer.BlockCopy(data,0,chat,0,rect);
UMessageumessage=(UMessage)_translator.Deserialize(newMemoryStream(chat));
intinfo=umessage.Info;
对反串行化后的信息进行处理,通过info参数辨认客户端行为(注册或者登录),对注册的信息进行数据库查询,注册信息可插入,则将用户信息插入数据库,否则返回客户端“注册出错”的信息:
#region处理用户注册信息
if(info==0)//分辨出用户发送的是注册信息
{
stringAccounts=umessage.Accounts;
SqlDataReaderusdr=FPara.SqlReader("select*fromTCP_UserInfowhereUserAccount='"+Accounts+"'",FPara.connStr);
if(usdr!
=null)
{
if(usdr.Read())
{
#region此处写入返回注册失败的代码
Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];
sc.Send(chat);
#endregion
}
else
{
#region此处写入插入数据库用户注册信息的代码
Streamms=newMemoryStream();
Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];
if(FPara.SqlCmd("insertintoTCP_UserInfo(UserAccount,UserNickname,UserEmail,JoinDate,UserIP,UserPassword)values('"+umessage.Accounts+"','"+umessage.Nickname+"','"+umessage.Email+"','"+System.DateTime.Now.ToString()+"','"+((IPEndPoint)uc.RemoteEndPoint).Address.ToString()+"','"+umessage.Password+"')",FPara.connStr)==null)
{
umessage.Info=1;
_translator.Serialize(ms,umessage);
byte[]d=newbyte[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=newbyte[ms.Length];
ms.Seek(0,SeekOrigin.Begin);
ms.Read(d,0,d.Length);
sc.Send(d);
}
#endregion
}
usdr.Close();
}
}
#endregion
如果发现用户发送的是登录信息,就根据登录信息中的用户名和密码判断是否存在用户,密码是否正确,成功后再查询出用户的好友信息并且赋值给FriendStruct,再将信息返回给客户端:
#region处理用户登录信息
elseif(info
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- TCP 服务器 客户端 软件 word 文档 良心 出品