Prepare


本文将使用一个NuGet公开的组件技术来实现一个局域网聊天程序,利用组件提供的高性能异步网络机制实现,免去了手动编写底层的困扰,易于二次开发,扩展自己的功能。

联系作者及加群方式(激活码在群里发放):http://www.hslcommunication.cn/Cooperation

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装:

Install-Package HslCommunication

NuGet安装教程  http://www.cnblogs.com/dathlin/p/7705014.html

Summary


之前已经有篇博客说明了同步网络通信的开发,同步网络通信适用于什么样的场景呢,适用于客户端向服务器请求数据,必须有数据返回的情况,无论成功还是失败。地址:http://www.cnblogs.com/dathlin/p/7697782.html

而异步的网络通信适用于什么情况呢,适用于服务器进行群发数据的时候,比如发送消息给所有的在线客户端,为了更好的说明异步网络通信的实现机制,开发一个多客户端的局域网聊天程序来演示异步操作。

特性如下:

  • 局域网聊天室支持多人在线,上限取决于服务器的电脑性能。
  • 支持用户名登录,支持重复的用户名登录。
  • 支持显示所有在线客户端的信息显示,包括在线时间,上线时间,ip地址,用户名等等。
  • 支持服务器主动发消息给客户端。
  • 支持服务器强制关闭客户端。
  • 支持其他人的上下线信息跟踪。

本聊天程序是基于C-S架构设计的,需要创建3个项目,一个服务器项目,用来中转所有的消息的,一个是客户端项目,也就是实际的聊天程序,本次项目还显示所有在线的客户端信息,ip地址,名字。

至于账户,本次不采用任何的用户名密码登录机制,就采用简易化处理,直接输入一个名字即可,当然,你也可以更改成用户名密码登录的机制,也不是特别困难。

简易的聊天程序不支持图片,表情包的发送接收,这部分实现起来不是同一个次元的,这部分以后攻克了再开新的博文。

------------> 小插曲

如果需要更复杂的功能,比如账户的登录,密码修改,版本控制,账户支持头像等等,一个基于本组件扩展出来的CS架构的基础模版项目,二次基于此进行方便的二次开发,该项目使用了好几处的文件管理:

https://github.com/dathlin/ClientServerProject

一个C-S模版,该模版由三部分的程序组成,一个服务端运行的程序,一个客户端运行的程序,还有一个公共的组件,实现了基础的账户管理功能,版本控制,软件升级,公告管理,消息群发,共享文件上传下载,批量文件传送功能。具体的操作方法见演示就行。本项目的一个目标是:提供一个基础的中小型系统的C-S框架,客户端有四种模式,无缝集成访问,winform版本,wpf版本,asp.net mvc版本,Android版本。方便企业进行中小型系统的二次开发和个人学习。

Reference


日志组件所有的功能类都在 HslCommunicationHslCommunication.Enthernet 命名空间,所以再使用之前先添加:在服务器程序和客户端程序都要添加

using HslCommunication;
using HslCommunication.Enthernet;

Start Program


首先先创建三个项目,server项目,client项目,common项目,然后使用Nuget将客户端和服务器两个项目都安装组件,然后切换到服务器程序,接下来就是真的创建程序了。

  • common项目:存放一些服务器和客户端共同用到的类。
  • server项目:消息路由中心。所有的客户端发送的消息都先经过服务器转发。
  • client项目:和用户交互的客户端,接受用户的输入并且显示出来。

在整个项目中,核心部分就是网络通信了,需要实现客户端向服务器发送消息,这个相对比较好实现,因为服务器的ip地址和端口都是公开的。但是客户端的ip和端口是未知的,因为我们要实现任意的电脑都能登录客户端。所以我们需要使用HslCommunication来方便的实现这些操作。

