How to check the Internet connection with .NET, C#, and WPF - c#

I am using .NET, C# and WPF, and I need to check whether the connection is opened to a certain URL, and I can't get any code to work that I have found on the Internet.
I tried:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
IAsyncResult result = socket.BeginConnect("localhost/myfolder/", 80, null, null);
bool success = result.AsyncWaitHandle.WaitOne(3000, true);
if (!success)
{
MessageBox.Show("Web Service is down!");
}
else
MessageBox.Show("Everything seems ok");
}
finally
{
socket.Close();
}
But I always get the message that everything is OK even if I shut down my local Apache server.
I also tried:
ing ping = new Ping();
PingReply reply;
try
{
reply = ping.Send("localhost/myfolder/");
if (reply.Status != IPStatus.Success)
MessageBox.Show("The Internet connection is down!");
else
MessageBox.Show("Seems OK");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
But this always gives an exception (ping seems to work only pinging the server, so localhost works but localhost/myfolder/ doesnt)
Please how to check the connection so it would work for me?

Many developers are solving that "problem" just by ping-ing Google.com. Well...? :/ That will work in most (99%) cases, but how professional is to rely work of Your application on some external web service?
Instead of pinging Google.com, there is an very interesting Windows API function called InternetGetConnectedState(), that recognizes whether You have access to Internet or not.
THE SOLUTION for this situation is:
using System;
using System.Runtime;
using System.Runtime.InteropServices;
 
public class InternetAvailability
{
    [DllImport("wininet.dll")]
    private extern static bool InternetGetConnectedState(out int description, int reservedValue);
 
    public static bool IsInternetAvailable( )
    {
        int description;
        return InternetGetConnectedState(out description, 0);
    }
}

In the end I used my own code:
private bool CheckConnection(String URL)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Timeout = 5000;
request.Credentials = CredentialCache.DefaultNetworkCredentials;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
return true;
else
return false;
}
catch
{
return false;
}
}
An interesting thing is that when the server is down (I turn off my Apache) I'm not getting any HTTP status, but an exception is thrown. But this works good enough :)

Use this:
private bool CheckConnection()
{
WebClient client = new WebClient();
try
{
using (client.OpenRead("http://www.google.com"))
{
}
return true;
}
catch (WebException)
{
return false;
}
}

You can try this;
private bool CheckNet()
{
bool stats;
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() == true)
{
stats = true;
}
else
{
stats = false;
}
return stats;
}

I went through all the solutions. NetworkInterface.GetIsNetworkAvailable() doesn't check internet connection. It only check whether any network connection is available.
Ping is not reliable as in many network ping is turned off. Connecting to google with webclient is also not 100% reliable and it also has performance overhead if you use it too frequently.
Using Windows NLM API seems a better solution to me.
using NETWORKLIST;
namespace Network.Helpers
{
public class InternetConnectionChecker
{
private readonly INetworkListManager _networkListManager;
public InternetConnectionChecker()
{
_networkListManager = new NetworkListManager();
}
public bool IsConnected()
{
return _networkListManager.IsConnectedToInternet;
}
}
}
This is how to add it to project.

I think this will be more accurate when it comes windows applications, Windows form or WPF apps, Instead of using WebClient or HttpWebRequest,
public class InternetChecker
{
[System.Runtime.InteropServices.DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
//Creating a function that uses the API function...
public static bool IsConnectedToInternet()
{
int Desc;
return InternetGetConnectedState(out Desc, 0);
}
}
While calling write
if(InternetCheckerCustom.CheckNet())
{
// Do Work
}
else
{
// Show Error MeassgeBox
}

Here is a solution similar to Mahbubur Rahman, but using the COM interface directly an without the need to have a reference to Network List Manager 1.0 Type Library :
dynamic networkListManager = Activator.CreateInstance(
Type.GetTypeFromCLSID(new Guid("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")));
bool isConnected = networkListManager.IsConnectedToInternet;

Can we use ping just asking?
try
{
System.Net.NetworkInformation.Ping ping = new Ping();
//If you use DNS name as below it will give random time outs
//PingReply result = ping.Send("www.google.com");
//INSTEAD USE IP ADDRESS LIKE BELOW IT WILL GIVE ACCURATE TIMEOUTS
PingReply result = ping.Send("8.8.8.8");
if (result.Status == IPStatus.Success)
return true;
return false;
}
catch
{
return false;
}

Related

Error when trying to use Ping in Unity - C#

I am trying to ping one of my servers using C# Ping to see whether it is available or not, but I am receiving a weird error and I'm not sure what's causing it
On first execution of the code, it returns an error but states that the operation was completed successfully
System.Net.Sockets.SocketException (0x80004005): The operation completed successfully.\r\n\r\n at System.Net.Sockets.Socket..ctor (System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType) [0x00069]
Each time the code is executed after the first, it will return a different error.
"An attempt was made to access a socket in a way forbidden by its access permissions."
System.Net.Sockets.SocketException (0x80004005)
The code I am using to ping is as follows which is pretty much pulled straight from MSDN. https://msdn.microsoft.com/en-us/library/system.net.networkinformation.pingreply(v=vs.110).aspx
public static bool pingHost(string nameOrAddress)
{
bool pingable = false;
if (nameOrAddress == "127.0.0.1")
{
return true;
}
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 3;//3 seconds?
PingReply reply = pingSender.Send(nameOrAddress, timeout);
if (reply.Status == IPStatus.Success)
{
pingable = true;
} else
{
pingable = false;
}
}
catch (PingException e)
{
Debug.Log("Error pinging: " + e.Message + " - " + e.StackTrace);
// Discard PingExceptions and return false;
}
return pingable;
}
I am able to ping the server from my terminal on my machine, but not through code. Why am I receiving this error?
EDIT
I have tested the code in a standard C# application and it works fine. This issue must be something related to Unity.
Unity has its own Ping class but can't be called from outside the main thread. The code below tries to utilise this, but it always returns false and -1 for the time.
Ping should definitely complete within 3 seconds? I have tried increasing this time to 10 seconds but still returns false. The address is definitely pingable as I can ping it from the terminal.
IEnumerator ping()
{
while (true)
{
UnityEngine.Ping pinger = new UnityEngine.Ping("ADDRESS");
yield return new WaitForSeconds(3.0f);
Debug.Log("Ping finished? " + pinger.isDone + " - " + pinger.time);
yield return new WaitForSeconds(2.0f);
}
}
As this doesn't work, my next question is how does the Unity ping actually work? My servers are in a secure environment with only specific open ports. If it is doing something unexpected other than the standard ping, it may not be able to.
EDIT 2
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
This code seems to work nicely, but only works from the main thread. I will need a solution that is able to be started from a separate task or thread.
This seems to work, but only from the main thread.
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
Here's a general idea of how to do it on/off the main thread:
(Caution: untested)
using System.Threading;
class Test : MonoBehaviour {
Ping result;
private object pingLock;
void Start() {
pingLock = new object();
new Thread(ThingRunningOffMainThread).Start();
StartCoroutine(DoPing());
}
IEnumerator DoPing()
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
Monitor.Enter(pingLock);
result = p;
Monitor.Pulse(pingLock);
Monitor.Exit(pingLock);
}
void ThingRunningOffMainThread() {
if (result == null) {
Monitor.Enter(pingLock);
while (result == null) {
Monitor.Wait(pingLock);
}
Monitor.Exit(pingLock);
}
PingFinished(pingLock);
}
}
To invoke from a background thread to the main thread, look at Main Thread Dispatchers, for example:
https://github.com/PimDeWitte/UnityMainThreadDispatcher/blob/master/UnityMainThreadDispatcher.cs

WPF C# - Standard (non - privilege) user not able to accss the webclient?

