




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
实验六 即时通信系统1实验目的(1)练习TcpClient和TcpListener的用法。(2)练习NetworkStream的用法。(3)练习StreamReadr和StreamWriter的用法。(4)练习线程的创建和使用方法。 (5)练习解决TCP协议消息边界问题的另一种方法。2建议用时建议用4-6小时完成本实验,或者根据自己的理解情况调整实际需要的时间。3实验内容开发一个简单的基于TCP的即时通信系统,服务器端和客户端设计界面分别如下图所示。功能要求:(1)任何一个客户端,均可以与服务器进行通信。(2)服务器要能显示客户端连接的状态,当客户端连接成功后,要自动及时告知客户端已经连接成功的信息。(3)客户端和服务器建立连接后,即可以和服务器聊天,也可以和其他任何客户聊天,用StreamReader和StreamWriter对象实现字符串的接收和发送。(4)不论客户端何时退出程序,服务器都要做出正确判断,并显示该客户连接和断开连接的情况。 图1-3 客户端设计界面图1-2 服务器设计界面 4实验要求(1)使用强类型的List泛型列表userList保存连接的用户。(2)定义委托解决一个线程调用另一个线程控件的问题。5实验步骤提示服务器端:(1)创建一个名为SyncChatServer的Windows应用程序,将Form1.cs换名为MainForm.cs,设计界面如图1-2所示。(2)在解决方案资源管理器中,鼠标右键单击项目名,选择【添加】【类】,添加一个类文件User.cs,用于保存与客户通信需要的信息。参考代码如下。class User public TcpClient client get; private set; public StreamReader sr get; private set; public StreamWriter sw get; private set; public User(TcpClient client) this.client = client; NetworkStream netStream = client.GetStream(); sr = new StreamReader(netStream, System.Text.Encoding.UTF8); sw = new StreamWriter(netStream, System.Text.Encoding.UTF8); public void Close() sr.Close(); sw.Close(); client.Close(); (3)在SyncChatServer中添加对应的代码和事件。代码如下。public partial class MainForm : Form / 保存连接的所有用户 private List userList = new List(); / 使用的本机IP地址 IPAddress localAddress; / 监听端口 private const int port = 51888; private TcpListener myListener; / 是否正常退出所有接收线程 bool isNormalExit = false; public MainForm() InitializeComponent(); listBoxStatus.HorizontalScrollbar = true; IPAddress addrIP = Dns.GetHostAddresses(Dns.GetHostName(); localAddress = addrIP0; buttonStop.Enabled = false; / 【开始监听】按钮的Click事件 private void buttonStart_Click(object sender, EventArgs e) myListener = new TcpListener(localAddress, port); myListener.Start(); AddItemToListBox(string.Format(开始在0:1监听客户连接, localAddress, port); /创建一个线程监听客户端连接请求 Thread myThread = new Thread(ListenClientConnect); myThread.Start(); buttonStart.Enabled = false; buttonStop.Enabled = true; / 接收客户端连接 private void ListenClientConnect() while (true) TcpClient newClient = null; try /等待用户进入 newClient = myListener.AcceptTcpClient(); catch /当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常 /因此可以利用此异常退出循环 break; /每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息 User user = new User(newClient); Thread threadReceive = new Thread(ReceiveData); threadReceive.Start(user); AddUser(user); SendIPAddressesToClients(); /显示工作状态 AddItemToListBox(string.Format(0进入, newClient.Client.RemoteEndPoint); AddItemToListBox(string.Format(当前连接用户数:0, userList.Count); / / 接收、处理客户端信息,应该给每客户都创建1个线程执行此方法 / / 客户信息 private void ReceiveData(object userState) User user = (User)userState; TcpClient client = user.client; while (isNormalExit = false) string receiveString = null; try /从网络流中读出字符串,此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串 receiveString = user.sr.ReadLine(); catch if (isNormalExit = false) AddItemToListBox(string.Format(与0失去联系,已终止接收该用户信息, client.Client.RemoteEndPoint); RemoveUser(user); break; AddItemToListBox(string.Format(来自0:1, user.client.Client.RemoteEndPoint, receiveString); string splitString = receiveString.Split(,); string sendString = ; switch (splitString0) case Login: /格式:Login sendString = Hello,我是服务器,你好!; SendToClient(user, sendString); break; case Logout: /格式:Logout AddItemToListBox(string.Format(0退出, user.client.Client.RemoteEndPoint); RemoveUser(user); /将变化后的用户IP发送给所有用户 /SendIPAddressesToClients(); return; case Talk: /格式:Talk,对话内容 if (splitString1 = client.Client.LocalEndPoint.ToString() | splitString1 = Dns.GetHostName() +:+ port.ToString() AddItemToListBox(string.Format(0说:1, client.Client.RemoteEndPoint, receiveString.Substring(splitString0.Length + splitString1.Length + 2); else /向交谈双方分别发送信息 receiveString = receiveString.Insert(5, client.Client.RemoteEndPoint.ToString()+,); /发起交谈方 SendToClient(user, receiveString); /接受交谈方 for (int i = 0; i userList.Count; i+) if (userListi.client.Client.RemoteEndPoint.ToString() = splitString1) SendToClient(userListi, receiveString); break; default: AddItemToListBox(什么意思啊: + receiveString); break; / / 发送信息给客户 / / 用于区分是哪个客户 / 要发送的信息 private void SendToClient(User user, string str) try /将字符串写入网络流,此方法会自动附加字符串长度前缀 user.sw.WriteLine(str); user.sw.Flush(); AddItemToListBox(string.Format(向0发送:1, user.client.Client.RemoteEndPoint, str); catch AddItemToListBox(string.Format(向0发送信息失败, user.client.Client.RemoteEndPoint); private delegate void SendIPAddressesToClientsDelegate(); / / 把和服务器连接的所有客户端的端点信息发给每个客户端 / private void SendIPAddressesToClients() if (this.InvokeRequired = true) SendIPAddressesToClientsDelegate d = new SendIPAddressesToClientsDelegate(SendIPAddressesToClients); this.Invoke(d); else StringBuilder temp = new StringBuilder(comboBoxReceiver.Items.Count * 20); temp.Append(AllIP); int intLen = comboBoxReceiver.Items.Count; for (int i = 0; i intLen; i+) temp.AppendFormat(,0, comboBoxReceiver.Itemsi); for (int j = 0; j intLen; j+) SendToClient(userListj, temp.ToString(); private delegate void AddUserDelegate(User user); / / 添加用户 / private void AddUser(User user) if (this.InvokeRequired = true) AddUserDelegate d = new AddUserDelegate(AddUser); this.Invoke(d, user); else userList.Add(user); comboBoxReceiver.Items.Add(user.client.Client.RemoteEndPoint); private delegate void RemoveUserDelegate(User user); / / 移除用户 / private void RemoveUser(User user) if (this.InvokeRequired = true) RemoveUserDelegate d = new RemoveUserDelegate(RemoveUser); this.Invoke(d, user); else comboBoxReceiver.Items.Remove(user.client.Client.RemoteEndPoint); comboBoxReceiver.Text = string.Empty; userList.Remove(user); user.Close(); AddItemToListBox(string.Format(当前连接用户数:0, userList.Count); private delegate void AddItemToListBoxDelegate(string str); / / 在ListBox中追加状态信息 / / 要追加的信息 private void AddItemToListBox(string str) if (listBoxStatus.InvokeRequired = true) AddItemToListBoxDelegate d = new AddItemToListBoxDelegate(AddItemToListBox); this.Invoke(d, str); else listBoxStatus.Items.Add(str); listBoxStatus.SelectedIndex = listBoxStatus.Items.Count - 1; listBoxStatus.ClearSelected(); / / 【停止监听】按钮的Click事件 / private void buttonStop_Click(object sender, EventArgs e) AddItemToListBox(开始停止服务,并依次使用户退出!); isNormalExit = true; for (int i = userList.Count - 1; i = 0; i-) RemoveUser(userListi); /通过停止监听让myListener.AcceptTcpClient()产生异常退出监听线程 myListener.Stop(); buttonStart.Enabled = true; buttonStop.Enabled = false; / / 【发送】按钮的Click事件 / private void buttonSend_Click(object sender, EventArgs e) int index = comboBoxReceiver.SelectedIndex; if (index = -1) MessageBox.Show(请先选择接收方,然后再单击发送); else User user = (User)userListindex; SendToClient(user, textBoxSend.Text); textBoxSend.Clear(); / / 关闭窗口时触发的事件 / private void MainForm_FormClosing(object sender, FormClosingEventArgs e) if (myListener != null) /触发buttonStop的Click事件 buttonStop.PerformClick(); / / 在控件具有焦点且用户按下并释放某键后触发的事件 / private void textBoxSend_KeyPress(object sender, KeyPressEventArgs e) if (e.KeyChar = (char)Keys.Return) /触发buttonSend的Click事件 buttonSend.PerformClick(); 客户端:(1)创建一个名为SyncChatClient的Windows应用程序,将Form1.cs换名为MainForm.cs,设计界面如图1-3所示。(2)在ChatClient中添加对应的代码和事件,参考代码如下。public partial class MainForm : Form private bool isExit = false; private TcpClient client; private StreamReader sr; private StreamWriter sw; public MainForm() InitializeComponent(); listBoxStatus.HorizontalScrollbar = true; / / 【连接服务器】按钮的Click事件 / private void buttonConnect_Click(object sender, EventArgs e) try /实际使用时要将Dns.GetHostName()改为服务器域名 client = new TcpClient(Dns.GetHostName(), 51888); AddListBoxItem(string.Format(本机EndPoint:0, client.Client.LocalEndPoint); AddListBoxItem(与服务器建立连接成功); catch AddListBoxItem(与服务器连接失败); return; buttonConnect.Enabled = false; /获取网络流 NetworkStream networkStream = client.GetStream(); /将网络流作为二进制读写对象 sr = new StreamReader(networkStream, System.Text.Encoding.UTF8); sw = new StreamWriter(networkStream, System.Text.Encoding.UTF8); SendString(Login); Thread threadReceive = new Thread(ReceiveData); threadReceive.Start(); / / 接收数据 / private void ReceiveData() string receiveString = null; while (isExit = false) try /从网络流中读出字符串 receiveString = sr.ReadLine(); catch if (isExit = false) MessageBox.Show(与服务器失去联系,请单击“确定”退出系统。); break; if (receiveString != null) string splitString = receiveString.Split(,); switch (splitString0) case AllIP: /格式:Login AddComboBoxItem(receiveString); AddListBoxItem(收到: + receiveString); break; case Talk: /格式:Talk,发送谈话方端点,对话内容 AddListBoxItem(string.Format(0对1说:2, splitString1, splitString2, receiveString.Substring(splitString0.Length + splitString1.Length + splitString2.Length + 3); break; default: AddListBoxItem(收到: + receiveString); break; Application.Exit(); private delegate void AddComboBoxDelegate(string str); / / 在ListBox中添加一项信息 / / 要添加的信息 private void AddComboBoxItem(string str) if (listBoxStatus.InvokeRequired = true) AddComboBoxDelegate d = new AddComboBoxDelegate(AddComboBoxItem); this.Invoke(d, str); else /把自己的信息去掉 str=str.Replace(string.Format(,0, client.Client.LocalEndPoint), ); string splitString = str.Split(,); /实际使用时要将Dns.GetHostName()改为服务器域名 splitString0 = string.Format(0:1, Dns.GetHostName(), 51888); comboBoxReceiver.Items.Clear(); comboBoxReceiver.Items.AddRange(splitString); / / 发送数据 / / 要发送的数据 private void SendString(string str) try /将字符串写入网络流,此方法会自动附加字符串长度前缀 sw.WriteLine(str); sw.Flush(); AddListBoxItem(string.Format(发送:0, str); catch AddListBoxItem(发送失败!); private
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 人工智能对新教师课堂互动方式的变革
- 新能源车辆在移动源污染防治中的作用
- 碳捕捉技术的绿色创新及其减排潜力
- 林下中药材采收与加工技术的创新与发展
- 2025版刁燕与赵敏的离婚财产分配及子女抚养协议
- 二零二五年度智能楼宇卷帘门安装与维护服务合同
- 2025年度大曰金地产高端楼盘销售代理合作协议
- 热轧卷板生产线项目招商引资报告
- 二零二五年度农产品展销中心场地租赁协议
- 2025版钢琴制作工艺技术合作合同范本
- 产品退货处理流产品退换货处理流程图
- 颅内动脉瘤疾病查房课件
- 2022年青岛市卫生健康系统事业单位招聘笔试试题及答案解析
- 10-1EJT-564-1991核电厂物项包装、运输、装卸、接收、贮存和维护要求
- 工程师职称工作证明模板
- 园林生态学(全套381张课件)
- 水印丝网版画
- 论刑事特情的指挥与使用
- 文言文《苏武传》翻译和考点解析
- 《列夫·托尔斯泰》 北雅中学谭嘉慧
- 小学生早恋教育(课堂PPT)
评论
0/150
提交评论