Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jiowchern/pinioncore.remote
This is a network transmission framework using c# as the main language of the server and client.
https://github.com/jiowchern/pinioncore.remote
c-sharp network remote-method-invocation server-client
Last synced: about 1 month ago
JSON representation
This is a network transmission framework using c# as the main language of the server and client.
- Host: GitHub
- URL: https://github.com/jiowchern/pinioncore.remote
- Owner: jiowchern
- License: mit
- Created: 2024-10-17T04:45:38.000Z (3 months ago)
- Default Branch: github-readme
- Last Pushed: 2024-12-10T22:17:41.000Z (about 1 month ago)
- Last Synced: 2024-12-10T23:21:20.093Z (about 1 month ago)
- Topics: c-sharp, network, remote-method-invocation, server-client
- Language: C#
- Homepage:
- Size: 75.8 MB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# PinionCore Remote
[![Maintainability](https://api.codeclimate.com/v1/badges/89c3a646f9daff42a38e/maintainability)](https://codeclimate.com/github/jiowchern/PinionCore.Remote/maintainability)
[![Build](https://github.com/jiowchern/PinionCore.Remote/actions/workflows/dotnet-desktop.yml/badge.svg?branch=master)](https://github.com/jiowchern/PinionCore.Remote/actions/workflows/dotnet-desktop.yml)
[![Coverage Status](https://coveralls.io/repos/github/jiowchern/PinionCore.Remote/badge.svg?branch=master)](https://coveralls.io/github/jiowchern/PinionCore.Remote?branch=master)
![commit last date](https://img.shields.io/github/last-commit/jiowchern/PinionCore.Remote)## Introduction
PinionCore Remote is a powerful and flexible server-client communication framework developed in C#. Designed to work seamlessly with the Unity game engine and any other .NET Standard 2.0 compliant environments, it simplifies network communication by enabling servers and clients to interact through interfaces. This object-oriented approach reduces the maintenance cost of protocols and enhances code readability and maintainability.Key features of PinionCore Remote include support for IL2CPP and AOT, making it compatible with various platforms, including Unity WebGL. It provides default TCP connection and serialization mechanisms but also allows for customization to suit specific project needs. The framework supports methods, events, properties, and notifiers, giving developers comprehensive tools to build robust networked applications.
With its stand-alone mode, developers can simulate server-client interactions without a network connection, facilitating development and debugging. PinionCore Remote aims to streamline network communication in game development and other applications, enabling developers to focus more on implementing business logic rather than dealing with the complexities of network protocols.
## Feature
Server and client transfer through the interface, reducing the maintenance cost of the protocol.![plantUML](http://www.plantuml.com/plantuml/svg/ZP31JiCm38RlUGeVGMXzWAcg9kq0ko4g7Y1aVql1IIR7GqAZxqvRLGdiD5zgsVw_ViekgHKzUpOdwpvj3tgMgD55fhf-WLCRUaRJN0nDDGI5TDQ13ey2A8IcnLeFhVr-0dEykrzcencDoTWMyWNv3rt3ZcrAT1EmyFOy8EYrPC6rqMC_TuLtwGRmSIpk_VejzBpQR9g2s6xpPJweVwegEvCn8Ig8qId5himNyi6V67wspMc3SAGviWPbwD_dvDK_Yzrh0iMt3pYbJgAdj3ndzOUpczgpvry0)
## Supports
* Support **IL2CPP & AOT**.
* Compatible with **.Net Standard2.0** or above development environment.
* **Tcp** connection is provided by default, and any connection can be customized according to your needs.
* **Serialization** is provided by default, and can be customized.
* Support **Unity3D WebGL**, provide server-side Websocket, client-side need to implement their own.
## Usage
1. Definition Interface ```IGreeter``` .```csharp
namespace Protocol
{
public struct HelloRequest
{
public string Name;
}
public struct HelloReply
{
public string Message;
}
public interface IGreeter
{
PinionCore.Remote.Value SayHello(HelloRequest request);
}
}
```
2. Server implemente ```IGreeter```.
```csharp
namespace Server
{
class Greeter : IGreeter
{
PinionCore.Remote.Value SayHello(HelloRequest request)
{
return new HelloReply() { Message = $"Hello {request.Name}." };
}
}
}
```3. Use ```IBinder.Bind``` to send the ```IGreeter``` to the client.
```csharp
namespace Server
{
public class Entry
{
readonly Greeter _Greeter;
readonly PinionCore.Remote.IBinder _Binder;
readonly PinionCore.Remote.ISoul _GreeterSoul;
public Entry(PinionCore.Remote.IBinder binder)
{
_Greeter = new Greeter();
_Binder = binder;
// bind to client.
_GreeterSoul = binder.Bind(_Greeter);
}
public void Dispose()
{
_Binder.Unbind(_GreeterSoul);
}
}
}
```4. Client uses ```IAgent.QueryNotifier``` to obtain ```IGreeter```.
```csharp
namespace Client
{
class Entry
{
public Entry(PinionCore.Remote.IAgent agent)
{
agent.QueryNotifier().Supply += _AddGreeter;
agent.QueryNotifier().Unsupply += _RemoveGreeter;
}
async void _AddGreeter(IGreeter greeter)
{
// Having received the greeter from the server,
// begin to implement the following code.
var reply = await greeter.SayHello(new HelloRequest() {Name = "my"});
}
void _RemoveGreeter(IGreeter greeter)
{
// todo: The server has canceled the greeter.
}
}
}
```
---
After completing the above steps, the server and client can communicate through the interface to achieve object-oriented development as much as possible.
#### Specification
**Interface**
In addition to the above example ``IGreeter.SayHello``, there are a total of four ways to ...* [```Method```](document/communications-method.md) <-- ```IGreeter.SayHello```
* [```Event```](document/communications-event.md)
* [```Property```](document/communications-property.md)
* [```Notifier```](document/communications-notifier.md)**Serialization**
For the types that can be serialized, see [```PinionCore.Serialization```](PinionCore.Serialization/README.md) instructions.
---
## Getting Started
This is a server-client framework, so you need to create three projects : ```Protocol```, ```Server``` and ```Client```.#### Requirements
* Visual Studio 2022 17.0.5 above.
* .NET Sdk 5 above.#### Protocol Project
Create common interface project ```Protocol.csproj```.
```powershell
Sample/Protocol>dotnet new classlib
```1. Add References
```xml
all
runtime; build; native; contentfiles; analyzers; buildtransitive
```
2. Add interface, ```IGreeter.cs```
```csharp
namespace Protocol
{
public interface IGreeter
{
PinionCore.Remote.Value SayHello(string request);
}
}
```
3. Add ```ProtocolCreater.cs```.
```csharp
namespace Protocol
{
public static partial class ProtocolCreater
{
public static PinionCore.Remote.IProtocol Create()
{
PinionCore.Remote.IProtocol protocol = null;
_Create(ref protocol);
return protocol;
}/*
Create a partial method as follows.
*/
[PinionCore.Remote.Protocol.Creater]
static partial void _Create(ref PinionCore.Remote.IProtocol protocol);
}
}
```
This step is to generate the generator for the ``IProtocol``, which is an important component of the framework and is needed for communication between the server and the client.
**_Note_**
>> As shown in the code above, Add ```PinionCore.Remote.Protocol``` attribute to the method you want to get ```IProtocol```, the method specification must be ```static partial void Method(ref PinionCore.Remote.IProtocol)```, otherwise it will not pass compilation.---
#### Server Project
Create the server. ```Server.csproj```
```powershell
Sample/Server>dotnet new console
```
1. Add References
```xml
```
2. Instantiate ```IGreeter```
```csharp
namespace Server
{
public class Greeter : Protocol.IGreeter
{
PinionCore.Remote.Value SayHello(string request)
{
// Return the received message
return $"echo:{request}";
}
}
}
```
3. The server needs an entry point to start the environment , creating an entry point that inherits from ``PinionCore.Remote.IEntry``. ```Entry.cs```
```csharp
namespace Server
{
public class Entry : PinionCore.Remote.IEntry
{
void IBinderProvider.RegisterClientBinder(IBinder binder)
{
binder.Binder(new Greeter());
}
void IBinderProvider.UnregisterClientBinder(IBinder binder)
{
// when client disconnect.
}void IEntry.Update()
{
// Update
}
}
}
```
4. Create Tcp service
```csharpnamespace Server
{
static void Main(string[] args)
{
// Get IProtocol with ProtocolCreater
var protocol = Protocol.ProtocolCreater.Create();
// Create Service
var entry = new Entry();
var set = PinionCore.Remote.Server.Provider.CreateTcpService(entry, protocol);
int yourPort = 0;
set.Listener.Bind(yourPort);
// Close service
set.Listener.Close();
set.Service.Dispose();
}
}```
---
#### Client Project
Create Client. ```Client.csproj```.
```powershell
Sample/Client>dotnet new console
```
1. Add References
```xml
```
2. Create Tcp client
```csharp
namespace Client
{
static async Task Main(string[] args)
{
// Get IProtocol with ProtocolCreater
var protocol = Protocol.ProtocolCreater.Create();
var set = PinionCore.Remote.Client.Provider.CreateTcpAgent(protocol);
bool stop = false;
var task = System.Threading.Tasks.Task.Run(() =>
{
while (!stop)
{
set.Agent.HandleMessages();
set.Agent.HandlePackets();
}
});
// Start Connecting
EndPoint yourEndPoint = null;
var peer = await set.Connector.Connect(yourEndPoint );set.Agent.Enable(peer);
// SupplyEvent ,Receive add IGreeter.
set.Agent.QueryNotifier().Supply += greeter =>
{
greeter.SayHello("hello");
};// SupplyEvent ,Receive remove IGreeter.
set.Agent.QueryNotifier().Unsupply += greeter =>
{
};// Close
stop = true;
task.Wait();
set.Connector.Disconnect();
set.Agent.Disable();}
}
```
---
## Standalone mode
In order to facilitate development and debugging, a standalone mode is provided to run the system without a connection.
```powershell
Sample/Standalone>dotnet new console
```
1. Add References
```xml
```
2. Create standlone service
```csharp
namespace Standalone
{
static void Main(string[] args)
{
// Get IProtocol with ProtocolCreater
var protocol = Protocol.ProtocolCreater.Create();
// Create service
var entry = new Entry();
var service = PinionCore.Remote.Standalone.Provider.CreateService(entry , protocol);
var agent = service.Create();
bool stop = false;
var task = System.Threading.Tasks.Task.Run(() =>
{
while (!stop)
{
agent.HandleMessages();
agent.HandlePackets();}
});
agent.QueryNotifier().Supply += greeter =>
{
greeter.SayHello("hello");
};
agent.QueryNotifier().Unsupply += greeter =>
{
};// Close
stop = true;
task.Wait();
agent.Dispose();
service.Dispose();}
}
```
---
## Custom Connection
If you want to customize the connection system you can do so in the following way.
#### Client
Create a connection use ```CreateAgent``` and implement the interface ```IStreamable```.
```csharp
var protocol = Protocol.ProtocolCreater.Create();
IStreamable stream = null ;// todo: Implementation Interface IStreamable
var service = PinionCore.Remote.Client.CreateAgent(protocol , stream) ;
```
implement ```IStreamable```.
```csharp
using PinionCore.Remote;
namespace PinionCore.Network
{
public interface IStreamable
{
///
/// Receive data streams.
///
/// Stream instance.
/// Start receiving position.
/// Count of byte received.
/// Actual count of byte received.
IWaitableValue Receive(byte[] buffer, int offset, int count);
///
/// Send data streams.
///
/// Stream instance.
/// Start send position.
/// Count of byte send.
/// Actual count of byte send.
IWaitableValue Send(byte[] buffer, int offset, int count);
}
}
```#### Server
Create a service use ```CreateService``` and implement the interface ```IListenable```.
```csharp
var protocol = Protocol.ProtocolCreater.Create();
var entry = new Entry();
IListenable listener = null; // todo: Implementation Interface IListenable
var service = PinionCore.Remote.Server.CreateService(entry , protocol , listener) ;
```
implement ```IListenable```.
```csharp
namespace PinionCore.Remote.Soul
{
public interface IListenable
{
// When connected
event System.Action StreamableEnterEvent;
// When disconnected
event System.Action StreamableLeaveEvent;
}
}
```
---
## Custom Serialization
implement ```ISerializable```.
```csharp
namespace PinionCore.Remote
{
public interface ISerializable
{
PinionCore.Memorys.Buffer Serialize(System.Type type, object instance);
object Deserialize(System.Type type, PinionCore.Memorys.Buffer buffer);
}
}
```
and bring it to the server ```CreateTcpService```.
```csharp
var protocol = Protocol.ProtocolCreater.Create();
var entry = new Entry();
ISerializable yourSerializer = null;
var service = PinionCore.Remote.Server.CreateTcpService(entry , protocol , yourSerializer) ;
```and bring it to the client ```CreateTcpAgent```.
```csharp
var protocol = Protocol.ProtocolCreater.Create();
ISerializable yourSerializer = null ;
var service = PinionCore.Remote.Client.CreateTcpAgent(protocol , yourSerializer) ;
```If need to know what types need to be serialized can refer ```PinionCore.Remote.IProtocol.SerializeTypes```.
```csharp
namespace PinionCore.Remote
{
public interface IProtocol
{
// What types need to be serialized.
System.Type[] SerializeTypes { get; }
System.Reflection.Assembly Base { get; }
EventProvider GetEventProvider();
InterfaceProvider GetInterfaceProvider();
MemberMap GetMemberMap();
byte[] VersionCode { get; }
}
}
```