实例介绍
【实例截图】
【核心代码】
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 } }
标签: C#局域网聊天
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论