基于TCP协议的简单即时通信软件讲解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
嵌入式系统设计与开发运用论文
专业名称:电气自动化
学生姓名:宋熙
学号: 0914********
指导教师:何老师
基于TCP协议的简单即时通信软件的设计与实现
摘要
即时通信(Instant Message),由于其具有实时性、跨平台性、成本低、效率高等优点而受到广泛的使用。
设计并实现一个能够处理多用户进行实时、安全的即时通信系统具有较强的现实意义。
即时通信的底层通信是通过SOCKET套接字接口实现的。
当前的主流UNIX系统和微软的WINDOWS系统都在内核提供了对SOCKET字接口的支持。
使用这个统一的接口,可以编写一个可移植的TCP/IP通信程序。
使信息能够在INTERNET上可靠的传输。
关键词:即时通信;文件传输;套接字;TCP协议
2
1引言
1.1课题背景
即时通信是一个终端连往一个即时通信网路的服务。
即时通信不同于e-mail 在于它的交谈是实时的。
大部分的即时通信服务提供了presence awareness的特性──显示联络人名单,联络人是否在在线与能否与联络人交谈。
最早的即时通信软件是ICQ,ICQ是英文中I seek you的谐音,意思是我找你。
四名以色列青年于1996年7月成立Mirabilis公司,并在11月份发布了最初的ICQ 版本,在六个月内有85万用户注册使用。
在因特网上受欢迎的即时通信服务包含了MSN Messenger、AOL Instant Messenger、Yahoo! Messenger、NET Messenger Service、Jabber、ICQ与QQ。
这些服务有赖于许多想法更久的(与普遍)的在线聊天媒介,如Internet Relay Chat 一样知名。
1970年代早期,一种更早的即时通信形式是柏拉图系统(PLATO system)。
之后在1980年代,UNIX/Linux的交谈实时信息被广泛的使用于工程师与学术界,1990年代即时通信更跨越了因特网交流。
1996年11月,ICQ是首个广泛被非UNIX/Linux 使用者用于因特网的即时通信软件。
在ICQ的介绍之后,同时在许多地方有一定数量的即时通信方式发展,且各式的即时通信程序有独立的协议,无法彼此互通。
这引导使用者同时执行两个以上的即时通信软件,或者他们可以使用支持多协议的终端软件,如Gaim、Trillian或Jabber。
2相关技术介绍
开发平台及C#.NET开发语言
.NET框架是Microsoft公司推出的一种全新的开发平台,提供了统一的、面向对象并且可以扩展的编程类库和完善的集成开发环境,大大简化了应用程序的开发过程,并且具有良好的移植性和安全性。
微软为了推行.NET战略,特别为.NET平台设计了一种语言——C#。
C#是由C 和C++派生而来的一种“简单、流行、面向对象、类型安全”的程序设计语言,其综合了Visual basic的高效率和C++的强大功能,然而更多的人感觉C#更类似JAVA。
事实上C#融合了大量的JAVA思想,C#是.NET的关键性语言,它是整个.NET平台的基础。
与C#相比,.NET所支持的其它语言显然是配角,包括VC++.NET在内。
但是微软并没有打算放弃VC++.NET,相反,微软对VC++.NET有着另一番独特的打算,VC++.NET的定位与C#不完全重合,VC++.NET应用范围仍强于C#,这一点无论对微
第 3 页
软公司还是软件业应用现状都非常重要。
可见VC++.NET在NET框架中已经退化成了底层的语言了,就像C++之前的标准C语言一样,以后将只有开发底层或桌面程序的程序员使用它。
它虽然仍旧强大,但是已经不是主流,而主流就是C#语言。
2.2 TCP协议
2.2.1TCP/IP网络协议
协议是对等的网络实体之间通信的规则,可以简单地理解为网络上各计算机彼此交流的一种“语言”。
网络通信协议设计的基本原则是层次化,层和协议的集合被称为网络体系结构。
相邻层之间的接口定义了下层向上层提供的基本操作和服务,下层向上层提供的服务分两种形式:面向连接的服务和无连接的服务。
计算机网络中已经形成的网络体系结构主要有两个:OSI参考模型和TCP/IP参考模型。
TCP/IP参考模型是因特网(Internet)的基础。
和OSI的7层协议相比,TCP/IP协议只有4个层次。
通常说的TCP/IP是一组协议的总称,TCP/IP实际上是一个协议族,包括100多个相互关联的协议,其中IP(Internet Protocol, 网际协议)是网络层最主要的协议;TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议是传输层中最主要的协议),一般认为IP、TCP、UDP是最根本的三种协议,是其他协议的基础。
2.2.2TCP——传输控制协议
面向连接的通信可以使用可靠通信,在这时候,第四层协议发送数据接收方的确认,如果未收到数据或者数据被损坏,则请求重新传输。
TCP协议就使用这种可靠通信。
使用TCP协议的应用层协议包括HTTP、FTP、SMTP和Telnet等。
TCP要求在发送数据之前必须打开连接。
服务器应用程序必须执行一个称作被动打开(passive open)的操作,以利用一个已知的端口号创建一个链接,这是,服务器并不是对网络进行呼叫,而是侦听并等待引入的请求。
客户应用程序必须执行一个主动打开(active open),为此,它向服务器应用程序发送一个同步序列号(SYN)以标识连接。
客户应用程序可以将动态端口号作为本地端口使用。
服务器必须向客户发送一个确认(ACK)以及服务器的序列号(SYN)。
随后,客户回复一个ACK,这样就建立了链接。
现在可以发送和接收消息了。
接收消息后,总是返回ACK消息。
如果在收到ACK
第 4 页
之前发送方已经超时,则消息将被放到重发队列中以再次发送。
2.3套接字
套接字这个术语并没有定义某个协议:它具有两层含义,但两者都与一个协议相关。
第一个含义是套接字编程API,它最初由伯克利大学为BSD UNIX而创建。
BSD 套接字在经过修改后被用作Windows环境的编程接口(并且被命名为WinSock)。
WinSock API被包装在.sockets命名空间的.NET类中。
Windows Sockets 是一个独立于协议的编程接口,用于编写网络应用程序。
套接字的第二层含义表示一个用于在进程间进行通信的终端。
在TCP/IP中,每个终端都与一个IP地址和一个端口号绑定。
我们必须对流式套接字和数据报套接字这两种类型进行区分。
流失套接字用TCP/IP协议来使用面向连接的通信;另一方面,数据报套接字用UDP/IP来使用无连接通信。
2.4流
2.4.1流的基本概念
流的概念已经存在很长时间了。
流是一个用于传输数据的对象。
数据的传输有两个方向:
1)如果数据从外部源传输到程序中,这就是读取流。
2)如果数据从程序传输到外部源,这就是写入流。
外部源常常是一个文件,但也不完全都是文件,它还可以是:
1)网络,使用一定的网络协议与网络上其它计算机或终端交换数据。
2)一个指定的管道。
3)一块内存区域。
中的流
在这些情况中,微软提供了一个.NET基类System.IO.MemoryStream来读写内存数据使用workStream处理网络数据。
读写管道没有相应的流类,但有一个常见的流类System.IO.Stream,如果要编写一个这样的类,可以从这个基类继承。
流对外部数据源不做任何假定。
外部源还可以是代码中的一个变量,使用流在变量之间传输数据的技术是一个非常有用的技巧,可以在数据类型之间转换。
在网络编程中我们经常会使用到网络中的流对象:NetworkStream。
它实现了.NET中标准的Stream机制,即可以使用NetworkStream通讯网络套接字用标准
第 5 页
的流操作进行网络数据的读写。
它提供以下的功能:
1)一个统一的从网络中读取数据的方法
2)与其他的.NET流兼容,这样你可以很容易地移植程序。
2.5同步、异步、阻塞和非阻塞
同步(synchronous):所谓同步方式,就是发送方发送数据包以后,不等接受方响应,就接着发送下一个数据包。
异步(asynchronous):异步方式就是当发送方发送一个数据包以后,一直等到接受方响应后,才接着发送下一个数据包。
阻塞(Block):指执行此套接字的网络调用时,直到调用成功才返回,否则此套节字就一直阻塞在网络调用上,比如调用StreamReader 类的Readlin ( )方法读取网络缓冲区中的数据,如果调用的时候没有数据到达,那么此Readlin ( )方法将一直挂在调用上,直到读到一些数据,此函数调用才返回
非阻塞(Unblock):指在执行此套接字的网络调用时,不管是否执行成功,都立即返回。
同样调用StreamReader 类的Readlin ( )方法读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。
2.6C/S模型
客户机/服务器模型,又称为Client/Server模型,简称C/S架构。
C/S计算技术在信息产业当中占有重要的地位。
这种客户机/服务器模型是一种非对称式编程模式。
该模式的基本思想是把集中在一起的应用划分成为功能不同的两个部分,分别在不同的计算机上运行,通过它们之间的分工合作来实现一个完整的功能。
对于这种模式而言其中一部分需要作为服务器,用来响应并为客户提供固定的服务;另一部分则作为客户机程序用来向服务器提出请求或要求某种服务。
在此“服务器”是指能在网络上提供服务的任何程序。
服务器接受网络上的请求,完成服务后将结果返回给申请者。
对于简单的服务,把每个请求用一个IP数据报发给服务器,服务器用另一个数据报返回响应。
客户机和服务器都是独立的计算机。
当一台连入网络的计算机向其他计算机提供各种网络服务(如数据、文件的共享等)时,它就被叫做服务器。
而那些用于访问服务器资料的计算机则被叫做客户机。
严格说来,客户机/服务器模型并不是从物理分布的角度来定义,它所体现的是一种网络数据访问的实现方式。
采用这种结构的系统目前应用非常广泛。
如宾馆、酒店的客房登记、结算系统,超市的POS系统,银行、邮电的网络系统等。
第 6 页
各种网络服务器基本都遵循同样的算法:创建一个端口(Port),接受从网络上来的客户服务请求,完成计算后把结果返回给客户,如此反复。
2.7即时通信协议
协议是一系列的步骤,它包括双方或者多方,设计它的目的是要完成一项任务。
即时通信协议,参与的双方或者多方是即时通信的实体。
协议必须是双方或者多方参与的,一方单独完成的就不算协议。
这样在协议动作的过程中,双方必须交换信息,包括控制信息、状态信息等等。
这些信息的格式必须是协议参与方同意并且遵循的。
好的协议要求清楚,完整,每一步都必须有明确的定义,并且不会引起误解;对每种可能的情况必须规定具体的动作。
有许多的 IM 系统,如 AOL IM、Yahoo IM 和 MSN IM,它们使用了不同的技术,而且它们互不兼容。
为了创建即时通信的统一标准,人们经过了多次尝试:IETF 的对话初始协议(SIP)和即时通信对话初始协议和表示扩展协议(SIMPLE)、应用交换协议(APEX)、显示和即时通信协议(PRIM)及基于 XML 且开放的可扩展通信和表示协议(XMPP)协议(常称为 Jabber 协议)。
人们多次努力,试图统一各大主要IM 供应商的标准(AOL、Yahoo 及 Microsoft),但无一成功,且每一种 IM 仍然继续使用自己所拥有的协议。
本系统目的在于实现一个简单的即时通信过程,没有必要采用通用的比较复杂的即时通信协议,因此使用了简单定义的XML标记定义来规范即时通信的各种网络信息,在网络中传输序列化的XML语言。
3系统总体设计
3.1需求分析
软件针对局域网内部用户,实现用户间的即时通信。
需要分别实现服务器端和客户端的软件设计。
服务器端负责监听用户连接请求,负责连接数据库存储用户信息,负责发送给用户好友信息,负责发送心跳报文检查用户在线状态并即时让用户更新好友在新信息。
3.2系统基本架构
基于C/S架构的即时通信软件便于对用户信息进行统一管理和保存,面向特定的用户,对信息的安全控制能力很强。
为了减轻服务器负担,客户端之间的信息传递是采用P2P模式的,服务器只负责用户的注册,登录和用户在线状态的检验。
基本结构如图:
第 7 页
第 8 页 CLIENT CLIENT
注册和登录信息
SERVER 返回信息注册和登录信息
返回信息
聊天信息,文件传输图1 系统基本架构
3.3 功能模块设计
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,下线时间等信息记录入数据库
第 9 页
第 10 页 3.4 逻辑图 注册
登录
注册回应
在线情况CLIENT SERVER
用户信
息管理
密码修改
信息修改
取得好友
列表
修改回应HASH 加密注册成功
登录回应
好友列表
发送
上线信息发送
注册信
息检查注册失败
Y N 心跳
测试N 离线文件传输消息加密
消息解密即时聊天
在线情况记录
Y
图2 逻辑图 3.5 数据库设计
3.5.1 实体关系图
服务器是作为记录和读取数据库信息的载体,与客户端关系并不复杂,这里需
要重点考虑客户端之间的关系。
用户与用户之间的关系是较为特殊的递归关系,即描述发生在两个相同实体上的关系。
E-R 图如下:
图3 E-R 图
3.5.2 详细列表
数据库包含两个表,分别为记录用户信息的TCP_Userinfo 和记录用户好友信息的TCP_Friendinfo 。
详细设计见下面两表:
表1 用户信息表TCP_UserInfo
TCP_Userinfo 列(属性)名 类型 主键 宽度 是否允许为空 备注
UserID numeric Y 9 NOT NULL 自增长 UserAccount nchar N 20 NOT NULL 用户帐号 UserNickname nchar N 20 NOT NULL 用户昵称,可重复
UserEmail nchar N 20 NOT NULL 用户EMAIL JoinDate nchar N 35 NOT NULL 注册日期 LastLogin nchar Y 20 NOT NULL 最后登录IP UserIP nchar Y 20 NOT NULL 用户IP
UserFav varchar N 100 NOT NULL 用户好友分组,有默认值
UserQuestion nchar Y 20 NOT NULL 密码问题 UserAnswer nchar Y 20 NOT NULL 密码答案 UserPassword nchar N 20 NOT NULL 用户密码
UserOnline
int
N
4 NOT NULL
在线状态,1在,0不在
表2 用户好友表TCP_FriendInfo
TCP_Userinfo 列(属性)名 类型 主键 宽度 是否允许为空 备注
InfoID numeric Y 9 NOT NULL 自增长 UserID nchar N 20 NOT NULL 用户ID FriendID nchar N 20 NOT NULL 用户好友ID FriendGroup
nchar
N
20 NOT NULL
用户好友分组
聊天 文件
n
n
用户ID
好友ID
状态
IP
客户端
账号
昵称
Email
ID
密码
好友分组
状态
客户端
账号
昵称
Email
ID
密码
好友分组
IP
4 系统实现
4.1 使用XML 定义的即时通信协议
4.1.1 信息结构MESSAGE.CS&UMESSAGE.CS
这两个C#类定义了包括服务器信息,状态信息,注册信息,登录信息,聊天信息或者请求文件传输信息的函数,服务器和客户端通过将它们实例化和序列化再转换成流在网络上进行传输。
4.1.2 数据结构FriendStruct
服务器如果保存和传递用户的好友信息是难点之一。
数据库的设计和信息的传递辨别都是比较难实现的。
在数据库方面,每个用户拥有各自的好友分组信息(UserFav ),分组中间使用“,”分隔,在TCP_FriendInfo 表中则分别保存了用户ID 和好友ID ,使用一个INT 字段保存分组信息。
数据库以用户ID 为标准对好友ID 和分组信息进行内连接查询,就可以得到基本的好友信息了。
4.2 数据库连接类
实现一个快捷简单的数据库连接的相关代码是非常有必要的。
实现的途径也多种多样,鉴于安全性和复杂性的需求不同,实现方法有简有繁。
本设计使用了一个简单的类(UserData.CS )实现了简单快捷的数据库连接和读取。
4.3 服务器端
服务器端的界面设计是基于便于测试的目的而实现的。
如下图:
图4 服务器端界面
4.3.1 同步套接字网络监听
基于同步套接字的网络监听器对服务器来说并不是最好的解决方案,但是仍然可行并且实现简单。
这里显示已连入的连接
这里显示传入的原始
信息
如果发现用户发送的是登录信息,就根据登录信息中的用户名和密码判断是否存在用户,密码是否正确,成功后再查询出用户的好友信息并且赋值给FriendStruct,再将信息返回给客户端:
4.3.2多线程
对于服务器来说,多线程是必不可少的,否则它将无法处理不断请求的新连
接。
C#的System.Threading提供了多线程编程的支持。
本设计实现代码如下: this.th = new Thread(new ThreadStart(Serve));//新建一个用于监听的线程
th.Start();//打开新线程
不仅仅是服务器,基于P2P模式聊天的客户端也必须支持多线程运行,实现代码与之类似,在客户端设计说明中将不再叙述。
4.3.3计时器
计时器用于实现心跳报文的功能,服务器在启动以后就开始计时,每隔一定时
间就向所有连入的客户端发送信息,核心代码如下:
//用计时器检查客户端是否掉线
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(CheckStatus);
// 设置引发时间的时间间隔此处设置为5秒(5000毫秒)
aTimer.Interval = 5000;
aTimer.Enabled = true;
CheckStatus就是用于向客户端发送检查信息的方法,它会向遍历连入的客户端(alSock),然后依次向客户端发送信息,如果发现客户端没有响应,就会如果发现对方无回应,则关闭相应的SOCKET,并更新数据库的用户在线状态,同时向该用户的所有好友发送用户已下线的通知。
4.4 客户端
图5 注册界面
图6 登录、聊天、文件传输界面
4.4.1 同步套接字客户端
客户端发起同步套接字连接,并传送登录或者注册信息,由于两者方式类似,这里仅列出用户登录的代码:
#region 发送服务器登录信息,并接收服务器反馈信息 public void Client()
{
建立SOCKET 发送信息:
try {
IPEndPoint ServerIPEP = new
IPEndPoint(IPAddress.Parse("222.18.170.16"),8888);
好友详细信息列表
聊天信息
c = new
Socket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);
c.Connect((EndPoint)ServerIPEP);
s = new MemoryStream();
_translator.Serialize(s,_message);
byte[] d=new byte[s.Length];
s.Seek(0, SeekOrigin.Begin);
s.Read(d, 0, d.Length);
int i = c.Send(d, 0, d.Length, SocketFlags.None);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
以下代码读取了服务器返回给客户端的信息(注册和登录的成功与失败),如果
返回了登录成功的信息,还会读取服务器给出的FriendStruct结构以得到用户的好
友信息:
#region 接收反馈信息
byte[] data = new byte[2048];
while(true)
{
int rect = c.Receive(data);
byte[] chat = new byte[rect];
Buffer.BlockCopy(data,0,chat,0,rect);
UMessage bumessage = (UMessage)_translator.Deserialize(new MemoryStream(chat));
string[] fg;
string _fg=bumessage.Fg;
if(==3)
{
}
else if(==11)
{
fg=_fg.Split(',');
int xxx=bumessage.Fn;
ff=bumessage.Fri;
for(int i=0;i<xxx;i++)
{
string[] ems=new string[5];
ems[0]=ff[i].account;
ems[1]=ff[i].nickname;
ems[2]=fg[int.Parse(ff[i].fg)];
ems[3]=ff[i].IP;
ems[4]=ff[i].status;
ListViewItem item = new ListViewItem(ems);
this.listView1.Items.Add(item);
}
CSERVER是一个用于开启监听P2P信息的方法,客户端在登录成功以后就会立
刻开启监听器,才能够实现与其它客户端的聊天:
th = new Thread(new ThreadStart(CServer));//新建一个用于监听其它客户端信息的线程
th.Start();//打开新线程
MessageBox.Show(bumessage.Accounts+"登录成功!");
this.Button1.Enabled=false;
this.Button3.Enabled=false;
}
else if (==2)
{
MessageBox.Show("服务器未知错误");
}
else
{MessageBox.Show(.ToString());}
}
#endregion
}
#endregion
图7 登录成功后的客户端界面
客户端之间的聊天同样使用了序列化的XML文档,用户在登录成功后就会启动一个新的监听器去监听其它客户端传入的聊天信息并且进行判断再将其它用户的聊天信息显示在界面上。
这里也不再阐述代码。
4.4.2采用异步套接字的文件传输
文件传输是通过一个类库实现的。
由于文件传输的代码实现复杂,通过类库可以大量的简化代码,使主程序简洁易懂。
类库working包括了ClientBase.cs,ClientInfo.cs,Delegates.cs,INPClient.cs,INPServer.cs,ClientBase.cs定义了基础的文件发送函数,INPClient.cs则仅包含初始化文件发送的函数;ServerBase.cs和INPServer.cs则是反之亦然。
结论
即时通信是是网络发展的必然趋势,它的技术仍然在不断的改进和蓬勃发展中。
本次设计虽然实现了简单的即时通信功能,但是从很多方面来说都是不完善的:实现了字符聊天却没有实现多媒体即时通信;实现了同步套接字聊天和异步套接字传送文件却没有实现更科学的异步套接字聊天和同步套接字传送文件。
在本次设计中,我深刻体会到SOCKET编程的基础性,多样化。
由于与网络紧密联系,SOCKET编程的也可能出现各种未知的问题,需要我们更深入地了解网络协议和架构,才可能做出通用性高,稳定性高的即时通信程序。
参考文献
[1] Tobin. Titus, Fabio Claudio Ferracchiati. C#线程参考手册[M].王敏译.北京:清华大学出版社,2003。
[2] 黄承安,谢东文,许聪. C#网络应用案例导航[M].北京:中国铁道出版社,2003。
[3] Andrew Krowczyk, vinod Kumar. .NET网络高级编程[M].北京:清华大学出版社,2003。
[4] 周存杰. Visual C# .NET网络核心编程[M].北京:清华大学出版社,2002。
[5] 方睿,吴四九,刁仁宏. 网络数据库原理及应用[M].四川:四川大学出版社,2005。
[6] 李文志,申剑,卢方国,柳正青,王宏,陈建伟. 在.NET框架下开发一个即时通信系统[J].现代计算机.2004(2):68-72。
[7] 王跃. INTERNET上大规模用户即时通信方法研究[D].北京:北京工业大学[硕士论文],2004。