超详细的TCP、Sokcket和SuperSocket与TCP入门指导
前言
本文主要介绍TCP、Sokcket和SuperSocket的基础使用。
创建实例模式的SuperSocket服务
首先创建控制台项目,然后Nuget添加引用SuperSocket.Engine。
然后编写服务代码,SuperSocket的服务代码主要是配置AppServer对象,因为AppServer已经很好的封装端口监听了。
代码如下所示:
class Program
{
static AppServer appServer { get; set; }
static void Main(string[] args)
{
var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig();
serverConfig.Port = 5180;
serverConfig.TextEncoding = "gb2312";
serverConfig.MaxConnectionNumber = 1000;
appServer = new AppServer();
//配置
if (!appServer.Setup(serverConfig))
{
Console.WriteLine("配置失败!");
return;
}
//启动
if (!appServer.Start())
{
Console.WriteLine("启动失败!");
return;
}
Console.WriteLine("启动成功,按Q退出!");
appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected);
appServer.SessionClosed += appServer_NewSessionClosed;
appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived);
while (Console.ReadKey().KeyChar != 'q')
{
continue;
}
//停止
appServer.Stop();
Console.WriteLine("服务已停止");
Console.ReadKey();
}
static void appServer_NewSessionConnected(AppSession session)
{
var count = appServer.SessionCount;
Console.WriteLine($"服务端得到来自客户端的连接成功 ,当前会话数量:" + count);
//这里也可以向会话的stream里写入数据,如果在这里向流写入数据,则客户端需要在Send之前先接收一次,不然的话,Send后接收的就是这条数据了
session.Send("连接成功");
}
static void appServer_NewSessionClosed(AppSession session, CloseReason aaa)
{
var count = appServer.SessionCount;
Console.WriteLine($"服务端 失去 来自客户端的连接" + session.SessionID + aaa.ToString()+ " 当前会话数量:" + count);
}
static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
{
Console.WriteLine($"Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
session.Send("我是返回值:" + requestInfo.Body);
}
}
AppServer:AppServer是SuperSocket中定义的Socket服务类,他替我们实现了复杂的端口监听,不用再写While循环,不用再关心线程阻塞的问题,在监听端口在这里,我们只要调用AppServer的对象的Start方法,就可以了;AppServer还提供了一个配置文件类—ServerConfig,通过它,我们可以配置具体监听的端口、并发数量、编码、最大传输字节数、传输模式(TCP/UDP)等等属性;此外还提供三个重要事件:会话连接启动事件(NewSessionConnected)、会话关闭事件(SessionClosed)、请求接受事件(NewRequestReceived)。
注:文中在连接成功的事件中,我们向客户端发送消息了,即,客户端在连接后,发送消息前,需要接收该信息。
创建TCP发送消息客户端
服务建立后,我们建立客户端。
代码如下所示:
static void Main(string[] args)
{
TCPConnect("127.0.0.1", 5180);
Console.ReadKey();
}
static void TCPConnect(String server, Int32 port)
{
string message = $"ADD kiba518 518" + "\r\n";
try
{
TcpClient client = new TcpClient();
client.Connect(server, port);
Byte[] data = System.Text.Encoding.Default.GetBytes(message);
String responseData = String.Empty;
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024 * 1024 * 2];
Int32 bytes = stream.Read(buffer, 0, buffer.Length);
responseData = System.Text.Encoding.Default.GetString(buffer, 0, bytes);
Console.WriteLine("接收服务器在连接事件中写入的数据: {0}", responseData);
stream.Write(data, 0, data.Length);
Console.WriteLine("发送数据: {0}", message);
data = new Byte[256];
bytes = stream.Read(buffer, 0, buffer.Length);
responseData = System.Text.Encoding.Default.GetString(buffer, 0, bytes);
Console.WriteLine("接收返回值: {0}", responseData);
stream.Close();
client.Close();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e.Message);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e.Message);
}
Console.Read();
}
代码很简单,就是使用TcpClient连接服务器的IP和端口,然后发送消息。
因为我们使用的SuperSocket,有格式要求,所以我们需要准守。
格式要求如下:
命令名称+空格+参数+参数+...参数+"\r\n"
对应的字符串如下:
$"ADD kiba518 518" + "\r\n"
因为上文中,服务在连接成功后就向客户端发送的流中写入了数据,所以,我们在Send消息前,先接收一下流中的数据。
客户端与服务联调
先运行服务,在运行客户端,结果服务端与客户端成功的完成了一次通信,如下图所示:
为了更清晰的了解通信内容,我们在服务接收消息事件中断点,如下图:
可以看到参数requestInfo完整的解析了我们发送的字符串【"ADD kiba518 518" + "\r\n"】。
创建配置模式的SuperSocket服务
现在我们创建一个配置模式的SuperSocket服务,这种模式客户通过配置创建多个SuperSocket,即可以在一个项目里通过配置监听多个端口,这里,我们只做一个端口监听的配置例子。
与实例模式的开始一样,先创建一个控制台程序,然后Nuget添加引用SuperSocket.Engine。
然后进行三步操作。
一,编写Main函数,启动SuperSocket,通过启动引导工厂BootstrapFactory实例化一个启动引导对象,然后初始化化,该初始化会遍历当前项目中所有继承了AppServer的类,然后调用他们的Start方法,代码如下所示:
static void Main(string[] args)
{
#region 初始化Socket
IBootstrap bootstrap = BootstrapFactory.CreateBootstrap();
if (!bootstrap.Initialize())
{
Console.WriteLine(DateTime.Now + ":Socket初始化失败\r\n");
return;
}
var result = bootstrap.Start();
foreach (var server in bootstrap.AppServers)
{
if (server.State == ServerState.Running)
{
Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket运行中\r\n"); }
else
{
Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket启动失败\r\n");
}
}
Console.ReadKey();
#endregion
}
二,修改App.config配置文件,在configuration节点下,增加superSocket的section,并配置superSocket,代码如下:
<configSections>
<section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine" />
</configSections>
<!--配置SocketServer路径-->
<superSocket>
<servers>
<!-- serverType属性有两个参数,第一个是服务类的完全限定名,第二个是服务类的命名空间 -->
<server name="MySocket" textEncoding="gb2312"
serverType="SuperSocketServerSessionMode.SocketServer, SuperSocketServerSessionMode"
ip="Any" port="5180" maxConnectionNumber="100">
</server>
</servers>
</superSocket>
三,创建SocketServer类、SocketSession类、SocketCommand类。
SocketServer类:继承泛型AppServer(其泛型类指定一个会话类)该类用于创建SuperSocket的服务并监听端口;其Setup方法,默认读取App.config配置文件中的superSocket节点—servers节点—server节点;读取时根据server的serverType属性匹配读取。
public class SocketServer : AppServer<SocketSession>
{
protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
{
Console.WriteLine("正在准备配置文件");
return base.Setup(rootConfig, config);
}
protected override void OnStarted()
{
Console.WriteLine("服务已开始");
base.OnStarted();
}
protected override void OnStopped()
{
Console.WriteLine("服务已停止");
base.OnStopped();
}
protected override void OnNewSessionConnected(SocketSession session)
{
Console.WriteLine("新的连接地址为" + session.LocalEndPoint.Address.ToString() + ",时间为" + DateTime.Now);
base.OnNewSessionConnected(session);
}
}
SocketSession类:继承AppSession,是SuperSocket的会话类。
如果客户端所发送的消息不合法,则会被会话的HandleUnknownRequest函数截获,如果合法,则发送到指定的命令类中。
代码如下:
public class SocketSession : AppSession<SocketSession>
{
public override void Send(string message)
{
Console.WriteLine("发送消息:" + message);
base.Send(message);
}
protected override void OnSessionStarted()
{
Console.WriteLine("Session已启动");
base.OnSessionStarted();
}
protected override void OnInit()
{
this.Charset = Encoding.GetEncoding("gb2312");
base.OnInit();
}
protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
{
Console.WriteLine($"遇到未知的请求 Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
base.HandleUnknownRequest(requestInfo);
}
}
SocketCommand类:是SuperSocket的命令类,定义明确的会话命令;类名即客户端发送消息的第一个空格前的字符串。
代码如下:
public class SocketCommand : CommandBase<SocketSession, StringRequestInfo>
{
public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
{
//根据参数个数或者其他条件判断,来进行一些自己的操作
Console.WriteLine($"调用成功 Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
session.Send("已经成功接收到你的请求\r\n");
}
}
创建配置模式的SuperSocket客户端
创建一个配置模式的SuperSocket客户端,这一次我们使用Socket类创建。
代码如下:
static Socket socketClient { get; set; }
static void Main(string[] args)
{
socketClient = new Socket(SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint point = new IPEndPoint(ip, 5180);
socketClient.Connect(point);
Thread thread = new Thread(Recive); //不停的接收服务器端发送的消息
thread.Start();
Thread thread2 = new Thread(Send);//不停的给服务器发送数据
thread2.Start();
}
static void Recive()
{
while (true)
{
//获取发送过来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
var effective = socketClient.Receive(buffer);
if (effective == 0)
{
break;
}
var str = Encoding.Default.GetString(buffer, 0, effective);
Console.WriteLine("服务器 --- " + str);
Thread.Sleep(2000);
}
}
static void Send()
{
int i = 0;int param1 = 0;int param2 = 0;
while (true)
{
i++;param1 = i + 1;param2 = i + 2;
Console.WriteLine($"Send i:{i} param1:{param1} param2:{param2}");
string msg = $"SocketCommand {param1} {param2}" + "\r\n";
Console.WriteLine($"msg:{msg}");
var buffter = Encoding.Default.GetBytes(msg);
var temp = socketClient.Send(buffter);
Console.WriteLine($"Send 发送的字节数:{temp} ");
Thread.Sleep(1000);
}
}
可以看到Socket的使用方式与Tcp的使用方式几乎相同,都是指定IP和端口号,只是Socket多了一步,需要指定协议类型ProtocolType,这里我们指定了是TCP。
客户端与服务联调
先运行服务,在运行客户端,结果通信成功,如下图所示:
----------------------------------------------------------------------------------------------------
到此TCP、Sokcket和SuperSocket的基本使用已经介绍完了,代码已经传到Github上了,欢迎大家下载。
代码已经传到Github上了,欢迎大家下载。
Github地址: https://github.com/kiba518/SuperSocketConsole
----------------------------------------------------------------------------------------------------
注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!
https://www.cnblogs.com/kiba/p/13728088.html
超详细的TCP、Sokcket和SuperSocket与TCP入门指导的更多相关文章
- webpack+vue+vueRouter模块化构建小demo实例超详细步骤(附截图、代码、入门篇)
说明:本demo使用yarn代替npm指令来下载一系列依赖,有详细指令说明:使用WebStorm下Terminal来输入指令: >开始(确认已经安装node环境和yarn包管理工具) 1.新建项 ...
- 一个基于TCP/IP的服务器与客户端通讯的小项目(超详细版)
1.目的:实现客户端向服务器发送数据 原理: 2.建立两个控制台应用,一个为服务器,用于接收数据.一个为客户端,用于发送数据. 关键类与对应方法: 1)类IPEndPoint: 1.是抽象类EndPo ...
- TCP/IP超详细总结
网络的基础知识 一.协议 1.简介: 在计算机网络与信息通信领域里,人们经常提及“协议”一词.互联网中常用的具有代表性的协议有IP.TCP.HTTP等.而LAN(局域网)中常用的协议有IPX/SPX” ...
- Java——TCP/IP超详细总结
网络的基础知识 一.协议 1.简介: 在计算机网络与信息通信领域里,人们经常提及“协议”一词.互联网中常用的具有代表性的协议有IP.TCP.HTTP等.而LAN(局域网)中常用的协议有IPX/SPX” ...
- 超强、超详细Redis数据库入门教程
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么2.redis的作者何许人也3.谁在使用red ...
- [转]超详细图解:自己架设NuGet服务器
本文转自:http://diaosbook.com/Post/2012/12/15/setup-private-nuget-server 超详细图解:自己架设NuGet服务器 汪宇杰 ...
- 超强、超详细Redis数据库入门教程(转载)
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...
- Linux 学习笔记之超详细基础linux命令(the end)
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 14---------------- ...
- 转帖: 一份超全超详细的 ADB 用法大全
增加一句 连接 网易mumu模拟器的方法 adb connect 127.0.0.1:7555 一份超全超详细的 ADB 用法大全 2016年08月28日 10:49:41 阅读数:35890 原文 ...
随机推荐
- js error 错误处理
(new) Error([message[, fileName[,lineNumber]]]) 单独定义Error()错误,函数继续进行 当像函数一样使用 Error 时 -- 如果没有 new,它将 ...
- 小程序开发-组件navigator导航篇
navigator 页面链接 navigator的open-type属性 可选值 navigate.redirect.switchTab,对应于wx.navigateTo.wx.redirectTo. ...
- 【Go语言入门系列】(九)写这些就是为了搞懂怎么用接口
[Go语言入门系列]前面的文章: [Go语言入门系列](六)再探函数 [Go语言入门系列](七)如何使用Go的方法? [Go语言入门系列](八)Go语言是不是面向对象语言? 1. 引入例子 如果你使用 ...
- 如何让SpringBoot工程在log/控制台中实时打印MyBatis执行的SQL语句
工程下载:https://files.cnblogs.com/files/xiandedanteng/gatling20200429-4.zip 其实就是一句话设置的事情,实现步骤: 在applica ...
- [POJ3253]Fence Repair(单调队列)
题目链接 http://poj.org/problem?id=3253 题目描述 大意:切长度为a的木条的花费是a,给定最终切好的n段各自的长度,问由原来的一根木条(长度为n段长度和)以最终总花费最小 ...
- 复习 | 重温jQuery和Zepto的API
jq和zepto很相似有许多共同的api,zepto也出了很多与jq不一样的api,总的来说,两者更相似,但是zepto更轻量一点,正好公司也在用,复习这两个没错 jq中的zepto的事件和ajax我 ...
- day53:django:URL别名/反向解析&URL分发&命名空间&ORM多表操作修改/查询
目录 1.URL别名&反向解析 2.URL分发&命名空间 3.ORM多表操作-修改 4.ORM多表操作-查询 4.1 基于对象的跨表查询 4.2 基于双下划线的跨表查询 4.3 聚合查 ...
- 代码检查工具 Sonar 安装&使用
本文主要说明Sonar的安装方式并附上依赖安装包,本文目标只实现本地搭建测试的Sonar环境,以及本地的测试项目的非定制化扫描 本机测试环境:Win10-X64,.vs2017 依赖包: 1 ...
- 如何使用 C# 中的 ValueTask
在 C# 中利用 ValueTask 避免从异步方法返回 Task 对象时分配 翻译自 Joydip Kanjilal 2020年7月6日 的文章 <How to use ValueTask i ...
- 浅谈SSRF
前言 最近主要是在思考考研的事.还是没想好-- 这几天的话写了一篇简单代审投稿了星盟,看了会SSRF.今天简单写下SSRF. 本文所有思路均来自互联网,并没有新想法.仅仅只是做个记录. 本文可能会有大 ...