




免费预览已结束,剩余12页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#网络编程课程设计报告基于加密的TCP/IP网络聊天软件的设计与实现1绪 论本课题是一个基于加密的TCP/IP网络聊天软件的设计与实现。通过基于网络方面的编程设计,深入理解C#语言的基础理论知识,更深刻地领会使用C#实现网络编程的精髓!TCP/IP协议是当前广域网和局域网通用的网络协议,因此,基于TCP/IP的编程就格外重要。从应用上来说,现在直接利用C层次Socket API进行TCP/IP编程的人确实越来越少了,各种现成的框架(如ACE、Java、.NET FCL)和控件(如IP*Works)大大简化了TCP/IP编程的难度。但是,如果想要在这个领域达到融会贯通的地步,不打下坚实的基础是不可想象的。正如Richard Stevens在TCP/IP Illustrated中所说,在网络编程领域,开发者所遇到的实际问题中,大约有90%都与开发者对于TCP/IP的理解相关。高层的框架和控件总结了TCP/IP的主要使用模式,并且进行了抽象和封装,这固然非常好,但是想要真正掌握TCP/IP网络编程的真谛,还得靠自己一不一个脚印从基础的开始。诚然C#语言的抽象、封装给我们使用带来方便,但是我觉得弄清楚其底层实现是非常重要的! 信息化的发展使得丰富的资源共享,而有的人就喜欢贪得无厌去窃取别人的隐私,所以加密技术也不断的发展。本课题是使用对称加密算法才加密数据。 信息时代计算机技术的发展给整个社会的生活、工作方式带来了一次革命。因此网络编程设计是很有意义的!2 系统原理分析1、 服务器和客户端连接基于TCP/IP套接字编程三个步骤:服务器监听,客户端请求,连接确认。所谓服务器监听,是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。客户端请求,是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。连接确认,是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。所以Socket接口的网络通讯原理:首先,服务端有一个进程(或多个进程)在指定的端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输。在使用TCP协议时,一般服务端进程先使用socket调用得到一个描述符,然后使用bind调用将一个名字与socket描述符连接起来,对于Internet域就是将Internet地址联编到socket。对于实例服务端用TcpListener监听,然后把连接的对象实例化为一个TcpClient,调用TcpClient.GetStream()方法,返回网络流实例化为一个NetworlStream流,然后进行Send,Receive。2、 使用对称加密传输流程分析本程序使用DESCryptoServiceProvider类 实现DES对称加密运算。服务器端:首先从客户端接收共密钥,然后使用公共密钥加密未来使用的对称密钥,再将加密了的对称密钥发给客户端,最后才给客户端发送加密了的信息!客户端:首先建立和发送公共密钥给服务器,然后从服务器接受加密的对称密钥,再解密该对称密钥将它作为自己私有的不对称密钥,最后才接收信息!3 详细代码设计服务器端开发的详细代码:/添加的命名空间引用(原始生成的略)using System.Net;using System.Net.Sockets;using System.Threading;using System.IO;using System.Security.Cryptography;namespace EncryptedTcpServer public partial class FormServer : Form /连接的用户 System.Collections.Generic.List userList = new List(); private delegate void SetListBoxCallback(string str); private SetListBoxCallback setListBoxCallback; private delegate void SetComboBoxCallback(User user); private SetComboBoxCallback setComboBoxCallback; /使用的本机IP地址 IPAddress localAddress; /监听端口 private int port = 6788;/和书上一样 private TcpListener myListener; public FormServer() InitializeComponent(); listBoxStatus.HorizontalScrollbar = true; setListBoxCallback = new SetListBoxCallback(SetListBox); setComboBoxCallback = new SetComboBoxCallback(AddComboBoxitem); IPAddress addrIP = Dns.GetHostAddresses(Dns.GetHostName(); localAddress = addrIP0; buttonStop.Enabled = false; /开始监听 private void buttonStart_Click(object sender, EventArgs e) myListener = new TcpListener(localAddress, port); myListener.Start(); SetListBox(string.Format(开始在0:1监听客户连接, localAddress, port); /创建一个线程监听客户端连接请求 ThreadStart ts = new ThreadStart(ListenClientConnect); Thread myThread = new Thread(ts); myThread.Start(); buttonStart.Enabled = false; buttonStop.Enabled = true; /接收客户端连接的线程 private void ListenClientConnect() while (true) TcpClient newClient = null; try /等待用户进入 newClient = myListener.AcceptTcpClient(); catch /当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常,因此可以利用此异常退出循环 break; /每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息 ParameterizedThreadStart pts = new ParameterizedThreadStart(ReceiveData); Thread threadReceive = new Thread(pts); User user = new User(newClient); threadReceive.Start(user); userList.Add(user); AddComboBoxitem(user); SetListBox(string.Format(0进入, newClient.Client.RemoteEndPoint); SetListBox(string.Format(当前连接用户数:0, userList.Count); /接收、处理客户端信息的线程,每客户1个线程,参数用于区分是哪个客户 private void ReceiveData(object obj) User user = (User)obj; TcpClient client = user.client; /是否正常退出接收线程 bool normalExit = false; /用于控制是否退出循环 bool exitWhile = false; while (exitWhile = false) /保存接收的命令字符串 string receiveString = null; /每条命令均带有一个参数,值为true或者false,表示是否有紧跟的字节数组 string splitString = null; byte receiveBytes = null; try /从网络流中读出命令字符串 /此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串 receiveString = user.br.ReadString(); splitString = receiveString.Split(,); if (splitString1 = true) /先从网络流中读出32位的长度前缀 int bytesLength = user.br.ReadInt32(); /然后读出指定长度的内容保存到字节数组中 receiveBytes = user.br.ReadBytes(bytesLength); catch /底层套接字不存在时会出现异常 SetListBox(接收数据失败); if (receiveString = null) if (normalExit = false) /如果停止了监听,Connected为false if (client.Connected = true) SetListBox(string.Format( 与0失去联系,已终止接收该用户信息, client.Client.RemoteEndPoint); break; SetListBox(string.Format(来自0:1, user.client.Client.RemoteEndPoint, receiveString); if (receiveBytes != null) SetListBox(string.Format(来自0:1, user.client.Client.RemoteEndPoint, Encoding.Default.GetString(receiveBytes); switch (splitString0)/公钥和私钥的加密解密实现 case rsaPublicKey: user.rsa.FromXmlString(Encoding.Default.GetString(receiveBytes); /加密对称加密的私钥 try byte encryptedKey = user.rsa.Encrypt(user.tdes.Key, false); SendToClient(user, tdesKey,true, encryptedKey); /加密IV byte encryptedIV = user.rsa.Encrypt(user.tdes.IV, false); SendToClient(user, tdesIV,true, encryptedIV); catch (Exception err) MessageBox.Show(err.Message); break; case Logout: /格式:Logout SetListBox(string.Format(0退出, user.client.Client.RemoteEndPoint); normalExit = true; exitWhile = true; break; case Talk: /解密 string talkString = DecryptText(receiveBytes, user.tdes.Key, user.tdes.IV); if (talkString != null) SetListBox(string.Format(0说:1, client.Client.RemoteEndPoint, talkString); break; default: SetListBox(什么意思啊: + receiveString); break; userList.Remove(user); client.Close(); SetListBox(string.Format(当前连接用户数:0, userList.Count); / 对称加密算法加密数据的具体实现 private byte EncryptText(string str, byte Key, byte IV) /创建一个内存流 MemoryStream memoryStream = new MemoryStream(); /使用传递的私钥和IV创建加密流 CryptoStream cryptoStream = new CryptoStream(memoryStream, new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV), CryptoStreamMode.Write); /将传递的字符串转换为字节数组 byte toEncrypt = Encoding.UTF8.GetBytes(str); try /将字节数组写入加密流,并清除缓冲区 cryptoStream.Write(toEncrypt, 0, toEncrypt.Length); cryptoStream.FlushFinalBlock(); /得到加密后的字节数组 byte encryptedBytes = memoryStream.ToArray(); return encryptedBytes; catch (Exception err) SetListBox(加密出错: + err.Message); return null; finally cryptoStream.Close(); memoryStream.Close(); /使用对称加密算法解密接收的数据 private string DecryptText(byte dataBytes, byte Key, byte IV) /根据加密后的字节数组创建一个内存流 MemoryStream memoryStream = new MemoryStream(dataBytes); /使用传递的私钥、IV和内存流创建解密流 CryptoStream cryptoStream = new CryptoStream(memoryStream, new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV), CryptoStreamMode.Read); /创建一个字节数组保存解密后的数据 byte decryptBytes = new bytedataBytes.Length; try /从解密流中将解密后的数据读到字节数组中 cryptoStream.Read(decryptBytes, 0, decryptBytes.Length); /得到解密后的字符串 string decryptedString = Encoding.UTF8.GetString(decryptBytes); return decryptedString; catch (Exception err) SetListBox(解密出错: + err.Message); return null; finally cryptoStream.Close(); memoryStream.Close(); /发送信息到客户端 private void SendToClient(User user, string command, byte bytes) /每条命令均带有一个参数,值为true或者false,表示是否有紧跟的字节数组 string splitCommand = command.Split(,); try /先将命令字符串写入网络流,此方法会自动附加字符串长度前缀 user.bw.Write(command); SetListBox(string.Format(向0发送:1, user.client.Client.RemoteEndPoint, command); if (splitCommand1 = true) /先将字节数组的长度(32位整数)写入网络流 user.bw.Write(bytes.Length); /然后将字节数组写入网络流 user.bw.Write(bytes); user.bw.Flush(); SetListBox(string.Format(向0发送:1, user.client.Client.RemoteEndPoint, Encoding.UTF8.GetString(bytes); if (splitCommand0 = Talk) SetListBox(加密前内容: + textBoxSend.Text); catch SetListBox(string.Format(向0发送信息失败, user.client.Client.RemoteEndPoint); private void AddComboBoxitem(User user) if (comboBoxReceiver.InvokeRequired = true) this.Invoke(setComboBoxCallback, user); else comboBoxReceiver.Items.Add(user.client.Client.RemoteEndPoint); private void SetListBox(string str) if (listBoxStatus.InvokeRequired = true) this.Invoke(setListBoxCallback, str); else listBoxStatus.Items.Add(str); listBoxStatus.SelectedIndex = listBoxStatus.Items.Count - 1; listBoxStatus.ClearSelected(); /单击停止监听按钮触发的事件 private void buttonStop_Click(object sender, EventArgs e) SetListBox(string.Format(目前连接用户数:0, userList.Count); SetListBox(开始停止服务,并依次使用户退出!); for (int i = 0; i userList.Count; i+) comboBoxReceiver.Items.Remove(userListi.client.Client.RemoteEndPoint); userListi.bw.Close(); userListi.br.Close(); userListi.client.Close(); /通过停止监听让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; /加密textBoxSend.Text的内容 byte encryptedBytes = EncryptText(textBoxSend.Text, user.tdes.Key, user.tdes.IV); if (encryptedBytes != null) SendToClient(user, Talk,true, encryptedBytes); textBoxSend.Clear(); private void FormServer_FormClosing(object sender, FormClosingEventArgs e) /未单击开始监听就直接退出时,myListener为null if (myListener != null) buttonStop_Click(null, null); /textBoxSend获得焦点并释放按键后触发的事件 private void textBoxSend_KeyPress(object sender, KeyPressEventArgs e) if (e.KeyChar = (char)Keys.Return) buttonSend_Click(null, null); /客户端具体的代码实现略:服务器和客户端的连接实现和教材上的例子具体实现是一样的,就是增加了一个连接时发送共钥和私钥的过程,客户端的加密解密实现原理和服务器端是一样的。 4调试分析1、服务器端2、客户端/分析:停止监听让myListener.AcceptTcpClient()产生异常退出监听线程,利用此异常客户端就断开连接,关闭程序!5设计小结在老师的悉心指导和同学们的热心帮助之下,我通过一个星期的学习,基本完成了本次课程设计,唯一遗憾的是没有及时答辩。因为对学习基础不够扎实,所以在设计的过程中花了很多的时间去看参考书,耽误了不少时间,影响到了设计!由于时间、条件和个人水平的限制,设计相对较简单 。但是通过这次课程设计,使我受到了一次用专业知识分析和解决问题的全面系统的锻炼,使我在综合知识的选用方面,在C#编程设计思路技巧的掌握方面都向前迈了一大步。课程设计对一个学生来说是一个非常的重要的学习过程,是一个动手实践的好机会。虽然课程设计接近尾声,但是我还会继续坚持去完善各模块功能,尤其是对加密算法的具体实现还不是很清楚,我将继续深入学习。总的来说,这次的课程设计是非常有意义的,在我的大学学习道路上起到了一个里程碑的作用,让我有一个质的飞跃!6 谢辞这一个星期来紧张有序的课程设计是检验自己所学知识习的试金石。首先我要感谢老师在本次设计过程中给与的悉心指导和帮助,让我走了很少弯路。其次,我还要感谢我们班的同学的帮助。由于自己学习基础不是很扎实尤其在可视化编程方面没有实战经验,是他们给予了我很多的帮助,特别是他们不厌其烦的给我解释指导,才让我在规定的时间内完成了课程设计。最后我要感谢所有帮助和支持我的人。7 参考文献1 刘新瑞.C#网络编程及应用.机械工业出版社2 Simmon Robinson.C#高级编程.清华大学出版社3 /4 /5 /5E2A+x*u$rZnWkThPeMaJ7G4C1z-w&t!qYmVjRgOdL9I6F3B0y(v%s#oXlUiQfNbK8H5D2A+x*u$qZnWkShPeMaJ7F4C1z)w&t!pYmUjRgOcL9I6E3B+y(v%r#oXlTiQfNbK8G5D2A-x*u$qZnVkShPdMaJ7F4C0z)w&s!pYmUjRfOcL9H6E3B+y(u%r#oWlTiQeNbJ8G5D1A-x*t$qYnVkSgPdMaI7F3C0z)v&s!pXmUjRfOcK9H6E2B+y(u%rZoWlThQeNbJ8G4D1A-w*t$qYnVjSgPdLaI7F3C0y)v&s#pXmUiRfNcK9H5E2B+x(u$rZoWkThQeMbJ8G4D1z-w*t!qYnVjSgOdLaI6F3C0y)v%s#pXlUiRfNcK8H5E2A+x(u$rZnWkThPeMbJ7G4C1z-w&t!qYmVjRgOdL9I6F3B0y)v%s#oXlUiQfNcK8H5D2A+x*u$rZnWkShPeMaJ7G4C1z)w&t!pYmVjRgOcL9I6E3B0y(v%r#oXlTiQfNbK8G5D2A-x*u$qZnVkShPdMaJ7F4C1z)w&s!pYmUjRgOcL9H6E3B+y(v%r#oWlTiQeNbK8G5D1A-x*t$qZnVkSgPdMaI7F4C0z)v&s!pXmUjRfK8H5D2A-x*u$qZnWkShPdMaJ7F4C1z)w&s!pYmUjRgOcL9H6E3B+y(v%r#oWlTiQeNbK8G5D1A-x*t$qZnVkSgPdMaI7F4C0z)v&s!pXmUjRfOcL9H6E2B+y(u%r#oWlThQeNbJ8G5D1A-w*t$qYnVkSgPdLaI7F3C0z)v&s#pXmUiRfOcK9H5E2B+x(u%rZoWkThQeMbJ8G4D1A-w*t!qYnVjSgPdLaI6F3C0y)v&s#pXlUiRfNcK9H5E2A+x(u$rZoWkThPeMbJ7G4D1z-w&t!qYmVjSgOdL9I6F3B0y)v%s#pXlUiQfNcK8H5E2A+x*u$rZnWkThPeMaJ7G4C1z-w&t!pYmVjRgOdL9I6E3B0y(v%s#oXlTiQfNbK8H5D2A-x*u$qZnWkShPdMaJ7F4C1z)w&t!pYmUjRgOcL9I6E3B+y(v%r#oXlTiQeNbK8G5D2A-x*t$qZnVkShPdMaI7F4C0z)w&s!pXmUjRfOcL9H6E2B+y(u%r#oWlTiQeNbJ8G5D1A-x*t$qYnVkSgPdMaI7F3C0z)v&s!pXmUiRfOcK9H6E2B+x(u%rZoWlThQeMbJ8G4D1A-w*t!qYnVjSgPdLaI7F3C0y)v&s#pXmUiRfNcK9H5E2B+x(u$rZoWkThQeMbJ7G4D1z-w*t!qYmVjSgOdLaI6F3B0y)v%s#pXlUiQfNcK8H5E2A+x*u$rZnWkThPeMbJ7G4C1z-w&t!qYmVjRgOdL9I6F3B0y(v%s#oXlUiQfNbK8H5D2A+x*u$qZnWkShPeMaJ7F4C1z)w&t!pYmUjRgOcL9I6E3B0y(v%r#oXlTiQfNbK8G5D2A-x*u$qZnVkShPdMaJ7F4C0z)w&s!pYmUjRfOcL9H6E3B+y(u%r#oWlTiQeNbJ8G5D1A-x*t$qYnVkSgPdMaI7F4C0z)v&s!pXmUjRfOcK9H6E2B+y(u%rZoWlThQeNbJ8G4z)w&s!pYmUjRfOcL9H6E3B+y(u%r#oWlTiQeNbK8G5D1A-x*t$qZnVkSgPdMaI7F4C0z)v&s!pXmUjRfOcK9H6E2B+y(u%rZoWlThQeNbJ8G4D1A-w*t$qYnVjSgPdLaI7F3C0y)v&s#pXmUiRfOcK9H5E2B+x(u%rZoWkThQeMbJ8G4D1z-w*t!qYnVjSgOdLaI6F3C0y)v%s#pXlUiRfNcK8H5E2A+x(u$rZnWkThPeMbJ7G4D1z-w&t!qYmVjSgOdL9I6F3B0y)v%s#oXlUiQfNcK8H5D2A+x*u$rZnWkShPeMaJ7G4C1z)w&t!pYmVjRgOcL9I6E3B0y(v%s#oXlTiQfNbK8H5D2A-x*u$qZnWkShPdMaJ7F4C1z)w&s!pYmUjRgOcL9H6E3B+y(v%r#oWlTiQeNbK8G5D1A-x*t$qZnVkSgPdMaI7F4C0z)w&s!pXmUjRfOcL9H6E2B+y(u%r#oWlThQeNbJ8G5D1A-w*t$qYnVkSgPdLaI7F3C0z)v&s#pXmUiRfOcK9H5E2B+x(u%rZoWlThQeMbJ8G4D1A-w*t!qYnVjSgPdLaI6F3C0y)v&WlThQeNbJ8G5D1A-w*t$qYnVkSgPdLaI7F3C0z)v&s#pXmUiRfOcK9H6E2B+x(u%rZoWlThQeMbJ8G4D1A-w*t!qYnVjSgPdLaI6F3C0y)v&s#pXlUiRfNcK9H5E2A+x(u$rZoWkThPeMbJ7G4D1z-w*t!qYmVjSgOdLaI6F3B0y)v%s#pXlUiQfNcK8H5E2A+x*u$rZnWkThPeMaJ7G4C1z-w&t!pYmVjRgOdL9I6E3B0y(v%s#oXlUiQfNbK8H5D2A+x*u$qZnWkShPeMaJ7F4C1z)w&t!pYmUjRgOcL9I6E3B+y(v%r#oXlTiQeNbK8G5D2A-x*t$qZnVkShPdMaI7F4C0z)w&s!pYmUjRfOcL9H6E3B+y(u%r#oWlTiQeNbJ8G5D1A-x*t$qYnVkSgPdMaI7F3C0z)v&s!pXmUiRfOcK9H6E2B+x(u%rZoWlThQeNbJ8G4D1A-w*t$qYnVjSgPdLaI7F3C0y)v&s#pXmUiRfNcK9H5E2B+x(u$rZoWkThQeMbJ7G4D1z-w*t!qYmVjSgOdLaI6F3y(u%rZoWlThQeNbJ8G4D1A-w*t$qYnVjSgPdLaI7F3C0y)v&s#pXmUiRfNcK9H5E2B+x(u$rZoWkThQeMbJ7G4D1z-w*t!qYnVjSgOdLaI6F3C0y)v%s#pXlUiRfNcK8H5E2A+x(u$rZnWkThPeMbJ7G4C1z-w&t!qYmVjRgOdL9I6F3B0y(v%s#oXlUiQfNcK8H5D2A+x*u$rZnWkShPeMaJ7G4C1z)w&t!pYmVjRgOcL9I6E3B0y(v%r#oXlTiQfNbK8G5D2A-x*u$qZnVkShPdMaJ7F4C0z)w&s!pYmU
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论