成都工业学院
课程设计报告
课程名称 计算机网络课程设计 项目名称 基于Socket的网络聊天系统的设计与实现
姓 名 陆海空
班 级 1506041 学 号 1501352247 指导教师 周行老师
设计时间
2016年12月12日 至 2016年12月16日
成都工业学院·计算机工程学院
1
目录
一. 需求分析 .............................................................................. 3 1.1 开发背景 ......................................................................... 3 1.2 功能要求 ......................................................................... 3 1.3 运行环境 ......................................................................... 3 1.4 功能实现 ......................................................................... 3 二.项目设计 ............................................................................. 4 2.1程序流程图 ...................................................................... 4 2.2 概要设计 ......................................................................... 5 2.3功能设计 .......................................................................... 5 2.4 详细设计 ......................................................................... 7 2.4.1界面设计 .................................................................. 7 客户端 ....................................................................... 8 服务器端...................................................................9 2.4.2程序结构设计 .......................................................... 8 三.代码及注释............................................................................9 3.1、客户端 ........................................................................... 9 3.2服务器端 ........................................................................ 15 四.课程设计小结 ...................................................................... 17 五.参考文献 .............................................................................. 17
2
一. 需求分析
1.1 开发背景
随着网络技术不断成熟,人们对于网络的依赖程度不断提高,网络似乎成了生活中必不可少的存在。由此而产生的聊天工具也在不断成长。类似微信、QQ等网络聊天工具的发展日新月异。但是,现有的聊天程序也仍然存在进步的空间。
QQ一直深受人们喜爱,随着版本的不断更新,虽然其功能不断增加不断完善,但始终有很多小问题有时让人难以忍受。在使用过程中,不断的弹窗和广告对用户的使用照成了很大程度的影响。因此我在本次课程设计的激励下,产生了一个制作类似QQ的网络聊天工具并且“无垃圾信息”洁净聊天工具的想法,虽然该工具不够完善,但是我希望通过制作本次程序能够更好地学习计算机网络知识。
1.2 功能要求
(1)登录功能。
(2)用户可以通过服务器转发,实现私密聊天和多人聊天。 (3)实现抖动和声音提醒。
(4)服务器端和客户端程序都能实时显示在线用户人数。 (5)应该具有友好、易用、美观的图形界面。 (6)无垃圾,广告信息
(7)保存和删除聊天信息。
1.3 运行环境
操作系统版本:Windows10 64位 软件版本:Visual studio 2015
1.4 功能实现
1.登录验证功能。对于账号重复等异常,给予用户提示。 2. 客户通过服务器转发,实现私密聊天和多人聊天。
3. 实时显示目前其它用户的状态,能够提示在线用户人数和状态等。 4. 保存并查看聊天记录。 5.申请新的用户号码。
6. 易用、美观的图形界面,实现系统托盘。 7.收到信息时,能够收到声音等提示信息,发送端还能通过发送抖动,提示聊天的对方。
3
二.项目设计
2.1程序流程图
服务器 Socket Bind Listen Accept Receive Send
Close
客户端 Socket Connect Send Receive Close 4
2.2 概要设计
通过C#,实现网络聊天的功能,采用Windows Socket编程,服务器与客户端采用了TCP/IP连接方式,在设计聊天方案时,实行将所有信息发往服务器端,再由服务器进行分别处理的思路,服务器端是所有信息的中心。
由于服务器端要保存用户信息,我们利用数据库来实现这一功能,因此首先需要建立用户信息数据库。
在客户端保存聊天纪录和用户号码这一功能的实现中,采用了文件系统设计。 在信息到来及好友上线时,通过闪动托盘图标和播放不同的音乐进行提示。 建立消息链表来保存用户接收的各种消息。
2.3功能设计
客户端:
1) 登录功能:建立与服务器的连接并登录,能显示登录错误信息。 2) 界面显示:将在线好友显示在好友列表中,并实现系统托盘。 3) 聊天功能:与好友聊天。
4) 聊天记录:能保存聊天纪录,并能察看聊天纪录。
5) 信息提示:闪动托盘图标提示到来信息,并播放不同音乐来提示。 6) 窗口抖动:发送端提示聊天的对方。
客户端 登陆到服务器 申请新的号码 显示在线用 户
接收各种信息 保存聊天纪录 保存用户号码
服务器端:
向客户端发布系统消息。
接受来自客户端的信息并处理。
1) 登录信息:检查登录信息是否正确,并向客户端返回登录信息。如信息正确,将在
线用户发给该用户,并将该用户的状态发给各在线用户。同时在服务器端显示。
5
2) 聊天信息:转发给消息指定的用户。
3) 申请信息:自动分配8位用户号码,并保存该用户,同时将信息返回给客户端。 4) 用户下线:将此用户下线消息发给各客户端,并改写用户在服务器端的状态。
服务器端 处理申请信息 转发聊天信息 发布系统消息 处理登陆信息
程序中主要变量及函数的功能说明如下:
客户端:
private void login_btn_Click(object sender, EventArgs e) --- 登陆到服务器
private void svrip_tb_TextChanged(object sender,EventArgs e)设置要连接的服务器的地址端口
private void chatrcd_rtb_TextChanged(object sender, EventArgs e)-- 显示好友发送的信息 private void send_btn_Click(object sender, EventArgs e) ---- 给好友发送信息 private void user_tb_TextChanged(object sender, EventArgs e) ----- 申请新的用户
private void chatrcd_rtb_TextChanged(object sender, EventArgs e) ---- 显示服务器消息 private void msg_tb_TextChanged(object sender, EventArgs e) ----- 显示消息输入文本
private void nudge_pb_Click(object sender, EventArgs e)------发送窗口抖动
private void broadcast_rb_CheckedChanged(object sender, EventArgs e)------聊天模式的变更 private void hide_cb_CheckedChanged(object sender, EventArgs e)-------最小化到托盘
服务器端:
用户及发送信息结构体类型:
public void StartUp()-------服务器启动,并且实时更新用户在线信息
public void GetConfig()------配置服务器端口号等信息
private void ThreadFunc(object obj)-----系统对于发送消息、发送抖动等的异常的处理 public void Close()--------关闭服务器
6
2.4 详细设计 2.4.1界面设计
客户端
1) 登陆界面
2) 显示当前状态
3) 最小化到托盘
4) 发送抖动
5) 聊天模式变更
6) 发送接收消息
7
服务器端
1) 服务器启动配置端口号
2) 实时更新在线用户信息
2.4.2程序结构设计
1.客户端:
8
2.服务器端为控制台程序
三.代码及注释
3.1、客户端
a)登陆功能
private void login_btn_Click(object sender, EventArgs e) {
//验证数据合法性 if (!ValidateInfo()) {
return; }
int port = int.Parse(svrport_tb.Text); //向服务器发出连接请求
TCPConnection conn = new TCPConnection(_ipAddr, port); TcpClient _tcpc = conn.Connect(); if (_tcpc == null)
9
{
MessageBox.Show(\无法连接到服务器,请重试!\, \错误\,
MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else {
NetworkStream netstream = _tcpc.GetStream(); //向服务器发送用户名以确认身份
netstream.Write(Encoding.Unicode.GetBytes(user_tb.Text), 0, Encoding.Unicode.GetBytes(user_tb.Text).Length); //得到登录结果
byte[] buffer = new byte[50];
netstream.Read(buffer, 0, buffer.Length);
string connResult = Encoding.Unicode.GetString(buffer).TrimEnd('\\0'); if (connResult.Equals(\)) {
MessageBox.Show(\您的用户名已经被使用,请尝试其他用户名!\, \提示\,
MessageBoxButtons.OK, MessageBoxIcon.Information); return; } else {
string svrskt = svrip_tb.Text + \ + svrport_tb.Text;
chat_frm chatFrm = new chat_frm(user_tb.Text, netstream, svrskt); chatFrm.Owner = this; this.Hide(); chatFrm.Show(); } } } b)发送消息功能
private void send_btn_Click(object sender, EventArgs e) {
string localTxt = null; string sendTxt = null;
string msg = msg_tb.Text.Trim(); if (msg == string.Empty) {
MessageBox.Show(\不能发送空消息\, \提示\,
10
MessageBoxButtons.OK, MessageBoxIcon.Information); return; }
//如果是聊天室模式则向服务器发送广播请求 if (broadcast_rb.Checked) {
localTxt = string.Format(\广播]您在 {0} 对所有人说:\\r\\n{1}\\r\\n\\r\\n\, DateTime.Now, msg);
sendTxt = string.Format(\广播]{0} 在 {1} 对所有人说:\\r\\n{2}\\r\\n\\r\\n\, _username, DateTime.Now, msg); //发送广播请求
_nws.Write(new byte[] { 0, 5 }, 0, 2); } else {
string _receiver = online_cb.Text; if (_receiver == string.Empty) {
MessageBox.Show(\请选择一个接收者!\\n如果没有接受者可选,表明当前只有您一个人在线\\t\,
\发送消息\,
MessageBoxButtons.OK, MessageBoxIcon.Information); return; }
localTxt = string.Format(\私聊]您在 {0} 对 {1} 说:\\r\\n{2}\\r\\n\\r\\n\, DateTime.Now, _receiver, msg);
sendTxt = string.Format(\私聊]{0} 在 {1} 对您说:\\r\\n{2}\\r\\n\\r\\n\, _username, DateTime.Now, msg); //发送接受者用户名
_nws.Write(Encoding.Unicode.GetBytes(_receiver), 0, Encoding.Unicode.GetBytes(_receiver).Length); }
_nws.Write(Encoding.Unicode.GetBytes(sendTxt), 0, Encoding.Unicode.GetBytes(sendTxt).Length);
chatrcd_rtb.AppendText(localTxt); msg_tb.Clear(); }
///
/// 有新消息来时闪烁任务栏并且保持聊天记录内容滚动到最底端
11
///
///
public static extern bool FlashWindow(IntPtr hWnd, bool bInvert); private void chatrcd_rtb_TextChanged(object sender, EventArgs e) {
chatrcd_rtb.ScrollToCaret();
if (this.WindowState == FormWindowState.Minimized) {
FlashWindow(this.Handle, true); } }
///
/// 当窗口恢复后取消任务栏的闪烁效果 /// 当窗口最小化时判断是否要隐藏到系统托盘 ///
///
private void chat_frm_SizeChanged(object sender, EventArgs e) {
switch (this.WindowState) {
case FormWindowState.Normal:
FlashWindow(this.Handle, false); break;
case FormWindowState.Minimized: if (_hideFlag) {
notifyIcon1.Visible = true; this.Visible = false; } break; default: break; } }
///
/// 在线列表下拉框显示之前向服务器发送请求在线列表的命令 ///
///
12
private void online_cb_DropDown(object sender, EventArgs e) {
_nws.Write(new byte[] { 0, 2 }, 0, 2); }
///
///
private void broadcast_rb_CheckedChanged(object sender, EventArgs e) {
if (private_rb.Checked) {
online_cb.Enabled = true; } else {
online_cb.Enabled = false; } }
///
/// 设置最小化到系统托盘的标记值 ///
///
private void hide_cb_CheckedChanged(object sender, EventArgs e) {
_hideFlag = hide_cb.Checked; }
///
if (notifyIcon1.Visible == true) {
return; }
if (this.WindowState == FormWindowState.Minimized) {
this.WindowState = FormWindowState.Normal;
13
}
int i = 0;
Point _old = this.Location;
Point _new1 = new Point(_old.X + 2, _old.Y + 2); Point _new2 = new Point(_old.X - 2, _old.Y - 2); _sp2.Play(); while (i < 4) {
this.Location = _new1; Thread.Sleep(60); this.Location = _new2; Thread.Sleep(60); i++; }
this.Location = _old; } c)抖动窗口功能
private void nudge_pb_Click(object sender, EventArgs e) {
string displayTxt = null;
if (private_rb.Checked && online_cb.Text == string.Empty) {
MessageBox.Show(\非聊天室模式下必须先选择一个接收者!\, \发送闪屏振动\, MessageBoxButtons.OK, MessageBoxIcon.Information); return; }
if (private_rb.Checked) {
_nws.Write(new byte[] { 0, 4 }, 0, 2); string _receiver = online_cb.Text;
_nws.Write(Encoding.Unicode.GetBytes(_receiver), 0, Encoding.Unicode.GetBytes(_receiver).Length);
displayTxt = string.Format(\系统提示]您向 {0} 发送了一个闪屏振动。\\r\\n\\r\\n\, _receiver); } else {
_nws.Write(new byte[] { 0, 3 }, 0, 2);
displayTxt = \系统提示]您向所有人发送了一个闪屏振动。\\r\\n\\r\\n\; }
chatrcd_rtb.AppendText(displayTxt); Nudge();
14
}
d)关闭,断开连接功能
private void close_btn_Click(object sender, EventArgs e) {
DialogResult ret;
ret = MessageBox.Show(\确定与服务器断开连接吗?\, \退出\,
MessageBoxButtons.OKCancel, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
if (ret == DialogResult.OK) {
//向服务器发送离线请求
_nws.Write(new byte[] { 0, 1 }, 0, 2); //结束接受消息的线程 if (_receiveThread != null) {
_receiveThread.Abort(); }
//关闭网络流 _nws.Close(); //关闭父窗口及自身 this.Owner.Close(); this.Close(); } }
3.2服务器端
1) 配置端口号
public void GetConfig()
{
string portParam;
Console.Write(\请输入监听端口,直接回车则接受默认端口8888: \); portParam = Console.ReadLine(); if (portParam != string.Empty) {
if (!int.TryParse(portParam, out _port) || _port < 1023 || _port > 65535) {
_port = 8888;
Console.WriteLine(\端口号不合法,默认端口号被接受!\); } }
15
}
2) 启动服务器监听客户端状态 public void StartUp()
{
IPAddress _ip = Dns.GetHostAddresses(Dns.GetHostName())[0]; _tcpl = new TcpListener(_ip, _port); _tcpl.Start();
Console.WriteLine(\服务器已启动,正在监听...\\n\);
Console.WriteLine(string.Format(\服务器IP:{0}\\t端口号:{1}\\n\, _ip, _port)); while (true) {
byte[] packetBuff = new byte[_maxPacket]; Socket newClient = _tcpl.AcceptSocket(); newClient.Receive(packetBuff);
string userName = Encoding.Unicode.GetString(packetBuff).TrimEnd('\\0'); //验证是否为唯一用户
if (_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(userName)) {
newClient.Send(Encoding.Unicode.GetBytes(\)); continue; } else {
newClient.Send(Encoding.Unicode.GetBytes(\)); }
//将新连接加入转发表并创建线程为其服务 _transmit_tb.Add(userName, newClient);
string svrlog = string.Format(\系统消息]新用户 {0} 在 {1} 已连接... 当前在线人数: {2}\\r\\n\\r\\n\, userName, DateTime.Now, _transmit_tb.Count); Console.WriteLine(svrlog);
Thread clientThread = new Thread(new ParameterizedThreadStart(ThreadFunc)); clientThread.Start(userName); //向所有客户机发送系统消息
foreach (DictionaryEntry de in _transmit_tb) {
string _clientName = de.Key as string; Socket _clientSkt = de.Value as Socket; if (!_clientName.Equals(userName)) {
_clientSkt.Send(Encoding.Unicode.GetBytes(svrlog)); } } }
16
}
3) 关闭服务器
public void Close()
{
if (_tcpl != null) {
_tcpl.Stop(); }
//关闭客户端连接并清理资源 if (_transmit_tb.Count != 0) {
foreach (Socket session in _transmit_tb.Values) {
session.Shutdown(SocketShutdown.Both); }
_transmit_tb.Clear(); _transmit_tb = null; } }
四、课程设计小结:
在做这次课程设计实习之前从未接触过网络编程,这次课程设计实习是在边学习边实践的基础上完成的。本学期课程内容和其他实验同样很丰富,因此实习时间不多,程序效果仍然不够理想,与自己原来的设想仍然有一定差距。通过本次课程设计实习,使我对计算机网络打下了更加牢固的基础。这次课程设计实习可以说是在理解网络的基础上对Socket 编程的一次学习过程,虽然做的不好,但也学到了很多知识,对自己以后进行网络开发一定有很大的帮助。
五、参考文献
1.明月创作室《Visual C#编程精彩百例》 北京人民邮电出版社 2001 2.王昊亮 李刚 《Visual C#程序设计教程》 北京清华大学出版社 2003 3.美国微软公司 《Visual C#2012软件帮助信息》 2012
4.刘亚秋 梁心东 《C#程序设计与应用》 北京电子工业出版社 2002
17
考核情况(由指导老师填写)
项目 得分 考勤 记录 考勤 (10%) 考勤日期 出勤记录 验收 (60%) 报告 (30%) 总分 验 收 情 况
18
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库成都工业学院计算机网络专周报告在线全文阅读。
相关推荐: