Im making a new addition to my PC game (server) by supporting an Android app (client) that will be a (custom)controller (sort of a wifi controller). The server broadcasts it's network address to the client because the client does not know the IP address beforehand. This is a LAN connection, so the client is on the same network as the server.
I have got it to work numerous times, but it is very inconsistent. If I reinstall the APK build of the android app, it works fine, but after 2 or 3 close/open cycles (like really closing the Android app and booting it up again) it stops picking up the broadcast. I have not found a solution for it yet.
Am I not cleaning old connections or something? I would have thougth that closing the app would clear any NetworkTransport thingies. The only thing I am sure of is that the server broadcast is fine because when I open the client app on another Android device, it works fine while maintaining the same session of the server.
Also, I am a complete novice in networking so do not blame me :p
Thanks in advance! :)
Code of the client-side NetworkDiscovery
public class NetworkDiscoveryController : NetworkDiscovery {
bool hasReceivedBroadcastAtLeastOnce = true;
private void OnEnable()
{
if(Application.isEditor){
Debug.LogWarning("Editor mode, IP: localhost");
hasReceivedBroadcastAtLeastOnce = false;
OnReceivedBroadcast("", "localhost:25025");
return;
}
Initialize();
hasReceivedBroadcastAtLeastOnce = false;
StartAsClient();
}
public override void OnReceivedBroadcast(string fromAddress, string data)
{
try
{
if(hasReceivedBroadcastAtLeastOnce){
return;
}
hasReceivedBroadcastAtLeastOnce = true;
Debugger.instance.setTextConnected("Broadcast found!");
string[] networkMessages = data.Split(':');
int port;
Int32.TryParse(networkMessages.Last(), out port);
Debug.Log(networkMessages.First());
Debug.Log(networkMessages.Last());
AndroidInputClient.Instance.networkAddress =
networkMessages.First();
AndroidInputClient.Instance.networkPort = port;
AndroidInputClient.Instance.client =
AndroidInputClient.Instance.StartClient();
gameObject.SetActive(false);
}
catch(Exception ex)
{
Debug.LogError("OnReceiveBroadcast went badly wrong");
Debug.LogError(ex.Message);
}
}
private void OnApplicationPause(bool pauseStatus)
{
if(pauseStatus)
{
Debug.LogWarning("Client stopping");
AndroidInputClient.Instance.StopClient();
StopBroadcast();
if(AndroidInputClient.Instance.connectionId != 0){
byte error;
NetworkTransport.Disconnect(AndroidInputClient.Instance.hostId,
AndroidInputClient.Instance.connectionId, out error);
Debug.LogError("Disconnect message: " + error);
}
}
else
{
OnEnable();
}
}
}
When the client has received the broadcast from the server, I connect the client to the actual server and stop the broadcast.
public override void OnClientConnect(NetworkConnection nc) {
base.OnClientConnect(nc);
_networkDiscoveryController.StopBroadcast();
_networkDiscoveryController.gameObject.SetActive(false);
connectionId = nc.connectionId;
hostId = nc.hostId;
Debug.Log("client! on client connect " + connectionId + " " + hostId);
// Handler setup
client.RegisterHandler(_stateSyncMsgType, OnServerGameState);
}
public override void OnClientDisconnect(NetworkConnection nc) {
StopClient();
_currentState = States.Launch;
OnStateChanged(_currentState);
_networkDiscoveryController.gameObject.SetActive(true);
Debugger.instance.setTextConnected("Connection lost");
}
I have my home server, and want to create manager what will wake up my computer and check if RDP connect now possible.
I accomplished WOL behavior, but now there is problem with checking if computer OS turned on and ready for RDP connections.
Is it possible to 'ping' RDP?
You can just check if you can connect to RDP port (by default 3389):
static bool IsRdpAvailable(string host) {
try {
using (new TcpClient(host, 3389)) {
return true;
}
}
catch {
return false;
}
}
Usage:
bool available = IsRdpAvailable("your_server_ip_or_name");
We are creating application to communicat external device with windows PC (here we are using windows 7), in PC we are using bluetooth dongle.
when we tried to discover and pair device it was successfull in windows PC.
But in code side we are trying to connect the device it was not successfull and here we are using 32feet.net to connect the device.
below code i am trying to connect the device.
////_serviceClassId = new Guid("9bde4762-89a6-418e-bacf-fcd82f1e0677");
Guid serviceClass = BluetoothService.RFCommProtocol;
int selectedIndex = device_list.SelectedIndex;
BluetoothDeviceInfo selectedDevice = this.array[selectedIndex];
var lsnr = new BluetoothListener(serviceClass);
lsnr.Start();
Task.Run(() => Listener(lsnr));
and the Listener method is
private void Listener(BluetoothListener lsnr)
{
try
{
while (true)
{
using (var client = lsnr.AcceptBluetoothClient())
{
using (var streamReader = new StreamReader(client.GetStream()))
{
try
{
var content = streamReader.ReadToEnd();
if (!string.IsNullOrEmpty(content))
{
////_responseAction(content);
}
}
catch (IOException)
{
client.Close();
break;
}
}
}
}
}
catch (Exception exception)
{
// todo handle the exception
// for the sample it will be ignored
}
}
If i run the application it will blocked in the lsnr.AcceptBluetoothClient() Can any one help what wrong in this?
Note : Bluetooth device created two comports one is incoming and anther one is outgoing port, when we connect through PC.
It is because it wait untill it have a client connected. You have to run it in a thread to work simultaneously!
I'm playing around with the TcpClient and I'm trying to figure out how to make the Connected property say false when a connection is dropped.
I tried doing
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
But it still will not show me if the TcpClient is disconnected. How would you go about this using a TcpClient?
I wouldn't recommend you to try write just for testing the socket. And don't relay on .NET's Connected property either.
If you want to know if the remote end point is still active, you can use TcpConnectionInformation:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
if (stateOfConnection == TcpState.Established)
{
// Connection is OK
}
else
{
// No active tcp Connection to hostName:port
}
}
client.Close();
See Also:
TcpConnectionInformation on MSDN
IPGlobalProperties on MSDN
Description of TcpState states
Netstat on Wikipedia
And here it is as an extension method on TcpClient.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
return foo != null ? foo.State : TcpState.Unknown;
}
As far as I know/remember there is no way to test if a socket is connected other than reading or writing to it.
I haven't used the TcpClient at all but the Socket class will return 0 from a call to Read if the remote end has been shutdown gracefully.
If the remote end doesn't shutdown gracefully [I think] you get a timeout exception, can't remember the type sorry.
Using code like 'if(socket.Connected) { socket.Write(...) } creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.
The solution of Peter Wone and uriel is very nice. But you also need to check on the Remote Endpoint, since you can have multiple open connections to your Local Endpoint.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)
&& x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint)
);
return foo != null ? foo.State : TcpState.Unknown;
}
I have created this function and working for me to check if client is still connected with server.
/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected()
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation c in tcpConnections)
{
TcpState stateOfConnection = c.State;
if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if (stateOfConnection == TcpState.Established)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
#uriel's answer works great for me, but I needed to code it in C++/CLI, which was not entirely trivial. Here is the (roughly equivalent) C++/CLI code, with a few robustness checks added in for good measure.
using namespace System::Net::Sockets;
using namespace System::Net::NetworkInformation;
TcpState GetTcpConnectionState(TcpClient ^ tcpClient)
{
TcpState tcpState = TcpState::Unknown;
if (tcpClient != nullptr)
{
// Get all active TCP connections
IPGlobalProperties ^ ipProperties = IPGlobalProperties::GetIPGlobalProperties();
array<TcpConnectionInformation^> ^ tcpConnections = ipProperties->GetActiveTcpConnections();
if ((tcpConnections != nullptr) && (tcpConnections->Length > 0))
{
// Get the end points of the TCP connection in question
EndPoint ^ localEndPoint = tcpClient->Client->LocalEndPoint;
EndPoint ^ remoteEndPoint = tcpClient->Client->RemoteEndPoint;
// Run through all active TCP connections to locate TCP connection in question
for (int i = 0; i < tcpConnections->Length; i++)
{
if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint)))
{
// Found active TCP connection in question
tcpState = tcpConnections[i]->State;
break;
}
}
}
}
return tcpState;
}
bool TcpConnected(TcpClient ^ tcpClient)
{
bool bTcpConnected = false;
if (tcpClient != nullptr)
{
if (GetTcpConnectionState(tcpClient) == TcpState::Established)
{
bTcpConnected = true;
}
}
return bTcpConnected;
}
Hopefully this will help somebody.
As of 2019, in a cross-platform and async environment, I use the code below to continuosly check that the TCP channel is open. This check fires e.g. if the ethernet cable is pulled on my Windows machine, or if the Wifi is disabled on my Android device.
private async Task TestConnectionLoop()
{
byte[] buffer = new byte[1];
ArraySegment<byte> arraySegment = new ArraySegment<byte>(buffer, 0, 0);
SocketFlags flags = SocketFlags.None;
while (!_cancellationSource.Token.IsCancellationRequested)
{
try
{
await _soc.SendAsync(arraySegment, flags);
await Task.Delay(500);
}
catch (Exception e)
{
_cancellationSource.Cancel();
// Others can listen to the Cancellation Token or you
// can do other actions here
}
}
}
Please note that I have found GSF.Communication wrapper for System.Net.Sockets.TcpClient to be helpful because it has a CurrentState property that indicates whether the socket is open/connected or closed/disconnected. You can find details on the NuGet package here:
https://github.com/GridProtectionAlliance/gsf
Here is how you could setup a simple TCP socket and test whether it is connected:
GSF.Communication.TcpClient tcpClient;
void TestTcpConnectivity()
{
tcpClient = new GSF.Communication.TcpClient();
string myTCPServer = "localhost";
string myTCPport = "8080";
tcpClient.MaxConnectionAttempts = 5;
tcpClient.ConnectionAttempt += s_client_ConnectionAttempt;
tcpClient.ReceiveDataComplete += s_client_ReceiveDataComplete;
tcpClient.ConnectionException += s_client_ConnectionException;
tcpClient.ConnectionEstablished += s_client_ConnectionEstablished;
tcpClient.ConnectionTerminated += s_client_ConnectionTerminated;
tcpClient.ConnectionString = "Server=" + myTCPServer + ":" + myTCPport;
tcpClient.Initialize();
tcpClient.Connect();
Thread.Sleep(250);
if (tcpClient.CurrentState == ClientState.Connected)
{
Debug.WriteLine("Socket is connected");
// Do more stuff
}
else if (tcpClient.CurrentState == ClientState.Disconnected)
{
Debug.WriteLine(#"Socket didn't connect");
// Do other stuff or try again to connect
}
}
void s_client_ConnectionAttempt(object sender, EventArgs e)
{
Debug.WriteLine("Client is connecting to server.");
}
void s_client_ConnectionException(object sender, EventArgs e)
{
Debug.WriteLine("Client exception - {0}.", e.Argument.Message);
}
void s_client_ConnectionEstablished(object sender, EventArgs e)
{
Debug.WriteLine("Client connected to server.");
}
void s_client_ConnectionTerminated(object sender, EventArgs e)
{
Debug.WriteLine("Client disconnected from server.");
}
void s_client_ReceiveDataComplete(object sender, GSF.EventArgs<byte[], int> e)
{
Debug.WriteLine(string.Format("Received data - {0}.", tcpClient.TextEncoding.GetString(e.Argument1, 0, e.Argument2)));
}
I recommend the code from the answer of the user 'Uriel' above. His code in principle works great:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
but it has a bug:
IPEndPoint.Equals() is used here to search the retrieved list of TCP connections for the one connection that has the same endpoints as the socket TcpClient.Client of the used TCP client.
The idea and concept are fine, but in real life may fail because of the coexistence of IPv4 and IPv6: Current operating systems like Windows 10 support IPv4 and IPv6, and sockets may be created with IPv6 addresses even if addresses like "100.111.1.251" in the IPv4 format were configured:
// Creation of TCP client:
m_tcpClient = new TcpClient ();
m_tcpClient.Connect ("100.111.1.251", 54321);
// Query of the local and remote IP endpoints in Visual Studio Immediate Window:
?m_tcpClient.Client.LocalEndPoint
{[::ffff:100.111.1.254]:55412}
Address: {::ffff:100.111.1.254}
AddressFamily: InterNetworkV6
Port: 55412
?m_tcpClient.Client.RemoteEndPoint
{[::ffff:100.111.1.251]:54321}
Address: {::ffff:100.111.1.251}
AddressFamily: InterNetworkV6
Port: 54321
// Query of the addresses of the local and remote IP endpoints in Visual Studio Immediate Window:
?((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address
{::ffff:100.111.1.254}
Address: '((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
?((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address
{::ffff:100.111.1.251}
Address: '((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
AddressFamily: InterNetworkV6 and IsIPv4MappedToIPv6: true indicate that the IP address in the local IP endpoint is an IPv6 address, although an IPv4 address was used to establish the connection. This obviously is because the socket is created in "dual-mode" or as "dual-stack":
https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses
https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isipv4mappedtoipv6
https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
https://www.ibm.com/docs/en/zos/2.2.0?topic=addresses-ipv4-mapped-ipv6
IPGlobalProperties.GetActiveTcpConnections() on the other side seems to always return IPEndPoint objects with IPv4 addresses:
?IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()[48].LocalEndPoint
{100.111.1.254:55412}
Address: {100.111.1.254}
AddressFamily: InterNetwork
Port: 55412
The consequence is that IPEndPoint.Equals() may return false even if two compared EndPoint objects refer to the same IP endpoint.
The solution for this problem is writing your own Equals() method, like:
public static class EndPointHelper
{
private static readonly AddressFamily[] addressFamilies =
{
AddressFamily.InterNetwork,
AddressFamily.InterNetworkV6
};
public static bool Equals (EndPoint? endPoint1, EndPoint? endPoint2)
{
if (endPoint1 is IPEndPoint ipEndPoint1 &&
endPoint2 is IPEndPoint ipEndPoint2)
{
if (ipEndPoint1.AddressFamily != ipEndPoint2.AddressFamily &&
addressFamilies.Contains(ipEndPoint1.AddressFamily) &&
addressFamilies.Contains(ipEndPoint2.AddressFamily))
{
var ipAddress1AsV6 = ipEndPoint1.Address.MapToIPv6();
var ipAddress2AsV6 = ipEndPoint2.Address.MapToIPv6();
return ipAddress1AsV6.Equals(ipAddress2AsV6)
&& ipEndPoint1.Port.Equals(ipEndPoint2.Port);
}
}
return object.Equals (i_endPoint1, i_endPoint2);
}
}
Furthermore, there is a bug in .NET 5, which makes the whole solution above unusable: IPGlobalProperties.GetActiveTcpConnections() has a memory leak (see https://github.com/dotnet/runtime/issues/64735), which will not be fixed in .NET 5 any more, because it has run out of support. The bug is not present in .NET 6. If you are tied to .NET 5, you will have to work around it by remembering the connection state yourself in a local variable (e.g. EnumState m_cachedState). Set this variable after each related operation, e.g. after a Connect() you would have to set it to EnumState.Connected.
This method of course will not detect when a connection was closed by the other side, so you have to cyclically check if the connection was closed, using this code:
var socket = m_tcpClient.Client;
bool state = socket.Poll (100, SelectMode.SelectRead);
int available = socket.Available;
return state && available == 0 // Condition for externally closed connection. The external close will not be recognized until all received data has been read.
? EnumState.Idle
: m_cachedState;
Try this, it works for me
private void timer1_Tick(object sender, EventArgs e)
{
if (client.Client.Poll(0, SelectMode.SelectRead))
{
if (!client.Connected) sConnected = false;
else
{
byte[] b = new byte[1];
try
{
if (client.Client.Receive(b, SocketFlags.Peek) == 0)
{
// Client disconnected
sConnected = false;
}
}
catch { sConnected = false; }
}
}
if (!sConnected)
{
//--Basically what you want to do afterwards
timer1.Stop();
client.Close();
ReConnect();
}
}
i used Timer because, I wanted to check connection state at regular interval
and not in a LOOP with Listening code [I felt it was slowing the sending-recieving process]
In my case, I was sending some command to a server (running in a virtual machine on the same computer) and waiting for the response. However, if the server stopped unexpectedly while waiting, I did not get any notification. I tried the possibilities proposed by the other posters, but neither did work (it always said that the server is still connected). For me, the only thing that is working is to write 0 bytes to the stream:
var client = new TcpClient();
//... open the client
var stream = client.GetStream();
//... send something to the client
byte[] empty = { 0 };
//wait for response from server
while (client.Available == 0)
{
//throws a SocketException if the connection is closed by the server
stream.Write(empty, 0, 0);
Thread.Sleep(10);
}
I have an application that was written for remote trucks to use on cell service. Before I do anything, I am checking the internet with this class:
using System.Net;
namespace SSS.ServicesConfig.MiscClasses
{
public class VerifyInternetAccess
{
public static bool HasInternet()
{
try
{
using (var client = new WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
}
}
In some cases, the light on the external cellular device has a green light as if it has internet. My test class comes back false so it thinks it does not have internet.
The driver can then open up internet explorer, close internet explorer, promptly run my application and it passes the test above.
The users are saying that IE is 'waking up' the internet so that it can transfer.
Doesn't my class do essentially the same thing? If not, how can I 'wake up' the internet connection as IE does?
You didn't state if you're restricted to a certain mobile OS but this works on a normal box.
I try to leverage two features of the System.Net.NetworkInformation namespace.
I start with registering for the NetworkChangedEvent. By calling GetIsNetworkAvailable you get an idea if there is at least one other NIC present that is not the loopback interface.
If there is no connection I try to wake-up the network layer by getting pinging a host.
I use the Dns.GetHostEntry to obtain all IP Adresses known for a host. Next I try to Ping the address one by one.
Be aware that not all hosts allow ICMP traffic which would lead to timeouts in all circumstances. If however in the meantime the network becomes available the NetworkChanged event should have been fired and set the HasConnection to true
public class VerifyInternetAccess
{
private static bool HasConnection = false;
static VerifyInternetAccess()
{
NetworkChange.NetworkAvailabilityChanged += (o, ca) =>
{
HasConnection = ca.IsAvailable;
};
HasConnection = NetworkInterface.GetIsNetworkAvailable();
}
public static bool HasInternet()
{
bool hasEnded = false;
if (!HasConnection)
{
// let's try to wake up...
using (var ping = new Ping())
{
var iphost = Dns.GetHostEntry("www.google.com");
foreach (var addr in iphost.AddressList)
{
var reply = ping.Send(addr);
if (reply.Status == IPStatus.Success)
{
HasConnection = true;
break;
}
}
}
}
return HasConnection;
}
}