这是一个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. 【uniapp】学习笔记day02 | uniapp搭建

    起因:需要做一个小程序,家人们谁懂啊,老师我真的不会做,由于懒得看视频学习,于是只能看博客学习了. uniapp 好处: 1.不用关心适配问题 2.可以发布到各大平台的小程序 3.上手容易,使用vue ...

  2. 【Javaweb】了解link标签

    link标签的属性 标签就是定义文档和外部的关系,常见用途是链接样式表.通常指存在于head部分. 规定被连接文档的位置 <link rel='stylesheet' href='./ease. ...

  3. 一文秒懂|Linux字符设备驱动

    1.前言 众所周知,Linux内核主要包括三种驱动模型,字符设备驱动,块设备驱动以及网络设备驱动. 其中,Linux字符设备驱动,可以说是Linux驱动开发中最常见的一种驱动模型. 我们该系列文章,主 ...

  4. springCore完整学习教程2,入门级别

    上集说到:2. 3,咱们从2.3集开始 2. Externalized Configuration 2.3. External Application Properties Spring Boot会自 ...

  5. Linux笔记03: Linux常用命令_3.2目录操作命令

    3.2 目录操作命令 3.2.1 ls命令 ●命令名称:ls. ●英文原意:list directory contents. ●所在路径:/usr/bin/ls. ●执行权限:所有用户. ●功能描述: ...

  6. C++ Qt开发:PushButton按钮组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QPushBu ...

  7. 理解Mysql索引原理及特性

    作为开发人员,碰到了执行时间较长的sql时,基本上大家都会说"加个索引吧".但是索引是什么东西,索引有哪些特性,下面和大家简单讨论一下. 1 索引如何工作,是如何加快查询速度 索引 ...

  8. style绑定及随机颜色

    一个小案例 颜色变换 style单机事件的绑定

  9. 神奇的 SQL ,高级处理之 Window Functions → 打破我们的局限!

    开心一刻 今天儿子跟老婆聊天 儿子:妈妈,我为什么没有两个爸爸呀 老婆:每个人都只有一个爸爸呀,你看谁有两个爸爸了 儿子一脸真诚的看着老婆:那你为什么就有两个爸爸呢 老婆一脸疑惑的望向儿子:我哪有两个 ...

  10. MySQL运维11-Mycat分库分表之应用指定分片

    一.应用指定分片 此规则是在运行阶段有应用自主决定路由到那个分片,根据提供的字段,然后按照指定的规则,截取该字段的部分子字符串当做分片的依据,该分别方法比较灵活,适用于某个字段有几个特殊的字符串拼接而 ...