您好,欢迎来到华佗健康网。
搜索
您的当前位置:首页即时通讯软件的设计与实现

即时通讯软件的设计与实现

来源:华佗健康网
课 程 设 计 报 告

学 院:专业名称:课程名称:课程代码:所在班级:学 号: 姓 名: 课题名称:任课教师:完成时间:

天津理工大学华信软件学院

软件工程 专业设计

即时通讯系统

2013年3月-2013年6月

即时通讯软件的设计与实现

摘要

随着互联网技术的不断发展和更新,互联网上人与人之间的消息传递方式从E-Mail到聊天室又到及时通讯软件。如今即时通讯软件的技术已经非常成熟,强大的功能和丰富的交流方式使其成为了人们最常使用的软件之一。系统使用Silverlight实现B/S与C/S结合的模式,体现了B/S结构方便用户访问的特性的同时也兼顾了C/S结构的强大功能。本文简述实现系统时使用的Windows Communication Foundation的主要概念,以及即时通讯软件的设计与实现过程,包括服务器协议的制定,客户端间通信协议的指定,客户端主要功能的实现以及部分网站的设计。最终目的是在已经成熟的即时通讯技术上有所突破和创新。

关键词:即时通讯,微软银光,Windows通讯框架。

Development and Implementation of Instant

Messaging System

Abstract

With the continuous development of Internet technology and update, the Internet between the person and person's message from E-Mail to chat and instant messaging software. Now IM software technology has been very mature, powerful and rich communication make it become one of the most commonly used software. The system uses Silverlight to realize the combination of B/S and C/S mode, embodies the characteristics of B/S structure is convenient for the user to access while also taking into account the powerful functions of C/S structure. The main concepts in this paper when the system is realized using Windows Communication Foundation, the process of design and implementation of instant messaging software, including server protocol development, specify the client communication protocol, design the main function of the realization of client and website. The ultimate aim is to make a breakthrough in the instant communication technology has been mature and innovation.

Key Words: Silverlight; Instant Messaging; Windows Communication Foundation.

目 录

引 言 ··················································································· 1 第一章 主要技术介绍 ································································· 2

1.1 WCF-Windows Communication Foundation ····································· 2 1.2 MVC ················································································ 2 1.3 Silverlight ····································································· 3 第二章 系统概述 ········································································ 4

1.1 系统开发背景和意义 ···························································· 4 1.2 开发环境 ········································································· 4 第三章 系统需求分析 ·································································· 5

2.1 任务概述 ········································································· 5 2.2 功能需求 ········································································· 6 2.3 性能需求 ········································································· 7 第四章 系统总体设计 ·································································· 8

3.1 系统总体流程 ···································································· 8 3.2 系统功能模块图 ······························································· 10 第五章 详细设计 ······································································ 11

4.1 程序流程图 ····································································· 11 4.2 程序详细流程图描述 ·························································· 12 4.3 主要功能描述 ·································································· 13 4.4 程序接口描述 ·································································· 15

4.4.1 服务器端服务接口 ···················································· 15 4.4.2 客户端内部接口 ······················································· 15 4.5 数据设计 ······································································· 16

4.5.1 数据的逻辑设计 ······················································· 16

第六章 测试分析报告 ································································ 18

6.1 测试计划和要点 ······························································· 18

6.1.1 主模块测试要点 ······················································· 18 6.1.2 登陆模块测试要点 ···················································· 18 6.1.3 聊天服务模块测试要点 ··············································· 18 6.1.4 文件服务模块测试要点 ··············································· 19 6.1.5 音频服务模块测试要点 ··············································· 19

6.2 测试用例 ······································································· 20

6.2.1 主模块测试用例 ······················································· 20 6.2.2 登陆模块测试用例 ···················································· 21 6.2.3 聊天服务模块测试用例 ··············································· 21 6.2.4文件服务模块测试用例 ················································ 22 6.2.5 音频服务模块测试用例 ··············································· 22 6.3 测试结果 ······································································· 23

6.3.1 测试的结果 ···························································· 23

第七章 总结 ············································································ 25 参考文献 ················································································· 26 附录 ······················································································· 27

天津理工大学2011届本科课程设计说明书(课程论文)

引 言

互联网的告诉发展不断影响着人们的生活方式,他在提供人们快速便捷的体验的同时,慢慢渗透到我们生活中的每一个角落。这其中,互联网人际交往也成为现代社会人际交往的一种时尚、便捷、多元化的方式。IM作为其工具,也变得流行起来。 从1996年世界上第一款IM软件ICQ的推出,到2005至2007年的迅速发展,电子商务运营商、综合门户网站、电信运营商都纷纷围绕各自核心业务,推出各具特点的IM即时通信工具。如今,即时通信产品功能已经从比较单一的文字聊天、好友查找、好友管理,在向集社会化网络、资讯、娱乐、位置服务、搜索、电子商务、办公协作和企业客户服务等为一体的综合化信息平台发展。

1

天津理工大学2011届本科课程设计说明书(课程论文)

第一章 主要技术介绍

1.1 WCF-Windows Communication Foundation

Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口。它是.NET框架的一部分,由 .NET Framework3.0 开始引入,与Windows Presentation Foundation及Windows Workflow Foundation并行为新一代 Windows操作系统以及 WinFX 的三个重大应用程序开发类库。在 .NET Framework2.0 以及前版本中,微软发展了 Web Service (SOAP with HTTP communication),.NET Remoting (TCP/HTTP/Pipeline communication) 以及基础的 Winsock 等通信支持。由于各个通信方法的设计方法不同,而且彼此之间也有相互的重叠性(例如 .NET Remoting 可以开发 SOAP, HTTP 通信),对于开发人员来说,不同的选择会有不同的程序设计模型,而且必须要重新学习,让开发人员在使用中有许多不便。同时,面向服务架构(Service-Oriented Architecture) 也开始盛行于软件工业中,因此微软重新查看了这些通信方法,并设计了一个统一的程序开发模型,对于数据通信提供了最基本最有弹性的支持,这就是 Windows Communication Foundation。