在server端和client端都需要安装HslCommunication组件。因为我们要实现在客户端和服务器端进行通信,通信功能众多,所以需要进行约定,消息的id,我们最终根据消息的id来区分不同的消息。

  • 1    系统消息,用于显示谁谁谁上线了,谁谁谁下线了
  • 2    是用户发送的消息,在聊天窗口进行显示的
  • 3    客户端在线信息,所以在线客户端的信息
  • 4    强制客户端下线,用于服务器向客户端发送关闭的指令,客户端接收到后退出程序。

综上所述,这个项目已经初步成型,而且通过消息id可以实现其他自己功能扩展,可以实现任何的交互操作。不一定是聊天系统,各种数据同步机制,推送机制,局域网机制的游戏程序也可以实现。

本项目的源代码地址如下:https://github.com/dathlin/NetChatRoom

Server


先填写核心块

        #region 核心网络服务相关

        private NetComplexServer complexServer;

        private void ComplexServerInitialization()
{
complexServer = new NetComplexServer(); // 实例化
complexServer.KeyToken = new Guid("91625bad-d581-44ab-b121-ffff5bcb83fb"); // 设置令牌,提升安全性
complexServer.LogNet = new HslCommunication.LogNet.LogNetSingle("log.txt"); // 设置日志记录,如果不需要,可以删除
complexServer.ClientOnline += ComplexServer_ClientOnline; // 客户端上线时触发
complexServer.ClientOffline += ComplexServer_ClientOffline; // 客户端下线时触发
complexServer.AllClientsStatusChange += ComplexServer_AllClientsStatusChange; // 只要有客户端上线或下线就触发
complexServer.AcceptString += ComplexServer_AcceptString; // 客户端发来消息时触发
complexServer.ServerStart(12345); // 启动服务,需要选择一个端口
} private void ComplexServer_AllClientsStatusChange(string object1)
{ } private void ComplexServer_AcceptString(AsyncStateOne object1, NetHandle object2, string object3)
{
// 我们规定
// 1 是系统消息,
// 2 是用户发送的消息
// 3 客户端在线信息
// 4 强制客户端下线
// 当你的消息头种类很多以后,可以在一个统一的类中心进行规定
if (object2 == 2)
{
// 来自客户端的消息,就只有这么一种情况
NetMessage msg = new NetMessage()
{
FromName = object1.LoginAlias,
Time = DateTime.Now,
Type = "string",
Content = object3,
}; // 群发出去
complexServer.SendAllClients(2, JObject.FromObject(msg).ToString());
}
} private void ComplexServer_ClientOffline(AsyncStateOne object1, string object2)
{
// 客户端下线,发送消息给客户端
complexServer.SendAllClients(1, object1.IpAddress + " " + object1.LoginAlias + " : " + object2);
// 发送在线信息
complexServer.SendAllClients(3, RemoveOnLine(object1.ClientUniqueID)); // 在主界面显示信息
ShowMsg(object1.IpAddress + " " + object1.LoginAlias + " : " + object2);
ShowOnlineClient( );
} private void ComplexServer_ClientOnline(AsyncStateOne object1)
{
// 客户端上线,发送消息给客户端
complexServer.SendAllClients(1, object1.IpAddress + " " + object1.LoginAlias + " : 上线");
// 发送在线信息
NetAccount account = new NetAccount()
{
Guid = object1.ClientUniqueID,
Ip = object1.IpAddress,
Name = object1.LoginAlias,
OnlineTime = DateTime.Now.ToString(),
};
complexServer.SendAllClients(3, AddOnLine(account)); // 在主界面显示信息
ShowMsg(object1.IpAddress + " " + object1.LoginAlias + " : 上线");
ShowOnlineClient( );
} #endregion

在此处有个功能是实现对在线客户端的信息记录,包含了许多的信息,并可以实现扩展

        #region 在线客户端信息实现块

        private List<NetAccount> all_accounts = new List<NetAccount>();
