how to send message to target clients in photon server? - c#

I'm developing a multiple players game with photon server and unity, have some questions on how server send messages to clients.
I know that I need a List of clientpeer to save the connecting clients, but I dont know how to save a peer to the List,and which send-message code should I use?
//here is the List that saving the clientpeers
public class ClientCollection
{
public List<PeerBase> clients;
public ClientCollection() { }
public void AddNewClient(PeerBase peer)
//is it right that I send in a PeerBase type argument?
{
clients.Add(peer);
}
public List<PeerBase> GetClients(PeerBase peer)
{
return clients;
}
}

Related

How to ping different devices at different time intervals efficiently

I am trying to create an application that pings the devices configured by the user and reflects the status online or offline. A user can specify IP and Ping Interval for a device and based on that configuration the application needs to ping the device. For example, if the user specifies IP 198.67.227.143 and Ping Interval as 5 seconds, then the application will ping 198.67.227.143 every 5 seconds and reflect the status of whether the device is online or offline.
There can be multiple devices with different ping intervals configured. For example, Device A has a ping interval of 10 seconds and Device B has a ping interval of 20 seconds.
I want to know what is the best way to check whether a device should be pinged or not. Currently, the solution I can come up with is setting up a process that runs every second and loops through all the configured devices and checks if the device should be pinged or not based on the LastPingTime of the device.
Is there a better way of approaching this problem? I am trying to accomplish this in C# and .NET 4.6.2.
One option you can try to have different timers for reach devices, you don't need to ping every second for each device.
I have done simple basic implantation for this, you can use this concept in your code.
//each device representation
public class Device
{
public string IpAddress { get; set; }
public int PingInterval { get; set; }
public Timer PingTimer { get; set; }
public bool IsOnline { get; set; }
}
public class DeviceManager
{
private List<Device> _devices;
public DeviceManager()
{
_devices = new List<Device>();
}
public void AddDevice(string ipAddress, int pingInterval)
{
var device = new Device
{
IpAddress = ipAddress,
PingInterval = pingInterval
};
device.PingTimer = new Timer(OnPingTimerElapsed, device, TimeSpan.Zero, TimeSpan.FromSeconds(pingInterval));
_devices.Add(device);
}
private void OnPingTimerElapsed(object state)
{
//you can log the device state at this place
var device = (Device)state;
// ping and update the status of the device
device.IsOnline = SendPing(device.IpAddress);
}
private bool SendPing(string ipAddress)
{
//ping logic implementation;
}
}
you can call like this.
DeviceManager deviceManager = new DeviceManager();
deviceManager.AddDevice("10.220.63.36", 5);
deviceManager.AddDevice("10.220.63.37", 10);

C# Dynamically create class instance

