基于加密的TCPIP网络聊天软件的设计与实现_第1页
基于加密的TCPIP网络聊天软件的设计与实现_第2页
基于加密的TCPIP网络聊天软件的设计与实现_第3页
基于加密的TCPIP网络聊天软件的设计与实现_第4页
基于加密的TCPIP网络聊天软件的设计与实现_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、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编程的难度。但是,如果想要在这个领域达到融会贯通的地步,不打下坚实的基础是

2、不可想象的。正如Richard Stevens在TCP/IP Illustrated中所说,在网络编程领域,开发者所遇到的实际问题中,大约有90%都与开发者对于TCP/IP的理解相关。高层的框架和控件总结了TCP/IP的主要使用模式,并且进行了抽象和封装,这固然非常好,但是想要真正掌握TCP/IP网络编程的真谛,还得靠自己一不一个脚印从基础的开始。诚然C#语言的抽象、封装给我们使用带来方便,但是我觉得弄清楚其底层实现是非常重要的! 信息化的发展使得丰富的资源共享,而有的人就喜欢贪得无厌去窃取别人的隐私,所以加密技术也不断的发展。本课题是使用对称加密算法才加密数据。 信息时代计算机技术的发展给整

3、个社会的生活、工作方式带来了一次革命。因此网络编程设计是很有意义的!2 系统原理分析1、 服务器和客户端连接基于TCP/IP套接字编程三个步骤:服务器监听,客户端请求,连接确认。所谓服务器监听,是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。客户端请求,是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。连接确认,是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线

4、程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。所以Socket接口的网络通讯原理:首先,服务端有一个进程(或多个进程)在指定的端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输。在使用TCP协议时,一般服务端进程先使用socket调用得到一个描述符,然后使用bind调用将一个名字与socket描述符连接起来,对于Internet域就是将Internet地址联编到socket。对于实例服务端用TcpListener监听,然后把连接的对象实

5、例化为一个TcpClient,调用TcpClient.GetStream()方法,返回网络流实例化为一个NetworlStream流,然后进行Send,Receive。2、 使用对称加密传输流程分析本程序使用DESCryptoServiceProvider类 实现DES对称加密运算。服务器端:首先从客户端接收共密钥,然后使用公共密钥加密未来使用的对称密钥,再将加密了的对称密钥发给客户端,最后才给客户端发送加密了的信息!客户端:首先建立和发送公共密钥给服务器,然后从服务器接受加密的对称密钥,再解密该对称密钥将它作为自己私有的不对称密钥,最后才接收信息!3 详细代码设计服务器端开发的详细代码:/添

6、加的命名空间引用(原始生成的略)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<User> userList = new List<User>(); private delega

7、te 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

8、 FormServer() InitializeComponent(); listBoxStatus.HorizontalScrollbar = true; setListBoxCallback = new SetListBoxCallback(SetListBox); setComboBoxCallback = new SetComboBoxCallback(AddComboBoxitem); IPAddress addrIP = Dns.GetHostAddresses(Dns.GetHostName(); localAddress = addrIP0; buttonStop.Enable

9、d = 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 myT

10、hread = 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()会产生异常,因此可以利用此异常退出循环

11、 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进入"

12、;, 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

13、; while (exitWhile = false) /保存接收的命令字符串 string receiveString = null; /每条命令均带有一个参数,值为true或者false,表示是否有紧跟的字节数组 string splitString = null; byte receiveBytes = null; try /从网络流中读出命令字符串 /此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串 receiveString = user.br.ReadString(); splitString = receiveString.Split(','); if (

14、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.Co

15、nnected = 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.Remot

16、eEndPoint, 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&quo

17、t;, 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.Rem

18、oteEndPoint); 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(&q

19、uot;什么意思啊:" + 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创建加密流 Crypto

20、Stream 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.FlushFina

21、lBlock(); /得到加密后的字节数组 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

22、) /根据加密后的字节数组创建一个内存流 MemoryStream memoryStream = new MemoryStream(dataBytes); /使用传递的私钥、IV和内存流创建解密流 CryptoStream cryptoStream = new CryptoStream(memoryStream, new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV), CryptoStreamMode.Read); /创建一个字节数组保存解密后的数据 byte decryptBytes = new bytedataBytes

23、.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();

24、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.clien

25、t.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 (splitC

26、ommand0 = "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 com

27、boBoxReceiver.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()

28、; /单击停止监听按钮触发的事件 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); user

29、Listi.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.SelectedI

30、ndex; 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) /未单击开始监听就直接退出时,myListe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论