C#Socket使⽤以及DotNetty和Supersocket框架1.Socket服务端与客户端通话
1服务端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace tSocket
{
class Program
{
byte[] bytes = new byte[1024];
Socket cSocket;
static void Main(string[] args)
{
Program p = new Program();
//打开链接
p.open();
//向服务端发送消息
Console.WriteLine("请输⼊你要对服务端发送的消息:");
string mes = Console.ReadLine();
string con = p.messge(mes);
Console.WriteLine("接受到服务端的消息:" + con);
}
byte[] data = new byte[1024];
string messge(string mes)
{
//将发送的消息转成字节数组
bytes = Encoding.UTF8.GetBytes(mes);
//发送
cSocket.Send(bytes);
while (true)
{
//接受服务端发送的消息,放⼊字节数组
int len = cSocket.Receive(data);
//将字节数组转成可读明⽂
string con = Encoding.UTF8.GetString(data, 0, len);
////返回
return con;
}
}
///<summary>
/
//打开链接
///</summary>
void open()
{
//创建Socket对象指定连接⽅式
cSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP,端⼝
IPAddress ip = IPAddress.Parse("10.116.253.10");
int port = 7526;
//封装IP和端⼝
IPEndPoint Ipoint = new IPEndPoint(ip, port);
/
/打开链接
cSocket.Connect(Ipoint);
}
}
}
2.客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ServerSocket
{
class Program
{
static void Main(string[] args)
{
//创建Socket对象,指定他的链接⽅式
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//建⽴IP
string ip = "10.116.253.10";
//创建端⼝
int prot = 7526;//1~9999
IPAddress IPAdd = IPAddress.Parse(ip);
//封装IP和端⼝
IPEndPoint point = new IPEndPoint(IPAdd, prot);
//绑定IP和端⼝
serverSocket.Bind(point);
//开始监听
serverSocket.Listen(100);
Console.WriteLine("开始监听!");
int i = 0;
while (true)
{
i++;
//接受客户链接
Socket cSocket = serverSocket.Accept();
Console.WriteLine("接受第"+i+"个客户的连接!");
Client c = new Client(cSocket);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ServerSocket
{
class Client
{
Socket sSocket;
byte[] data = new byte[1024];
Thread t;
public Client(Socket cSocket)
{
//接受客户的连接
sSocket = cSocket;
//创建线程
t = new Thread(Mess);
//开始线程
t.Start();
}
void Mess()
{
try
{
while (true)
{
//将⽤户发送的数据以⼀个字节数组装起
int length = sSocket.Receive(data);
Console.WriteLine("接受客户端发的消息!");
string mess = Encoding.UTF8.GetString(data, 0, length);
if (mess == "con")
{
string con = "DataSource =.";
byte[] bytes = Encoding.UTF8.GetBytes(con);
sSocket.Send(bytes);
}
Console.WriteLine("接到⽤户的消息:" + mess);
}
}
catch (Exception)
{
sSocket.Close();
}
}
}
}
2.DotNetty
DotNetty是微软的Azure团队,使⽤C#实现的Netty的版本发布。不但使⽤了C#和.Net平台的技术特点,并且保留了Netty原来绝⼤部分的编程接⼝。让我们在使⽤时,完全可以依照Netty官⽅的教程来学习和使⽤DotNetty应⽤程序。
Netty 是⼀个异步事件驱动的⽹络应⽤程序框架,⽤于快速开发可维护的⾼性能协议服务器和客户端。
优点
1. 关注点分离——业务和⽹络逻辑解耦;
2. 模块化和可复⽤性;
3. 可测试性作为⾸要的要求
历史
1. 阻塞Socket通信特点:
1. 建⽴连接要阻塞线程,读取数据要阻塞线程
2. 如果要管理多个客户端,就需要为每个客户端建⽴不同的线程
3. 会有⼤量的线程在休眠状态,等待接收数据,资源浪费
4. 每个线程都要占⽤系统资源
5. 线程的切换很耗费系统资源
2. ⾮阻塞Socket(NIO)特点:
1. 如图,每个Socket如果需要读写操作,都通过事件通知的⽅式通知选择器,这样就实现了⼀个线程管理多个Socket的⽬的。
2. 选择器甚⾄可以在所有的Socket空闲的时候允许线程先去⼲别的事情
3. 减少了线程数量导致的资源占⽤,减少了线程切换导致的资源消耗
Netty设计的关键点
异步和事件驱动是Netty设计的关键
核⼼组件
Channel:⼀个连接就是⼀个Channel
回调:通知的基础
官⽅也提供了⼀些例⼦。地址如下
writeline特点3.Supersocket
开源地址github/kerryjiang/SuperSocket
SuperSocket是重量轻的可扩展套接字应⽤程序框架。您可以使⽤它轻松构建始终连接的套接字应⽤程序,⽽⽆需考虑如何使⽤套接字,如何维护套接字连接以及套接字如何⼯作。这是⼀个纯C#项⽬,旨在进⾏扩展,因此只要以.NET语⾔开发它们,就可以轻松地将它们集成到您的现有系统中。
⾸先安装:SuperSocket.Engine
SuperSoket的三⼤对象:
Session: 每⼀个⽤户连接就是⼀个Session
AppServer: Socket服务器实例
Commands: 客户端向服务器发送消息的命令集合
⾸先在配置⽂件加⼊如下配置
<configSections>
<section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/> </configSections>
<superSocket>
<servers>
<server name="ChatSocket" textEncoding="gb2312"
serverType="XT.SocketService.AppServer.ChatServer, XT.SocketService"
ip="Any" port="2020"
maxConnectionNumber="1000">
</server>
<!-- 可以配置多个Server-->
</servers>
</superSocket>
AppServer代码如下
[AuthorisizeFilter]
public class ChatServer:AppServer<ChatSession>
{
protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
{
Console.WriteLine("准备读取配置⽂件。。。。");
return base.Setup(rootConfig, config);
}
protected override void OnStarted()
{
Console.WriteLine("Chat服务启动。。。");
base.OnStarted();
}
protected override void OnStopped()
{
Console.WriteLine("Chat服务停⽌。。。");
base.OnStopped();
}
///<summary>
///新的连接
///</summary>
///<param name="session"></param>
protected override void OnNewSessionConnected(ChatSession session)
{
Console.WriteLine($"Chat服务新加⼊的连接:{session.LocalEndPoint.Address.ToString()}");
base.OnNewSessionConnected(session);
}
}
Session代码如下
///<summary>
///表⽰⽤户连接
///</summary>
//[AuthorisizeFilter]
public class ChatSession : AppSession<ChatSession>
{
public string Id { get; set; }
public string PassWord { get; set; }
public bool IsLogin { get; set; }
public DateTime LoginTime { get; set; }
public DateTime LastHbTime { get; set; }
public bool IsOnline
{
get
{
return this.LastHbTime.AddSeconds(10) > DateTime.Now;
}
}
///<summary>
/
//消息发送
///</summary>
///<param name="message"></param>
public override void Send(string message)
{
Console.WriteLine($"准备发送给{this.Id}:{message}");
base.Send(message.Format());
}
protected override void OnSessionStarted()
{
this.Send("Welcome to SuperSocket Chat Server");
}
protected override void OnInit()
{
this.Charset = Encoding.GetEncoding("gb2312");
base.OnInit();
}
protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
{
Console.WriteLine("收到命令:" + requestInfo.Key.ToString());
this.Send("不知道如何处理 " + requestInfo.Key.ToString() + " 命令");
}
/
//<summary>
///异常捕捉
///</summary>
///<param name="e"></param>
protected override void HandleException(Exception e)
{
this.Send($"\n\r异常信息:{ e.Message}");
//base.HandleException(e);
}
///<summary>
///连接关闭
/
//</summary>
///<param name="reason"></param>
protected override void OnSessionClosed(CloseReason reason)
{
Console.WriteLine("链接已关闭。。。");
base.OnSessionClosed(reason);
}
}
Commands代码如下 : 客户端发送消息命令 Check 1 123456
Check 代表类名,1代表session.id(会话ID),1代表session.PassWord (会话密码)
public class Check : CommandBase<ChatSession, StringRequestInfo>
{
public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
{
if (requestInfo.Parameters != null && requestInfo.Parameters.Length == 2)
{
ChatSession oldSession = session.AppServer.GetAllSessions().FirstOrDefault(a => requestInfo.Parameters[0].Equals(a.Id));
if (oldSession != null) // 说过之前有⽤户⽤这个Id 登录过
{
oldSession.Send("您的账号已经在他处登录,您已经被踢下线了");
oldSession.Close();
}
#region这⾥就可以连接数据库进⾏数据验证做登录
///---------------------
#endregion
session.Id = requestInfo.Parameters[0];
session.PassWord = requestInfo.Parameters[1];
session.IsLogin = true;
session.LoginTime = DateTime.Now;
session.Send("登录成功");
{ // 获取当前登录⽤户的离线消息
ChatDataManager.SendLogin(session.Id, c =>
{
session.Send($"{c.FromId} 给你发送消息:{c.Message} {c.Id}");
});
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论