Here is the code I am using to check the internet connection. But it always fails. This runs fine with my admin user but not working for standard (non-privilege) user I made. What could be missing here..
if (!App.IsInternetConnected)
{
await Task.Factory.StartNew(() =>
{
App.IsInternetConnected = Utils.IsInternetConnected();
});
}
if (!App.IsInternetConnected)
{
App.ShowMessage("FeatureNotAvailable");
LoginProgress.Visibility = System.Windows.Visibility.Hidden;
return;
}
IsInternetConnected method is as below.
internal static bool IsInternetConnected()
{
try
{
WebClient webclient = new WebClientPool().GetIdleWebClientObject();
try
{
webclient.DownloadString("http://www.google.com");
return true;
}
}
catch (Exception)
{
return false;
}
}
GetIdleWebClientObject is as below.
[MethodImpl(MethodImplOptions.Synchronized)]
public WebClient GetIdleWebClientObject()
{
foreach (WebClient item in WebClientItems)
{
if (!item.IsBusy )
{
Log.Instance.WriteLine("reused webclient");
item.Headers.Clear();
return item;
}
}
Log.Instance.WriteLine("new webclient");
WebClient NewItem = new WebClient();
NewItem.UseDefaultCredentials = true;
//NewItem.Credentials = CredentialCache.DefaultNetworkCredentials;
NewItem.Proxy = WebRequest.GetSystemWebProxy();
WebClientItems.Add(NewItem);
return NewItem;
}
My issue was bit out of way but may help anyone.
It was in line this Log.Instance.WriteLine("new webclient"); This line was creating and writing log file in C:\ drive. Which was not allowed to standard user and throwing exception.
which lead me to show no internet error which was not actually related.

Writing and reading using socket

This is my code
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;
public class s_TCP : MonoBehaviour {
internal Boolean socketReady = false;
TcpClient mySocket;
NetworkStream theStream;
StreamWriter theWriter;
StreamReader theReader;
String Host = "198.57.44.231";
Int32 Port = 1337;
string channel = "testingSona";
void Start () {
setupSocket();
//string msg = "__SUBSCRIBE__"+channel+"__ENDSUBSCRIBE__";
string msg = "Sending By Sona";
writeSocket(msg);
readSocket();
}
void Update () {
//readSocket();
}
public void setupSocket() {
try {
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e) {
Debug.Log("Socket error: " + e);
}
}
public void writeSocket(string theLine) {
if (!socketReady)
return;
String foo = theLine + "\r\n";
theWriter.Write(foo);
theWriter.Flush();
}
public String readSocket() {
if (!socketReady)
return "";
if (theStream.DataAvailable){
string message = theReader.ReadLine();
print(message);print(12345);
return theReader.ReadLine();
}
else{print("no value");
return "";
}
}
public void closeSocket() {
if (!socketReady)
return;
theWriter.Close();
theReader.Close();
mySocket.Close();
socketReady = false;
}
}
Connection created. But message not writing into server and reading
How can i do it
I think you have taken this code from http://answers.unity3d.com/questions/15422/unity-project-and-3rd-party-apps.html, but I think there is an error in this code. I'll repeat here what I posted there.
The following code does not work correctly:
public String readSocket() {
if (!socketReady)
return "";
if (theStream.DataAvailable)
return theReader.ReadLine();
return "";
}
This caused me a headache for quite few hours. I think that checking DataAvailable on the stream is not a reliable way to check if there is data to be read on the streamreader. So you do not want to check for DataAvailable. However, if you just remove that, then the code will block on ReadLine when there is no more to read. So instead, you need to set a timeout for reading from the stream, so that you won't wait longer than (say) a millisecond:
theStream.ReadTimeout = 1;
And then, you can use something like:
public String readSocket() {
if (!socketReady)
return "";
try {
return theReader.ReadLine();
} catch (Exception e) {
return "";
}
}
This code isn't perfect, I still need to improve it (e.g., check what kind of exception was raised, and deal with it appropriately). And maybe there's a better way overall to do this (I experimented with using Peek(), but the -1 it returns I suspect is for when the socket closes, and not just when there is no more data to read for now). However, this should solve problems with the posted code, like those I was having. If you're finding data is missing from the server, then it's probably sitting in your reader stream, and won't be read until new data is sent from the server and stored in the stream such that theStream.DataAvailable returns true.

