c#实现网络聊天室(socket)仿QQ课程设计

更新时间:2024-04-02 10:04:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Visual C#程序设计

课 程 设 计(报告)

题目: 网络聊天室

专业班级: 地信131

学生姓名: 胡宏勇

学 号: 1220130912

完成时间:_________ 2015.7.12______________________

任务书

项目四 网络聊天室

4.1、目的与要求

1. 目的:

1)要求学生达到熟练掌握.NET基本结构以及C#语言的基本知识和技能; 2)基本掌握面向对象程序开发的基本思路和方法; 3)掌握网络程序开发的基本知识;

4)能够利用所学的基本知识和技能,进行简单的网络通信程序设计。 2. 要求 基本要求:

1)要求利用C#的编程思想以及套接字开发原理来完成系统的设计; 2)突出C#语言与其它语言不同点(即体现C#的高级功能,如属性概念、接口、事件、委托等);

3)体现可视化编程基本东西,如系统带有菜单、工具栏、状态栏以及一些

常用的高级控件。 创新要求: 在基本要求达到后,可进行创新设计,如加入文件传输功能,以及远程控制功能。 4.2、信息描述

有关该系统基本信息的描述,如:客户端实例的信息等。类似于QQ。 4.3、功能描述

1. 聊天室服务器端的创建。

2. 聊天室客户端的创建。

3. 实现客户与服务器的连接通讯。 4. 实现客户之间的私聊。

5. 实现客户端的在线信息显示。

6. 实现服务器端当前在线客户信息。 7. 保存谈话记录。 4.4、解决方案

1. 首先进行需求分析,搞清楚系统功能和任务。

2. 然后总体设计中确定模块结构,划分功能模块,将软件功能需求分配给所划分的最小单元模块。确定模块间的联系,确定数据结构、文件结构、数据库模式,确定测试方法与策略。

3. 详细设计中为每个模块确定采用的算法,选择适当的工具表达算法的过程(流程图),描述模块的详细过程;确定每一模块使用的数据结构;确定模块接口的细节,包括对系统外部的接口和用户界面,对系统内部其它模块的接口。 4. 依据分析编写C#代码。

目录

1.需求分析 - - - - - - - - - - - - - - - - - - - - 1 1.1 摘要

1.2 系统开发背景

1.3聊天软件的开发目标

2.概要设计 - - - - - - - - - - - - - - - - - - - - 2 2.1 服务器端 2.2 客户端

3.详细设计 - - - - - - - - - - - - - - - - - - - - 3

4.编码 - - - - - - - - - - - - - - - - - - - - 6 4.1 服务器端核心编码 4.2 客户端核心代码

5.调试分析 - - - - - - - - - - - - - - - - - - - 18

6.用户使用说明 - - - - - - - - - - - - - - - - - 27

7.课程设计总结 - - - - - - - - - - - - - - - - 28

8.参考文献 - - - - - - - - - - - - - - - - - - - 28

1.需求分析

1.1摘 要

作为除电视、报纸、广播之外的第四大媒体,互联网不仅成为人们获取新闻信息的主要来源,更成为了人们闲暇之余的一种休闲手段。随着互联网技术的发展,各种各样基于网络的应用也随之诞生,网络聊天工具便是其中的一种。本文采用Visual Studio 2010+SQL Server 2008开发环境,结合WinForms、ADO.NET等多种技术,实现了一个类似QQ的网络聊天工具,并在WINDOWS平台上加以了实现。通过C#语言进行网络编程,通过公共的数据库交换各种信息,实现了人性化的界面设计与功能设计。软件经过测试,满足现代人们即时通信的需求,达到预期的设计效果,对网络聊天工具的人性化设计具有一定的现实意义,同时也为其他相关项目的设计提供了参考。

关键词:网络聊天工具 C# 即时通信 数据库 人性化

1.2 系统开发背景