1.2 MVC

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

2

天津理工大学2011届本科课程设计说明书(课程论文)

1.3 Silverlight

Microsoft Silverlight是一个跨浏览器的、跨平台的插件,为网络带来下一代基于NET Framework的媒体体验和丰富的交互式应用程序。Silverlight提供灵活的编程模型,并可以很方便地集成到现有的网络应用程序中。Silverlight可以对运行在Mac或Windows上的主流浏览器提供高质量视频信息的快速、低成本的传递。Microsoft Silverlight的中文名为“微软银光”,是一种新的Web呈现技术,能在各种平台上运行。借助该技术,您将拥有内容丰富、视觉效果绚丽的交互式体验,而且,无论是在浏览器内、还是在桌面操作系统(如Windows和Apple Macintosh)中,您都可以获得这种一致的体验。Microsoft .NET Framework3.0(Windows 编程基础结构)中的呈现技术XAML(可扩展应用程序标记语言)遵循WPF(Windows Presentation Foundation),它是Silverlight呈现功能的基础。

3

天津理工大学2011届本科课程设计说明书(课程论文)

第二章 系统概述

1.1 系统开发背景和意义

内部通讯是每一个组织机构必须切实面对的工作,但一直以来人们使用传统的方式进行信息交换。例如传真和内部电话。这些方式存在着许多缺点,如效率低、保密性差且较为繁琐。

随着网络技术的不断发展和普及,这种传统的通信方法必然被以计算机网络为基础的方法所取代。即时通讯系统作为网络应用的一个分支,有着传统通讯方法无法比拟的优点,如易于管理,可靠性高,部署简单等。

因此,开发一套能够为企业机构提供内部资源信息交换的系统,是十分必要的。 国内外的企业级内部通讯软件平台技术都已经非常成熟,集成了电话会议,视频会议,邮件系统,提供二次开发和与其他系统(例如OA)的集成。典型的项目例如微软的Lync,腾讯的RTX等。

1.2 开发环境

开发环境的选择会影响到数据库的设计,所以在这里给出图书管理系统开发与运行环境的选择如下:

开发环境:Windows 8.1 开发工具:VisualStudio 2013

数据库管理系统: SQL Server 2012 Express 数据库服务器: SQL Server 2012 Express

4

天津理工大学2011届本科课程设计说明书(课程论文)

第三章 系统需求分析

2.1 任务概述

经过对同类软件的研究,发现同类软件之间的基本原理相差不大。主要实现一对一聊天,一对多聊天,广播通知,文件互发,语音聊天等。基于TCP/IP协议实现。为了减少服务器的负载,客户端也同时集成了服务器的功能,使基本的聊天信息不在经过主服务器发送,而是由客户端之间进行配对发送。

新用户首先对主服务器进行http请求,服务器返回登陆界面,新用户进行注册并下载客户端程序后便可正常使用客户端进行聊天。

根据以上调查分析,整个系统的构成如图2.1所示。

图2.1 系统概念构成图

Fig. 2.1 Structure diagram of system concept

5

天津理工大学2011届本科课程设计说明书(课程论文)

2.2 功能需求

经过以上详细的用户调查,在现行业务流程和数据分析的基础上,基本可以确定系统设计必须达到的目标。

以下是即时通讯系统必须具备的功能:

1.后台客户端:处理与网络相关的信息。包括获取当前可用网络的ip,当前网络是否可以连接到服务器,自动绑定至可连接的ip等功能。由于SilverLight功能的局限性,不得不考虑将客户端分为两部分。一部分专门为用户提供应用程序的可视化接口服务,一部分处理网络通信。

2.网站与服务器:网站提供用户的注册和登陆。用户可通过页面内置的SilverLight客户端来使用聊天服务,也可以下载SilverLight客户端到本地来使用。下载到本地的SilverLight客户端使用服务器进行登陆,

3.前台客户端模块:向服务器发送登录信息,发送注册信息,呈现用户界面,提供基本服务,向后台客户端提供数据。

4.主要功能模块:主要功能模块分为3个子模块,分别为文字聊天模块,图片/文件传输模块,音频聊天模块。每个模块使用单独的信道通信,并适当使用多线程技术提高并发处理能力。

5.异常处理模块:前后台客户端都应设有异常处理模块。当信道出现异常时尝试自动重置信道以排除异常并重新连接至目标终结点,提高程序的健壮性。

6

天津理工大学2011届本科课程设计说明书(课程论文)

2.3性能需求

为了保证系统能够长期、安全、稳定、可靠、高效的运行,即时通讯系统应该满足以下的性能需求:

1、系统处理的准确性和及时性

系统处理的准确性和及时性是衡量系统性能的重要指标。在系统设计和开发过程中,要充分考虑系统当前和将来可能承受的工作量,使系统的处理能力和响应时间能够满足企业对信息传送的需要的同时,尽可能的迅速和准确。

2、系统的开放性和系统的可扩充性

即时通讯系统在开发过程中,必须充分考虑以后的可扩充性。例如用户对数据传送的需求会不断的更新和发展,系统必须尽可能的满足这些需求并且只花费较少的时间和金钱。这就要求系统提供足够的手段进行功能的调整和扩充。而要实现这一点,应通过系统的开放性来完成,既系统应是一个开放系统,只要符合一定的规范,可以简单的加入和减少系统的模块,配置系统的硬件。通过软件的修补、替换完成系统的升级和更新换代。

3、系统的易用性和易维护性

即时通讯系统是直接面对使用人员的,而使用人员往往对计算机并不时非常熟悉。这就要求该系统必须有较为完善的用户帮助信息和友好的系统界面,帮助用户尽快熟悉系统的使用方法,缩短磨合时间。

4、系统的先进性

现代计算机通讯技术发展极为迅速,如果想要该系统尽可能的延长生命周期,必须在开发时使用相对较新的技术。同时系统必须具有足够的开放性和良好的耦合度,通过快速和廉价的升级方案,防止系统过快淘汰。

