这是一个SuperSocket 简单示例,包括服务端和客户端。

一、首先使用NuGet安装SuperSocket和SuperSocket.Engine

二、实现IRequestInfo(数据包):

数据包格式:

包头4个字节,前2个字节是请求命令,后2个字节是正文长度

using SuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SuperSocketServer
{
public class MyRequestInfo : IRequestInfo
{
public MyRequestInfo(byte[] header, byte[] bodyBuffer)
{
Key = ASCIIEncoding.ASCII.GetString(new byte[] { header[0], header[1] });
Data = bodyBuffer;
} public string Key { get; set; } public byte[] Data { get; set; } public string Body
{
get
{
return Encoding.UTF8.GetString(Data);
}
}
}
}

三、实现FixedHeaderReceiveFilter(数据包解析):

using SuperSocket.Facility.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SuperSocketServer
{
public class MyReceiveFilter : FixedHeaderReceiveFilter<MyRequestInfo>
{
public MyReceiveFilter() : base(4)
{ } protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
{
return BitConverter.ToInt16(new byte[] { header[offset + 2], header[offset + 3] }, 0);
} protected override MyRequestInfo ResolveRequestInfo(ArraySegment<byte> header, byte[] bodyBuffer, int offset, int length)
{
byte[] body = bodyBuffer.Skip(offset).Take(length).ToArray();
return new MyRequestInfo(header.Array, body);
}
}
}

四、实现AppSession:

using SuperSocket.SocketBase;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace SuperSocketServer
{
public class MySession : AppSession<MySession, MyRequestInfo>
{
public MySession()
{ } protected override void OnSessionStarted()
{ } protected override void OnInit()
{
base.OnInit();
} protected override void HandleUnknownRequest(MyRequestInfo requestInfo)
{ } protected override void HandleException(Exception e)
{ } protected override void OnSessionClosed(CloseReason reason)
{
base.OnSessionClosed(reason);
}
}
}

五、实现AppServer:

using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils; namespace SuperSocketServer
{
public class MyServer : AppServer<MySession, MyRequestInfo>
{
public MyServer() : base(new DefaultReceiveFilterFactory<MyReceiveFilter, MyRequestInfo>())
{
this.NewSessionConnected += MyServer_NewSessionConnected;
this.SessionClosed += MyServer_SessionClosed;
} protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
{
return base.Setup(rootConfig, config);
} protected override void OnStarted()
{
base.OnStarted();
} protected override void OnStopped()
{
base.OnStopped();
} void MyServer_NewSessionConnected(MySession session)
{
LogHelper.Log("新客户端连接,SessionID=" + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper());
} void MyServer_SessionClosed(MySession session, CloseReason value)
{
LogHelper.Log("客户端失去连接,SessionID=" + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper() + ",原因:" + value);
}
}
}

六、实现CommandBase<MySession, MyRequestInfo>:

using SuperSocket.SocketBase.Command;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils; namespace SuperSocketServer
{
public class EC : CommandBase<MySession, MyRequestInfo>
{
public override void ExecuteCommand(MySession session, MyRequestInfo requestInfo)
{
LogHelper.Log("客户端 " + session.SessionID.Substring(session.SessionID.Length - 6).ToUpper() + " 发来消息:" + requestInfo.Body);
byte[] bytes = ASCIIEncoding.UTF8.GetBytes("消息收到");
session.Send(bytes, 0, bytes.Length);
}
}
}

七、服务端Form1.cs代码:

using SuperSocket.SocketBase.Config;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Utils; namespace SuperSocketServer
{
public partial class Form1 : Form
{
private MyServer _myServer; public Form1()
{
InitializeComponent();
LogHelper.Init(this, txtLog);
} private void Form1_Load(object sender, EventArgs e)
{
_myServer = new MyServer();
ServerConfig serverConfig = new ServerConfig()
{
Port = 2021
};
_myServer.Setup(serverConfig);
_myServer.Start();
} private void button1_Click(object sender, EventArgs e)
{
foreach (MySession session in _myServer.GetAllSessions())
{
byte[] bytes = ASCIIEncoding.UTF8.GetBytes("服务端广播消息");
session.Send(bytes, 0, bytes.Length);
}
}
}
}

