Network stream no longer works after connection loss - c#

I'm working on an android app in xamarin which connects to a server. The server application follows processes etc based on the client connection. However if I say turn the device into airplane mode then turn airplane mode back off the connection no longer works. Basically in the real world the problem is that users will be using the android device which is liable to brief losses of connection due to wifi disturbances etc. I have tried a "reconnect" technique(as i noticed the Tcp.Connected value was still true) by simply trying to reaqcuire the NetworkStream however it did not work. Below is code:
public NetworkStream NetworkStream;
public TcpClient TcpClient;
public string LastGetData = null;
public string LastPostData = null;
public bool Disconnected = true;
public Stream InitializeStream(IPAddressAndPort ipObject)
{
NetworkStream clientStream = null;
try
{
IPAddress address = IPAddress.Parse(ipObject.Address);
TcpClient client = new TcpClient();
client.SendTimeout = 3000;
IPEndPoint serverEndPoint = new IPEndPoint(address, ipObject.Port);
client.ConnectAsync(serverEndPoint.Address, serverEndPoint.Port).Wait(5000);
if (client.Connected)
{
clientStream = client.GetStream();
TcpClient = client;
NetworkStream = clientStream;
Disconnected = false;
SendData("CLIENTSOFTWARENAME");
string initReturnValue = ReadData();
LastGetData = initReturnValue;
}
}
catch (Exception ex)
{
LastGetData = ex.Message;
}
return clientStream;
}
public void AttemptReconnect()
{
if (TcpClient != null)
{
try
{
if (TcpClient.Connected)
{
NetworkStream clientStream = TcpClient.GetStream();
NetworkStream = clientStream;
Disconnected = false;
}
}
catch (Exception ex)
{
LastGetData = ex.Message;
}
}
}
public string RunCommand(string dataToSend)
{
string returnValue = string.Empty;
try
{
if (Disconnected) AttemptReconnect();
SendData(dataToSend);
returnValue = ReadData();
if (returnValue == string.Empty)
Disconnected = true;
}
catch
{
returnValue = "An error occured during the action! Please logout and try again.";
}
return returnValue;
}
public void SendData(string dataToSend)
{
if (NetworkStream != null)
{
var serverStream = NetworkStream;
byte[] outStream = System.Text.Encoding.UTF8.GetBytes(dataToSend);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
LastPostData = dataToSend;
}
}
public string ReadData()
{
if (NetworkStream != null)
{
string returnValue = string.Empty;
byte[] bReads = new byte[1024];
int readAmount = 0;
DateTime endProcess = DateTime.Now.AddSeconds(20);
while (returnValue == string.Empty && endProcess > DateTime.Now)
{
while (NetworkStream.DataAvailable)
{
readAmount = NetworkStream.Read(bReads, 0, bReads.Length);
returnValue += string.Format("{0}", Encoding.UTF8.GetString(bReads, 0, readAmount));
}
}
LastGetData = returnValue;
return returnValue;
}
return null;
}

Solved: Once NetworkStream or TCPClient erros out it becomes useless. We decided to store information about the device in order to reconnect to existing process and create a new TCPClient and NetworkStream

Related

C# Socket is not responding in seperate thread