在互联网相当普及的今天,你们对网络的依赖越来越大,越来越离不开网络,网络聊天更是成为了人们的“家常便饭”。通过网络聊天工具,人们足不出户就可进行闲聊甚至工作会谈,极大地方便了人们的日常生活与工作需求。

常用的网络聊天工具主要是QQ与MSN。MSN主要用于国际,而国内的主流网络聊天工具是QQ。为了方便同学之间的交流,我决定设计一个类似QQ并且无垃圾信息的网络聊天工具,此外也希望通过本次课程设计能更好地学习与掌握网络软件编程知识。

1.3 聊天软件的开发目标

本次课程设计的主要工作是设计一个类似QQ的网络即时聊天工具,主要是

采用WinForms+ADO.NET+Socket通信技术实现。软件功能主要包括用户注册、用户登录、用户间聊天、查找/添加好友、个人设置以及服务器的搭建等。客户端通过公共的数据库交换信息,消息的发送和读取都是通过Socket通信技术和操作数据库来完成的。在程序中采用定时扫描数据库的方式来查找登录用户。以及Socket通信技术实现信息交换。

1

2.概要设计

(1)数据库端

MODEL类:数据库的模型层包括Users(用户层)Stars(用户所对应的星座)Friends(用户之间的好友关系层)BloodType(用户所对应的血型)

DAL类:sqlHelper(数据库与数据层DAL的连接类)UsersDAL(用户的数据层)StasDAL(用户所对应的星座数据层)FriendsDAL(用户之间的好友关系的数据层)BloodTypeDAL(用户所对应的血型的数据层)

BLL类:UsersBLL(用户的业务层)StarsBLL(用户所对应的星座的业务层) FriendsBLL(用户之间的好友关系的业务层)BloodTypeBLL(用户所对应的血型的业务层) (2)服务器端

Server类:ClientManager(客户端通信管理类)DGSendMsg(显示消息的委托类)MainServer(主窗体) (3)客户端 新建客户端类:Login(登录主窗体)FrmInformation(登录后的消息提示)MainList(主界面与聊天窗口)AddFriend(通过Id添加好友)Apply(申请号码)forgetpwd(找回密码)HeadList(选择更换头像)MyDetail(个人详细资料设计)MyHead(浮动头像框)Search(不同条件查询好友)

2

3.详细设计

设计中定义的所有数据类型涉及太多就不一一列出,下面是我程序个个的调用流程图。

(1)(模型层-数据层-业务层) Users(用户层) 模

层 Stars(用户的星座) M

O

D Friends(用户好友关系层) E

L

BloodType(用户所对应的血型)

SQLServer sqlHelper

数 UsersDAL

层 StasDAL D

A

L FriendsDAL

(业务层与UI层) BloodTypeDAL

UsersBLL

层 StarsBLL B L 3 L FriendsBLL

业务层 用户详细信息 以及当前登录的 IP和端口号

4

(客户端与服务器通信)

5

4.编码

(1)(服务器端核型代码)

//服务器监听套接字 Socket sokServer = null; //监听线程

Thread thrServer = null; //客户端管理类

ClientManager clientManage = null;

BLL.UsersBLL userBll = new BLL.UsersBLL(); //点击开启服务器