C# Networking : Server hangs after receiving more than 65535 bytes

UPDATE:
Due to problems with the admins here on Stackoverflow, I have posted a very trimmed-down version of the same problem on MSDN forum. This text below used MyNetworking.dll, but that is not the problem. Here is a very slimmed Client-Server thing and the problem is exactly the same. Feel free to try it out =)
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/d3d33eb9-7dce-4313-929e-a8a63d0f1e03
/UPDATE
So, I have a strange error.
Normally, we have a DLL that handles our networking. Lets call that MyNetworking.dll. We use it everywhere in our servers and clients and have done so for 5 years. I haven't had a problem with it, until now.
I have an "XMLPoller", that reads XML from a MySQL database, serializes that into a byte[] array and sends it over the network. These particular XML messages is 627 bytes in serialized form.
The XMLPoller connects to a port on a "remote server" (that happens to be localhost) and sends the packets, one at a time. At exactly packet nbr 105 the connection is closed. 104 packets are sent from XMLPoller and received by the Server. 104 x 627 = 65208 bytes. But packet 105, when the total number of bytes sent would be 65835 the connection is closed with this error:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
This is the error on the server. However, I have stepped through the XMLPoller (client), and I see when the last 627 bytes are sent (thus sending up til 65835 bytes) and I see no errors on the client, it passes sending without problems.
UPDATE 20:15 SWEDISH TIME
I also get this error in the Client when I debug a little more:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
I think I have confirmed that it is in the Client the error exists. I am stepping through the code and before any Exceptions are caught on the server, I get an exception on the Client as stated above.
/ENDUPDATE
It seems to me that the Server never receives it, getting the error above. The server gets the connection closed because of something happening on the Client. However, the error on the client is in TCPInput; the stream reading data is dead for some reason?
I am not buffering anything in MyNetworking.dll.
When I get a new connection on a Socket (on the Server), I do this code:
public void setConnected(Socket thisClient)
{
NetworkStream stream = new NetworkStream(thisClient);
socket = thisClient;
output = new TCPOutput(stream, outputHandler,this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), null);
}
catch (Exception e)
{
this.disconnect();
}
}
and then, the OnDataReceived method (where the data is actually received):
public void OnDataReceived(IAsyncResult asyn)
{
int nbrRead = 0;
byte[] tmp = null;
try
{
nbrRead = stream.EndRead(asyn);
tmp = new byte[nbrRead];
}
catch (Exception e)
{
// *** HERE IS WHERE THE EXCEPTION IS CAUGHT ***
System.Diagnostics.Debugger.Log(0, "Bla1", e.ToString());
this.disconnect();
}
if (nbrRead > 0)
{
try
{
Array.Copy(inputBuffer, 0, tmp, 0, nbrRead);
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla2", e.ToString());
this.disconnect();
}
preProcessMessage(tmp);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), new object());
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla3", e.ToString());
this.disconnect();
}
}
else
this.disconnect();
}
Right now Im sort of clueless as to what is going on... Any ideas?
UPDATE 1:
Client code for sending data:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
Update 2
I tried to do a Flush on the outgoing stream from the client - no effect:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
UPDATE 3: Posting more code as per request
This code is old and not the pretties in the world, I know. But it has been working very well for 5 years so =)
ClientHandler.cs (what the actual Client is using for sending etc)
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
/// <summary>
/// Summary description for connectionHandler.
/// </summary>
public class ClientHandler
{
#region Fields (17) 
string address;
Connector connector;
DataHandler dataHandler;
int id;
TCPInput input;
int interval;
string localAddress;
IPEndPoint localPoint;
int localPort;
NetworkStream outputStream;
public TTCPClientInterface parent;
int port;
tWorks.tNetworking.Protocol.Protocol protocol;
bool reconnect;
string remoteIP;
Socket socket;
public State state;
#endregion Fields 
#region Enums (1) 
public enum State {Disconnected,Connecting,Connected}
#endregion Enums 
#region Constructors (4) 
public ClientHandler(int id, TTCPClientInterface parent, Socket socket, tWorks.tNetworking.Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent, Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
state = State.Disconnected;
}
public ClientHandler(int id, TTCPClientInterface parent, Socket socket)
{
this.id=id;
this.parent = parent;
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent)
{
this.id=id;
this.parent = parent;
this.protocol = null;
changeState(State.Disconnected);
}
#endregion Constructors 
#region Delegates and Events (4) 
// Delegates (2) 
public delegate void ConnectionLostDelegate(string message);
public delegate void exceptionDelegate(Exception ex);
// Events (2) 
public event exceptionDelegate ConnectionFailed;
public event ConnectionLostDelegate ConnectionLostEvent;
#endregion Delegates and Events 
#region Methods (17) 
// Public Methods (16) 
public void connect(string address, int port, int retryInterval, bool reestablish)
{
System.Random rand = new Random();
localPort = rand.Next(40000, 60000);
IPAddress localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; // new IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList[0].Address);
connect(address, port, retryInterval, reestablish, localIP.ToString(), localPort);
}
/// <summary>
/// Will connect to the address and port specified. If connection failed a new attempt will be made according to the Interval parameter.
/// If connection is lost attempts to reastablish it will be made if Reestablish is set to true.
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="retryInterval"></param>
/// <param name="reestablish"></param>
public void connect(string address, int port, int retryInterval, bool reestablish, string localAddress, int localPort)
{
this.reconnect = reestablish;
this.address = address;
this.port = port;
this.interval = retryInterval;
this.localAddress = localAddress;
this.localPort = localPort;
changeState(State.Connecting);
connector = new Connector(address, port, this, interval, localPoint, reestablish);
connector.Connect();
}
public void disconnect()
{
reconnect = false;
if (connector != null)
{
connector.stopConnecting();
}
setDisconnected();
}
public void dispose()
{
}
public void failedConnect(Exception e)
{
if (ConnectionFailed != null)
ConnectionFailed(e);
}
public int getID()
{
return this.id;
}
public string getIP()
{
return remoteIP;
}
public bool isConnected()
{
return this.state == State.Connected;
}
public void outDataLog(int nbrBytes)
{
parent.outDataLog(nbrBytes, id);
}
public void preProcessMessage(byte[] data)
{
//data = Crypto.Decrypt("a1s2d3", data);
if(protocol != null)
dataHandler.addData(data);
else
processMessage(data);
}
public void processMessage(byte[] data)
{
parent.processMessage(data,this);
}
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
public void setConnected(Socket thisClient)
{
socket = thisClient;
outputStream = new NetworkStream(thisClient);
input = new TCPInput(outputStream, this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
}
public void setDisconnected()
{
try
{
if (this.state == State.Connected)
{
changeState(State.Disconnected);
//socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch { }
if (reconnect)
this.connect(address, port, interval, true, localAddress, localPort);
}
public void stopConnect()
{
connector.stopConnecting();
changeState(State.Disconnected);
}
public override string ToString()
{
string returnString = "(D)";
if(this.state == State.Connected)
returnString = this.getIP();
return returnString;
}
// Private Methods (1) 
private void changeState(State state)
{
if (this.state == State.Connected && state == State.Disconnected)
{
if (ConnectionLostEvent != null)
ConnectionLostEvent("Uppkoppling bröts.");
}
this.state = state;
parent.connStateChange(this);
}
#endregion Methods 
}
}
This is TCPInput.cs that is listening on incoming data and forwarding that to the ClientHandler (seen above):
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
public class TCPInput
{
NetworkStream stream;
ClientHandler client;
public TCPInput(NetworkStream nS, ClientHandler client)
{
stream = nS;
this.client = client;
Thread t = new Thread(new ThreadStart(run));
t.IsBackground = true;
t.Name = "TCPInput";
t.Start();
}
public void run()
{
bool continueRead = true;
byte[] readBuffer = new byte[32768];
byte[] receivedBuffer = null;
int nbrBytesRead = 0;
int receivedBufferPos = 0;
while(continueRead)
{
try
{
nbrBytesRead = 0;
nbrBytesRead = stream.Read(readBuffer, 0, 10000);
receivedBuffer = new byte[nbrBytesRead];
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when stream.Read: " + e.ToString());
continueRead = false;
}
if(nbrBytesRead > 0)
{
try
{
Array.Copy(readBuffer, 0, receivedBuffer, receivedBufferPos, nbrBytesRead);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when Array.Copy: " + e.ToString());
continueRead = false;
}
client.preProcessMessage(receivedBuffer);
}
else
{
// *** I can break here, the nbrOfBytes read is 0 when this whole thing explodes =)
System.Diagnostics.Debug.WriteLine("TCPInput> Number of bytes read == 0! Setting continueRead = false");
continueRead = false;
}
}
client.setDisconnected();
}
}
}
The problem is in your other code, the 'client'. It closes the connection after sending all the 'packets'. You must wait until the server has received all of them. A simple approach, beyond negotiating it explicitly, is to wait for the server to close the connection.
That number ("thus sending up til 65835 bytes") is magically close to 2^16-1 (65535) -- looks like just one packet over!
(I'm assuming it's just the larger size that made things go kaboom! -- this can be tested reliably.)
I suspect there is an unsigned 16-bit variable used (in the library) where you need something with more range. Perhaps you can "empty" the internals of the library periodically or perform the operation in multiple connection? (Okay, just trying to throw out some 'quick hack' ideas :-)
So, after much testing and discussing with my partner-in-crime we found out that instead of using port 21 and taking for example port 22 - the problem goes away.
I have no idea why it behaves like this, but it does...
You post raises questions for me. Like why are you choosing well known ports for this service? I don't believe in coincidences and suspect your use of the term "partner-in-crime" may have more truth then I would care to be associated with.
Then also I am wondering why you assume a Windows bug and not one in the MyNetowrking.dll. Sure, you have been using this for five years. But it still hasn't had the level of vetting that Microsoft gives their code.

C# Keeping Pipes Open

I've Got two Programs (Server / Client)
I'm trying to setup IPC for them (They both run on the same box)
Using System.IO.Pipes & Net 3.5
When I call ComOpen, it opens the Pipe correctly, sends the Process ID to the server, but then the Pipe closes and I get an error when it tries to send "Second Write Test"
So Question is.
How do I keep the Pipe open for the Life of the Program?
(I use the Process ID on the server to close everything down if the Client crashes)
private static StreamWriter MyWriter;
private static StreamReader MyReader;
private static NamedPipeClientStream IPCPipe = new NamedPipeClientStream(".", "MyPipe", PipeDirection.InOut);
public static bool MyWrite(string DataOut)
{
bool ValidPipeOut = false;
if(ValidComPort)
try
{
// Send Data
using (QstWriter = new StreamWriter(IPCPipe))
{
QstWriter.AutoFlush = true;
QstWriter.WriteLine(QstDataOut);
QstWriter.Close();
QstWriter.Dispose();
}
ValidPipeOut = true;
}
catch
{
ValidPipeOut = false;
}
return ValidPipeOut;
}
public static bool ComOpen()
{
ValidComPort = true;
try { IPCPipe.Connect(1000); }
catch (Exception ex)
{
string Erroris;
Erroris = ex.Message;
if (Erroris == "Already in a connected state.")
{
// We're Already Connected, Ignore this error.
ValidComPort = true;
}
else
{
ValidComPort = false;
MessageBox.Show(Erroris);
}
}
if (ValidComPort)
{
string ClientProcessID = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
MyReader = new StreamReader(IPCPipe);
ValidComPort = MyWrite(ClientProcessID);
ValidComPort = MyWrite("Second Write Test");
}
return ValidComPort;
}
The problem is the following line:
using (QstWriter = new StreamWriter(IPCPipe))
At the end of the using statement, the StreamWriter will be disposed and that will in turn dispose the IPCPipe. You are also explicitly calling Dispose and Close on QstWriter, which will close the pipe too.
To fix this, remove the using statement and the calls to Dispose and Close on QstWriter. And assign+initialize QstWriter only once.

Categories