I'm using Lidgren to connect a unity game to a gameserver. everything works fine. the only problem is when the client disconnects from the server (by loss of internet connection or even manually) it cannot connect again. I have to close and reopen the game to be able to connect again. I have tried this outside the unity too and got the same results:
connection method is like this:
public IEnumerator Connect()
{
m_Client.Start();
var hail = m_Client.CreateMessage();
AuthRequest id = new AuthRequest()
{
Name = PlayerSettings.Name,
};
hail.Write(new Packet(PacketType.AuthRequest, id).SerializePacket());
m_Client.Connect(k_ServerAddress, k_Port, hail);
Debug.Log("Connecting " + id.Name + " to " + k_ServerAddress + ":" + k_Port);
NetConnectionStatus status = m_Client.ConnectionStatus;
while (m_Client.ConnectionStatus != NetConnectionStatus.Disconnected)
{
if (m_Client.ConnectionStatus != status)
{
status = m_Client.ConnectionStatus;
Debug.Log("Status: " + status);
}
yield return null;
}
}
If I use this code:
LidgrenClient m_Client = new LidgrenClient();
m_Client.Connect();
the client gets connected, but when the client gets disconnected from the server the update method below just logs Trying to Reconnect every 5 minutes but actually does nothing:
void Update()
{
if (!waiting && !m_Client.Connected)
{
Debug.Log("Trying to Reconnect");
StartCoroutine(TryReconnect());
}
m_Client.ReadMessages();
}
IEnumerator TryReconnect()
{
waiting = true;
m_Client.Connect();
yield return new WaitForSeconds(5f);
waiting = false;
}
Related
I have a C# application which creates a CimSession or a ManagementScope connection and queries the "PercentProcessorTime" parallel on dozens of remote PCs in every second.
Usually the app is working fine for a couple of hours and then suddenly starts filling up the memory. The RAM usage from the average 100MB jumps so 4-5GB in an hour.
I am unable to find out what is happening here.
Here are the two method which are running in every seconds:
public static bool DumpProcessesCpu(string hostname)
{
bool overTreshold = false;
try
{
CimSessionOptions sessionOptions = new CimSessionOptions() { Timeout = TimeSpan.FromSeconds(5) };
using (CimSession mySession = CimSession.Create(hostname, sessionOptions))
{
string Namespace = #"root\cimv2";
IEnumerable<CimInstance> queryInstance = mySession.QueryInstances(Namespace, "WQL", queryString);
foreach (CimInstance cimInstance in queryInstance)
{
int currentValue = Convert.ToInt32(cimInstance.CimInstanceProperties["PercentProcessorTime"].Value);
if (showLiveData == "true") Log.Debug("{0} - {1}", hostname, currentValue.ToString());
if (currentValue >= treshold)
{
overTreshold = true;
}
}
}
}
catch (SystemException e)
{
Log.Error("An error occurred while querying for WMI data for " + hostname + ": " + e.Message);
}
return overTreshold;
}
and
public static bool DumpProcessesCpuLegacy(string hostname)
{
bool overTreshold = false;
try
{
ConnectionOptions options = new ConnectionOptions() { Timeout = TimeSpan.FromSeconds(5) };
ObjectQuery query = new ObjectQuery(queryString);
ManagementScope scope = new ManagementScope(#"\\" + hostname + #"\root\cimv2", options);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject queryObj in searcher.Get())
{
int currentValue = Convert.ToInt32("" + queryObj["PercentProcessorTime"]);
if (showLiveData == "true") Log.Debug("{0} - {1}", hostname, currentValue.ToString());
if (currentValue >= treshold)
{
overTreshold = true;
}
}
}
}
catch (ManagementException e)
{
Log.Error("An error occurred while querying for WMI data for " + hostname + ": " + e.Message);
}
return overTreshold;
}
I am using Parallel.Foreach to run one of these methods on every remote PC in every second.
I am using extensive logging and try-catch everywhere and there are no error messages.
What could be the problem here? Where should I continue the investigation?
Thank you
I have currently wrote a code which scans the local network with a function called "bool ping()". I want to add a capability to provide basic device information when the function returns 'true'. I've found 'ManagementObjectSearcher'.
At first it looked perfect but when It gets used for a non-windows device it crash. Therefore I suppose that this method cannot be used for non-windows devices.
As I want to add the below code ( or login , after enough polishing ), to an android app that scans the local network and returns the
A) IP address and
B) (one of the following )
the device type ( desktop , laptop , smartphone)
and/or
the OS type ( android , windows , linux , tvOS )
Is there a valid way I can do what I am looking for? I believe I have experienced apps that do stuff like that, though I don't know what language they were based on.
namespace LanConsole
{
class Program
{
static void Main(string[] args)
{
string host = "192.168.1.10"; // android smartphone IP
string temp = null;
// arguments I found
string[] _searchClass = { "Win32_ComputerSystem", "Win32_OperatingSystem", "Win32_BaseBoard", "Win32_BIOS" };
string[] param = { "UserName", "Caption", "Product", "Description" };
bool v = ping(host, 10, 900); // bool function send ping to host
if (v == true)
{
Console.WriteLine("true");
for (int i = 0; i <= _searchClass.Length - 1; i++)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + host + "\\root\\CIMV2", "SELECT *FROM " + _searchClass[i]);
foreach (ManagementObject obj in searcher.Get())
{
temp += obj.GetPropertyValue(param[i]).ToString() + "\n";
if (i == _searchClass.Length - 1)
{
Console.WriteLine(temp, "Hostinfo: " + host);
break;
}
}
Console.WriteLine("");
}
}
else
Console.WriteLine("false");
}
public static bool ping(string host, int attempts, int timeout)
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply pingReply;
for (int i = 0; i < attempts; i++)
{
try
{
pingReply = ping.Send(host, timeout);
// If there is a successful ping, return true.
if (pingReply != null &&
pingReply.Status == System.Net.NetworkInformation.IPStatus.Success)
{
return true;
}
}
catch
{
// supressing errors
}
}
// Return false if ping fales "attempts" times
return false;
}
}
}
Im stuck. I have joined the project that uses Named Pipes, and have lets say "not ideal architecture". And seems like I accidentally received a deadlock:(
The logic is following. There is Named Pipe. Client and Server model. On server part there is a loop, that always pings named pipe and process what client sends, sometimes sending back responses.
On Client side of my pipe, I have following method, from other developer, that is being used to send request to server and receive and return the response.
private object locker = new Object();
private string ListenOnce(string msg)
{
Debug.WriteLine("Will listen for message " + msg);
string msgFrom = "";
if (run) {
string toReturn = "";
lock (locker) {
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain(); //Waiting for another process to read the command
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
if (toReturn.Contains('¥'))
{
string[] split = toReturn.Split('¥');
if (split.Length > 1)
{
var roomNames = this.connection.application.GameCache.GetRoomNames();
for (int i = 1; i < split.Length; i++)
{
string[] split2 = split[i].Split('¶');
if (split2.Length > 1)
{
string accountName = split2[0];
int offenderActorID = int.Parse(split2[1]);
string offenderRoomName = split2[2];
foreach (var roomName in roomNames)
{
Room room;
if (this.connection.application.GameCache.TryGetRoomWithoutReference(roomName, out room))
{
Game game = room as Game;
if (game != null && game.Name == offenderRoomName)
{
GameClientPeer peer = (GameClientPeer)game.ActorsManager.ActorsGetActorByNumber(offenderActorID).Peer;
if (peer != null)
{
peer.KickPlayer();
}
}
}
}
}
}
}
}
}
if (toReturn.Contains('¥'))
{
return toReturn.Split('¥')[0];
}
else
{
return toReturn;
}
}
return "";
}
The problem is - in some cases I cant receive response from pipe right when requested, and need to start what I called here "poller". This is a task, that loops 5 times, and during those 5 times "polls" the pipe through this ListenOnce method.
private void PollTargets()
{
timer.Dispose();
Debug.WriteLine("Going to start polling");
Task.Factory.StartNew(() => {
int runCount = 0;
while (true)
{
runCount++;
PipeOperation request = new PipeOperation(Consts.Pipes.RequestTargets, uniqueID);
string responseStr = unityConnection.client.SendMessage(JsonConvert.SerializeObject(request));
Debug.WriteLine("Task is running, response is " + responseStr);
if (!string.IsNullOrEmpty(responseStr))
{
try
{
PipeOperation pipeResponse = JsonConvert.DeserializeObject<PipeOperation>(responseStr);
if (!string.IsNullOrEmpty(pipeResponse.Payload))
{
GrenadeExplosionData explosionData = JsonConvert.DeserializeObject<GrenadeExplosionData>(pipeResponse.Payload);
if (explosionData != null)
{
//probably need to invoke that in main thread
DealDamage(explosionData);
//isRunning = false;
Debug.WriteLine("Received nice response, will damage targets");
break;
}
}
}
catch (Exception exc)
{
Debug.WriteLine("Something went wrong while polling...");
Debug.WriteLine(exc.Message);
break;
}
}
if (runCount > 5)
{
Debug.WriteLine("run count exceed " + runCount.ToString());
break;
}
}
RemoveGrenadeFromUnityConnection();
});
}
I am starting poller when the Grenade explodes, from timer like that:
timer = new System.Threading.Timer((obj) =>
{
PollTargets();
},
null, 4000, System.Threading.Timeout.Infinite);
And thats it. After people play 2-3 hrs. Seems like I receive a deadlock. It should be taken into account that there might be many grenades on server who starts that poller, so probably it just goes mad at some point over there.
Pls help, Im stuck with that. Who has ideas?
We should keep in mind, that
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain();
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
should be used only by one thread at a time, as stream might be read only from one source.
There are several calls to ListenOnce from the code, but not a lot. One is being fired every 4 minutes.The rest ones are not constant, but conditional.
Hope somebody would see where is a mistake here...
Found what locks everything...However, it does not help a lot:)
Its
stream.WaitForPipeDrain();
it tries to read another end of pipe, but because of there is no timeouts in message mode, it just hangs for ever..
I have this script to interact with my database which is on mySql
string dataSubmitURL = "http://localhost/HighScore/AddScore.php?";
string dataGetURL = "http://localhost/HighScore/GetScore.php?";
// Use this for initialization
void Start () {
StartCoroutine(GetScores());
}
// Update is called once per frame
void Update () {
}
IEnumerator PostScores(string playerName, int score) {
string submitURL = dataSubmitURL + "name="+ playerName + "&score=" + score;
print(submitURL);
WWW submitData = new WWW(submitURL);
yield return submitData;
if (submitData.error != null)
{
Debug.LogError("Error occur when Submitting data : " + submitData.error);
Debug.LogError("Error occur when Submitting data : " + submitData.text);
Debug.LogError("Error occur when Submitting data : " + submitData.responseHeaders);
//submitData.text
}
else {
print(" Submitted");
}
IEnumerator GetScores() {
WWW getData = new WWW(dataGetURL);
yield return getData;
if (getData.error != null)
{
Debug.LogError("There was an error getting the high score: " + getData.error);
}
else {
print(getData.text);
}
}
}
But the problem is i am getting
There was an error getting the high score: Empty reply from server
Although these both urls
string dataSubmitURL = "http://localhost/HighScore/AddScore.php?";
string dataGetURL = "http://localhost/HighScore/GetScore.php?";
working fine in browser when i directly put it. I also added this crossDomain.xml in my root folder so that it can accessible to all. What I am doing wrong.
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
I don't know what was the problem all the code is correct and it works by changing the IP Address only.
string dataSubmitURL = "http://YouripAddress/HighScore/AddScore.php?";
string dataGetURL = "http://YouripAddress/HighScore/GetScore.php?";
I am currently building an Android messaging app and I am trying to send notifications to all users who are part of a group. I have an Azure Notification Hub set up which is working fine for sending a notification to all devices that are registered, but I cannot seem to get it working for just a subset of all user ie a group.
The devices register with Azure and with GCM on startup.
I have tried using "Tags" to try send a notification to an individual but I am not sure if I am doing it right... I must not be because it isn't working!
In the following code I am trying to send a notification to an individual by using their username as a Tag...
This is the code in my service to send a notification:
// POST api/notification
public async Task<IHttpActionResult> Post([FromBody]Notification notification)
{
var notificationToSave = new Notification
{
NotificationGuid = Guid.NewGuid().ToString(),
TimeStamp = DateTime.UtcNow,
Message = notification.Message,
SenderName = notification.SenderName
};
var recipientNames = await GetRecipientNamesFromNotificationHub();
var recipientNamesString = CreateCustomRecipientNamesString(recipientNames);
string notificationJsonPayload =
"{\"data\" : " +
" {" +
" \"message\": \"" + notificationToSave.Message + "\"," +
" \"senderName\": \"" + notificationToSave.SenderName + "\"," +
" \"recipientNames\": \"" + recipientNamesString + "\"" +
" }" +
"}";
var result = await _hubClient.SendGcmNativeNotificationAsync(notificationJsonPayload, "ken#test.com"); // If this second parameter is omitted then a notification is sent to all registered devices.
notificationToSave.TrackingId = result.TrackingId;
notificationToSave.Recipients = recipientNames;
await Session.StoreAsync(notificationToSave);
return Ok(notificationToSave);
}
And this is how I am registering a device on the Android side:
private void sendRegistrationIdToBackend(String registrationId) {
String backendBaseUrl = "http://myurl.net/";
if (backendBaseUrl == null || backendBaseUrl == "")
{
return;
}
PushNotificationClient client = new PushNotificationClient(backendBaseUrl);
Device device = createDevice(registrationId);
client.registerDevice(device, new Callback<Device>() {
#Override
public void success(Device device, Response response) {
//writeStringToSharedPreferences(SettingsActivity.SETTINGS_KEY_DEVICEGUID, device.DeviceGuid);
Toast.makeText(context, "Device successfully registered with backend, DeviceGUID=" + device.DeviceGuid, Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError retrofitError) {
Toast.makeText(context, "Backend registration error:" + retrofitError.getMessage(), Toast.LENGTH_LONG).show();
}
});
Log.i(TAG, registrationId);
}
private Device createDevice(String registrationId) {
Device device = new Device();
device.Platform = "Android";
device.Token = registrationId;
device.UserName = LogInActivity.loggedInUser;
device.DeviceGuid = null;
//todo set device.PlatformDescription based on Android version
device.SubscriptionCategories = new ArrayList<>();
device.SubscriptionCategories.add("ken#test.com"); // This should be adding this username as a Tag which is referenced in the service.... Not sure if this is how I should do it!
return device;
}
This is how I registering a device:
private async Task<RegistrationDescription> RegisterDeviceWithNotificationHub(Device device)
{
var hubTags = new HashSet<string>()
.Add("user", new[] { device.UserName })
.Add("category", device.SubscriptionCategories);
var hubRegistrationId = device.HubRegistrationId ?? "0";//null or empty string as query input throws exception
var hubRegistration = await _hubClient.GetRegistrationAsync<RegistrationDescription>(hubRegistrationId);
if (hubRegistration != null)
{
hubRegistration.Tags = hubTags;
await _hubClient.UpdateRegistrationAsync(hubRegistration);
}
else
{
hubRegistration = await _hubClient.CreateGcmNativeRegistrationAsync(device.Token, hubTags);
}
return hubRegistration;
}
good evening.
You should try check your registrations by using Visual studio 2015.
Install it, connect azure, azure hubs, registred devices. And try send your test message on test token (+check "does your registration exist on notification hub").