5、系统的响应速度

即时通讯系统在日常处理中的响应速度为秒级,达到实时要求,以及时反馈信息。在进行数据传输时,根据所需数据量的不同而从秒级到分钟级,原则是保证操作人员不会因为速度问题而影响工作效率。

7

天津理工大学2011届本科课程设计说明书(课程论文)

第四章 系统总体设计

3.1 系统总体流程

根据需求分析得到的性能和功能要求,得出系统的大致工作流程。程序开始运行后,首先进行用户的登陆验证。之后初始化系统的各项功能所依赖的对象,之后等待用户进行输入,根据输入的信息进行相应的处理,例如发送文字聊天信息,图片,文件和发起音频会议。用户使用完毕之后,关闭程序之前进行登出操作。之后关闭程序。

图3.1 即时通讯系统总体流程图

Fig. 3.1 The overall flow chart of instant messaging system

针对这个总体上的业务流程,必须要进行一些合理的改进以适应实际情况。例如初始化失败;连接后台客户端失败;无法连接到登陆服务器等实际情况,必须采取相应的措施排除错误和异常。实际使用过程中可能遇到的问题及改进措施如下:

网络连接类错误:错误发生后尝试重新连接,在尝试一定次数仍失败后提示用户。 用户输入类错误:提示用户重新输入正确的信息。

机会错误和未知错误:提示用户后关闭程序,暂时不进行处理。

8

天津理工大学2011届本科课程设计说明书(课程论文)

9

天津理工大学2011届本科课程设计说明书(课程论文)

3.2 系统功能模块图

根据需求分析阶段得到的功能需求,以及对系统对性能的需求以及系统特点,得出系统的功能模块图如下:

图3.2 即时通讯系统功能模块图

Fig. 3.2 Function models diagram of instant messaging System

10

天津理工大学2011届本科课程设计说明书(课程论文)

第五章 详细设计

4.1 程序流程图

依据软件工程的基本原理,详细设计阶段的根本任务是确定应该怎样具体实现所要求的系统,也就是说,经过这个阶段的设计工作,应该得出对目标系统的精确描述,从而在系统实现阶段可以把这个描述直接翻译成用某种程序设计语言书写的程序。具体来说就是把经过总体设计得到的各个模块详细的加以描述。

根据总体设计中对总体流程图提出的改进要求,画出详细流程图如下图4.2所示。

图4.1 程序详细流程图 Fig. 4.1 Detailed program flowchart

11

天津理工大学2011届本科课程设计说明书(课程论文)

4.2 程序详细流程图描述

程序开始运行后,首先尝试与后台客户端进行连接。如果连接失败则进行重试,如果连接成功则后台客户端进行初始化,之后返回监听地址到SL客户端以便进行用户登录。验证用户登录,如果失败则提示失败,重新获取必要信息后重新验证。如果登陆成功则向服务器获取登陆用户的好友列表。服务器返回列表之后SL客户端进行用户界面的初始化并等待用户进行操作。关闭客户端时自动向服务器发送离线信息。

12

天津理工大学2011届本科课程设计说明书(课程论文)

4.3 主要功能描述

系统主要功能有客户端与服务器之间的连接,客户端与客户端之间的连接,发送不同种类的数据。发送数据的方式有两种,分为缓冲模式和流模式。分别对应简短数据和大型数据。

用户登陆登出功能时序图:

图4.2 登陆登出时序图

Fig. 4.2 Sequence diagram of Login/Logout

用户登陆登出采用BasicHttpBinding缓冲模式发送和接收数据。用户在登录时需要提供用户名和密码,以及一个代表自身网络地址的终结点Uri。服务器接收登陆请求后验证用户名密码是否正确并异步送回验证结果。登陆成功后服务器记录登陆者的Uri并设置登陆状态。

发送消息功能时序图

图4.3 发送消息功能时序图

Fig.4.3 Sequence diagram of sending message

图4.3表示的是一个发送过程。此过程在本系统中是通用的,换句话说,此过程使用在一些实现相似功能的模块中 。发送过程开始前需要进行普通服务客户端的初始化。在此我们认为初始化过程已经完成并且连接正常。之后需要构建一个Communication Data以表示需要

13

天津理工大学2011届本科课程设计说明书(课程论文)

发送的数据。客户端接收到请求后,会构建一个CommunicationRequest,其中包含一个CommunicationInformation并携带一个消息目的地的Uri,然后它会通知主服务客户端发送此Request到目标地址并等待此请求返回。请求返回的结果同样是一个

CommunicationRequest。不同的是其中的PingPongCount会加1,普通服务客户端会检测这个值,如果此值小于2就继续发送一个CommunicationRequest并且PingPongCount加1。返回的Request还携带了一个ReplyAddress。这个地址表明了普通服务客户端需要的目的地址。有了这个地址,普通服务客户端就可以和远程的相应主机进行通信了。

接收消息功能时序图:

图4.4 接收消息功能时序图

Fig.4.4 Sequence diagram of receiving message

图4.4表示的是一个通用接收过程。在主服务主机接收到Communication Request之后检测普通服务主机是否存在,若不存在则会新建。之后检测Request中的PingPongCount并回发携带ReplyAddress的Request。

通过使用和重复使用以上三个功能,我们可以构建一个功能强大的客户端。

14

天津理工大学2011届本科课程设计说明书(课程论文)

4.4 程序接口描述

4.4.1 服务器端服务接口

共三个接口,分为登陆服务接口,好友列表获取接口,登出接口。分别提供登陆, 获取好友列表,登出功能。

图4.5 接口原型

Fig.4.5 Prototype of service interface

具体实现详见附录第一部分。

4.4.2 客户端内部接口

客户端模块间接口采用数据耦合方式,通过参数表传送数据,交换信息。

15

天津理工大学2011届本科课程设计说明书(课程论文)

4.5 数据设计

4.5.1 数据的逻辑设计

根据在需求分析和系统设计阶段得到的功能需求和系统流程,分析出系统所需要使用的数据结构。以下是三个最主要的数据的结构MessageBody,CommunicationInformation和CommunicationData。