private object obj_lock = new object(); // 新增一个用户账户到在线客户端
private string AddOnLine(NetAccount item)
{
string result = string.Empty;
lock(obj_lock)
{
all_accounts.Add(item);
result = JArray.FromObject(all_accounts).ToString();
}
return result;
} // 移除在线账户并返回相应的在线信息
private string RemoveOnLine(string guid)
{
string result = string.Empty;
lock (obj_lock)
{
for (int i = 0; i < all_accounts.Count; i++)
{
if(all_accounts[i].Guid == guid)
{
all_accounts.RemoveAt(i);
break;
}
}
result = JArray.FromObject(all_accounts).ToString();
}
return result;
} #endregion

关于在线信息的类

    /// <summary>
/// 扩展实现的账户信息,记录唯一标记,ip地址,上线时间,名字
/// </summary>
public class NetAccount
{
/// <summary>
/// 唯一ID
/// </summary>
public string Guid { get; set; }
/// <summary>
/// Ip地址
/// </summary>
public string Ip { get; set; }
/// <summary>
/// 上线时间
/// </summary>
public string OnlineTime { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 字符串标识形式
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "[" + Ip + "] : " + Name;
}
}

下面演示在服务器端如何发送一个系统消息给所有客户端

        private void userButton1_Click(object sender, EventArgs e)
{
// 服务器发送系统消息到客户端
if(!string.IsNullOrEmpty(textBox2.Text))
{
// 来自客户端的消息,就只有这么一种情况
NetMessage msg = new NetMessage()
{
FromName = "系统",
Time = DateTime.Now,
Type = "string",
Content = textBox2.Text,
}; // 群发出去
complexServer.SendAllClients(2, JObject.FromObject(msg).ToString());
}
}

这样就可以实现消息的发送了。

Client


先填写核心块

       #region 客户端网络块

        private NetComplexClient net_socket_client = new NetComplexClient();

        private void Net_Socket_Client_Initialization()
{
try
{
net_socket_client.KeyToken = new Guid("91625bad-d581-44ab-b121-ffff5bcb83fb"); // 设置令牌,必须与连接的服务器令牌一致
net_socket_client.EndPointServer = new System.Net.IPEndPoint(
System.Net.IPAddress.Parse("127.0.0.1"),12345); // 连接的服务器的地址,必须和服务器端的信息对应
net_socket_client.ClientAlias = LoginName; // 传入账户名
net_socket_client.AcceptString += Net_socket_client_AcceptString; // 接收到字符串信息时触发
net_socket_client.ClientStart();
}
catch (Exception ex)
{
SoftBasic.ShowExceptionMessage(ex);
}
} /// <summary>
/// 接收到服务器的字节数据的回调方法
/// </summary>
/// <param name="state">网络连接对象</param>
/// <param name="customer">用户自定义的指令头,用来区分数据用途</param>
/// <param name="data">数据</param>
private void Net_socket_client_AcceptString(AsyncStateOne state, NetHandle customer, string data)
{
// 我们规定
// 1 是系统消息,
// 2 是用户发送的消息
// 3 客户端在线信息
// 4 退出指令
// 当你的消息头种类很多以后,可以在一个统一的类中心进行规定
if (customer == 1)
{
ShowSystemMsg(data);
}
else if(customer == 2)
{
ShowMsg(data);
}
else if(customer == 3)
{
ShowOnlineClient(data);
}
else if(customer == 4)
{
// 退出系统
QuitSystem( );
}
} #endregion

用户在输入发送信息的时候,就调用如下的方法:

        // 发送消息
private void userButton1_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox3.Text)) return; net_socket_client.Send(2, textBox3.Text);
textBox3.Clear();
}

具体的代码逻辑还需要参照github上的源代码。

