一、GFF简介
GFF是仿QQ界面,通信基于SAEA.MessageSocket、SAEA.Http、SAEA.MVC实现包含客户端和服务器的程序,源码完全公开,项目源码地址:https://github.com/yswenli/GFF ,大家可以去我的github了解,欢迎follow,star与fork。
GFF消息采用高性能基于IOCP模型的tcp实现,文件采用http实现,代码简洁,一目了然,非常适合想要了解聊天通信关键技术的朋友。
二、运行界面
GFF已实现了消息、表情、图片、截图等关键功能,已编译的绿色版https://github.com/yswenli/GFF/releases下载下来后运行如下图:
三、关键技术
1.界面采用了CSkin的一套QQ皮肤,更多的可以百度一下CSkin相关的资料,或者查看GFF的源码。
2.客户端通信使用了SAEA.MessageSocket的封装类MessageHelper,代码非常简洁,不到100行代码,轻松实现通信。
/*****************************************************************************************************
* 本代码版权归Wenli所有,All Rights Reserved (C) 2015-2016
*****************************************************************************************************
* 所属域:WENLI-PC
* 登录用户:Administrator
* CLR版本:4.0.30319.17929
* 唯一标识:20da4241-0bdc-4a06-8793-6d0889c31f95
* 机器名称:WENLI-PC
* 联系人邮箱:[email protected]
*****************************************************************************************************
* 命名空间:MCITest * 创建年份:2015
* 创建时间:2015-12-02 11:15:24
* 创建人:Wenli
* 创建说明:
*****************************************************************************************************/ using GFF.Component.Config;
using SAEA.MessageSocket;
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks; namespace GFFClient
{
public class MessageHelper
{
public delegate void OnErrorHander(Exception ex, string msg); public delegate void OnMessageHanndle(string channelID, string msg); private static readonly object lockObj = new object(); private string _channelID; private string _userName; ClientConfig clientConfig; public MessageHelper()
{
clientConfig = ClientConfig.Instance();
} /// <summary>
/// Tcp客户端
/// </summary>
public MessageClient Client { get; private set; } public void Start(string userName, string channelID)
{
_userName = userName;
_channelID = channelID; Client = new MessageClient(, clientConfig.IP, clientConfig.Port);
Client.OnChannelMessage += Client_OnChannelMessage;
Client.OnPrivateMessage += Client_OnPrivateMessage;
Client.OnError += Client_OnError;
Client.Connect();
Client.Login();
Client.Subscribe(channelID);
} private void Client_OnError(string ID, Exception ex)
{
OnError.Invoke(ex, ex.Message);
} private void Client_OnChannelMessage(SAEA.MessageSocket.Model.Business.ChannelMessage msg)
{
OnMessage?.Invoke(_channelID, msg.Content);
} private void Client_OnPrivateMessage(SAEA.MessageSocket.Model.Business.PrivateMessage msg)
{
OnMessage?.Invoke(msg.Receiver, msg.Content);
} public void Publish(string channelID, string value)
{
Client.SendChannelMsg(channelID, value);
} public void SendFile(string channelID, string fileName, Action<string> callBack)
{
HttpSendFileAsync(fileName, url => { callBack?.Invoke(url); });
} public void HttpSendFileAsync(string fileName, Action<string> callBack)
{
Task.Run(() =>
{
using (WebClient webClient = new WebClient())
{
var url = clientConfig.Url + Encoding.UTF8.GetString(webClient.UploadFile(clientConfig.Url + "Upload", fileName));
callBack.Invoke(url);
}
});
} public void Stop()
{
try
{
Client.Dispose();
}
catch { }
} public event OnMessageHanndle OnMessage; public event OnErrorHander OnError;
}
}
3.服务端使用SAEA.MessageSocket实现服务端消息处理逻辑、SAEA.MVC实现文件处理逻辑,有兴趣的朋友可以在此基础上实现更多实际业务。
/*****************************************************************************************************
* 本代码版权归Wenli所有,All Rights Reserved (C) 2015-2016
*****************************************************************************************************
* 所属域:WENLI-PC
* 登录用户:Administrator
* CLR版本:4.0.30319.17929
* 唯一标识:20da4241-0bdc-4a06-8793-6d0889c31f95
* 机器名称:WENLI-PC
* 联系人邮箱:[email protected]
*****************************************************************************************************
* 命名空间:MCITest * 创建年份:2015
* 创建时间:2015-12-02 11:15:24
* 创建人:Wenli
* 创建说明:
*****************************************************************************************************/ using GFF.Component.Config;
using GFF.Helper;
using SAEA.MessageSocket;
using SAEA.MVC;
using SAEA.Sockets.Interface;
using System; namespace GFFServer
{
internal class Program
{
private static MessageServer messageServer; private static SAEAMvcApplication mvcApplication; private static void Main(string[] args)
{
Console.Title = "GFFServer"; ConsoleHelper.WriteLine("正在初始化消息服务器...", ConsoleColor.Green);
messageServer = new MessageServer();
messageServer.OnAccepted += Server_OnAccepted;
messageServer.OnError += Server_OnError;
messageServer.OnDisconnected += Server_OnDisconnected;
ConsoleHelper.WriteLine("消息服务器初始化完毕...", ConsoleColor.Green); ConsoleHelper.WriteLine("正在初始化文件服务器...", ConsoleColor.DarkYellow);
var filePort = ServerConfig.Instance().FilePort;
mvcApplication = new SAEAMvcApplication(port: filePort);
mvcApplication.SetDefault("File", "Test");
ConsoleHelper.WriteLine("文件服务器初始化完毕,http://127.0.0.1:" + filePort + "/...", ConsoleColor.DarkYellow); ConsoleHelper.WriteLine("正在启动消息服务器...", ConsoleColor.Green);
messageServer.Start();
ConsoleHelper.WriteLine("消息服务器启动完毕...", ConsoleColor.Green); ConsoleHelper.WriteLine("正在启动文件服务器...", ConsoleColor.DarkYellow);
mvcApplication.Start();
ConsoleHelper.WriteLine("文件服务器启动完毕...", ConsoleColor.DarkYellow); ConsoleHelper.WriteLine("点击回车,结束服务");
Console.ReadLine();
} private static void Server_OnDisconnected(string ID, Exception ex)
{
ConsoleHelper.WriteInfo(string.Format("客户端{0}已断开连接,当前连接数共记:{1}", ID, messageServer.ClientCounts));
} private static void Server_OnError(string ID, Exception ex)
{
ConsoleHelper.WriteErr(ex);
} private static void Server_OnAccepted(IUserToken userToken)
{
ConsoleHelper.WriteInfo(string.Format("客户端{0}已连接,当前连接数共记:{1}", userToken.ID, messageServer.ClientCounts));
}
}
}
using SAEA.MVC;
using System.IO; namespace GFFServer.Controllers
{
/// <summary>
/// 文件处理
/// </summary>
public class FileController : Controller
{
public ActionResult Test()
{
return Content("GFF File Server");
} [HttpPost]
public ActionResult Upload()
{
var postFile = HttpContext.Request.PostFiles[];
var filePath = HttpContext.Server.MapPath("/Files");
if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
filePath = Path.Combine(filePath, postFile.FileName);
System.IO.File.WriteAllBytes(filePath, postFile.Data);
return Content("Download?fileName=" + postFile.FileName);
} public ActionResult Download(string fileName)
{
var filePath = Path.Combine(HttpContext.Server.MapPath("/Files"), fileName);
return File(filePath);
}
}
}
四、项目结构
1.GFF.Component 封装客户的截图、聊天展现、表情、配置等
2.GFF.Helper 封装了GFF项目中需要使用的一些工具类
3.GFF.Model 是GFF中使用到类、接口、枚举等
4.GFFClient 是GFF的客户端主体项目
5.GFFServer 是GFF的服务端主体项目