Hello I am working on some code which envolves a hello protocol between two servers as a keep alive and to process files on the brother if a server goes down.
I run the same service on two different machines but on one machine it does not recieve and gets stuck on socket.recieve().
i have traced a wireshark and c# debug but the client sends but the server never responds, which is causing a problem for this feature
Thanks
Richard
public static void Listen(ServiceController serviceController, Server server, List<Server> RemoteServers)
{
while (!serviceController.StopService)
{
if (server.ThisDevice)
{
TcpListener listener = new TcpListener(1);
string response = "Hello Recieved";
byte[] responsebyte = Encoding.ASCII.GetBytes(response);
try
{
listener = new TcpListener(server.IPAddress, 11000);
listener.Start();
byte[] Bytes = new byte[256];
Listening = true;
while (!serviceController.StopService)
{
Socket socket = listener.AcceptSocket();
int result = socket.Receive(Bytes);
ASCIIEncoding aSCII = new ASCIIEncoding();
string strres = aSCII.GetString(Bytes,0,result);
string stripped = strres.Substring(0, 5);
if (stripped == "Hello")
{
Console.WriteLine(stripped);
socket.Send(responsebyte);
string clientIP = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString();
ProcessHello(stripped,clientIP,RemoteServers);
}
socket.Close();
}
}
catch (Exception ex)
{
listener.Stop();
Listening = false;
}
}
}
}
}
public static void StartClient(Server server)
{
if (!server.ThisDevice)
{
TcpClient tcpClient = new TcpClient(server.IPAddress.ToString(),11000);
NetworkStream stream = tcpClient.GetStream();
string msg = "Hello";
string response = "";
byte[] bytes = new byte[256];
bytes = Encoding.ASCII.GetBytes(msg);
stream.Write(bytes, 0, bytes.Length);
StreamReader reader = new StreamReader(stream, Encoding.ASCII);
try
{
response = reader.ReadToEnd();
}
finally
{
// Close the reader
reader.Close();
}
tcpClient.Close();
}
public void StartClient(List<Server> servers)
{
_ClientStarted = true;
var remote = servers.Where(s => !s.ThisDevice).ToList();
Thread t = new Thread(() => ExecuteThreadedClient(remote));
t.Start();
}
void ExecuteThreadedClient(List<Server> servers)
{
while (!_ServiceController.StopService)
{
try
{
//Token.ThrowIfCancellationRequested();
foreach (var server in servers)
{
TCPHelloClient.StartClient(server);
}
Thread.Sleep(_HelloTimer);
}
catch (OperationCanceledException e)
{
Thread.Sleep(60000);
}
catch(Exception e)
{
Thread.Sleep(_HelloTimer);
}
}
_ClientStarted = false;
// Task.Delay(_HelloTimer).Wait();
}
public void StartServer(List<Server> servers)
{
try
{
//var task = Task.Run(() => ExecuteThreadedServer(server), Token);
Server local = servers.First(s => s.ThisDevice);
var remote = servers.Where(s => !s.ThisDevice).ToList();
Thread t = new Thread(() => TCPHelloServer.Listen(_ServiceController, local, remote));
t.Start();
}
catch(Exception e)
{
}
}

In the IPv6(NAT64) environment,networkStream.BeginRead does't work

The following code works well in IPV4,And,In the IPv6(NAT64) environment,it can connect the server and send message success,It can capture the data from server, But,the callback OnRead never be executed.
It's been bothering me for a long time.
private TcpClient client = null;
private const int MAX_READ = 8192;
private NetworkStream outStream = null;
private byte[] byteBuffer = new byte[MAX_READ];
public void ConnectServerByIP(string ip, int port) {
client = new TcpClient(AddressFamily.InterNetworkV6);
client.SendTimeout = 1000;
client.ReceiveTimeout = 1000;
client.NoDelay = true;
IPAddress ipAddr = IPAddress.Parse(ip);
try {
client.BeginConnect(ipAddr, port, new AsyncCallback(OnConnect), null);
} catch (Exception e) {
Close(); Debug.LogError(e.Message);
}
}
void OnConnect(IAsyncResult asr) {
outStream = client.GetStream();
client.GetStream ().BeginRead (byteBuffer, 0, MAX_READ,new AsyncCallback(OnRead), null);
NetworkManager.AddEvent(Protocal.Connect, new ByteBuffer());
}
void OnRead(IAsyncResult asr) {
Debug.Log ("Hello~");
}

Finding out whether a TCP server has sent a data

I have a TCP server which writes data back to the client only for certain messages which the clients sends to the server.
It is basically is a command based server for which the server responds with a string only for certain commands otherwise nothing is sent back to the client.
The code given below is an approach which assumes that if any data is sent by the server it shows it as "MESSAGE FROM SERVER" appended with the data which was sent.
class TcpEchoClient
{
static void Main(string[] args)
{
Console.WriteLine("Starting echo client...");
string ipaddress = "127.0.0.1";
TcpClient client = null;
NetworkStream netstream = null;
try
{
client = new TcpClient(ipaddress,1000);
netstream = client.GetStream();
}
catch
{
Console.ReadKey();
Environment.Exit(0);
}
while(true)
{
Console.WriteLine("Message : ");
string t = Console.ReadLine();
string readdata = null;
Console.WriteLine("\n");
if (write(t,netstream))
{
Console.WriteLine("Message sent.");
if (client.Available!=0)
{
readdata = read(netstream);
Console.WriteLine("MESSAGE FROM SERVER : "+readdata);
}
}
else
{
Console.WriteLine("Unable to send message.");
}
}
}
static bool write(string dat, NetworkStream stream)
{
try
{
StreamWriter writer = new StreamWriter(stream) { AutoFlush = true };
try{writer.WriteLine(dat);}
catch (IOException){return false;}
if (SHAHash(dat, "DATA") != SHAHash(read(stream), "DATA"))
return false;
}catch (InvalidOperationException){return false;}
return true;
}
static string read(NetworkStream stream)
{
StreamReader reader = new StreamReader(stream);
string readdata = null;
try
{
readdata = reader.ReadLine();
reader.BaseStream.Flush();
}
catch(IOException)
{
return null;
}
return readdata;
}
}
The function SHAHash is not shown in this post. Its format is SHAHash(message,salt).
The problem faced is that messages sent by the server is not always read by the client. Sometimes the data sent by the server shows up a the client console, and sometimes it does not.
What correction should I make to the above code so that I can read data from the server only when it sends it. That is I require the following code to be executed only when the server sends some data to the client otherwise it should not be executed.
readdata = read(netstream);
Console.WriteLine("MESSAGE FROM SERVER : "+readdata);
Be prudent when using flush or autoflush. Sometimes it executes before send/receive operations... but this usually happens when working with threads.
My first tip that the stream readers/writers are not destructed properly. Try packing them into a using statement.
TCP isnt synchronous so you can't write data and expect the response to be available immediately. When you do the following check
if (client.Available!=0)
there is no guarantee that the server has sent any response yet. You need to keep checking until there is data available or read the data asynchronously
I would use NetworkStream.BeginRead and callbacks to get the server response
class StreamData
{
public NetworkStream netstream;
public byte[] myReadBuffer;
}
class TcpEchoClient
{
static void Main(string[] args)
{
Console.WriteLine("Starting echo client...");
string ipaddress = "127.0.0.1";
TcpClient client = null;
NetworkStream netstream = null;
try
{
client = new TcpClient(ipaddress, 13000);
netstream = client.GetStream();
}
catch
{
Console.ReadKey();
Environment.Exit(0);
}
var streamData = new StreamData
{
netstream = netstream,
myReadBuffer = new byte[1024],
};
netstream.BeginRead(streamData.myReadBuffer, 0, streamData.myReadBuffer.Length,
new AsyncCallback(myReadCallBack),
streamData);
while (true)
{
Console.WriteLine("Message : ");
string t = Console.ReadLine();
Console.WriteLine("\n");
if (write(t, netstream))
{
Console.WriteLine("Message sent.");
}
else
{
Console.WriteLine("Unable to send message.");
}
}
}
static void myReadCallBack(IAsyncResult ar)
{
var streamData = (StreamData)ar.AsyncState;
int bytesRead = streamData.netstream.EndRead(ar);
var readdata = Encoding.ASCII.GetString(streamData.myReadBuffer, 0, bytesRead);
//Be aware that this might not be the complete message depending on the size of the message and the buffer size
Console.WriteLine("You received the following message : " + readdata);
//Start waiting for more data
streamData.netstream.BeginRead(streamData.myReadBuffer, 0, streamData.myReadBuffer.Length,
new AsyncCallback(myReadCallBack),
streamData);
}
static bool write(string dat, NetworkStream stream)
{
try
{
StreamWriter writer = new StreamWriter(stream) { AutoFlush = true };
try { writer.WriteLine(dat); }
catch (IOException) { return false; }
//if (SHAHash(dat, "DATA") != SHAHash(read(stream), "DATA"))
// return false;
}
catch (InvalidOperationException) { return false; }
return true;
}
}

C# and NetworkStream, sending is ok but receiving is not working

here is the source code, I can't understand what happens. When I receive data from server then writes back to the NetworkStream then it works but when I try to send first before reading from the server it does not work :
void BtnConnectClick(object sender, EventArgs e)
{
TcpClient clientSocket = null;
NetworkStream networkStream = null;
try{
clientSocket = new TcpClient();
clientSocket.SendTimeout = 5000;
clientSocket.ReceiveTimeout = 5000;
clientSocket.Connect("192.168.0.13",7777);
networkStream = clientSocket.GetStream();
const string strToAndroid = "hi from client";
char[] carray = strToAndroid.ToCharArray();
for (int i=0;i<carray.GetLength(0);i++)
{
networkStream.WriteByte((byte)carray[i]);
}
log("sent to Android = " + strToAndroid);
string strFromAndroid = "";
int j=0;
while (j!=-1)
{
try
{
j = networkStream.ReadByte();
if (j!=-1)
strFromAndroid += (char)j;
}
catch(Exception ex){
break;
}
}
log("received from Android = " + strFromAndroid);
networkStream.Close();
clientSocket.Close();
}
catch(Exception ex){
log("002:" + ex.Message);
if (networkStream != null)
networkStream.Close();
if (clientSocket != null)
clientSocket.Close();
}
}
This was a server side issue so this code is ok.
The server was never receiving the value -1 so it did not reply back.

Problem with simple tcp\ip client-server

i'm trying to write simple tcp\ip client-server.
here is server code:
internal class Program
{
private const int _localPort = 7777;
private static void Main(string[] args)
{
TcpListener Listener;
Socket ClientSock;
string data;
byte[] cldata = new byte[1024];
Listener = new TcpListener(_localPort);
Listener.Start();
Console.WriteLine("Waiting connections [" + Convert.ToString(_localPort) + "]...");
try
{
ClientSock = Listener.AcceptSocket();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
int i = 0;
if (ClientSock.Connected)
{
while (true)
{
try
{
i = ClientSock.Receive(cldata);
}
catch
{
}
try
{
if (i > 0)
{
data = Encoding.ASCII.GetString(cldata).Trim();
ClientSock.Send(cldata);
}
}
catch
{
ClientSock.Close();
Listener.Stop();
Console.WriteLine(
"Server closing. Reason: client offline. Type EXIT to quit the application.");
}
}
}
}
}
And here is client code:
void Main()
{
string data; // Юзерская дата
byte[] remdata ={ };
TcpClient Client = new TcpClient();
string ip = "127.0.0.1";
int port = 7777;
Console.WriteLine("\r\nConnecting to server...");
try
{
Client.Connect(ip, port);
}
catch
{
Console.WriteLine("Cannot connect to remote host!");
return;
}
Console.Write("done\r\nTo end, type 'END'");
Socket Sock = Client.Client;
while (true)
{
Console.Write("\r\n>");
data = Console.ReadLine();
if (data == "END")
break;
Sock.Send(Encoding.ASCII.GetBytes(data));
Sock.Receive(remdata);
Console.Write("\r\n<" + Encoding.ASCII.GetString(remdata));
}
Sock.Close();
Client.Close();
}
When i'm sending to my server i cannt receive data back answer. Sock.Receive(remdata) returns nothing! Why?
You're trying to receive to an empty buffer. You should allocate the buffer with a sensible size, and then take note of the amount of data received:
byte[] buffer = new byte[1024];
...
int bytesReceived = socket.Receive(buffer);
string text = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
(It's somewhat unconventional to use PascalCase for local variables, by the way. I'd also urge you not to just catch Exception blindly, and not to swallow exceptions without logging them.)

Categories