I am in a situation where "I don't know what I don't know" so I am unsure if this is even the correct way of approaching this problem, apologies if this comes off as plain ignorant.
I have a program which connects to Ethernet controllers. The program allows users to configure what is connected to the system and set up I/O communication.
Each controller is its own device, and may have different IO depending on what model it is. Controllers have their own API.
The program saves the configuration to an XML config file which is read at startup. I need to then connect to each unknown device and set up a connection to each, leaving me with a method of referring to each device at a later time.
Here is what I am trying to achieve:
using Brainboxes.IO;
public class BrainBoxes
{
public string[] Devices = new string[] { "192.168.16.147", "192.168.16.148", "192.168.16.149", "192.168.16.150" };
List<string> EDDeviceList = new List<string>();
public BrainBoxes() // set up devices and connections to all devices connected in the constructor
{
foreach (string Device in Devices)
{
EDDevice BB400 = EDDevice.Create("192.168.16.147");
// BB400 is a typical name but how do I make this dynamic at the same time making it
// available for other members of the class?
EDDeviceList.Add(BB400); // add the device to a list to refer to later in the constructor
}
for (int i = 0; i < EDDeviceList.Count - 1; i++) { BB400.Connect()}; // connect to each device in sequence.
}
public void Outputs(int Relay)
{
// this would be a switch statement
BB400.Outputs[Relay].Value = 1;
Thread.Sleep(75);
BB400.Outputs[Relay].Value = 0;
}
~BrainBoxes()
{
BB400.Disconnect();
}
}
It sounds like you're trying to do quite a few things at once. To paraphrase what you want: to achieve (looking at both your question, your sample code and your comment)
When your application starts, you want it to connect to a collection of different devices automatically
When running, users can connect to and configure (the right) device
Ensure that connections are closed when the application stops
Also your question is rather open ended and from your first statement, I'm going to assume that you're a beginner. I know that it's quite dry, but you are going to have to look up the documentation for the hardware you're using. Luckily, it looks quite comprehensive
You need to give your class a more representative name. E.g. BrainboxController or BrainboxManager as, by the sounds of it, that is what it's for.
Looks like BB400 is one of the possible hardware devices, it is part of an inheritance hierarchy, so you don't want to restrict yourself to just that
I would avoid doing a lot of work in the constructor, it makes it harder to find problems
Use a dictionary to store your devices, that's how you'll "refer to each device at a later time"
public class BrainboxController : IDisposable
{
private readonly HashSet<string> _deviceIps; // potentially you can get away without having this if you call InitialiseDevices() in the constructor
private Dictionary<string, EDDevice> _devices = new Dictionary<string, EDDevice>(); // possibly use IDevice<C, P> instead of EDDevice
public BrainboxController(IEnumerable<string> devices)
{
_deviceIps = new HashSet<string>(devices);
}
public void InitialiseDevices()
{
foreach (string ip in _deviceIps)
_devices.Add(ip, EDDevice.Create(ip));
}
public void AddDevice(string ip)
{
if (_deviceIps.Add(ip))
_devices.Add(ip, EDDevice.Create(ip));
}
public void RemoveDevice(string ip)
{
if(_devices.ContainsKey(ip))
{
var device = _devices[ip];
device.Disconnect();
device.Dispose();
_devices.Remove(ip);
_deviceIps.Remove(ip);
}
}
public EDDevice GetDevice(string deviceIp)
{
if (_devices.ContainsKey(deviceIp))
return _devices[deviceIp];
return null;
}
public string GetConfiguration(string deviceIp)
{
if (_devices.ContainsKey(deviceIp))
return _devices[deviceIp].Describe(); // I'm assuming that this gets the config data
return "Device not found";
}
public bool SetConfiguration(string deviceIp, string xml)
{
if (_devices.ContainsKey(deviceIp))
{
_devices[deviceIp].SendCommand(xml); // I'm assuming this is how the config data is set
return true;
}
// log device not found
return false;
}
public IOList<IOLine> GetOutputs(string deviceIp, int relay)
{
if (_devices.ContainsKey(deviceIp))
return _devices[deviceIp].Outputs[relay];
// log device not found
return new IOList<IOLine>();
}
public void Dispose()
{
foreach(var device in _devices.Values)
{
device.Disconnect();
device.Dispose();
}
}
}
Strictly speaking, if you follow the single responsibility principle, this class should just be managing your devices and their connections. The methods GetConfiguration(), SetConfiguration() and GetOutputs() are shown as examples and really should live somewhere else.
Your calling code could be look like this (without dependency injection):
var deviceAddresses = new[] { "192.168.16.147", "192.168.16.148", "192.168.16.149", "192.168.16.150" };
var controller = new BrainboxController(deviceAddresses);
controller.InitialiseDevices();
var currentDevice = controller.GetDevice("192.168.16.147");
// do something with currentDevice
Finally, whatever it is you're trying to do with your Outputs method, that looks like business logic and this also should live somewhere else.

How do I connect an AppSession to a server with SuperSocket?

