基本信息
源码名称:C# wpf 局域网聊天 实例源码下载
源码大小:0.61M
文件格式:.rar
开发语言:C#
更新时间:2017-04-21
友情提示:(无需注册或充值,赞助后即可获取资源下载链接)
嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300
本次赞助数额为: 2 元×
微信扫码支付:2 元
×
请留下您的邮箱,我们将在2小时内将文件发到您的邮箱
源码介绍
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetworkCommsDotNet;
using DPSBase;
namespace WPFChatClientExplain
{
public abstract class ChatAppBase
{
#region Private Fields
/// <summary>
/// A boolean used to track the very first initialisation(一个用于跟踪第一个初始化的布尔值)
/// </summary>
protected bool FirstInitialisation { get; set; }
/// <summary>
/// Dictionary to keep track of which peer messages have already been written to the chat window(保持跟踪的对等消息已被写入聊天窗口)
/// </summary>
protected Dictionary<ShortGuid, ChatMessage> lastPeerMessageDict = new Dictionary<ShortGuid, ChatMessage>();
/// <summary>
/// The maximum number of times a chat message will be relayed(聊天信息将被传递的最大次数 )
/// </summary>
int relayMaximum = 3;
/// <summary>
/// A local counter used to track the number of messages sent from(用于跟踪发送的消息的本地计数器)
/// this instance.(本实例)
/// </summary>
long messageSendIndex = 0;
/// <summary>
/// An optional encryption key to use should one be required.(使用一个可选的加密密钥应该是必需的。)
/// This can be changed freely but must obviously be the same(这可以自由地改变,但必须是相同的)
/// for both sender and reciever.(对于发送者和接收者。)
/// </summary>
string _encryptionKey = "ljlhjf8uyfln23490jf;m21-=scm20--iflmk;";
#endregion
#region Public Fields
/// <summary>
/// The type of connection currently used to send and recieve messages. Default is TCP.
/// 目前用于发送和接收消息的连接类型。默认是TCP。
/// </summary>
public ConnectionType ConnectionType { get; set; }
/// <summary>
/// The IP address of the server
/// 服务器的地址
/// </summary>
public string ServerIPAddress { get; set; }
/// <summary>
/// The port of the server
/// 服务器的端口
/// </summary>
public int ServerPort { get; set; }
/// <summary>
/// The local name used when sending messages
/// 发送消息时使用的本地名称
/// </summary>
public string LocalName { get; set; }
/// <summary>
/// A boolean used to track if the local device is acting as a server
/// 当本地设备作为服务器时使用的布尔值
/// </summary>
public bool LocalServerEnabled { get; set; }
/// <summary>
/// A boolean used to track if encryption is currently being used
/// 如果当前正在使用加密,则布尔用于跟踪
/// </summary>
public bool EncryptionEnabled { get; set; }
#endregion
/// <summary>
/// Constructor for ChatAppBase
/// 聊天应用程序库的构造
/// </summary>
public ChatAppBase(string name, ConnectionType connectionType)
{
LocalName = name;
ConnectionType = connectionType;
//Initialise the default values(初始化默认值)
ServerIPAddress = "";
ServerPort = 10000;
LocalServerEnabled = false;
EncryptionEnabled = false;
FirstInitialisation = true;
}
#region NetworkComms.Net Methods
/// <summary>
/// Updates the configuration of this instance depending on set fields
/// 更新这个实例的配置,这取决于集合域
/// </summary>
public void RefreshNetworkCommsConfiguration()
{
#region First Initialisation
//On first initilisation we need to configure NetworkComms.Net to handle our incoming packet types
//首先我们需要配置INI tilisation networkcomms .net处理传入的数据包的类型
//We only need to add the packet handlers once. If we call NetworkComms.Shutdown() at some future point these are not removed.
//我们只需要添加一次数据包处理程序。如果我们把networkcomms。shutdown()在不久的将来这些没有被删除。
if (FirstInitialisation)
{
FirstInitialisation = false;
//Configure NetworkComms.Net to handle any incoming packet of type 'ChatMessage'
//配置网络通信。净处理传入的数据包的类型'聊天'
//e.g. If we recieve a packet of type 'ChatMessage' execute the method 'HandleIncomingChatMessage'
//如果我们收到一包式的聊天消息的执行方法的handleincoming聊天消息”
NetworkComms.AppendGlobalIncomingPacketHandler<ChatMessage>("ChatMessage", HandleIncomingChatMessage);
//Configure NetworkComms.Net to perform some action when a connection is closed
//配置networkcomms .NET执行一些操作当连接关闭时
//e.g. When a connection is closed execute the method 'HandleConnectionClosed'
//例如,当连接关闭时执行该方法的handleconnectionclosed”
NetworkComms.AppendGlobalConnectionCloseHandler(HandleConnectionClosed);
}
#endregion
#region Optional Encryption
//Configure encryption if requested(如果要求配置加密)
if (EncryptionEnabled && !NetworkComms.DefaultSendReceiveOptions.DataProcessors.Contains(DPSBase.DPSManager.GetDataProcessor<DPSBase.RijndaelPSKEncrypter>()))
{
//Encryption is currently implemented using a pre-shared key (PSK) system
//加密技术是目前使用预共享密钥(PSK)系统的实现
//NetworkComms.Net supports multiple data processors which can be used with any level of granularity
//networkcomms .NET支持多数据处理器可用于任何级别的粒度
//To enable encryption globally (i.e. for all connections) we first add the encryption password as an option
//为了使加密在全球范围内(即所有连接),我们首先添加加密密码作为一个选项
DPSBase.RijndaelPSKEncrypter.AddPasswordToOptions(NetworkComms.DefaultSendReceiveOptions.Options, _encryptionKey);
//Finally we add the RijndaelPSKEncrypter data processor to the sendReceiveOptions
//最后,我们将rijndaelpskencrypter数据处理器发送接收选项
NetworkComms.DefaultSendReceiveOptions.DataProcessors.Add(DPSBase.DPSManager.GetDataProcessor<DPSBase.RijndaelPSKEncrypter>());
}
else if (!EncryptionEnabled && NetworkComms.DefaultSendReceiveOptions.DataProcessors.Contains(DPSBase.DPSManager.GetDataProcessor<DPSBase.RijndaelPSKEncrypter>()))
{
//If encryption has been disabled but is currently enabled
//如果加密已禁用,但目前启用
//To disable encryption we just remove the RijndaelPSKEncrypter data processor from the sendReceiveOptions
//禁用加密我们移除Rijndael PSK加密数据处理器从发送接收选项
NetworkComms.DefaultSendReceiveOptions.DataProcessors.Remove(DPSBase.DPSManager.GetDataProcessor<DPSBase.RijndaelPSKEncrypter>());
}
#endregion
#region Local Server Mode and Connection Type Changes
if (LocalServerEnabled && ConnectionType == ConnectionType.TCP && !TCPConnection.Listening())
{
//If we were previously listening for UDP we first shutdown comms.
//如果我们以前听我们首先关闭UDP通信
if (UDPConnection.Listening())
{
AppendLineToChatHistory("Connection mode has been changed. Any existing connections will be closed.");
NetworkComms.Shutdown();
}
else
{
AppendLineToChatHistory("Enabling local server mode. Any existing connections will be closed.");
NetworkComms.Shutdown();
}
//Start listening for new incoming TCP connections(开始听新的TCP连接)
//Parameter is true so that we listen on a random port if the default is not available
//参数是真的,所以我们在一个随机端口上侦听,如果不提供默认值
TCPConnection.StartListening(true);
//Write the IP addresses and ports that we are listening on to the chatBox
//写的IP地址和端口,我们聆听到客舱
AppendLineToChatHistory("Listening for incoming TCP connections on:");
foreach (var listenEndPoint in TCPConnection.ExistingLocalListenEndPoints())
AppendLineToChatHistory(listenEndPoint.Address ":" listenEndPoint.Port);
//Add a blank line after the initialisation output
//初始化输出后添加一个空白行
AppendLineToChatHistory(System.Environment.NewLine);
}
else if (LocalServerEnabled && ConnectionType == ConnectionType.UDP && !UDPConnection.Listening())
{
//If we were previously listening for TCP we first shutdown comms.
//如果我们以前听TCP首先关闭通讯。
if (TCPConnection.Listening())
{
AppendLineToChatHistory("Connection mode has been changed. Any existing connections will be closed.");
NetworkComms.Shutdown();
}
else
{
AppendLineToChatHistory("Enabling local server mode. Any existing connections will be closed.");
NetworkComms.Shutdown();
}
//Start listening for new incoming UDP connections
//开始听新的UDP连接
//Parameter is true so that we listen on a random port if the default is not available
//参数是真的,所以我们在一个随机端口上侦听,如果不提供默认值
UDPConnection.StartListening(true);
//Write the IP addresses and ports that we are listening on to the chatBox
//写的IP地址和端口,我们聆听到客舱
AppendLineToChatHistory("Listening for incoming UDP connections on:");
foreach (var listenEndPoint in UDPConnection.ExistingLocalListenEndPoints())
AppendLineToChatHistory(listenEndPoint.Address ":" listenEndPoint.Port);
//Add a blank line after the initialisation output
//初始化输出后添加一个空白行
AppendLineToChatHistory(System.Environment.NewLine);
}
else if (!LocalServerEnabled && (TCPConnection.Listening() || UDPConnection.Listening()))
{
//If the local server mode has been disabled but we are still listening we need to stop accepting incoming connections
//如果本地服务器模式已被禁用,但我们仍然在聆听我们需要停止接受传入的连接
NetworkComms.Shutdown();
AppendLineToChatHistory("Local server mode disabled. Any existing connections will be closed.");
AppendLineToChatHistory(System.Environment.NewLine);
}
else if (!LocalServerEnabled &&
((ConnectionType == ConnectionType.UDP && NetworkComms.GetExistingConnection(ConnectionType.TCP).Count > 0) ||
(ConnectionType == ConnectionType.TCP && NetworkComms.GetExistingConnection(ConnectionType.UDP).Count > 0)))
{
//If we are not running a local server but have changed the connection type after creating connections we need to close
//如果我们不在本地服务器上运行,但在创建连接之后改变了连接类型,我们需要关闭
//existing connections.(现有的连接。 )
NetworkComms.Shutdown();
AppendLineToChatHistory("Connection mode has been changed. Existing connections will be closed.");
AppendLineToChatHistory(System.Environment.NewLine);
}
#endregion
}
/// <summary>
/// Performs whatever functions we might so desire when we recieve an incoming ChatMessage
/// 执行我们可能如此渴望当我们接待来聊天消息的任何功能
/// </summary>
/// <param name="header">The PacketHeader corresponding with the recieved object</param>(与接待对象相应的标签)
/// <param name="connection">The Connection from which this object was recieved</param>(从该连接对象接待)
/// <param name="incomingMessage">The incoming ChatMessage we are after</param>(我们正在收到的聊天信息)
protected virtual void HandleIncomingChatMessage(PacketHeader header, Connection connection, ChatMessage incomingMessage)
{
//We only want to write a message once to the chat window(我们只想在聊天窗口中写一个信息)
//Because we support relaying and may recieve the same message twice from multiple sources
//因为我们支持可以传递收到两次同样的信息从多个来源
//we use our history and message indexes to ensure we have a new message
//我们使用我们的历史和信息索引,以确保我们有一个新的消息
//We perform this action within a lock as HandleIncomingChatMessage could be called in parallel
//我们在一个锁内执行这个动作,作为输入聊天信息,可以被称为并行
lock (lastPeerMessageDict)
{
if (lastPeerMessageDict.ContainsKey(incomingMessage.SourceIdentifier))
{
if (lastPeerMessageDict[incomingMessage.SourceIdentifier].MessageIndex < incomingMessage.MessageIndex)
{
//If this message index is greater than the last seen from this source we can safely
//write the message to the ChatBox
//如果此消息指数大于上看到从这个源头我们可以写邮件聊天
AppendLineToChatHistory(incomingMessage.SourceName " - " incomingMessage.Message);
//We now replace the last recieved message with the current one
//我们现在收到的消息取代过去与当前的
lastPeerMessageDict[incomingMessage.SourceIdentifier] = incomingMessage;
}
}
else
{
//If we have never had a message from this source before then it has to be new
//by defintion
//如果我们从未有过这样的消息来源之前,它必须是新的通过定义
lastPeerMessageDict.Add(incomingMessage.SourceIdentifier, incomingMessage);
AppendLineToChatHistory(incomingMessage.SourceName " - " incomingMessage.Message);
}
}
//This last section of the method is the relay feature
//此方法的最后一节是中继功能
//We start by checking to see if this message has already been relayed the maximum number of times
//我们开始通过检查,看看这个消息是否已经被传递了最多的时间
if (incomingMessage.RelayCount < relayMaximum)
{
//If we are going to relay this message we need an array of (如果我们要传递这个信息,我们需要一个数组)
//all known connections, excluding the current one(所有已知的连接,不包括当前)
var allRelayConnections = (from current in NetworkComms.GetExistingConnection() where current != connection select current).ToArray();
//We increment the relay count before we send(我们在发送前增加了继电器计数)
incomingMessage.IncrementRelayCount();
//We now send the message to every other connection(现在我们将消息发送到其他连接)
foreach (var relayConnection in allRelayConnections)
{
//We ensure we perform the send within a try catch(我们确保我们在一个尝试捕捉)
//To ensure a single failed send will not prevent the(确保单个失败将不会阻止)
//relay to all working connections.(传递到所有工作连接)
try { relayConnection.SendObject("ChatMessage", incomingMessage); }
catch (CommsException) { /* Catch the comms exception, ignore and continue */ }
//(赶上通讯异常,忽略并继续)
}
}
}
/// <summary>
/// Performs whatever functions we might so desire when an existing connection is closed.
/// 执行任何功能,当一个现有的连接被关闭时,我们可能会这样做。
/// </summary>
/// <param name="connection">The closed connection</param>(关闭连接)
private void HandleConnectionClosed(Connection connection)
{
//We are going to write a message to the chat history when a connection disconnects
//我们要写一个消息的聊天记录时,连接断开
//We perform the following within a lock incase mutliple connections disconnect simultaneously
//我们执行以下内锁,多连接断开的同时
lock (lastPeerMessageDict)
{
//Get the remoteIdentifier from the closed connection(从关闭连接到远程确定)
//This a unique GUID which can be used to identify peers(这一独特的GUID可用来识别同行)
ShortGuid remoteIdentifier = connection.ConnectionInfo.NetworkIdentifier;
//If at any point we recieved a message with a matching identifier we can(如果在任何时候我们收到消息标识符可以匹配)
//include the peer name in the disconnection message.(包括断开信息中的对等名。)
if (lastPeerMessageDict.ContainsKey(remoteIdentifier))
AppendLineToChatHistory("Connection with '" lastPeerMessageDict[remoteIdentifier].SourceName "' has been closed.");
else
AppendLineToChatHistory("Connection with '" connection.ToString() "' has been closed.");
//Last thing is to remove this peer from our message history(最后一件事是从我们的历史信息删除此节点 )
lastPeerMessageDict.Remove(connection.ConnectionInfo.NetworkIdentifier);
}
}
/// <summary>
/// Send a message.(发送消息。)
/// </summary>
public void SendMessage(string stringToSend)
{
//If we have tried to send a zero length string we just return
//如果我们试着发送一零长度的字符串,我们只是返回
if (stringToSend.Trim() == "") return;
//We may or may not have entered some server connection information
//我们可以或可能不会输入一些服务器连接信息
ConnectionInfo serverConnectionInfo = null;
if (ServerIPAddress != "")
{
try { serverConnectionInfo = new ConnectionInfo(ServerIPAddress, ServerPort); }
catch (Exception)
{
ShowMessage("Failed to parse the server IP and port. Please ensure it is correct and try again");
return;
}
}
//We wrap everything we want to send in the ChatMessage class we created
//我们把所有我们想发送的信息都发送到我们创建的聊天信息类中
ChatMessage chatMessage = new ChatMessage(NetworkComms.NetworkIdentifier, LocalName, stringToSend, messageSendIndex );
//We add our own message to the message history incase it gets relayed back to us
//我们把我们自己的消息的消息历史,它得到回传给我们
lock (lastPeerMessageDict) lastPeerMessageDict[NetworkComms.NetworkIdentifier] = chatMessage;
//We write our own message to the chatBox(我们写我们自己的短信聊天)
AppendLineToChatHistory(chatMessage.SourceName " - " chatMessage.Message);
//Clear the input box text(清除输入框中的文字 )
ClearInputLine();
//If we provided server information we send to the server first
//如果我们提供服务器信息,我们首先发送给服务器
if (serverConnectionInfo != null)
{
//We perform the send within a try catch to ensure the application continues to run if there is a problem.
//我们在一个尝试的范围内完成发送,以确保应用程序继续运行,如果有问题
try
{
if (ConnectionType == ConnectionType.TCP)
TCPConnection.GetConnection(serverConnectionInfo).SendObject("ChatMessage", chatMessage);
else if (ConnectionType == ConnectionType.UDP)
UDPConnection.GetConnection(serverConnectionInfo, UDPOptions.None).SendObject("ChatMessage", chatMessage);
else
throw new Exception("An invalid connectionType is set.");
}
catch (CommsException) { AppendLineToChatHistory("Error: A communication error occured while trying to send message to " serverConnectionInfo ". Please check settings and try again."); }
catch (Exception) { AppendLineToChatHistory("Error: A general error occured while trying to send message to " serverConnectionInfo ". Please check settings and try again."); }
}
//If we have any other connections we now send the message to those as well
//This ensures that if we are the server everyone who is connected to us gets our message
//We want a list of all established connections not including the server if set
//如果我们有任何其他连接,我们现在把信息发送给那些
//这确保了,如果我们是连接到我们的服务器的每个人都得到我们的信息,
//我们想要一个列表的所有已建立的连接不包括服务器设置
List<ConnectionInfo> otherConnectionInfos;
if (serverConnectionInfo != null)
otherConnectionInfos = (from current in NetworkComms.AllConnectionInfo() where current.RemoteEndPoint != serverConnectionInfo.RemoteEndPoint select current).ToList();
else
otherConnectionInfos = NetworkComms.AllConnectionInfo();
foreach (ConnectionInfo info in otherConnectionInfos)
{
//We perform the send within a try catch to ensure the application continues to run if there is a problem.
//(我们在一个尝试的范围内完成发送,以确保应用程序继续运行,如果有问题。)
try
{
if (ConnectionType == ConnectionType.TCP)
TCPConnection.GetConnection(info).SendObject("ChatMessage", chatMessage);
else if (ConnectionType == ConnectionType.UDP)
UDPConnection.GetConnection(info, UDPOptions.None).SendObject("ChatMessage", chatMessage);
else
throw new Exception("An invalid connectionType is set.");
}
catch (CommsException) { AppendLineToChatHistory("Error: A communication error occured while trying to send message to " info ". Please check settings and try again."); }
catch (Exception) { AppendLineToChatHistory("Error: A general error occured while trying to send message to " info ". Please check settings and try again."); }
}
return;
}
#endregion
#region GUI Interface Methods(GUI接口的方法)
/// <summary>
/// Outputs the usage instructions to the chat window(输出到聊天窗口的使用说明 )
/// </summary>
public void PrintUsageInstructions()
{
AppendLineToChatHistory("");
AppendLineToChatHistory("使用说明:");
AppendLineToChatHistory("");
AppendLineToChatHistory("步骤 1. 至少打开两聊天应用程序。你可以选择从Android,Windows Phone,iOS或windows版本.");
AppendLineToChatHistory("Step 2. 选择一个客户端用作服务器.");
AppendLineToChatHistory("Step 3. 设置IP和网络端口.");
AppendLineToChatHistory("Step 4. 启动客户端.");
AppendLineToChatHistory("");
AppendLineToChatHistory("注意: 连接被建立在第一消息发送.");
AppendLineToChatHistory("");
}
/// <summary>
/// Append the provided message to the chat history text box.(将所提供的信息附加到聊天记录文本框中)
/// </summary>
/// <param name="message">Message to be appended</param>(附加信息)
public abstract void AppendLineToChatHistory(string message);
/// <summary>
/// Clears the chat history(清除聊天记录 )
/// </summary>
public abstract void ClearChatHistory();
/// <summary>
/// Clears the input text box(清除输入文本框)
/// </summary>
public abstract void ClearInputLine();
/// <summary>
/// Show a message box as an alternative to writing to the chat history(显示一个消息框,作为一种替代文字的聊天记录)
/// </summary>
/// <param name="message">Message to be output</param>(要输出消息 )
public abstract void ShowMessage(string message);
#endregion
}
}