基于加密的TCPIP网络聊天软件的设计与实现Word下载.docx
《基于加密的TCPIP网络聊天软件的设计与实现Word下载.docx》由会员分享,可在线阅读,更多相关《基于加密的TCPIP网络聊天软件的设计与实现Word下载.docx(15页珍藏版)》请在冰豆网上搜索。
对于实例服务端用TcpListener监听,然后把连接的对象实例化为一个TcpClient,调用TcpClient.GetStream()方法,返回网络流实例化为一个NetworlStream流,然后进行Send,Receive。
2、使用对称加密传输流程分析
本程序使用DESCryptoServiceProvider类实现DES对称加密运算。
服务器端:
首先从客户端接收共密钥,然后使用公共密钥加密未来使用的对称密钥,再将加密了的对称密钥发给客户端,最后才给客户端发送加密了的信息!
客户端:
首先建立和发送公共密钥给服务器,然后从服务器接受加密的对称密钥,再解密该对称密钥将它作为自己私有的不对称密钥,最后才接收信息!
3详细代码设计
服务器端开发的详细代码:
//添加的命名空间引用(原始生成的略)
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Threading;
usingSystem.IO;
usingSystem.Security.Cryptography;
namespaceEncryptedTcpServer
{
publicpartialclassFormServer:
Form
{
//连接的用户
System.Collections.Generic.List<
User>
userList=newList<
();
privatedelegatevoidSetListBoxCallback(stringstr);
privateSetListBoxCallbacksetListBoxCallback;
privatedelegatevoidSetComboBoxCallback(Useruser);
privateSetComboBoxCallbacksetComboBoxCallback;
//使用的本机IP地址
IPAddresslocalAddress;
//监听端口
privateintport=6788;
//和书上一样
privateTcpListenermyListener;
publicFormServer()
InitializeComponent();
listBoxStatus.HorizontalScrollbar=true;
setListBoxCallback=newSetListBoxCallback(SetListBox);
setComboBoxCallback=newSetComboBoxCallback(AddComboBoxitem);
IPAddress[]addrIP=Dns.GetHostAddresses(Dns.GetHostName());
localAddress=addrIP[0];
buttonStop.Enabled=false;
}
//开始监听
privatevoidbuttonStart_Click(objectsender,EventArgse)
myListener=newTcpListener(localAddress,port);
myListener.Start();
SetListBox(string.Format("
开始在{0}:
{1}监听客户连接"
localAddress,port));
//创建一个线程监听客户端连接请求
ThreadStartts=newThreadStart(ListenClientConnect);
ThreadmyThread=newThread(ts);
myThread.Start();
buttonStart.Enabled=false;
buttonStop.Enabled=true;
//接收客户端连接的线程
privatevoidListenClientConnect()
while(true)
TcpClientnewClient=null;
try
//等待用户进入
newClient=myListener.AcceptTcpClient();
catch
//当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常,因此可以利用此异常退出循环
break;
//每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
ParameterizedThreadStartpts=newParameterizedThreadStart(ReceiveData);
ThreadthreadReceive=newThread(pts);
Useruser=newUser(newClient);
threadReceive.Start(user);
userList.Add(user);
AddComboBoxitem(user);
[{0}]进入"
newClient.Client.RemoteEndPoint));
当前连接用户数:
{0}"
userList.Count));
//接收、处理客户端信息的线程,每客户1个线程,参数用于区分是哪个客户
privatevoidReceiveData(objectobj)
Useruser=(User)obj;
TcpClientclient=user.client;
//是否正常退出接收线程
boolnormalExit=false;
//用于控制是否退出循环
boolexitWhile=false;
while(exitWhile==false)
//保存接收的命令字符串
stringreceiveString=null;
//每条命令均带有一个参数,值为true或者false,表示是否有紧跟的字节数组
string[]splitString=null;
byte[]receiveBytes=null;
//从网络流中读出命令字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString=user.br.ReadString();
splitString=receiveString.Split('
'
);
if(splitString[1]=="
true"
)
//先从网络流中读出32位的长度前缀
intbytesLength=user.br.ReadInt32();
//然后读出指定长度的内容保存到字节数组中
receiveBytes=user.br.ReadBytes(bytesLength);
//底层套接字不存在时会出现异常
SetListBox("
接收数据失败"
if(receiveString==null)
if(normalExit==false)
//如果停止了监听,Connected为false
if(client.Connected==true)
SetListBox(string.Format(
"
与[{0}]失去联系,已终止接收该用户信息"
client.Client.RemoteEndPoint));
来自[{0}]:
{1}"
user.client.Client.RemoteEndPoint,receiveString));
if(receiveBytes!
=null)
user.client.Client.RemoteEndPoint,Encoding.Default.GetString(receiveBytes)));
switch(splitString[0])//公钥和私钥的加密解密实现
{
case"
rsaPublicKey"
:
user.rsa.FromXmlString(Encoding.Default.GetString(receiveBytes));
//加密对称加密的私钥
byte[]encryptedKey=user.rsa.Encrypt(user.tdes.Key,false);
SendToClient(user,"
tdesKey,true"
encryptedKey);
//加密IV
byte[]encryptedIV=user.rsa.Encrypt(user.tdes.IV,false);
tdesIV,true"
encryptedIV);
catch(Exceptionerr)
MessageBox.Show(err.Message);
Logout"
//格式:
Logout
[{0}]退出"
user.client.Client.RemoteEndPoint));
normalExit=true;
exitWhile=true;
Talk"
//解密
stringtalkString=DecryptText(receiveBytes,user.tdes.Key,user.tdes.IV);
if(talkString!
[{0}]说:
client.Client.RemoteEndPoint,talkString));
default:
什么意思啊:
"
+receiveString);
userList.Remove(user);
client.Close();
//对称加密算法加密数据的具体实现
privatebyte[]EncryptText(stringstr,byte[]Key,byte[]IV)
//创建一个内存流
MemoryStreammemoryStream=newMemoryStream();
//使用传递的私钥和IV创建加密流
CryptoStreamcryptoStream=newCryptoStream(memoryStream,
newTripleDESCryptoServiceProvider().CreateEncryptor(Key,IV),
CryptoStreamMode.Write);
//将传递的字符串转换为字节数组
byte[]toEncrypt=Encoding.UTF8.GetBytes(str);
//将字节数组写入加密流,并清除缓冲区
cryptoStream.Write(toEncrypt,0,toEncrypt.Length);
cryptoStream.FlushFinalBlock();
//得到加密后的字节数组
byte[]encryptedBytes=memoryStream.ToArray();
returnencryptedBytes;
加密出错:
+err.Message);
returnnull;
finally
cryptoStream.Close();
memoryStream.Close();
//使用对称加密算法解密接收的数据
privatestringDecryptText(byte[]dataBytes,byte[]Key,byte[]IV)
//根据加密后的字节数组创建一个内存流
MemoryStreammemoryStream=newMemoryStream(dataBytes);
//使用传递的私钥、IV和内存流创建解密流
newTripleDESCryptoServiceProvider().CreateDecryptor(Key,IV),
CryptoStreamMode.Read);
//创建一个字节数组保存解密后的数据
byte[]decryptBytes=newbyte[dataBytes.Length];
//从解密流中将解密后的数据读到字节数组中
cryptoStream.Read(decryptBytes,0,decryptBytes.Length);
//得到解密后的字符串
stringdecryptedString=Encoding.UTF8.GetString(decryptBytes);
returndecryptedString;
解密出错:
//发送信息到客户端
privatevoidSendToClient(Useruser,stringcommand,byte[]bytes)
string[]splitCommand=command.Split('
//先将命令字符串写入网络流,此方法会自动附加字符串长度前缀
user.bw.Write(command);
向[{0}]发送:
user.client.Client.RemoteEndPoint,command));
if(splitCommand[1]=="
//先将字节数组的长度(32位整数)写入网络流
user.bw.Write(bytes.Length);
//然后将字节数组写入网络流
user.bw.Write(bytes);
user.bw.Flush();
user.client.Client.RemoteEndPoint,Encoding.UTF8.GetString(bytes)));
if(splitCommand[0]=="
加密前内容:
+textBoxSend.Text);
向[{0}]发送信息失败"
privatevoidAddComboBoxitem(Useruser)
if(comboBoxReceiver.InvokeRequired==true)
this.Invoke(setComboBoxCallback,user);
else
comboBoxReceiver.Items.Add(user.client.Client.RemoteEndPoint);
privatevoidSetListBox(stringstr)
if(listBoxStatus.InvokeRequired==true)
this.Invoke(setListBoxCallback,str);
listBoxStatus.Items.Add(str);
listBoxStatus.SelectedIndex=listBoxStatus.Items.Count-1;
listBoxStatus.ClearSelected();
//单击停止监听按钮触发的事件
privatevoidbuttonStop_Click(objectsender,EventArgse)
目前连接用户数:
开始停止服务,并依次使用户退出!
for(inti=0;
i<
userList.Count;
i++)
comboBoxReceiver.Items.Remove(userList[i].client.Client.RemoteEndPoint);
userList[i].bw.Close();
userList[i].br.Close();
userList[i].client.Close();
//通过停止监听让myListener.AcceptTcpClient()产生异常退出监听线程
myListener.Stop();
buttonStart.Enabled=true;
//单击发送按钮的Click事件
privatevoidbuttonSend_Click(objectsender,EventArgse)
intindex=comboBoxReceiver.SelectedIndex;
if(index==-1)
MessageBox.Show("
请先选择接收方,然后再单击[发送]"
Useruser=(User)userList[index];
//加密textBoxSend.Text的内容
byte[]encryptedBytes=EncryptText(textBoxSend.Text,user.tdes.Key,user.tdes.IV);
if(encryptedBytes!
Talk,true"
encryptedBytes);
textBoxSend.Clear();
privatevoidFormServer_FormClosing(objectsender,FormClosingEventArgse)
//未单击开始监听就直接退出时,myListener为null
if(myListener!
buttonStop_Click(null,null);
//textBoxSend获得焦点并释放按键后触发的事件
privatevoidtextBoxSend_KeyPres