C# 异步通信 网络聊天程序开发 局域网聊天室开发的更多相关文章

  1. Java网络编程以及简单的聊天程序

    网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...

  2. Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程

    SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...

  3. 利用TCP协议,实现基于Socket的小聊天程序(初级版)

    TCP TCP (Transmission Control Protocol)属于传输层协议.其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送.可靠性.有效流控.全双工操作和多路复用 ...

  4. 移动应用(手机应用)开发IM聊天程序解决方案

    这个解决方法已经定制下来很久了,上一段时间比较忙,没有时间整这些东西.最近稍微好些,不怎么加班.所以抽空总结下,同时也分享给大家,也算是给大家一个借鉴吧!或许这并不是最好的解决方案,但只要能满足当前需 ...

  5. 【Python】iichats —— 命令行下的局域网聊天程序

    转载请声明出处:http://www.cnblogs.com/kevince/p/3941728.html   ——By Kevince ii系列工具第三弹,命令行下的局域网聊天程序 原理: 程序启动 ...

  6. Socket网络编程--聊天程序(1)

    很早的一段时间,看了APUE和UNPv1了解了网络编程,但是但是只是看而已,没有具体的实践,趁现在没有什么事做,就来实践了解一下网络编程.写博客保存下来,方便以后用到的时候可以查到. 此次的聊天程序是 ...

  7. hello/hi的简单的网络聊天程序

    hello/hi的简单的网络聊天程序 0 Linux Socket API Berkeley套接字接口,一个应用程序接口(API),使用一个Internet套接字的概念,使主机间或者一台计算机上的进程 ...

  8. Android 网络编程基础之简单聊天程序

    前一篇讲了Android的网络编程基础,今天写了一个简单的聊天程序分享一下 首先是服务端代码: package com.jiao.socketdemo; import java.io.Buffered ...

  9. 网络编程(UDP协议-聊天程序)

    网络编程中的UDP协议中聊天程序,发送端口,和接受端口. 发送端口(Send): <span style="font-size:18px;">package cn.it ...

随机推荐

  1. Java正则表达式草稿程序*2

    1.成绩统计. 输入文件input.txt: 张三 语文12 数学31 英语11 李四 语文22 数学22 英语22 王五 语文33 数学33 英语33 期待输出output.txt: 张三 语文12 ...

  2. PXC添加新节点

    先拉数据,再启用节点,可以避免SST 拉数据 [root@pxc_node1_172.16.11.132 ~]# /usr/bin/innobackupex --defaults-file=/etc/ ...

  3. Html 标签初知

    Html 标签初知 什么是Html 标签 超文本标记语言(外国语简称:HTML)标记标签通常被称为HTML标签,HTML标签是HTML语言中最基本的单位,HTML标签是HTML(标准通用标记语言下的一 ...

  4. ant_<target>标签含义与使用

    <target>标记目标 目标是一个或多个任务的集合,任务是一段可执行的代码:构建文件中包含一个项目,在项目内部声明了所有目标: <target name = "run&q ...

  5. UVA11992 Fast Matrix Operations

    思路 注意到最多20行,拆成20颗线段树即可 注意set标记清空左右儿子的add,不要清空自己的add,因为这个set操作之后可能还有add存在这个节点上 代码 #include <cstdio ...

  6. (转) Ensemble Methods for Deep Learning Neural Networks to Reduce Variance and Improve Performance

    Ensemble Methods for Deep Learning Neural Networks to Reduce Variance and Improve Performance 2018-1 ...

  7. Java 成员变量和属性的区别

    例一: 一个Student pojo类: public class Student{ private String name; private int age; public String getNa ...

  8. linux解压类型总结

    1.*.tar 用 tar –xvf 解压2.*.gz 用 gzip -d或者gunzip 解压3.*.tar.gz和*.tgz 用 tar –xzf 解压4.*.bz2 用 bzip2 -d或者用b ...

  9. Linux wc -l 统计文件行数存在的问题

    1.使用这种方式效率较低,而且不注意可能出现错误 find  . -name "*.pc" |xargs wc -l 直接查看 total 不是正确的值. 原因: 这种方式存在一个 ...

  10. Cocos Creator 使用protobufjs

    Win7 + Creator 2.0.0 + protobufjs 6.8.8 1.下载安装protobufjs npm install -g protobufjs 可以看到protobufjs安装在 ...