图4.6 MessageBody类结构图 Fig.4.6 Class diagram of MessageBody

16

天津理工大学2011届本科课程设计说明书(课程论文)

图4.7 CommunicationInformation类结构图 Fig.4.7 Class diagram of CommunicationInformation

图4.8 CommunicationData类结构图 Fig.4.8 Class diagram of CommunicationData

17

天津理工大学2011届本科课程设计说明书(课程论文)

第六章 测试分析报告

有两种基本方法可以用来标识测试用例,即功能测试(黑盒测试)和结构测试(白盒测试)。本次测试我主要采用了功能测试。

功能测试的基本观点是,任何程序都可以看作是将输入定义域取值映射到输出值域的函数。

6.1 测试计划和要点

软件测试的本质是针对要测试的内容确定一组测试用例。在讨论之前,我先把要测试各个模块的计划和要点列出:

6.1.1 主模块测试要点

服务器连接情况:正常情况,数据库文件缺少,外部系统异常。 系统设置获取:正常情况,外部系统异常。

对用户输入的响应:合法输入,能够正常调用子模块;

非法输入,系统能否辨别,并作出响应(提出警告); 子模块的异常状况,系统能否及时做出响应。

6.1.2 登陆模块测试要点

模块正常运行流程

用户输入数据检查(用户名,密码),包括数据合理性检查,以及合法性检查 网络连接异常时的响应情况

6.1.3 聊天服务模块测试要点

连接异常 发送信息失败 初始化出错 未知错误

18

天津理工大学2011届本科课程设计说明书(课程论文)

6.1.4 文件服务模块测试要点

连接异常 发送信息失败 初始化出错 未知错误

6.1.5 音频服务模块测试要点

连接异常

发送信息失败 初始化错误

19

天津理工大学2011届本科课程设计说明书(课程论文)

6.2 测试用例

测试用例是为了特定目的(如考察特定程序路径或验证是否符合特定的需求)而设计的测试数据及与之相关的测试规程的一个特定的集合,或称为有效地发现软件缺陷的最小测试执行单元。

根据上一节给出的测试要点,又因为测试是不可能穷举的。所以我们采用等价划分法来进行对图书管理系统的测试。它将不能穷举的测试过程进行合理分类,从而保证设计出来的测试用例具有代表性和完整性。

6.2.1 主模块测试用例

表6.1 主模块测试用例 Table 6.1 Main service test case

字段名称 标识符 测试项 输入标准 C1 主模块的初始化与关闭 1.打开主模块 2.退出程序 描 述 1.模块未做任何操作,单击退出按钮,能正常退出,无提示信息。 输出标准 2.打开任意子窗体,单机退出按钮,能正常退出,无任何错误。 3.在打开相应的子窗体时,发送任意信息之后关闭程序,无任何错误

20

天津理工大学2011届本科课程设计说明书(课程论文)

6.2.2 登陆模块测试用例

表6.2 登陆模块测试用例 Table 6.2 Login model test case

字段名称 标识符 测试项 输入标准 C2 登陆模块的功能测试 1.打开程序,进入登陆界面 2.输入正确的用户名和密码。 描 述 3.输入不正确的用户名和密码。 输出标准 输入正确的用户名密码后登陆成功进入下一界面。输入错误用户名密码后登陆提示登陆错误。点击退出按钮后正常退出。

6.2.3 聊天服务模块测试用例

表6.3 聊天服务模块测试用例 Table 6.3 Normal service test case

字段名称 标识符 测试项 C3 聊天服务模块的功能测试 1打开程序,进入聊天窗口 输入标准 描 述 2.输入一些聊天文字,选择字体,颜色,大小等。 3.选择一副图片进行发送。 4.点击发送。 模块未做任何操作,单击退出按钮,能正常退出,无提示信息。 输出标准

21

天津理工大学2011届本科课程设计说明书(课程论文)

6.2.4文件服务模块测试用例

表6.4 文件服务模块测试用例 Table 6.4 File service test case

字段名称 标识符 测试项 输入标准 输出标准 C4 文件服务模块的功能测试 1.打开程序,进入聊天窗口 描 述 2.单击文件发送按钮,选择文件进行发送。点击确定。 3.单击文件发送按钮,选择文件,点击取消。 模块未做任何操作,单击 “退出”命令,能正常退出,无提示信息。

6.2.5 音频服务模块测试用例

表6.5 音频服务模块测试用例 Table 6.5 Audio service test case

字段名称 标识符 测试项 输入标准 输出标准 C5 音频服务模块的功能测试 1.打开程序,进入聊天窗口 2.点击音频服务按钮。 描 述 模块未做任何操作,单击 “退出”命令,能正常退出,无提示信息。

22

天津理工大学2011届本科课程设计说明书(课程论文)

6.3 测试结果

6.3.1 测试的结果

我们按照6.2节中给出的测试用例的顺序来给出相应的测试结果。

表6.6 主模块测试结果 Table 6.6 Main service test result

标识符 测试结果 说明的问题 C1 正常操作无任何异常出现 主模块通过了功能测试

表6.7 登陆模块测试结果 Table 6.7 Login model test result

与预期的偏差 无 标识符 测试结果 说明的问题 C2 正常操作无任何异常处理出现 登陆模块通过了功能测试

表6.88 聊天服务模块测试结果 Table 6.8 Normal service test result

与预期的偏差 无 标识符 测试结果 说明的问题 C3 正常操作时偶尔出现连接错误。但属于正常错误范围。 学生查询模块的借阅功能有待改进

23

与预期的偏差 无 天津理工大学2011届本科课程设计说明书(课程论文)

表6.9 文件服务模块测试结果 Table 6.9 File service test result

标识符 测试结果 说明的问题 C4 正常操作无任何异常出现 文件服务模块通过了功能测试

表6.10 音频服务模块测试结果 Table 6.10 Audio service test result

与预期的偏差 无 标识符 测试结果 说明的问题 C5 正常无任何异常出现 音频服务模块通过了功能测试 与预期的偏差 无

