C# 异步通信 网络聊天程序开发 局域网聊天室开发
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
日志组件所有的功能类都在 HslCommunication 和 HslCommunication.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# 异步通信 网络聊天程序开发 局域网聊天室开发的更多相关文章
- Java网络编程以及简单的聊天程序
网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...
- Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程
SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...
- 利用TCP协议,实现基于Socket的小聊天程序(初级版)
TCP TCP (Transmission Control Protocol)属于传输层协议.其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送.可靠性.有效流控.全双工操作和多路复用 ...
- 移动应用(手机应用)开发IM聊天程序解决方案
这个解决方法已经定制下来很久了,上一段时间比较忙,没有时间整这些东西.最近稍微好些,不怎么加班.所以抽空总结下,同时也分享给大家,也算是给大家一个借鉴吧!或许这并不是最好的解决方案,但只要能满足当前需 ...
- 【Python】iichats —— 命令行下的局域网聊天程序
转载请声明出处:http://www.cnblogs.com/kevince/p/3941728.html ——By Kevince ii系列工具第三弹,命令行下的局域网聊天程序 原理: 程序启动 ...
- Socket网络编程--聊天程序(1)
很早的一段时间,看了APUE和UNPv1了解了网络编程,但是但是只是看而已,没有具体的实践,趁现在没有什么事做,就来实践了解一下网络编程.写博客保存下来,方便以后用到的时候可以查到. 此次的聊天程序是 ...
- hello/hi的简单的网络聊天程序
hello/hi的简单的网络聊天程序 0 Linux Socket API Berkeley套接字接口,一个应用程序接口(API),使用一个Internet套接字的概念,使主机间或者一台计算机上的进程 ...
- Android 网络编程基础之简单聊天程序
前一篇讲了Android的网络编程基础,今天写了一个简单的聊天程序分享一下 首先是服务端代码: package com.jiao.socketdemo; import java.io.Buffered ...
- 网络编程(UDP协议-聊天程序)
网络编程中的UDP协议中聊天程序,发送端口,和接受端口. 发送端口(Send): <span style="font-size:18px;">package cn.it ...
随机推荐
- 使用 mysqladmin debug 查看死锁信息
使用 mysqladmin debug 查看死锁信息 mysqladmin -S /mysql/data/mysql.sock debug 然后在error日志中,会看到: 11 lock struc ...
- 对比PG数据库结构是否一致的方法
如果版本升级涉及数据库更新,测试时要对比旧版数据库更新后是否和全新安装的是否一致,但是数据库结构很复杂的时候对比就很麻烦,postgre可以使用以下方法对比:pg_dump.exe –h 数据库IP ...
- 绑定到外部验证服务LDAP、配置 autofs
题1:您的系统需要按照以下要求绑定到这个服务上:验证服务器的基本 DN 是: dc=xxxx,dc=xxxx,dc=xxxx. 帐户信息和验证信息都是由 LDAP 提供的.连 接 需 要 使 用 证 ...
- 02:golang基础
1.1 golang中的init函数和main函数 1.init函数和main函数 1. golang里面有两个保留的函数:init函数(用于所有package)和main函数(只能用于package ...
- 关闭vs的编译警告
现象:出现warning cxxxx.. 解决:项目,属性,C/C++,高级,禁用特定警告,把xxxx输入
- 关于乱码(MessyCode)问题
乱码本质:读取二进制时采用的编码和最初将字符转成二进制时的编码不一致 编码时(得二进制数组时)不抛出异常,数据就不会被破坏 Java关于乱码(MessyCode)问题 Java使用的是Unicode编 ...
- jQuery validator plugin之Selector
原文 :unchecked Selector Selects all elements that are unchecked. jQuery( ":unchecked" ) Inv ...
- nyoj308-Substring
#include<stdio.h> #include<string.h> #include<string> #include<math.h> #incl ...
- 力扣(LeetCode)804. 唯一摩尔斯密码词
国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: "a" 对应 ".-", "b" 对应 &q ...
- JS模态框 简单案例
演示: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8 ...