八、客户端Form1.cs代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace SuperSocketClient
{
public partial class Form1 : Form
{
private Socket _socket; private NetworkStream _socketStream; public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
EndPoint serverAddress = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2021);
_socket = new Socket(serverAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(serverAddress);
_socketStream = new NetworkStream(_socket); //SocketAsyncEventArgs socketAsyncArgs = new SocketAsyncEventArgs();
//byte[] buffer = new byte[10240];
//socketAsyncArgs.SetBuffer(buffer, 0, buffer.Length);
//socketAsyncArgs.Completed += ReciveAsync;
//_socket.ReceiveAsync(socketAsyncArgs); Receive(_socket); } private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
Random rnd = new Random();
string cmd = "EC";
string msg = "测试消息00" + rnd.Next(0, 100).ToString("00");
Send(cmd, msg);
});
} public void Send(string cmd, string msg)
{
byte[] cmdBytes = Encoding.ASCII.GetBytes(cmd);
byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
byte[] lengthBytes = BitConverter.GetBytes((short)msgBytes.Length); _socketStream.Write(cmdBytes, 0, cmdBytes.Length);
_socketStream.Write(lengthBytes, 0, lengthBytes.Length);
_socketStream.Write(msgBytes, 0, msgBytes.Length);
_socketStream.Flush();
Log("发送:" + msg);
} private void ReciveAsync(object obj, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0)
{
string data = ASCIIEncoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
Log("接收:" + data);
}
} private void Receive(Socket socket)
{
Task.Factory.StartNew(() =>
{
try
{
while (true)
{
byte[] buffer = new byte[10240];
int receiveCount = _socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
if (receiveCount > 0)
{
string data = ASCIIEncoding.UTF8.GetString(buffer, 0, receiveCount);
Log("接收:" + data);
}
}
}
catch (Exception ex)
{
Log("Receive出错:" + ex.Message + "\r\n" + ex.StackTrace);
}
}, TaskCreationOptions.LongRunning);
} #region Log
/// <summary>
/// 输出日志
/// </summary>
private void Log(string log)
{
if (!this.IsDisposed)
{
this.BeginInvoke(new Action(() =>
{
txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " " + log + "\r\n\r\n");
}));
}
}
#endregion }
}

辅助工具类LogHelper:

using SuperSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace Utils
{
public class LogHelper
{
private static Form1 _frm; private static TextBox _txtLog; public static void Init(Form1 frm, TextBox txt)
{
_frm = frm;
_txtLog = txt;
} /// <summary>
/// 输出日志
/// </summary>
public static void Log(string log)
{
if (!_frm.IsDisposed)
{
_frm.BeginInvoke(new Action(() =>
{
_txtLog.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " " + log + "\r\n\r\n");
}));
}
} }
}

测试截图:

问题:

1、客户端使用SocketAsyncEventArgs异步接收数据,第一次能收到数据,后面就收不到了,不知道什么原因,同步接收数据没问题

2、SuperSocket源码中的示例和网上相关的博客,客户端要么是原生Socket实现,要么是Socket调试工具,客户端不需要复杂一点的功能或数据结构吗?客户端不需要解包吗?SuperSocket不能用来写客户端吗?