24

天津理工大学2011届本科课程设计说明书(课程论文)

第七章 总结

在课题设计的整个过程中我深深认识到了软件设计过程中,规划和设计的重要性。良好的设计准备工作可以使代码的编写变得更加简单,提高工作效率,减轻编码和调试的压力。尤其是对可重用的框架部分,一个好的设计更是可以事半功倍。对于编码过程中需要使用到的数据类,也需要进行充分的设计和规划。它并不同于数据库设计,它的设计目的并不是为了存储数据,而是在于数据的传递。它的设计过程与数据库设计十分类似,也需要考虑不同数据实体之间的关系和层次,以及基础的数据类型问题。我个人把这个设计过程称为数据设计。

通过这次的设计,我熟悉了MVC,MVVM的框架概念和开发流程,增加了我的开发经验,让我了解到对于一些常见问题的解决方法。

回顾此次设计过程,从开始对WCF和MVC以及Silverlight一窍不通,到现在可以熟练掌握开发过程和技巧,能够解决一些常见的问题,毫无疑问我得到了很大的提高。在这个过程中我也遇到了很多难题,通过网上的一些资料以及说明文档,加上自己的分析,我最终解决了这些问题。虽然到最后我的代码并不是毫无瑕疵,也由于时间问题有许多功能无法完成,但是在老师肯定我成果的时候,我还是能感受到极大的成就感。

在代码调试过程中遇到的问题也提高了我解决问题的能力,能够自己解决程序中一些常见的问题。与此同时,在学习,我深刻的体会到一个优秀的程序员的过程中要努力培养自己的编程思想,语言只是一种工具,我们要做的不是学会工具如何使用,而是学会如何制作一件完美的艺术品。

综上,在开发之初就必须要注意系统的详细需求分析,这个过程是很重要的。进行软件开发,很可能会在提高性能的某些方面的同时,在其他方面付出代价,因此,我们要根据用户的需求,使系统作为一个整体,通盘考虑,权衡的优点和缺点,决定取舍,这样,我们才能开发设计出性能良好,满足用户需求的软件。

25

天津理工大学2011届本科课程设计说明书(课程论文)

参考文献

[1]张海藩.软件工程导论(第四版).北京:清华大学出版社,2003年12月 [2]朱少民.软件测试方法和技术.北京:清华大学出版社,2005年7月

[3]Paul C.Jorgensen.软件测试(第二版).北京:机械工业出版社,2006年2月 [4]蒋金楠.WCF全面解析.北京:电子工业出版社,

2012年4月 26

天津理工大学2011届本科课程设计说明书(课程论文)

附 录

1.服务器主要功能代码:

