C#聊天室代码客户端代码:
using System;
using System.Collections.Generic;
using https://www.wendangku.net/doc/c612381124.html,ponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using https://www.wendangku.net/doc/c612381124.html,;
using https://www.wendangku.net/doc/c612381124.html,.Sockets;
using System.Windows.Forms;
namespace EasyChat
{
public partial class login_frm : Form
{
///
/// IP地址
///
private IPAddress _ipAddr;
#region登录窗体构造函数
///
///构造函数,自动生成
///
public login_frm()
{
InitializeComponent();
}
#endregion
#region登录窗体的私有方法
///
///验证登录信息
///
///
private bool ValidateInfo()
{
if (user_tb.Text.Trim() == string.Empty)
{
MessageBox.Show("请填写用户名!",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
return false;
}
if (!IPAddress.TryParse(svrip_tb.Text, out _ipAddr))
{
MessageBox.Show("IP地址不合法!",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
return false;
}
int _port;
if (!int.TryParse(svrport_tb.Text, out _port))
{
MessageBox.Show("端口号不合法!",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
return false;
}
else
{
if (_port < 1024 || _port > 65535)
{
MessageBox.Show("端口号不合法!",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
return false;
}
}
return true;
}
///
///取消,关闭窗体
///
///
///
private void cancel_btn_Click(object sender, EventArgs e)
{
this.Close();
}
///
///登录
///
///
///
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)
{
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);//该方法将数据读入 buffer 参数并返回成功读取的字节数。如果没有可以读取的数据,则 Read 方法返回 0。
string connResult = Encoding.Unicode.GetString(buffer).TrimEnd('\0');
if (connResult.Equals("cmd::Failed"))
{
MessageBox.Show("您的用户名已经被使用,请尝试其他用户名!",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
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();
}
}
}
///
///初始化登录信息
///
///
///
private void login_frm_Load(object sender, EventArgs e)
{
svrip_tb.Text = "192.168.1.164";
svrport_tb.Text = "8888";
user_tb.Focus();
}
#endregion
}
}
//===================================================================== using System;
using System.Collections;
using System.Collections.Specialized;
using https://www.wendangku.net/doc/c612381124.html,ponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using https://www.wendangku.net/doc/c612381124.html,.Sockets;//++++
using System.Windows.Forms;
using System.Threading;//++++
using System.Runtime.Serialization;//++++
using System.Runtime.InteropServices;//++++
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;//++++
using System.Media;//+++++
namespace EasyChat
{
public partial class chat_frm : Form
{
#region私有字段
///
///当前用户名
///
private string _username = null;
///
///数据缓冲区大小
///
private int _maxPacket = 2048;//2K的缓冲区
///
///用于接受消息的线程
///
private Thread _receiveThread = null;
///
///用于接受和发送的网络流,从登录窗体得到
///
private NetworkStream _nws = null;
///
///服务器套接字的字符串形式,从登录窗体得到
///
private string _svrskt = null;
///
///播放消息提示的播放器
///
private SoundPlayer _sp1 = new SoundPlayer(Properties.Resources.msg); private SoundPlayer _sp2 = new SoundPlayer(Properties.Resources.nudge); ///
///指示是否最小化到托盘
///
private bool _hideFlag = false;
#endregion
#region聊天窗体构造函数
///
///构造函数,得到登录窗体的一些信息
///
///当前用户名
///接受和发送消息的网络流
///服务器套接字的字符串形式
public chat_frm(string userName, NetworkStream nws, string svrskt)
{
InitializeComponent();
_username = userName;
_nws = nws;
_svrskt = svrskt;
}
#endregion
#region聊天窗体的私有方法
///
///保存聊天记录
///
///
///
private void save_btn_Click(object sender, EventArgs e)
{
DialogResult ret;
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "文本文件(*.txt)|*.txt";
sfd.AddExtension = true;
if ((ret = sfd.ShowDialog()) == DialogResult.OK)
{
chatrcd_rtb.SaveFile(sfd.FileName, RichTextBoxStreamType.PlainText); }
}
///
///清除聊天记录
///
///
///
private void clear_btn_Click(object sender, EventArgs e)
{
DialogResult ret;
ret = MessageBox.Show("确定清除吗?清除后不可恢复。",
"提示",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
if (ret == DialogResult.OK)
{
chatrcd_rtb.Clear();
}
}
///
///向服务器发送离线请求,结束接受消息线程,清理资源并关闭父窗体和自身窗体///
///
///
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();
}
}
///
///提取命令
///格式为两个一位整数拼接成的字符串。
///第一位为0表示客户机向服务器发送的命令,为1表示服务器向客户机发送的命令。///第二位表示命令的含义,具体如下:
/// "11"-服务器要求客户机更新在线列表
/// "12"-服务器要求客户机做闪屏振动
/// default-接受用户消息或者系统消息的正文
///
///要解析的包含命令的byte数组,只提取前两个字节
///
private string DecodingBytes(byte[] s)
{
return string.Concat(s[0].ToString(), s[1].ToString());
}
///
///接受消息的线程执行体
///
private void ReceiveMsg()
{
while (true)
{
byte[] packet = new byte[_maxPacket];
_nws.Read(packet, 0, packet.Length);
string _cmd = DecodingBytes(packet);
switch (_cmd)
{
/// "11"-服务器要求客户机更新在线列表
/// "12"-服务器要求客户机做闪屏振动
/// default-接受用户消息或者系统消息的正文
case"11":
{
byte[] onlineBuff = new byte[_maxPacket];
int byteCnt = _nws.Read(onlineBuff, 0, onlineBuff.Length);
IFormatter format = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
stream.Write(onlineBuff, 0, byteCnt);
stream.Position = 0;
StringCollection onlineList = (StringCollection)format.Deserialize(stream); online_cb.Items.Clear();
foreach (string onliner in onlineList)
{
if (!onliner.Equals(_username))
{
online_cb.Items.Add(onliner);
}
}
break;
}
case"12":
{
Nudge();
break;
}
default:
{
string displaytxt = Encoding.Unicode.GetString(packet);
chatrcd_rtb.AppendText(displaytxt);
_sp1.Play();
break;
}
}
}
}
///
///启动接受消息线程并显示相关信息
///
///
///
private void chat_frm_Load(object sender, EventArgs e)
{
_receiveThread = new Thread(new ThreadStart(ReceiveMsg));
_receiveThread.Start();
online_cb.Enabled = false;
user_lb.Text = "当前用户:" + _username;
svrskt_lb.Text = "服务器:" + _svrskt;
}
///
///通过窗体右上角关闭窗体
///
///
///
private void chat_frm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == https://www.wendangku.net/doc/c612381124.html,erClosing)
{
e.Cancel = true;
}
if (e.CloseReason == CloseReason.FormOwnerClosing)
{
return;
}
close_btn_Click(sender, e);
}
///
///发送消息,将接受方用户名和消息正文分开发送,便于服务器端处理
///
///
///
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("不能发送空消息",
"提示",
MessageBoxButtons.OK,
https://www.wendangku.net/doc/c612381124.html,rmation);
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,
https://www.wendangku.net/doc/c612381124.html,rmation);
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();
}
///
///有新消息来时闪烁任务栏并且保持聊天记录内容滚动到最底端,QQ就是这么玩滴~
///
///
///
[DllImport("user32.dll")]
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;
}
}
///
///在线列表下拉框显示之前向服务器发送请求在线列表的命令
///
///
///
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;
}
///
///产生闪屏振动效果
///
private void Nudge()
{
if (notifyIcon1.Visible == true)
{
return;
}
if (this.WindowState == FormWindowState.Minimized)
{
this.WindowState = FormWindowState.Normal;
}
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;
}
///
///发送闪屏振动
///
///
///
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,
https://www.wendangku.net/doc/c612381124.html,rmation);
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();
}
///
///以下是系统托盘菜单的处理函数
///
///
///
private void close_tsmi_Click(object sender, EventArgs e)
{
close_btn_Click(sender, e);
}
private void notifyIcon1_DoubleClick(object sender, EventArgs e) {
comeback_tsmi_Click(sender, e);
}
private void comeback_tsmi_Click(object sender, EventArgs e)
{
notifyIcon1.Visible = false;
this.Visible = true;
this.WindowState = FormWindowState.Normal;
this.BringToFront();
}
#endregion
//private void msg_tb_KeyDown(object sender, KeyEventArgs e)
//{
// if (e.KeyCode == Keys.Control && e.KeyValue == 13)
// {
// send_btn.Click += new EventHandler(send_btn_Click);
// send_btn_Click(sender, e);
// }
//}
private void msg_tb_KeyPress(object sender, KeyPressEventArgs e) {
}
}
}
//============================================================= using System;
using System.Text;
using https://www.wendangku.net/doc/c612381124.html,.Sockets;
using https://www.wendangku.net/doc/c612381124.html,;
namespace EasyChat
{
///
/// TCP连接类,成功连接返回TcpClient引用,否则返回null
///
class TCPConnection
private IPAddress _ip = null;
private int _port;
private TcpClient _tcpc = null;//为 TCP 网络服务提供客户端连接
public TCPConnection(IPAddress ip, int port)
{
_ip = ip;
_port = port;
}
public TcpClient Connect()
{
try
{
_tcpc = new TcpClient();
_tcpc.Connect(_ip, _port);//连接到服务
}
catch (Exception)
{
return null;
}
return _tcpc;
}
}
}
//==================================================== using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Threading;
using https://www.wendangku.net/doc/c612381124.html,.Sockets;
using https://www.wendangku.net/doc/c612381124.html,;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
服务端代码:
namespace EasyChat_Server
{
class Listener
{
#region字段定义
///
///服务器程序使用的端口,默认为8888
///
private int _port = 8888;
///
///接收数据缓冲区大小64K
///
private const int _maxPacket = 64 * 1024;
///
///服务器端的监听器
///
private TcpListener _tcpl = null;
///
///保存所有客户端会话的哈希表
///
private Hashtable _transmit_tb = new Hashtable(); #endregion
#region服务器方法
///
///关闭监听器并释放资源
///
public void Close()
{
if (_tcpl != null)
{
_tcpl.Stop();//如果不为空就停止 tcplistener
}
//关闭客户端连接并清理资源
if (_transmit_tb.Count != 0)//客户端会话的哈希表{
foreach (Socket session in _transmit_tb.Values) {
session.Shutdown(SocketShutdown.Both);
}
_transmit_tb.Clear();
_transmit_tb = null;
}
}
///
///配置监听端口号
///
public void GetConfig()
{
string portParam;
Console.Write("请输入监听端口,直接回车则接受默认端口8888: ");
//portParam = Console.ReadLine();
portParam = Console.ReadLine();
if (portParam != string.Empty)
{
if (!int.TryParse(portParam, out _port) || _port < 1023 || _port > 65535)//很是精炼的语句
{
_port = 8888;
Console.WriteLine("端口号不合法,默认端口号被接受!");
}
}
}
///
///序列化在线列表,向客户端返回序列化后的字节数组
///
///
private byte[] SerializeOnlineList()
{
StringCollection onlineList = new StringCollection();
foreach (object o in _transmit_tb.Keys)
{
onlineList.Add(o as string);//转换语句
}
IFormatter format = new BinaryFormatter();//以二进制格式将对象或整个连接对
//象图形序列化和反序列化。
MemoryStream stream = new MemoryStream();
format.Serialize(stream, onlineList);//保持到内存流
byte[] ret = stream.ToArray();
stream.Close();
return ret;
}
///
///提取命令
///格式为两个一位整数拼接成的字符串。
///第一位为0表示客户机向服务器发送的命令,为1表示服务器向客户机发送的命令。///第二位表示命令的含义,具体如下:
/// "01"-离线
/// "02"-请求在线列表
/// "03"-请求对所有人闪屏振动
/// "04"-请求对指定用户闪屏振动
/// "05"-请求广播消息
/// default-转发给指定用户
///
///要解析的包含命令的byte数组,只提取前两个字节
///
private string DecodingBytes(byte[] s)
{
return string.Concat(s[0].ToString(), s[1].ToString());
}
///
///线程执行体,转发消息-------------------
///
///传递给线程执行体的用户名,用以与用户通信 private void ThreadFunc(object obj)
{
//通过转发表得到当前用户套接字
Socket clientSkt = _transmit_tb[obj] as Socket;
while (true)
{
try
{
//接受第一个数据包。
//仅有两种情况,一为可以识别的命令格式,否则为要求转发给指定用户的用户名。//这里的实现不够优雅,但不失为此简单模型的一个解决之道。
byte[] _cmdBuff = new byte[128];
clientSkt.Receive(_cmdBuff);
string _cmd = DecodingBytes(_cmdBuff);
/// "01"-离线
/// "02"-请求在线列表
/// "03"-请求对所有人闪屏振动
/// "04"-请求对指定用户闪屏振动
/// "05"-请求广播消息
/// default-转发给指定用户
switch (_cmd)
{
case"01":
{
_transmit_tb.Remove(obj);
string svrlog = string.Format("[系统消息]用户 {0} 在 {1} 已断开... 当前在线人数: {2}\r\n\r\n", obj, DateTime.Now, _transmit_tb.Count);
Console.WriteLine(svrlog);
//向所有客户机发送系统消息
foreach (DictionaryEntry de in _transmit_tb)
{
string _clientName = de.Key as string;
Socket _clientSkt = de.Value as Socket;
_clientSkt.Send(Encoding.Unicode.GetBytes(svrlog));//给其他用户通知现在上线的用户
}
Thread.CurrentThread.Abort();
break;
}
case"02":
{
byte[] onlineBuff = SerializeOnlineList();
//先发送响应信号,用于客户机的判断,"11"表示服务发给客户机的更新在线列表的命令clientSkt.Send(new byte[] { 1, 1 });
clientSkt.Send(onlineBuff);
break;
}
case"03":
{
string displayTxt = string.Format("[系统提示]用户 {0} 向您发送了一个闪屏振动。\r\n\r\n", obj);
foreach (DictionaryEntry de in _transmit_tb)
{
string _clientName = de.Key as string;
Socket _clientSkt = de.Value as Socket;
if (!_clientName.Equals(obj))
{
//先发送响应信号,用于客户机的判断,"12"表示服务发给客户机的闪屏振动的命令
_clientSkt.Send(new byte[] { 1, 2 });
_clientSkt.Send(Encoding.Unicode.GetBytes(displayTxt));
实现用C#做一个聊天室客户端的代码: using System; using System.Collections.Generic; using https://www.wendangku.net/doc/c612381124.html,ponentModel; using System.Data; using System.Drawing; using System.Text; using https://www.wendangku.net/doc/c612381124.html,; using https://www.wendangku.net/doc/c612381124.html,.Sockets; using System.Windows.Forms; namespace EasyChat { public partial class login_frm : Form { ///
if (user_tb.Text.Trim() == string.Empty) { MessageBox.Show("请填写用户名!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } if (!IPAddress.TryParse(svrip_tb.Text, out _ipAddr)) { MessageBox.Show("IP地址不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } int _port; if (!int.TryParse(svrport_tb.Text, out _port)) { MessageBox.Show("端口号不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } else { if (_port < 1024 || _port > 65535) { MessageBox.Show("端口号不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } } return true; } ///
目录 1.需求分析 (2) 2.相关知识............................................... - 3 -2.1W INSOCK介绍 (3) 2.2MFC类CA SYNCSOCKET和CS OCKET (3) 2.3利用CS OCKET进行有连接的通信 (4) 3.详细设计................................... 错误!未定义书签。 3.1客户端的实现 (4) 3.2服务端的实现 (8) 4.程序运行结果.......................................... - 13 -4.1服务器端 .. (13) 4.2客户端 (13) 5.参考文献 ................................................................................................................... 错误!未定义书签。
1.需求分析 当前是数字信息时代,网络时代,任何一种编辑工具都不能忽视在网络上的应用,并且随着Internet 的普及和宽带技术的成熟,越来越多的用户进入网络世界中享用浏览新闻、查询信息、发送邮件、在线观看电影等服务,享受网络带来的便利和办公的高效,与此同时一个新型的Web应用程序为网民之间提供了一个实时通信的功能和场所,这就是聊天室。 在网络早期就开始盛行,不论是BBS,IRC 都有类似网上聊天室的机制。聊天室为网友提供了实时性对话的渠道,是网络上极为流行的一项服务。 聊天室适用于网上会议或闲聊的一些场合。聊天室为网友提供了较好的交友环境,网友之间相互以文字交谈,在形式上有点类似笔友的性质,却大大节省了书信往返的时间,这也是网上交友之所以如此热门的原因。 聊天室的设计目标 本课题是建立聊天通信模型,设计一个聊天室软件,包括服务器端和客户端,主要功能为: 服务器端功能: 1、初始化socket, 创建服务器端。 2、维护一个链表,保存所有用户的IP地址、端口信息。 3、接受用户传送来的聊天信息,然后向链表中的所用用户转发。 4、接受用户传送来的连接判断命令,并向用户发出响应命令。 客户端功能: 客户端界面上的两个文本框,一个用于显示接受的聊天信息,一个用来接受用户输入的聊天信息。当按下“发送”按钮时将信息发送给服务器。 通过本课题的毕业设计,可以比较深入的了解和掌握WINSOCK控件基本属性、方法和事件,理解网络聊天通信的概念,输控制协议(TCP)进行数据交流,初步掌握网络聊天通信程序的设计方法。并能巩固和扩展大学期间的学习内容,进行项目的设计开发训练,更好的适应社会的需求。
Java程序课程设计任务书 JAVA聊天室的系统的设计与开发 1.主要内容: 用JA V A实现基于C/S模式的聊天室系统。聊天室分为服务器端和客户端两部分,服务器端程序主要负责侦听客户端发来的信息,客户端需要登陆到服务器端才可以实现正常的聊天功能。 2.具体要求(包括技术要求等): 系统的功能要求: A.服务器端主要功能如下: 1.在特定端口上进行侦听,等待客户端连接。 2.用户可以配置服务器端的侦听端口,默认端口为8888。 3.向已经连接到服务器端的用户发送系统消息。 4.统计在线人数。 5.当停止服务时,断开所有的用户连接。 B.客户端的主要功能如下: 1.连接到已经开启聊天服务的服务器端。 2.用户可以配置要连接的服务器端的IP地址和端口号。 3.用户可以配置连接后显示的用户名。 4.当服务器端开启的话,用户可以随时登录和注销。 5.用户可以向所有人或某一个人发送消息。 学习并掌握一下技术:Java JavaBean 等 熟练使用一下开发工具:Eclipse,JCreator 等 实现系统上诉的功能。 3.进度安排: 12月28日~ 12月29日:课程设计选题,查找参考资料 12月30日~ 1月1日:完成系统设计 1月2日~ 1月5日:完成程序代码的编写 1月6日:系统测试与完善 1月7日:完成课程设计报告,准备答辩 4.主要参考文献: [1].张广彬孟红蕊张永宝.Java课程设计(案例精编)[M].清华大学出版社.2007年版
摘要 在网络越来越发达的今天,人们对网络的依赖越来越多,越来越离不开网络,由此而产生的聊天工具越来越多,例如,国外的ICQ、国内腾讯公司开发的OICQ。基于Java网络编程的强大功能,本次毕业设计使用Java编写一个聊天系统。 一般来说,聊天工具大多数由客户端程序和服务器程序外加服务器端用于存放客户数据的数据库组成,本系统采用客户机/服务器架构模式通过Java提供的Soket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能用多线程可完成多点对多点的聊天,数据库管理系统用SQL Server2000完成并通过JDBC-ODBC桥访问数据库。 本系统建立在JAVA平台上,系统的设计使用了面向对象技术和面向对象的设计原则。系统采用C/S结构,客户端与客户端以及客户端与服务器端之间通过Socket传送消息。使用JAVA语言编写,开发工具采用Eclipse。服务器端设计与实现过程中,采用了多线程技术,可以在单个程序当中同时运行多个不同的线程,执行不同的任务。大大增强了程序对服务器资源的利用。 聊天系统完成后将可进行多人对多人的聊天,对好友进行添加、删除,对新用户的注册,发送消息、接受消息等等功能。 关键词:多线程;客户机/服务器;JA V A ;Socket ;Eclipse ;TCP/IP
Java 聊 天 室 制作人:_____杨永生_____ 制作时间:2012.9.26 目录 1本文简介 (2) 2聊天室截图与说明 (2) 2.1用Java编译: (2) 2.2服务器登录界面 (2) 2.3服务器窗口 (2) 2.4客服端登录界面 (3) 2.5客服端窗口 (3) 3服务器端 (6) 3.1MyServer()方法 (6) 3.2Login()方法 (10) 3.3Time()方法 (13) 4客户端 (14) 4.1MyClient()方法 (14) 4.2Login()方法 (18) 4.3Time()方法 (20)
1 本文简介 这是一个简单的Java聊天室,仅提供给一些刚学Java的学生做实验,本文也是仅供参考. 本文代码都有注释,希望读者能读懂代码,本实验内部还有一些错误,比如只能一条一条的发信息,不能连发,希望能解决本问题的朋友能给我发信息,我的QQ号就是百度号! 2 聊天室截图与说明 2.1 用Java编译: 本代码有七个类,放在六个java文件中,类名在下方希望读者自己观看, 2.2 服务器登录界面 要先运行服务器端的程序 用户名:y 密码:1 用户名密码可以自己设定点击确定可以登录,2秒后到服务端界面 2.3 服务器窗口
聊天室的IP为本机的网络虚拟IP,在任何电脑上都能用,端口应设置在1024以后, 2.4 客服端登录界面 和服务器端的登录一样 2.5 客服端窗口
当登录上后客服端就显示已经连接了,此时服务器端的窗口如下
由于本程序设计的不是很完整,具体的聊天要先从客服端开始: 在客服端输入一条聊天内容后按确定,在服务器端就可以收到信息,之后客户端不能输入了,要等待服务器端来信息后才能继续输入信息. 想要结束聊天,直接可以关闭窗口,也可以输入’bye’后断开聊天
聊天室客户端主要代码 CSocket.h class CChat_ClientDlg; //dlg类声明 class CCSocket : public CSocket { DECLARE_DYNAMIC(CCSocket); //动态类声明 public: CCSocket(CChat_ClientDlg* pDlg); //添加构造函数的入口函数 virtual ~CCSocket(); CChat_ClientDlg* m_pDlg;//指向对话框的指针变量。 virtual void OnReceive(int nErrorCode); //CSocket类添加的事件响应函数 }; CSokcet.cpp #include"stdafx.h" #include"Chat_Client.h" #include"CSocket.h" #include"Chat_ClientDlg.h" //自行添加的头文件,调用到dlg类的成员函数。 IMPLEMENT_DYNAMIC(CCSocket,CSocket) //动态类声明 // CCSocket构造函数、析构函数 CCSocket::CCSocket(CChat_ClientDlg* pDlg) { m_pDlg=pDlg; //初始化对话框指针变量 } CCSocket::~CCSocket() { m_pDlg=NULL; } // CCSocket 成员函数
void CCSocket::OnReceive(int nErrorCode) { // TODO: 在此添加专用代码和/或调用基类 CSocket::OnReceive(nErrorCode); if(nErrorCode==0) m_pDlg->OnReceive(); //调用对话框类的对应函数} CChat_ClientDlg.h #pragma once #include"afxwin.h" #include"Msg.h" //自行添加的包含头文件 #include"CSocket.h" //自行添加的包含头文件 class CCSocket; //自行添加的类声明 // CChat_ClientDlg 对话框类构造函数、析构函数 …… …… protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnBnClickedButtonConnect(); //按钮单击事件响应函数声明 afx_msg void OnBnClickedButtonClose(); afx_msg void OnBnClickedButtonSend(); afx_msg void OnDestroy(); //对话框销毁事件响应函数声明DECLARE_MESSAGE_MAP() public: CString m_strSName; // 服务器名称 CString m_strCName; // 客户名称 //控件变量 UINT m_nPort; // 端口号,即聊天室频道 CButton m_btnConnect; CButton m_btnClose; CString m_strMsg;
C#是微软随着https://www.wendangku.net/doc/c612381124.html,新推出的一门语言。它作为一门新兴的语言,有着C++的强健, 又有着VB等的RAD特性。而且,微软推出C#主要的目的是为了对抗Sun公司的Java。大家都知道Java语言的强大功能,尤其在网络编程方面。于是,C#在网络编程方面也自然不甘落后于人。本文就向大家介绍一下C#下实现套接字(Sockets)编程的一些基本知识,以期能使大家对此有个大致了解。首先,我向大家介绍一下套接字的概念。 套接字基本概念: 套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。 套接字可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的套接字间进行通信。不过只要底层的通信协议允许,不同类型的套接字间也照样可以通信。套接字有两种不同的类型:流套接字和数据报套接字。 套接字工作原理: 要通过互联网进行通信,你至少需要一对套接字,其中一个运行于客户机端,我们称之为ClientSocket,另一个运行于服务器端,我们称之为ServerSocket。 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。 所谓服务器监听,是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。 所谓客户端请求,是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。 所谓连接确认,是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。 C#中的套接字编程实例:
聊天室介绍: ---- 聊天室基本原理是,抛开OGI和WWW服务器,根据HTML规范,接收到浏览器的请求以后,模仿WWW服务器的响应,将聊天内容发回浏览器。在浏览器看来就像浏览一个巨大的页面一样始终处于页面联接状态,这就是一个专门的聊天服务器,一个简化了的WWW服务器。 ----这样相比CGI方式来说,聊天室的优点就很明显: 不需要专门的WWW服务器,在聊天服务器里完成必要的工作,避开耗时的CGI 过程。 如果使用单进程服务器,就不需要每次产生新进程。 数据交换完全在内存中进行,不用读写文件。 不需要定时刷新,减少屏幕的闪烁,减少对服务器的请求次数。 ----下面我们来看看具体实现流程。 一、聊天服务器实现流程 ----用户数据输入都是通过URL传送,下面是几个URL实例,结合后面客户端流程,可以更好地理解系统结构。 ----这是一个用户名密码均为…aaa''''的聊天用户登录系统,说了一句话“hello”,然后退出所产生的一系列请求,其中密码用系统函数crypt加密过: 二、客户端具体登录过程 ---- 我们先看看聊天界面: ----聊天界面由三个frame组成,其中chat帧是聊天内容显示部分,talk帧是用户输入部分,包括内容输入、动作、过滤以及管理功能都在这一帧输入,names是在线名单显示部分,这一部分是定时刷新的。 ---- 让我们从浏览器的角度来看看进入聊天室的过程。 ---- 1.首先浏览器请求页面: ---- 此时产生了一个连接到服务器聊天端口的联接,并发送了一行数据: ----2.服务器生成一个session ID,验证密码以后,发回: ----然后服务器关闭联接。 ----3.浏览器收到以上文件后,将会依次打开三个联接(其中的$sid和$encrypt_pass是变量):----这三个联接中的第一个联接chat在整个聊天过程中都是保持联接的,这样从浏览器角度来看,就是一个始终下载不完的大页面,显示效果上就是聊天内容不是靠刷新来更新,而是不断地向上滚动。通过察看代码可以看到,然后就是不断增加的聊天内容. ---- 另外两个联接在页面发送完毕以后,就关闭了。 ---- 这样一次登录聊天室实际上有四次联接,但登录完成以后,只有chat帧的是保持联接的,用于接收来自服务器的聊天信息,这是聊天室的关键所在。 ----在服务器端储存了所有参加聊天的客户的chat,当有人发言时,服务器就向所有chat发送聊天内容。 ---- Talk与names帧的html实际上和普通的form是一样的。 ---- 4.在用户登录以后,服务器端保存了一张包括用户信息的表格: ---- 在perl实现中,我们使用哈希结构储存信息,以session ID 作为key索引。这样的存储结构便于存取数据,回收空间。每个客户信息是一个数组: [name,passwd,privilige,filter,login_time,color]:储存chat帧联接name:用户名passwd:密码privilige:权限filter:某个用户的过滤列表的引用(reference)login_time:记录登录时间,以便以后清除一些超时联接color:用户聊天颜色 ----以上用户数据大部分是在login阶段,用户通过密码验证以后填入的。只有chat要等到chat帧显示以后才得到。如果超过一定时间,还是没有填入,说明浏览器取得主框架以后连接中断了,这时候就需要删除该用户数据。
目录 1 引言 (1) 1.1项目背景 (1) 1.2国内外研究现状 (2) 1.3主要思路 (2) 2 需求分析 (4) 2.1设计目标 (4) 2.2开发环境 (4) 2.3功能要求 (4) 2.4实现效果 (5) 2.5网络聊天室系统E-R图 (6) 3 系统概要设计 (7) 3.1需求规定 (7) 3.2系统层次结构 (7) 3.3系统数据结构设计 (8) 3.4系统流程图 (9) 4 详细设计及编码方式 (11) 4.1登录功能模块设计 (11) 4.2注册功能模块设计 (13) 4.3房间选择功能模块设计 (14) 4.4聊天室主界面设计 (16) 4.4.1聊天室整体框架设计 (16) 4.4.2导航区设计 (18) 4.4.3显示在线区用户设计 (19) 4.4.4显示聊天信息区设计 (20) 4.4.5发送信息区设计 (21) 4.5修改密码功能模块设计 (23) 4.6选择头像功能模块设计 (25)
4.7用户管理功能模块设计 (26) 5 系统测试 (29) 5.1系统测试目标 (29) 5.2系统测试内容 (29) 5.3系统测试结论 (30) 6 结论 (31) 参考文献 (32) 致谢 (33)
1引言 1.1项目背景 21世纪的一些重要特征就是数字化、网络化和信息化,它是一个以网络为核心的信息时代。要实现这些就要依靠完善的网络,因此网络现在已经成为信息社会的命脉和发展知识经济的重要基础。网络对社会生活的方方面面已经产生了不可估量的影响[1]。 截止2010年6月底,我国网民规模达4.2亿,互联网普及率持续上升增至31.8%,这其中手机网民增长明显,半年内新增4334万,达到2.77亿人[2]。我国网民的互联网应用表现出商务化程度迅速提高、娱乐化倾向继续保持、沟通和信息工具价值加深的特点。社交网站、即时通信使用率增长较快,半年用户增长19.6%和11.7%[3]。 由于交通的发达,现代人会经常地流动,因此面对面的亲身交流往往不可企及。而网络恰好就为这些希望能够经常交流的人们提供了加强联系、增进交流的平台。社交网络源自网络社交,网络社交的起点是电子邮件。早期的电子邮件解决了远程邮件传输的问题,至今它也是互联网上最普及的应用,而后BBS把网络社交推进了一步。即时通信的出现更像是前面两个社交工具的升级版本,提高了即时效果和同时交流能力[4]。社科院2005年调查关注了人们使用这些网络交流工具的情况,调查表明,人们最常用的网络交流工具为电子邮件,其次是ICQ和聊天[5]。 聊天室作为因特网应用工具之一,在社会上起着越来越重要的作用。70年代末,有一种冒险游戏,在这个游戏中,就有一些对话,它帮助了互联网中聊天室的诞生。也就是IRC。IRC是芬兰人Jarkko Oikarnen于1988年首创的一种在网络中进行聊天的协议。直到今天,大部分聊天室都会以IRC为基础。网络聊天室刚开始的时候是以文本聊天为主,后来出现了语音聊天,到了今天,视频、语音、文字都很好的融入到了聊天工具当中。网络聊天之所以不同于现实聊天,是因为网络聊天是在虚拟的环境中完成的,从某种意义上讲,网络聊天是现实聊天的延伸。虚拟的网络聊天客服了现实聊天中的空间限制,是的聊天的空间大大的扩展了。网络聊天因其技术的发展实现了空间的无限扩展,形成了只要有互联网,不同地方的人们就可以聊天的状况,使得现实生活的交往范围大大扩展了。随着互联网技术的不断发
服务器端代码: import .*; import .*; import .*; import .*; public class Server { private static final int PORT=6666; G_Menu gm=new G_Menu(); private ServerSocket server; public ArrayList
实验5 掌握简单的网络通讯技术 实验6 掌握基于典型协议的的网络通讯技术 一实验目的 1.熟悉Socket的通讯机制,了解网络程序的设计方法。 2. 熟悉典型协议的通讯机制,掌握基于它们的网络系统设计方法。如TCP、UDP。 二实验环境 1.Windows7 2.Visual C++ 6.0 三实验程序设计 1.实验原理 1.C/S模式 C/S模式是指一个服务器同时为多个客户端服务。并发性是C/S模式的的基础,正是由于并发性的支持,多个客户端能够获得同一种服务,而不必等待服务器完成对上一个请求的处理。 在C/S模式中,当请求到达服务器时,服务器将它交给一个控制线程,它能与已有的线程并发的执行。 在设计并发服务器时,一般服务器代码由两部分组成,第一部分代码负责监听并接收客户端的请求,还负责为客户端请求创建新的服务线程;另一部分代码负责处理单个客户机请求,如与客户机交换数据,提供具体服务。 下图所示为服务器创建多个线程来为多个客户机服务。 2.基于TCP的socket通信 服务器与客户端是通过套接字来进行通信的。 在基于TCP的网络通信程序中,首先服务器端通过socket()函数创建套接字,然后通过bind()函数来命名套接字,调用listen()函数开启服务器端的监听。接着执行accept()函数来接收客户的连接,服务器阻塞等待客户连接请求,直到有客户请求连接。 客户端创建套接字,接着通过connect()函数请求连接服务器,连接成功后,就可以与服务器进行通信了。 服务器与客户机通过send()各recv()调用来进行信息的发送和接收。只有当有信息可接收时,recv()才返回,否则将阻塞。
服务器端代码: import https://www.wendangku.net/doc/c612381124.html,.*; import java.io.*; import java.util.*; import java.util.concurrent.*; import javax.swing.*; public class Server { private static final int PORT=6666; G_Menu gm=new G_Menu(); private ServerSocket server; public ArrayList
/**建数据库*/ if EXISTS(select*from sysdatabases where name='ChatRoom') drop database ChatRoom create database ChatRoom on primary( name='ChatRoom_data', filename='F:\JAVA\JAVA高级\聊天室\Data\ChatRoom_data.mdf', size= 5mb, maxsize= 100mb, filegrowth= 15% ) log on ( name='ChatRoom_log', filename='F:\JAVA\JAVA高级\聊天室\Data\ChatRoom_data.ldf', size= 2mb, filegrowth= 1mb ) go use ChatRoom GO /**建表*/ drop table chatMsg create table chatMsg( msg_id int identity (1,1), client_IP varchar(20), client_msg varchar(500) ) /**创建存储过程*/ if exists(select*from sysobjects where name='p_chatMsg_Add') drop proc p_chatMsg_Add go create proc p_chatMsg_Add @sIP varchar(20), @sMsg varchar(500) as
begin insert into chatMsg(client_IP,client_msg)values (@sIP,@sMsg) end select*from chatMsg package https://www.wendangku.net/doc/c612381124.html,.ChatRoomServer; import java.util.ArrayList; public class Broadcast implements Runnable { ArrayList
网络聊天室程序-需求分析报告 班级 :通信工程01班 小组成员:25黄浩(组长)、 10何昶卫、 05徐志庆、 26卢翱、 24罗泽思、
目录 1、引言--------------------------------------------------------------------------------------------------- 1 1.1编写目的----------------------------------------------------------------------------------------- 1 1.2项目背景----------------------------------------------------------------------------------------- 1 1.3预备知识----------------------------------------------------------------------------------------- 1 1.4参考资料----------------------------------------------------------------------------------------- 2 2、项目简介---------------------------------------------------------------------------------------------2 2.1项目要求----------------------------------------------------------------------------------------- 2 2.2整体思路----------------------------------------------------------------------------------------- 3 2.3功能需求分析----------------------------------------------------------------------------------- 3 3、系统分析与设计-----------------------------------------------------------------------------------4 3.1设计思路------------------------------------------------------------------------------------------4 3.2开发环境及工具------------------------------------------------------------------------------- 4 3.3服务器结构-------------------------------------------------------------------------------------- 4 3.4客户端结构-------------------------------------------------------------------------------------- 5 3.5功能实现细节----------------------------------------------------------------------------------- 5 3.5.1客户端运行细节-------------------------------------------------------------------------- 6 3.5.2服务器端运行细节---------------------------------------------------------------------- 7 4、用户注册、登录流程以及系统界面---------------------------------------------------------8 4.1用户注册过程-----------------------------------------------------------------------------------8 4.2用户登录过程-----------------------------------------------------------------------------------8 4.3服务器界面-------------------------------------------------------------------------------------- 9 4.4登录界面----------------------------------------------------------------------------------------- 9 4.5聊天室界面-----------------------------------------------------------------------------------------------10
C#聊天室代码客户端代码: using System; using System.Collections.Generic; using https://www.wendangku.net/doc/c612381124.html,ponentModel; using System.Data; using System.Drawing; using System.Text; using https://www.wendangku.net/doc/c612381124.html,; using https://www.wendangku.net/doc/c612381124.html,.Sockets; using System.Windows.Forms; namespace EasyChat { public partial class login_frm : Form { ///
MessageBox.Show("请填写用户名!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } if (!IPAddress.TryParse(svrip_tb.Text, out _ipAddr)) { MessageBox.Show("IP地址不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } int _port; if (!int.TryParse(svrport_tb.Text, out _port)) { MessageBox.Show("端口号不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } else { if (_port < 1024 || _port > 65535) { MessageBox.Show("端口号不合法!", "提示", MessageBoxButtons.OK, https://www.wendangku.net/doc/c612381124.html,rmation); return false; } } return true; } ///
C语言聊天室代码(服务端) /* server.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include<Winsock2.h> #include<process.h> #pragma comment(lib,"ws2_32.lib") #include<windows.h> #define REG 1 //表示注册 #define LOGIN 2 //表示登陆 #define TALK_PRIVATE 3 //表示私聊 #define TALK_PUBLIC 4 //表示群聊 #define LIST 11 //表示显示所有在线不隐身用户 #define EXIT 12 //退出客户端 struct user { char username[50]; char password[50]; int cmd; char target_user[20]; char content[50]; }; struct user user; char *file_name(char *p,struct user user) //生成登陆名.txt文件函数 { int i = 0; int username_len; username_len = strlen(https://www.wendangku.net/doc/c612381124.html,ername); strcpy(p,https://www.wendangku.net/doc/c612381124.html,ername); strcat(p,".txt"); return p;