private void btnSerStar_Click(object sender, EventArgs e) {

try {

sokServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPAddress ip = IPAddress.Parse(txtSerIP.Text.Trim()); //创建端口号对象 IPEndPoint point = new IPEndPoint(ip, int.Parse(txtSerPort.Text.Trim())); // 监听

sokServer.Bind(point); //最多连几个

sokServer.Listen(Convert.ToInt32(cmbSerMax.SelectedItem)); //开启新线程

thrServer = new Thread(WatchConnection); thrServer.IsBackground = true; thrServer.Start(); //管理类对象实例化

clientManage = new ClientManager(listChat, AppendMsg); AppendMsg(\开始监听~~~~!\ }

catch (Exception ex) {

MessageBox.Show(\异常:\+ ex.Message + DateTime.Now.ToString());

AppendMsg(\异常:\+ ex.Message + \+ DateTime.Now.ToString());

6

} }

bool isWatching = true; void WatchConnection() {

try {

while (isWatching) {

//负责通信的socket

Socket sokMsg = sokServer.Accept(); //加入通信管理类

clientManage.AddClient(sokMsg);

txtOnlineCount.Text = listChat.Items.Count.ToString(); } }

catch (SocketException ex1) {

AppendMsg(\异常:\+ ex1.Message \ }

catch (Exception ex) {

AppendMsg(\异常:\+ ex.Message + \DateTime.Now.ToString()); } }

//通信管理类

///

/// 客户端管理 ///

public class ClientManager {

//好友列表控件

private System.Windows.Forms.ListBox listClient; DGSendMsg dgSendMsg;

//通信套接字key :客户端ip value :对应的通信套接字 private Dictionary ClientSocket; public ClientManager() { }

///

/// 客户端管理类 ///

7

+

+

///

///

public ClientManager(System.Windows.Forms.ListBox lb,DGSendMsg dgSendMsg) {

this.listClient = lb;

this.dgSendMsg = dgSendMsg;

// dictClientSocket = new Dictionary(); ClientSocket = new Dictionary(); }

///

/// 添加通信套接字 ///

/// public void AddClient(Socket sokMsg) {

//获取客户端通信套接字

string strEndPoint = sokMsg.RemoteEndPoint.ToString(); //通信套接字加入字典

ClientSocket.Add(strEndPoint, sokMsg); //显示列表

System.Threading.Thread.Sleep(500);

BLL.UsersBLL userbll = new UsersBLL();

Users adduser= userbll.SelectByIp(strEndPoint);

listClient.Items.Add(strEndPoint + \+ adduser.Name + \+ adduser.Id + \

Thread thrMag = new Thread(ReciveMsg); thrMag.IsBackground = true; thrMag.Start(sokMsg);

dgSendMsg(strEndPoint + \成功连接上服务端~~~!\+ DateTime.Now.ToString()); }

bool isReceing = true;

void ReciveMsg(object sokMsgObj) {

Socket sokMsg=null; try {

//sokMsg接收消息的socket

sokMsg = sokMsgObj as Socket;

byte[] arrMsg = new byte[5 * 1024 * 1024]; while (isReceing) {

8

//接收到消息 //测试

int realLength = sokMsg.Receive(arrMsg); if (realLength==0) {

RemoveClient(sokMsg.RemoteEndPoint.ToString()); }

string strMsg = Encoding.UTF8.GetString(arrMsg, 0, realLength);

//dgSendMsg(strMsg);

SendMsgToClient(strMsg);

string[] msgTxt = strMsg.Split('|'); if (msgTxt.Length<1) {

RemoveClient(sokMsg.RemoteEndPoint.ToString()); } } } catch {

RemoveClient(sokMsg.RemoteEndPoint.ToString()); } }

public void RemoveClient(string strClientID) {

if (listClient.Items.Contains(strClientID)) {

listClient.Items.Remove(strClientID); }

if (ClientSocket.Keys.Contains(strClientID)) {

ClientSocket[strClientID].Close(); ClientSocket.Remove(strClientID); } }

public void SendMsgToClient(string Msg) {

//解析发来的数据

string[] msgTxt = Msg.Split('|');

//不可解析数据

9

if (msgTxt.Length < 2) {

return; }

string strTo = msgTxt[1];

int strToId = Convert.ToInt32(strTo);

Users userTo = new BLL.UsersBLL().SelectById(strToId); if (ClientSocket.Keys.Contains(userTo.IP)) {

byte[] buffer = System.Text.Encoding.UTF8.GetBytes(Msg); Socket conn = ClientSocket[userTo.IP]; conn.Send(buffer); } }

(客户端)

//与服务器通信的socket

#region sokConnect()负责通信的socket void sokConnect() {

//负责通信的socket try {

socketSent = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPAddress ip = IPAddress.Parse(txtIP.Text.Trim());

socketSent.Connect(ip, Convert.ToInt32(txtProt.Text.Trim())); // showmsg(\连接成功\ //将IP更新回数据库 new BLL.UsersBLL().UpDateIp(nowuser.Id, socketSent.LocalEndPoint.ToString()); // 接收消息,的新线程

Thread th = new Thread(recive); //后台运行

th.IsBackground = true; th.Start(); }

catch (Exception) {

MessageBox.Show(\服务器异常\

10

//this.Close(); } }

#endregion

//解析服务端发来的消息

#region 服务端发来的消息 ///

/// 服务端发来的消息 ///

void recive() {

try {

while (true) {

byte[] buffer = new byte[1024 * 1024 * 5]; int r = socketSent.Receive(buffer); if (r == 0) {

break; }

//一般文字消息 if (buffer[0] == 0) {

//不解析第一位0

string str = Encoding.UTF8.GetString(buffer, 1, r - 1); string[] msgTxt = str.Split('|'); string strFrom = msgTxt[0];

int strFromId = Convert.ToInt32(strFrom);

Users userfrom = new BLL.UsersBLL().SelectById(strFromId); //使用FileStream来写入数据 //File.AppendAllText()

string newstr = userfrom.Name + \+ msgTxt[2] + \ ____[\

if (userfrom.Id==nowfriend.Id) {

showmsg(newstr); } else {

11

for (int i=0; i

if

(listView.Items[i].Text==nowfriend.Name+\ { } else {

if (listView.Items[i].Text == userfrom.Name + \+ userfrom.Id + \

{

listView.Items[i].Text= userfrom.Name + \+ userfrom.Id + \好友发来消息\ } } } }

using (FileStream fsWrite = new FileStream(path + \+ userfrom.Id + \ {

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); } }

//解析文件

else if (buffer[0] == 1) {

string str = Encoding.UTF8.GetString(buffer, 1, r - 1); string[] msgTxt = str.Split('|'); string strFrom = msgTxt[0];

int strFromId = Convert.ToInt32(strFrom);

Users userfrom = new BLL.UsersBLL().SelectById(strFromId); //使用FileStream来写入数据 //File.AppendAllText()

string newstr = userfrom.Name + \发送了一个文件\ ____[\

if (userfrom.Id == nowfriend.Id) {

showmsg(newstr); }

using (FileStream fsWrite = new FileStream(path + \+ userfrom.Id + \

12

{

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); }

if (MessageBox.Show(\好友\发来一个文件是否接收\收到文件\ {

SaveFileDialog sfd = new SaveFileDialog(); sfd.Title = \保存文件\ sfd.Filter = \全部文件|*.*\ sfd.InitialDirectory = @\

sfd.ShowDialog(this);

using (FileStream fs = new FileStream(sfd.FileName, FileMode.OpenOrCreate, FileAccess.Write)) {

fs.Write(buffer, 1, r - 1); }

MessageBox.Show(\保存成功\

using (FileStream fsWrite = new FileStream(path + %userfrom.Id + \ {

byte[] newbuffer = Encoding.UTF8.GetBytes(\接收成功\

fsWrite.Write(newbuffer, 0, newbuffer.Length); } } else {

using (FileStream fsWrite = new FileStream(path + %userfrom.Id + \ {

byte[] newbuffer = Encoding.UTF8.GetBytes(\接收不成功\

fsWrite.Write(newbuffer, 0, newbuffer.Length); } } }

//解析抖动

else if (buffer[0] == 2) {

string str = Encoding.UTF8.GetString(buffer, 1, r - 1); string[] msgTxt = str.Split('|'); string strFrom = msgTxt[0];

13

int strFromId = Convert.ToInt32(strFrom);

Users userfrom = new BLL.UsersBLL().SelectById(strFromId);

string newstr = userfrom.Name + \+ \震动了一下\\ ____[\

if (userfrom.Id == nowfriend.Id) {

showmsg(newstr); }

for (int i = 0; i < 100; i++) {

Random rd = new Random(); int x = rd.Next(200, 250); Random rx = new Random(); int y = rx.Next(200, 250);

this.Location = new Point(x, y); System.Threading.Thread.Sleep(5); Application.DoEvents(); }

using (FileStream fsWrite = new FileStream(path + \+ userfrom.Id + \ {

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); } } } } catch { } }

#endregion

//点击发送文字信息

private void btnsent_Click(object sender, EventArgs e) {

try {

string newstr = \我\ ____[\+ DateTime.Now.ToString() + \ showmsg(newstr);

14

using (FileStream fsWrite = new FileStream(path + \\ {

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); }

string str = nowuser.Id +\ byte[] buffer = Encoding.UTF8.GetBytes(str); List newbufferMsg = new List(); //自定义协议0位

newbufferMsg.Add(0);

newbufferMsg.AddRange(buffer);

byte[] newBuffer = newbufferMsg.ToArray(); socketSent.Send(newBuffer); textBox4.Text = \ }

catch { } }

//点击发送文件

private void toolStripButton3_Click(object sender, EventArgs e) {

string newstr = \我\文件\ ____[\DateTime.Now.ToString() + \ showmsg(newstr);

using (FileStream fsWrite = new FileStream(path + \+ nowfriend.Id + \ {

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); } try {

using (FileStream fs = new FileStream(txtpath.Text, FileMode.OpenOrCreate, FileAccess.Read)) {

string str = nowuser.Id + \+ nowfriend.Id + \+ textBox4.Text.Trim();

byte[] buffer0 = Encoding.UTF8.GetBytes(str); byte[] buffer = new byte[1024 * 1024 * 5]; int r = fs.Read(buffer, 0, buffer.Length); List list = new List(); //自定义协议位1

15

list.Add(1);

list.AddRange(buffer0); list.AddRange(buffer);

byte[] newbuffer = list.ToArray(); socketSent.Send(newbuffer); } }

catch { } }

//点击发送抖动

private void toolStripButton1_Click(object sender, EventArgs e) {

try {

string newstr = \我\+ \+ \震动了一下\+ \ ____[\+ DateTime.Now.ToString() + \ showmsg(newstr);

using (FileStream fsWrite = new FileStream(path + \\ {

byte[] newbuffer = Encoding.UTF8.GetBytes(newstr); fsWrite.Write(newbuffer, 0, newbuffer.Length); }

string str = nowuser.Id + \ byte[] buffer = Encoding.UTF8.GetBytes(str); List newbuffer1 = new List(); //自定义协议位2 newbuffer1.Add(2);

newbuffer1.AddRange(buffer);

byte[] newBuffer = newbuffer1.ToArray(); socketSent.Send(newBuffer); }

catch { }; }

16

5.调试分析

(运行结果展示)

(1)在运行管理中ip地址为本机现在所连网络,服务器监听是要注意线程卡死的现象,使用多线程的方法后台运行。

(2)若该端口会一直接收空字符,则判断该用户下线。

17

登录 - - 注册 ---- 找回密码

18

(1)登录时,首先要判断验证码,防止恶意攻击,其次是密码验证,最后检测是否连接端口号

19

登录成功提示----主界面

20

主界面功能展示 (头像展示)

(功能列表)

(查找好友)

21

(准确添加好友)

(音乐播放功能)

(娱乐功能)

22

(头像切换功能)

该功能使用的是listview,和listimage控件完成的

(个人资料设置)

23

(程序核心 --- 聊天功能 ) 胡宏勇与朱立星交谈

交谈过程的实现思路, (1) 自定义协议

根据协议编码: 自定义协议规则

第一位是自定义协议一位 命令:0-文件 1-文字 2-震动 //例如胡宏勇(id号1220130912)发送一个“你好”给朱立星(id号1220130921) 第一位是自定义协议一位

* 命令(0)| 自己的Id|对方的Id|内容

代码为 01220130912|1220130921|你好 (注意这里是二进制流的形式) 以二进制流的形式发送给服务器

24

(2)服务器解码转发

首先将二进制流解码,根据“|”split分割,找出“1220130921”的发送对象,通过socket发送,

(3)客户端解码,显示消息,

找出

程序还可以进行窗口抖动,这里就不演示了,下面是发送文件

25

(显示别的好友发来信息)

26

整合:

(1)通信过程中要注意try ,catch 的使用,避免给用户经常报错

(2)对于重复代码的封装还比较少,类的没有正真使用到位, (3)总结

1、认真上好专业实验课,多在实践中锻炼自己。 2、写程序的过程中要考虑周到,严密。

3、在做设计的时候要有信心,有耐心,切勿浮躁。

4、认真的学习课本知识,掌握课本中的知识点,并在此基础上学会灵活运用。

5、在课余时间里多写程序,熟练掌握在调试程序的过程中所遇到的常见错误,以便能节省调试程序的时间。

6.用户使用说明

(1) /*********************协议说明***********************/ //根据协议解码 /*

* 自定义协议规则

命令:0-文件 1-文字 2-震动 * 内容: * 文件

* 文字(内容) * 震动()

第一位是自定义协议一位 *

* 文件:

* 命令(0)| 自己的Id|对方的Id|内容(文件大小和文件全名)|响应(文件内容) | ...]

* 文字:

* 命令(1)| 自己的Id|对方的Id| 内容(文字) | ...] * 震动

* 命令(2)|自己的Id|对方的Id|

(2)数据库:远程虚拟机上的数据库,用户你要再有网络的地方都可以使用(数据库的配置文件在每个UI层的APP.config里面)

(3)通信必须在服务器打开的状态下,如果出现服务器异常,则不可以进行与好友之间的通信。

27

7.课程设计总结

总结

为期两周的课程设计结束了,在老师和同学的帮助下,我基本完成系统的设计。我按照系统工程软件设计的要求,从需求分析,概念设计,总体设计,详细设计,系统测试等各个步骤,分步完成系统的各项任务,实现了系统中的学生信息查询,学生信息更新,学生信息添加等模块的功能。

本次课程设计的目的旨在通过C#实现更为人性化的网络聊天工具,通过不断地调试,掌握了网络socket通信的基本知识,通过系统功能的实现,充分的复习了winform编程,ADO.net数据库编程,加深了对基础知识的了解,了解到基础知识的重要性。

8.参考文献

(1)博客园-----网络编程之Socket的TCP协议实现客户端与客户端之间

的通信 http://www.cnblogs.com/nsky/p/4511861.html

(2)传智播客------传智播客.Net学院--特供精品.Net基础全套视频教程2014版\\特供精品.Net基础全套视频教程2014版--04Winform应用程序\\02--多线程和Socket网络编程\\特供.Net基础全套视频教程2014版(第十六天)

(3)51ASPX源码

(1)51aspx_SocketChatTools68c6e423-990d-438c-a8cc-86e678edfcb0 (2)LikeQQLAN_4cad6d68-1659-4f92-b4ca-86684db046f0 (3)QQLiveChat_c1779263-473b-4bb5-aa54-e903fbd2aec8

9.提示

作者博客园地址 http://www.cnblogs.com/ATtuing(本程序内容更新在我博客园上并有源码下载)。

作者个人网站:http://www.sharegis.cn“共享GIS”(谢谢关注)

28

江 西 理 工 大 学

Visual C#程序设计课程设计成绩表

建测学院 地信 专业 13 级 1 班 学生胡宏勇

题目:网络聊天室

平时成绩(40%) 程序运行、调试成绩(30%) 课程设计报告成 绩(30%) 综合 成绩

29

本文来源:https://www.bwwdw.com/article/v5hr.html

Top