public class DBService {

public static readonly MVCChat_DBEntities DBContext = new MVCChat_DBEntities(); public static string ValidateUserNameAndPwd(DBOperationData data) {

User u = DBContext.Users.Where(x => x.UserName.Trim() == data.UserName.Trim()).SingleOrDefault(); if (u == null) {

return \"用户名不存在\"; }

if (u.Password.Trim() != data.UserPwd.Trim()) {

return \"密码错误\"; } else {

u.IsOnline = 1;

u.EndpointAddress = data.EndPointAddress.Trim();

DBContext.Entry(u).State = System.Data.Entity.EntityState.Modified; DBContext.SaveChanges();

int id = DBContext.Users.Where(x => x.UserName.Trim() == data.UserName.Trim()).Select(x => x.ID).Single();

foreach (var item in DBContext.Friends.Where(x => x.Friend_ID == id).Select(x => x.User_ID)) {

User user = DBContext.Users.Where(x => x.ID == item && x.IsOnline == 1).SingleOrDefault();

if (user != null) { try {

OnlineNotifyReference.OnlineNotifyServiceClient ONClient = new OnlineNotifyReference.OnlineNotifyServiceClient(new

System.ServiceModel.NetTcpBinding(System.ServiceModel.SecurityMode.None), new

System.ServiceModel.EndpointAddress(string.Format(\"net.tcp://{0}:{1}/OnlineNotify\", new

27

天津理工大学2011届本科课程设计说明书(课程论文)

Uri(user.EndpointAddress).Host, new Uri(user.EndpointAddress).Port + 5))); ONClient.OnlineNotify(data.UserName, data.EndPointAddress, true); }

catch (Exception e) {

//System.Windows.Forms.MessageBox.Show(e.Message);

//FileStream fs = File.Open(@\"e:\\MyWebSite\\MyServiceTest\\log.txt\FileMode.OpenOrCreate, FileAccess.Read);

//StreamWriter sw = new StreamWriter(fs); //sw.Write(e.Message); }

} }

return \"登陆成功\"; } }

public static List GetFriends(DBOperationData data) {

int id = DBContext.Users.Where(x => x.UserName.Trim() == data.UserName.Trim()).Select(x => x.ID).Single();

List Fids = DBContext.Friends.Where(x => x.User_ID == id).Select(x => x.Friend_ID).ToList();

List friends = new List(); foreach (var item in Fids) {

User u = DBContext.Users.Where(x => x.ID == item).Single();

friends.Add(new DCFriend() { Name = u.UserName.Trim(), EndPointAddress = u.EndpointAddress, OnlineState = u.IsOnline }); }

return friends; }

public static User GetUser(int id) {

return DBContext.Users.Where(x => x.ID == id).SingleOrDefault(); }

public static int LogOut(string userName) {

User u = DBContext.Users.Where(x => x.UserName.Trim() == userName).Single();

int id = DBContext.Users.Where(x => x.UserName.Trim() == userName.Trim()).Select(x =>

28

天津理工大学2011届本科课程设计说明书(课程论文)

x.ID).Single(); foreach (var item in DBContext.Friends.Where(x => x.Friend_ID == id).Select(x => x.User_ID)) {

User user = DBContext.Users.Where(x => x.ID == item && x.IsOnline == 1).SingleOrDefault(); if (user != null) { try {

OnlineNotifyReference.OnlineNotifyServiceClient ONClient = new OnlineNotifyReference.OnlineNotifyServiceClient(new

System.ServiceModel.NetTcpBinding(System.ServiceModel.SecurityMode.None), new

System.ServiceModel.EndpointAddress(string.Format(\"net.tcp://{0}:{1}/OnlineNotify\", new Uri(user.EndpointAddress).Host, new Uri(user.EndpointAddress).Port + 5))); ONClient.OnlineNotify(u.UserName, null, false); }

catch (Exception) { } } }

u.IsOnline = 0;

u.EndpointAddress = null;

DBContext.Entry(u).State = System.Data.Entity.EntityState.Modified; DBContext.SaveChanges(); return 1; }

}

2.客户端主要功能代码: 2.1主服务逻辑部分代码:

void service_OnCommunicationRequest(object sender, CommunicationRequestEventArgs e) {

lock (mutexLock) {

if (WindowsFormsApplication1.Program.MainForm.SilverLightClientImplements != null) {

#region 普通聊天请求

if (e.InCommingRequest.RequestType == RequestType.NormalRequest)

29

天津理工大学2011届本科课程设计说明书(课程论文)

{ #region 判断是否已创建SilverLightClient实例 bool contains = false; foreach (var item in

WindowsFormsApplication1.Program.MainForm.SilverLightClientImplements) {

#region 已经创建SilverLightClient的情况

if (item.CommunicationInfo.ToUser == e.InCommingRequest.FromUserName) {

contains = true;

if (item._NormalServiceClient != null) { } else {

if (item._NormalServiceHost == null) {

item._NormalServiceHost = new NormalServiceHost();

item._NormalServiceHost.service.OnCommunicationDataReceived += item.service_OnCommunicationDataReceived;

item._NormalServiceHost.InitializeNormalService(string.Format(\"net.tcp://localhost:{0}/NormalService\", WindowsFormsApplication1.Program.MainForm.ServerPortsHelper.Count + 20600)); item._NormalServiceHost.Open(); }

if (item._NormalServiceClient == null) {

item._NormalServiceClient = new NormalServiceClient(e.InCommingRequest.ReplyAddress.ToString());

if (item._NormalServiceClient.Channel.State == CommunicationState.Created)

{

item._NormalServiceClient.Channel.Open(); } }

#region 将绑定的本地地址进行转换 可以转换为局域网中可用的主机地址或Internet中可用的ip地址

Uri tempUri =

item._NormalServiceHost.host.Description.Endpoints.First().ListenUri; string newUri = tempUri.ToString(); if (tempUri.Host == \"localhost\")

30

天津理工大学2011届本科课程设计说明书(课程论文)

{

WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper helper = new WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper();

newUri = newUri.Replace(\"localhost\", helper.GetAvailableIPAddress().ToString()); }

#endregion

if (e.InCommingRequest.PingPongCount <= 2) {

///创建待发送的CommunicationRequest CommunicationRequest request = new CommunicationRequest(RequestType.NormalRequest, new Uri(newUri)); request.FromUserName = WindowsFormsApplication1.Program.MainForm.HostUserName;

request.PingPongCount = e.InCommingRequest.PingPongCount + 1; if

(!WindowsFormsApplication1.Program.MainForm.mainServiceClient.CheckContains(e.InCommingRequest.FromUserName))

{ if

(!WindowsFormsApplication1.Program.MainForm.mainServiceClient.CheckContains(e.InCommingRequest.FromUri))

{

WindowsFormsApplication1.Program.MainForm.mainServiceClient.CreateChannel(e.InCommingRequest.FromUserName.Trim(), e.InCommingRequest.FromUri.ToString()); }

}

WindowsFormsApplication1.Program.MainForm.mainServiceClient.SendCommunicationRequestToUser(e.InCommingRequest.FromUserName.Trim(), request); } }

item.NormalServiceAutoResetEvent.Set(); break; }

#endregion }

31

天津理工大学2011届本科课程设计说明书(课程论文)

#region 未创建SilverLightClient的情况 此判断仅用于调试 if (!contains) {

CommunicationInformation comuinfo; comuinfo = new

CommunicationInformation(WindowsFormsApplication1.Program.MainForm.HostUserName, e.InCommingRequest.FromUserName,

WindowsFormsApplication1.Program.MainForm.mainServiceHost.host.Description.Endpoints.Single().ListenUri, e.InCommingRequest.ReplyAddress);

WCF.SilverLightWCF.SilverLightClientImplement implement = new WCF.SilverLightWCF.SilverLightClientImplement(new ClientInformation(), comuinfo); implement.CallBackChannel = WindowsFormsApplication1.Program.MainForm.SLCallBackChannel;

service_OnCommunicationRequest(sender, e);

//throw new Exception(\"Fatel Error:Request Implement is missing\"); }

#endregion #endregion }

#endregion #region 文件请求

else if (e.InCommingRequest.RequestType == RequestType.FileRequest) {

bool contains = false; foreach (var item in

WindowsFormsApplication1.Program.MainForm.SilverLightClientImplements) {

if (item.CommunicationInfo.ToUser == e.InCommingRequest.FromUserName.Trim()) {

contains = true;

//1communicationrequst如何解决回发问题 2如何解决并发发送和并发接收 if (item._FileServiceHost != null) { if

((item._FileServiceHost.Host.Description.Endpoints.Single().ListenUri.Port !=

e.InCommingRequest.FileRequestPort) || item._FileServiceHost.Host.State != CommunicationState.Opened) {

item._FileServiceHost = null;

service_OnCommunicationRequest(sender, e); }

32

天津理工大学2011届本科课程设计说明书(课程论文)

} else {

item._FileServiceHost = new FileServiceHost(string.Format(\"net.tcp://localhost:{0}/FileService\", e.InCommingRequest.FileRequestPort));

item._FileServiceHost.Open(); } break; } }

}

#endregion #region 音频请求

else if (e.InCommingRequest.RequestType == RequestType.AudioRequest) {

foreach (var item in

WindowsFormsApplication1.Program.MainForm.SilverLightClientImplements) {

if (item.CommunicationInfo.ToUser == e.InCommingRequest.FromUserName.Trim()) {

if (item._AudioServiceClient == null || item._AudioServiceHost == null) {

if (item._AudioServiceHost == null) {

item._AudioServiceHost = new AudioServer(new LumiSoft.Net.Media.Codec.Audio.PCMA()); }

if (item._AudioServiceClient == null) {

item._AudioServiceClient = new AudioClient(new LumiSoft.Net.Media.Codec.Audio.PCMA());

item._AudioServiceClient.RemoteIPEndPoint.Add(e.InCommingRequest.AudioReplyIPAddress); } else { if

(item._AudioServiceClient.RemoteIPEndPoint.Contains(e.InCommingRequest.AudioReplyIPAddress))

33

天津理工大学2011届本科课程设计说明书(课程论文)

{ } else {

item._AudioServiceClient.Stop();

item._AudioServiceClient.RemoteIPEndPoint.Add(e.InCommingRequest.AudioReplyIPAddress); } }

if (e.InCommingRequest.PingPongCount < 3) {

CommunicationRequest re = new CommunicationRequest(RequestType.AudioRequest, null);

re.PingPongCount = e.InCommingRequest.PingPongCount + 1; re.FromUserName = WindowsFormsApplication1.Program.MainForm.HostUserName;

re.AudioReplyIPAddress = item._AudioServiceHost.LocalAddress[0];

WindowsFormsApplication1.Program.MainForm.mainServiceClient.SendCommunicationRequestToUser(e.InCommingRequest.FromUserName, re);

} } else { if

(item._AudioServiceClient.RemoteIPEndPoint.Contains(e.InCommingRequest.AudioReplyIPAddress)) { } else {

item._AudioServiceClient.Stop();

item._AudioServiceClient.RemoteIPEndPoint.Add(e.InCommingRequest.AudioReplyIPAddress); }

if (e.InCommingRequest.PingPongCount < 2) {

CommunicationRequest re = new CommunicationRequest(RequestType.AudioRequest, null);

re.PingPongCount = e.InCommingRequest.PingPongCount + 1;

34

天津理工大学2011届本科课程设计说明书(课程论文)

re.AudioReplyIPAddress = item._AudioServiceHost.LocalAddress[0];

WindowsFormsApplication1.Program.MainForm.mainServiceClient.SendCommunicationRequestToUser(e.InCommingRequest.FromUserName, re);

} }

item._AudioServiceHost.Start(); item._AudioServiceClient.Start(); break; } } }

#endregion } else {

throw new Exception(\"Fatel Error:ClinetImplements is Null Please try restarting the program to fix it!\"); } } }

2.2普通聊天服务逻辑代码:

public void service_OnCommunicationDataReceived(object sender, CommunicationDataEventArgs e) {

string fromUserName = e.InCommingData.CommunicationInfo.FromUser;

if (this.CallBackChannel != null && this.CallBackChannel.State == CommunicationState.Opened) {

foreach (var item in e.InCommingData.Body.Inlines) {

foreach (var r in item.Inlines) {

if (r.RealType == InlineType.InlineUIContainer) {

r.ImageFilePath = WindowsFormsApplication1.Program.MainForm.PersonalFolder + @\"\\\" + r.Text + r.ImageFilePath; } }

35

天津理工大学2011届本科课程设计说明书(课程论文)

} CallBackChannel.SendCommunicationDataBack(e.InCommingData); } else {

throw new Exception(\"Fatel Error:CallBackChannel error!\"); } }

2.3文件服务逻辑代码:

void Service_OnStreamIn(object sender, StreamInEventArgs e) {

#region 作为图片随聊天信息一起发送的情况 if (e.Message.Header.IsPicRequest) {

if (!Directory.Exists(WindowsFormsApplication1.Program.MainForm.PersonalFolder)) {

Directory.CreateDirectory(WindowsFormsApplication1.Program.MainForm.PersonalFolder); }

FileInfo temp = new FileInfo(e.Message.Header.SourceName); string extension = temp.Extension;

FileInfo fi = new FileInfo(WindowsFormsApplication1.Program.MainForm.PersonalFolder + @\"\\\" + e.Message.Header.PicGuid + extension);

FileStream targetfs = fi.Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.None); byte[] buffer = new byte[65536]; int count = 0;

while ((count = e.Message.Body.Read(buffer, 0, buffer.Length)) != 0) {

targetfs.Write(buffer, 0, count); }

targetfs.Close();

//TODO:添加回调SilverLight的过程 以填充InlineUIContainer 需要提供guid foreach (var item in

WindowsFormsApplication1.Program.MainForm.SilverLightClientImplements) {

if (item.CommunicationInfo.FromUser == e.Message.Header.CommunicationInfo.ToUser && item.CommunicationInfo.ToUser == e.Message.Header.CommunicationInfo.FromUser) {

CommunicationData data = new

CommunicationData(e.Message.Header.CommunicationInfo, new MessageBody());

36

天津理工大学2011届本科课程设计说明书(课程论文)

data.DataType = DataType.FileData; List runlist = new List(); RunBody r = new RunBody();

r.RealType = InlineType.InlineUIContainer; r.Text = e.Message.Header.PicGuid.ToString(); r.ImageFilePath = fi.FullName; runlist.Add(r); ParagraphBody pb = new

ChatHelper.CommunicationDataDefined.ParagraphBody(runlist);

data.Body.Inlines = new ParagraphBody[] { pb }; item.CallBackChannel.SendCommunicationDataBack(data); } } }

#endregion

#region 普通的文件传输 else {

AutoResetEvent are = new AutoResetEvent(false); SaveFileDialog sfd = new SaveFileDialog();

sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); sfd.FileName = e.Message.Header.SourceName;

SFDAsync_Object SFDO = new SFDAsync_Object() { Sfd = sfd, e = e, CallBack = new Action(SFD_CallBack),ARE = are };

System.Threading.Thread t = new System.Threading.Thread(new

System.Threading.ParameterizedThreadStart((x) => { (x as SFDAsync_Object).Result = (x as SFDAsync_Object).Sfd.ShowDialog(); (x as SFDAsync_Object).CallBack((x as SFDAsync_Object)); })); t.SetApartmentState(ApartmentState.STA); t.Start(SFDO); are.WaitOne(); }

#endregion }

2.4音频服务逻辑代码:

public class AudioServer {

#region Fields

private static readonly object mutexLock = new object(); private List _sSockets = null;

private Dictionary _sTable = null;

37

天津理工大学2011届本科课程设计说明书(课程论文)

private PortsHelper.PortsHelper portsHelper = null; private AudioFormat audioFormat = null; private AudioCodec audioCodec = null; private List threads = null; #endregion

#region Properties ///

/// 获取该AudioServer绑定的本地IP终结点地址 ///

public IPEndPoint[] LocalAddress { get {

if (_sSockets != null && _sSockets.Count != 0) {

List ipList = new List(); foreach (var item in _sSockets) {

ipList.Add(item.LocalEndPoint as IPEndPoint); }

return ipList.ToArray(); } else {

throw new Exception(\"Socket has not been initialized!\"); }

} }

public AudioFormat AudioFormat { get {

if (this.audioFormat != null) {

return this.audioFormat; } else {

throw new Exception(\"Socket has not been initialized!\");

38

天津理工大学2011届本科课程设计说明书(课程论文)

} } }

#endregion #region Methods ///

/// 使用默认 8000采样率 16位宽 单通道初始化音频设备 ///

public AudioServer(AudioCodec codec) {

audioCodec = codec;

audioFormat = new AudioFormat(8000, 16, 1);

if (WindowsFormsApplication1.Program.MainForm.ServerPortsHelper != null) {

portsHelper = WindowsFormsApplication1.Program.MainForm.ServerPortsHelper; } else {

throw new Exception(\"Fatel Error:Client has not been initialized\"); }

if (_sSockets == null) {

_sSockets = new List(); }

WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper helper = new WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper();

Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true); s.Bind(new IPEndPoint(helper.GetAvailableIPAddress(), 20900 + portsHelper.Count)); _sSockets.Add(s);

_sTable = new Dictionary(); threads = new List(); }

///

/// 使用自定义采样率位宽和通道数量初始化音频设备 ///

/// 编码类型PCMA或PCMU /// 采样率 /// 采样深度 /// 通道数

public AudioServer(AudioCodec codec, int samplepersec, int bitspersample, int channels)

39

天津理工大学2011届本科课程设计说明书(课程论文)

{ audioCodec = codec;

audioFormat = new AudioFormat(samplepersec, bitspersample, channels); if (WindowsFormsApplication1.Program.MainForm.ServerPortsHelper != null) {

portsHelper = WindowsFormsApplication1.Program.MainForm.ServerPortsHelper; } else {

throw new Exception(\"Fatel Error:Client has not been initialized\"); }

if (_sSockets == null) {

_sSockets = new List(); }

WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper helper = new WindowsFormsApplication1.NetworkInterface.NetworkInterfaceHelper();

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true); s.Bind(new IPEndPoint(helper.GetAvailableIPAddress(), 20900 + portsHelper.Count)); _sSockets.Add(s);

_sTable = new Dictionary(); threads = new List(); }

///

/// 开始在本机所有ip地址上接受并播放数据 /// 方法成功返回1,未成功调用返回0; ///

public int Start() {

if ((_sSockets!=null&&_sSockets.Count!=0)&&threads.Count==0) {

foreach (var item in _sSockets) {

ParameterizedThreadStart PTS = new ParameterizedThreadStart(receive); Thread t = new Thread(PTS); t.Start(item); threads.Add(t); }

return 1;

40

天津理工大学2011届本科课程设计说明书(课程论文)

} else {

return 0; } }

///

/// 关闭接收线程 停止接收播放数据 ///

/// 方法成功调用返回1,否则返回0 public int Stop() {

if (threads!=null&&threads.Count!=0) {

foreach (var socket in _sSockets) {

socket.Close(); }

foreach (var item in threads) {

item.Abort(); }

threads.Clear(); return 1; } else {

return 0; } }

#endregion

#region PrivateMethods ///

/// 在子线程上运行的方法 监听端口上所有接收到的数据 为来源相同的主机分配同一AudioOut实例。方法用来保证来自同一主机的音频信息线性播放 不同主机的音频信息并发播放 从而实现多人音频聊天。 ///

/// 要监听的socket private void receive(Socket socket) {

41

此 天津理工大学2011届本科课程设计说明书(课程论文)

byte[] buffer = new byte[8192]; SocketFlags sf = new SocketFlags();

EndPoint ep = new IPEndPoint(IPAddress.Any, 0); AudioOut ao;

IPPacketInformation info; int count; while (true) {

if ((count = socket.ReceiveMessageFrom(buffer, 0, buffer.Length, ref sf, ref ep, out info)) != 0) {

bool result; lock (mutexLock) {

result = _sTable.TryGetValue(info.Address, out ao); }

if (result) {

ao.Write(buffer, 0, count); } else {

ao = new AudioOut(AudioOut.Devices[0], audioFormat); ao.Write(buffer, 0, count); lock (mutexLock) {

_sTable.Add(info.Address, ao); } } }

Thread.Sleep(50); }

}

///

/// 在子线程上运行的方法 监听端口上所有接收到的数据 为来源相同的主机分配同一AudioOut实例。 此方法用来保证来自同一主机的音频信息线性播放 不同主机的音频信息并发播放 从而实现多人音频聊天。 ///

42

天津理工大学2011届本科课程设计说明书(课程论文)

/// 要监听的socket(object类型重载) object socket) as Socket); 致 43

2014年6月 private void receive( {

receive(socket }

#endregion }

天津理工大学2011届本科课程设计说明书(课程论文)

44

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo0.com 版权所有 湘ICP备2023021991号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务