I'm setting up a new client-server-network with SuperSocket and can't connenct an AppSession to the server.
I found this question and tried it for my program.
The server is running fine, but at the moment I can only connect with the 'AsynTcpSession'. When I check the connected sessions it is shown as an 'AppSession' at the server. I want to use 'AppSession', because you can give them custom parameter.
My created AppSession:
public class MyAppSession : AppSession<MyAppSession, MyRequestInfo>
{
// those parameter
public int ClientKey { get; set; }
public string HashKey { get; set; }
}
Server:
MyAppServer _server = new MyAppServer();
ServerConfig _socketServerConfig = new ServerConfig { ReceiveBufferSize = 5000, MaxRequestLength = 5000, Name = "Test- Server", SendingQueueSize = 5000, ServerType = "MyAppServer", Port = 6000};
if (_server.Setup(_socketServerConfig))
{
DoStuff();
}
Client:
ClientSession _gateway = new AsyncTcpSession();
_gateway.Connect(6000);
On receiving telegram from Client:
private void ReceivedDataFromClient(MyAppSession session, MyRequestInfo requestinfo)
{
// session.SocketSession contains the Client AsynTcpSession
}
EDIT:
The AppSession has an void Initialize(IAppServer<TAppSession, TRequestInfo> appServer, ISocketSession socketSession)-Function. How do I use it? The session only knows the server ip and port.
AsynTcpSession and AppSession are different things, althought they are all called 'session'.
Any client connection packages / classes have no matter with AppSession. (eg. AsynTcpSession)
The AppSession just a temporary storage of client connection for AppServer.
Let the AppServer controlls the client connections, identify each clients, controll the connections pool...etc.
You can define many variables in the AppSession, But to assign values will still by your own codes (and client should send these informations).

Show connected ids of clients in a Gridview or a listbox winform using SIgnalR

I have a hub class which overrides the OnConnected method...
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(Context.ConnectionId);
string RemoteIpAddress = Context.Request.GetRemoteIpAddress();
return base.OnConnected();
}
...and a static class is which keeps the count of connected clients and their connection ids.
public static class UserHandler
{
public static List<string> ConnectedIds = new List<string>();
}
I also have a form that is intended to show all the connected clients with their ids...
private void button2_Click(object sender, EventArgs e)
{
IHubContext hubContext = lobalHost.ConnectionManager.GetHubContext<MyHub>();
UserHandler.ConnectedIds = hubContext.Clients.All.ConnectionId;
listBox1.Items.Add(UserHandler.ConnectedIds);
}
What I want to achieve...
I want to show the connected clients with their ids - and once it completes then I will make such login, so that if I want to chat with a specific client, I will just click on that client's id shown in a grid and select send message.
Try to remove the first and second line in your button2_Click method. You already added the connectionIds to your UserHandler instance in your overridden OnConnected method.
//edit
I have not changed anything at your code. I don't know how you still get an error.
//edit
You already have the connectionIds in your list? Why not using them? This will add the connectionIds to your datagrid. If you need more information like the username you could replace ConnectedIds in your UserHandler with a class with two properties username and connectionId.
if (UserHandler.ConnectedIds.Count != 0)
{
foreach(var connectionId in UserHandler.ConnectedIds)
{
dataGridView1.Rows.Add(connectionId);
}
}

Session data in SignalR: Where to store them?

Let's assume that I have a game which uses SignalR to share information between clients. In my Hub class I have a method called "joinGame()" which is called when some client wants to join. I need to add his ID to some array, to know that he has already joined the game. It doesn't need to be in database, because I need this information only during this session.
public class GameHub : Hub
{
public List<int> Players = new List<int>();
public void joinGame(int id) //player updates his position
{
Clients.All.newPlayer(id);
Players.Add(id);
}
}
This code won't work, because "Players" variable seems to be cleared every time I call "joinGame()" function.
How can I do it properly?
You can use Groups:
public async Task JoinGame(int id)
{
await Groups.Add(Context.ConnectionId, id);
Clients.All.newPlayer(id);
}

Categories