SuperSocket 简单示例的更多相关文章

  1. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  2. C# 构建XML(简单示例)

    C# 构建XML的简单示例: var pars = new Dictionary<string, string> { {"url","https://www. ...

  3. 根据juery CSS点击一个标签弹出一个遮罩层的简单示例

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  4. ACEXML解析XML文件——简单示例程序

    掌握了ACMXML库解析XML文件的方法后,下面来实现一个比较完整的程序. 定义基本结构 xml文件格式如下 <?xml version="1.0"?> <roo ...

  5. demo工程的清单文件及activity中api代码简单示例

    第一步注册一个账户,并创建一个应用.获取app ID与 app Key. 第二步下载sdk 第三步新建工程,修改清单文件,导入相关的sdk文件及调用相应的api搞定. 3.1 修改清单文件,主要是加入 ...

  6. spring-servlet.xml简单示例

    spring-servlet.xml简单示例 某个项目中的spring-servlet.xml 记下来以后研究用 <!-- springMVC简单配置 --> <?xml versi ...

  7. SignalR 简单示例

    一.什么是 SignalR ASP.NET SignalR is a library for ASP.NET developers that simplifies the process of add ...

  8. Web API 简单示例

    一.RESTful和Web API Representational State Transfer (REST) is a software architecture style consisting ...

  9. XML引入多scheme文件约束简单示例

    XML引入多scheme文件约束简单示例,用company.xsd和department.xsd来约束company.xml: company.xsd <?xml version="1 ...

  10. HTML-003-模拟IDE代码展开收起功能简单示例

    当先我们在日常的编程开发工作中使用编程工具(例如 Eclipse.Sublime 等等)都有相应的代码折叠展开功能,如下图所示,极大的方便了我们的编码工作.

随机推荐

  1. 从源码分析 Redis 异步删除各个参数的具体作用

    以前对异步删除几个参数的作用比较模糊,包括网上的很多资料都是一笔带过,语焉不详. 所以这次从源码(基于 Redis 7.0.5)的角度来深入分析下这几个参数的具体作用: lazyfree-lazy-u ...

  2. CentOS 7替换默认软件源

    安装CentOS 7后,默认源在国外,可以替换为国内的源以提升访问速度 参考https://mirrors.ustc.edu.cn/help/centos.html sudo vi /etc/yum. ...

  3. 【vue】【外包杯】jtl和html文件的区别

    ftl(freemaker) jsp(jstl) 举例:html ftl

  4. AntDesignBlazor示例——列表查询条件

    本示例是AntDesign Blazor的入门示例,在学习的同时分享出来,以供新手参考. 示例代码仓库:https://gitee.com/known/AntDesignDemo 1. 学习目标 重构 ...

  5. IDEA提示Cannot resolve symbol 'String'

    一.解决方案: 1.问题原因: 系统提示Cannot resolve symbol 'String',是由于没有正确导入JDK : 2.解决方案: 在project SDK中正确配置即可. 二.完成. ...

  6. 【译】使用 GitHub Copilot 编写 Git 提交

    在花费数小时修复 bug 或更新特性之后,我们开发人员最不愿意做的事情往往是仔细说明 Git 提交的内容.最新的 Visual Studio 预览版可以帮到您.使用新的生成 Git 提交消息特性来帮助 ...

  7. 吉特日化MES系统--通过浏览器调用标签打印

    三年来做制造行业,差不多做了近30个工厂,也由纯软件转入到了大量的硬件对接,包含厂房设计(这个目前还只是小菜鸟),硬件设计(只是提提意见),安装实施调试(软件和硬件撕逼操作),当然面向的对象也由计算机 ...

  8. 24、Go语言中的OOP思想

    1.是什么? OOP:面向对象 Go语言的解构体嵌套 1.模拟集成性:is - a type A struct { field } type B struct { A // 匿名字段 } 这种方式就会 ...

  9. MySQL|MySQL执行计划

    使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈. explain执行计划包含的信息 每列的内容 列 含义 ...

  10. zabbix 默认消息

    故障事件: {TRIGGER.NAME}监控状态: {TRIGGER.STATUS}报警严重性: {TRIGGER.SEVERITY}触发结果: {TRIGGER.URL}告警时间:{EVENT.DA ...