c# NetworkStream disposed over tcp/ip - c#

I'm hoping someone can tell me why I'm getting an object disposed exception in my tcpListener/tcpClient code.
In the acceptConnections and connectToServer methods I use the keepalive method to tell me when I get disconnected and it works fine.
However, if I uncomment the for loop for my sendMsg method I will get an ObjectDisposedException on the server and an IOException on the client.
The tcpClient.getStream()'s NetworkStream in SendMsg seems to be the issue but I am unsure why it would get a disposed stream. Do I need 2 threads to work with it?
static void Main(string[] args)
{
server.Listen();
server.AcceptConnections();
client.ConnectToServer();
//for (int i = 0; i < 5; i++) {
// Thread.Sleep(3000);
// server.SendMsg("SENT MSG");
//}
Console.ReadLine();
}
public async void SendMsg(String message) {
try {
NetworkStream networkStream = tcpClient.GetStream();
using (var writer = new StreamWriter(networkStream)) {
await writer.WriteLineAsync(message);
Console.WriteLine("msg sent");
};
} catch (Exception e) {
}
}
private async void KeepAlive(TcpClient tcpClient) {
bool clientConnected = true;
using (NetworkStream networkStream = tcpClient.GetStream())
using (var reader = new StreamReader(networkStream))
using (var writer = new StreamWriter(networkStream)) {
writer.AutoFlush = true;
char keepalive = '0';
while (clientConnected) {
try {
await writer.WriteLineAsync(keepalive);
string dataFromClient = await reader.ReadLineAsync();
Console.WriteLine("Server: " + dataFromClient);
Thread.Sleep(500);
} catch (IOException e){
} catch(ObjectDisposedException e) {
clientConnected = false;
clientsConnected--;
} catch (Exception e){
}
}
}
}
EDIT: posting my AcceptConnections method as well
public async void AcceptConnections() {
while (true) {
while (clientsConnected <= maxConnections) {
try {
tcpClient = await tcpListener.AcceptTcpClientAsync();
KeepAlive(tcpClient);
} catch (Exception e) {
Console.WriteLine("TOP EXCEPTION :: " + e);
}
clientsConnected++;
Console.WriteLine("SERVER Clients connected: " + clientsConnected);
}
}
}

Your SendMsg method uses using on a StreamWriter. The default for a StreamWriter is to cascade the dispose, so this will close the NetworkStream. If that isn't your intent, you need to pass leaveOpen: true to the constructor overload.
Frankly though, there's no reason to use StreamWriter here - I would suggest dealing with the Stream and Encoding APIs directly. One advantage of StreamWriter is that internally it might re-use a buffer for the byte[] work, but that "advantage" is moot if you're only using it for one Write before disposing it, and can be readily achieved with a buffer pool.

Related

C# Async Sockets - Code Analysis

My client part is closing after I do a request to server a second time, but without errors, it just goes away:
class Client
{
static void Main(string[] args)
{
try
{
Console.Title = "Client";
AsyncClient client = new AsyncClient(60101);
client.Connect();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.Read();
}
}
}
public class AsyncClient
{
private IPAddress ipAddress;
private int port;
/// <summary>
/// Connects to the local IPAddress.
/// </summary>
/// <param name="port"></param>
public AsyncClient(int port)
{
this.port = port;
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
this.ipAddress = null;
for (int i = 0; i < ipHostInfo.AddressList.Length; i++)
{
if (ipHostInfo.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
this.ipAddress = ipHostInfo.AddressList[i];
break;
}
}
if (this.ipAddress == null)
throw new Exception("No IPv4 address has been found");
}
public AsyncClient(string ip, int port)
{
this.port = port;
IPAddress.TryParse(ip, out ipAddress);
}
public async void Connect()
{
int attempts = 0;
TcpClient client = new TcpClient();
while (!client.Connected)
{
try
{
attempts++;
client.Connect(this.ipAddress, this.port);
Console.Clear();
Console.WriteLine("Connected");
await Process(client);
}
catch (SocketException)
{
Console.Clear();
Console.WriteLine("Connection Attempts: {0}", attempts);
}
}
}
public async Task Process(TcpClient tcpClient)
{
try
{
NetworkStream stream = tcpClient.GetStream();
StreamWriter writer = new StreamWriter(stream);
StreamReader reader = new StreamReader(stream);
writer.AutoFlush = true;
while (true)
{
Console.WriteLine("Enter a Request: ");
await writer.WriteLineAsync(Console.ReadLine());
string response = await reader.ReadLineAsync();
if (response != null)
Console.WriteLine(response);
else
break;
}
}
catch (Exception)
{
//
}
finally
{
if (!tcpClient.Connected)
{
for (int i = 5; i >= 1; i--)
{
Console.WriteLine($"Connection lost, trying to reconnect in {i}");
Thread.Sleep(1000);
}
Connect();
}
}
}
}
This under is the server side code, it's just for study purpose. I am trying to learn how to work with sockets and after trying with many different ways like "begin" methods, etc, I feel like I've finally found the right way to do it, since with the others I had problems like concurrent access, closing connection, etc, but this time I believe I got it right.
Am I wrong or this time it's really all good with my code?
class Server
{
static void Main(string[] args)
{
try
{
Console.Title = "Server";
AsyncServer server = new AsyncServer(60101);
server.Run();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.Read();
}
}
}
public class AsyncServer
{
private IPAddress ipAddress;
private int port;
public AsyncServer(int port)
{
this.port = port;
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
this.ipAddress = null;
for (int i = 0; i < ipHostInfo.AddressList.Length; i++)
{
if (ipHostInfo.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
this.ipAddress = ipHostInfo.AddressList[i];
break;
}
}
if (this.ipAddress == null)
throw new Exception("No IPv4 address for server");
}
public async void Run()
{
TcpListener listener = new TcpListener(this.ipAddress, this.port);
listener.Start();
Console.WriteLine($"Server is now online on Port: {this.port}");
Console.WriteLine("Hit <Enter> to stop the service");
while (true)
{
try
{
TcpClient tcpClient = await listener.AcceptTcpClientAsync();
Process(tcpClient);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private async void Process(TcpClient tcpClient)
{
string clientEndPoint = tcpClient.Client.RemoteEndPoint.ToString();
Console.WriteLine($"Received connection request from {clientEndPoint}");
try
{
NetworkStream networkStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(networkStream);
StreamWriter writer = new StreamWriter(networkStream);
writer.AutoFlush = true;
while (true)
{
string request = await reader.ReadLineAsync();
if (request != null)
Handle(request, writer);
else
break;
}
}
catch (Exception)
{
//
}
finally
{
if (tcpClient.Connected)
tcpClient.Close();
Console.WriteLine($"{clientEndPoint} has closed the connection, aborting operation");
}
}
private string Response(string request)
{
Thread.Sleep(10000);
if (request.ToLower() == "get time")
return DateTime.Now.ToLongTimeString();
else
return $"\"{request}\" is a invalid request";
}
private async void Handle(string request, StreamWriter writer)
{
try
{
Console.WriteLine($"Received request: {request}");
string response = Response(request);
Console.WriteLine($"Computed response is: {response}");
await writer.WriteLineAsync(response);
}
catch (Exception)
{
//
}
}
}
Plus, I would like to know, if I want to make it work on my external IP, so ppl from different IPs can use it, what should I change?
My client part is closing after I do a request to server a second
time, but without errors, it just goes away:
The reason for this is that your client calls async method client.Connect(), but doesn't (a)wait this method, so execution on the main thread continues to the next line, Console.Read(), which blocks only until you press [ENTER] for the second time (first [ENTER] is consumed by Console.ReadLine() in a Process() method). Then there is nothing for main thread to do and main thread (as well as whole client application) exits.
As a side note, it is good practise to name all async methods such that it's name ends with 'Async', so that caller of such a method is aware of it's async behaviour and doesn't forget to (a)wait the method. So you should rename Connect to ConnectAsync and Process to ProcessAsync.
Solution is to change return type of Connect method to Task, making method awaitable (it is strongly discouraged for async method to return void anyway):
public async Task ConnectAsync()
and add .Wait() in the Main method, which blocks main thread, until ConnectAsync() exits.
client.ConnectAsync().Wait();
In C# 7.1 you could also use async Main instead:
static async Task Main(string[] args)
{
...
await client.ConnectAsync();
...
}
Plus, I would like to know, if I want to make it work on my external
IP, so ppl from different IPs can use it, what should I change?
Just make sure that if server has more than one IP address, TcpListener listens on the correct one, and enable port or application in the firewall.

How to detect the disconnected TCP connection and again connect

I have a TCP/IP client program in a Windows service written in C#. As of now everything is working fine. But I have a query that supposes my connection to the machine goes down due to any reasons say machine is out of the network or something. How will my application detect that and also tries to connect or regain the connection again?
Here is the code that I am using in my Windows service:
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
_thread = new Thread(DoWork);
_thread.Start();
System.Timers.Timer _timer = new System.Timers.Timer(60 * 1000); // every 60 seconds
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start(); // <- important
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (client.Connected)
{
//Do nothing
}
else {
//close the thread and again start.
try
{
using (StreamWriter streamWriter = File.AppendText(textfileSaveLocation))
{
streamWriter.WriteLine("Disconnected!!!!");
}
}
catch (Exception Ex)
{
Ex.Message.ToString();
}
_shutdownEvent.Set();
_thread.Start();
}
}
private void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
TcpClient client = new TcpClient();
string data= "";
fileSaveLocation = location;
try
{
client.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
}
catch (Exception ex)
{
// Log the error here.
client.Close();
continue;
}
try
{
using (NetworkStream stream = client.GetStream())
{
byte[] notify = Encoding.ASCII.GetBytes("Hello");
stream.Write(notify, 0, notify.Length);
byte[] data = new byte[1024];
while (!_shutdownEvent.WaitOne(0))
{
int numBytesRead = stream.Read(data, 0, data.Length);
if (numBytesRead > 0)
{
data= Encoding.ASCII.GetString(data, 0, numBytesRead);
}
}
}
}
catch (Exception ex)
{
// Log the error here.
client.Close();
}
}
}
protected override void OnStop()
{
_shutdownEvent.Set(); // trigger the thread to stop
_thread.Join(); // wait for thread to stop
}
Please help me. Any suggestions will be helpful. Thanks ..
TcpClient does not get notified when the connection is closed or disconnected. You can check manually if TcpClient is connected in every certain period like -
if(tcpClient.Connected)
{
//code
}
else
{
//renew connection
}
Or, you have to handle the Exception in Catch block and code as required.

StreamSocket, DataWriter.StoreAsync(), DataReader.LoadAsync() -- Asynchronous problems

I'm creating a Win 8 store app in which I connect to a server, written in Java, using StreamSocket. When I run the app in debug, with breakpoints on StreamSocket.ConnectAsync(...), DataWriter.StoreAsync(), and DataReader.LoadAsync(...), it connects, sends the message, and receives a message back. However, once I remove any one of my breakpoints, that method doesn't do it's job. How can I can fix this issue? Here is my code:
public async void Connect()
{
try
{
await socket.ConnectAsync(new Windows.Networking.HostName(ip),
"50000", SocketProtectionLevel.PlainSocket);
Connected = true;
}
catch (Exception e)
{
if (SocketError.GetStatus(e.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
Windows.UI.Popups.MessageDialog md =
new Windows.UI.Popups.MessageDialog("Error: " + e.Message);
return;
}
return;
}
public async void HandShake()
{
try
{
//output
writer = new DataWriter(socket.OutputStream);
writer.UnicodeEncoding =
Windows.Storage.Streams.UnicodeEncoding.Utf8;
byte[] nameBytes = Encoding.UTF8.GetBytes(Name.ToCharArray());
writer.WriteBytes(nameBytes);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
writer.Dispose();
//input
reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
uint bytesAvailable = await reader.LoadAsync(4096);
byte[] byArray = new byte[bytesAvailable];
reader.ReadBytes(byArray);
string temp = Encoding.UTF8.GetString(byArray, 0,
Convert.ToInt32(bytesAvailable));
temp = temp.Substring(0, temp.Length - 1);
if (temp == "NAME OK")
{
GoodName = true;
}
reader.DetachStream();
reader.Dispose();
}
catch (Exception e)
{
//await Task.WhenAll(tasks.ToArray());
if (SocketError.GetStatus(e.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
Windows.UI.Popups.MessageDialog md =
new Windows.UI.Popups.MessageDialog("Error: " + e.Message);
md.ShowAsync();
}
}
LoadAsync by default will not block until all the requested bytes have been read. You are probably receiving a partial message.
You'll need to implement whatever kind of message framing your protocol uses, as I describe on my blog.
P.S. Avoid async void. It really complicates your error handling.
I changed the return type of Connect() to Task. Then called it as such, await Connect(); I put send and receive code in separate methods and did the same. My issue was an asynchronous problem and this fixed it.

Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host

I have an update server that sends client updates through TCP port 12000. The sending of a single file is successful only the first time, but after that I get an error message on the server "Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host". If I restart the update service on the server, it works again only one time. I have normal multithreaded windows service.
SERVER CODE
namespace WSTSAU
{
public partial class ApplicationUpdater : ServiceBase
{
private Logger logger = LogManager.GetCurrentClassLogger();
private int _listeningPort;
private int _ApplicationReceivingPort;
private string _setupFilename;
private string _startupPath;
public ApplicationUpdater()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
init();
logger.Info("after init");
Thread ListnerThread = new Thread(new ThreadStart(StartListener));
ListnerThread.IsBackground = true;
ListnerThread.Start();
logger.Info("after thread start");
}
private void init()
{
_listeningPort = Convert.ToInt16(ConfigurationSettings.AppSettings["ListeningPort"]);
_setupFilename = ConfigurationSettings.AppSettings["SetupFilename"];
_startupPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
}
private void StartListener()
{
try
{
logger.Info("Listening Started");
ThreadPool.SetMinThreads(50, 50);
TcpListener listener = new TcpListener(_listeningPort);
listener.Start();
while (true)
{
TcpClient c = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ProcessReceivedMessage, c);
}
}
catch (Exception ex)
{
logger.Error(ex.Message);
}
}
void ProcessReceivedMessage(object c)
{
try
{
TcpClient tcpClient = c as TcpClient;
NetworkStream Networkstream = tcpClient.GetStream();
byte[] _data = new byte[1024];
int _bytesRead = 0;
_bytesRead = Networkstream.Read(_data, 0, _data.Length);
MessageContainer messageContainer = new MessageContainer();
messageContainer = SerializationManager.XmlFormatterByteArrayToObject(_data, messageContainer) as MessageContainer;
switch (messageContainer.messageType)
{
case MessageType.ApplicationUpdateMessage:
ApplicationUpdateMessage appUpdateMessage = new ApplicationUpdateMessage();
appUpdateMessage = SerializationManager.XmlFormatterByteArrayToObject(messageContainer.messageContnet, appUpdateMessage) as ApplicationUpdateMessage;
Func<ApplicationUpdateMessage, bool> HandleUpdateRequestMethod = HandleUpdateRequest;
IAsyncResult cookie = HandleUpdateRequestMethod.BeginInvoke(appUpdateMessage, null, null);
bool WorkerThread = HandleUpdateRequestMethod.EndInvoke(cookie);
break;
}
}
catch (Exception ex)
{
logger.Error(ex.Message);
}
}
private bool HandleUpdateRequest(ApplicationUpdateMessage appUpdateMessage)
{
try
{
TcpClient tcpClient = new TcpClient();
NetworkStream networkStream;
FileStream fileStream = null;
tcpClient.Connect(appUpdateMessage.receiverIpAddress, appUpdateMessage.receiverPortNumber);
networkStream = tcpClient.GetStream();
fileStream = new FileStream(_startupPath + "\\" + _setupFilename, FileMode.Open, FileAccess.Read);
FileInfo fi = new FileInfo(_startupPath + "\\" + _setupFilename);
BinaryReader binFile = new BinaryReader(fileStream);
FileUpdateMessage fileUpdateMessage = new FileUpdateMessage();
fileUpdateMessage.fileName = fi.Name;
fileUpdateMessage.fileSize = fi.Length;
MessageContainer messageContainer = new MessageContainer();
messageContainer.messageType = MessageType.FileProperties;
messageContainer.messageContnet = SerializationManager.XmlFormatterObjectToByteArray(fileUpdateMessage);
byte[] messageByte = SerializationManager.XmlFormatterObjectToByteArray(messageContainer);
networkStream.Write(messageByte, 0, messageByte.Length);
int bytesSize = 0;
byte[] downBuffer = new byte[2048];
while ((bytesSize = fileStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
networkStream.Write(downBuffer, 0, bytesSize);
}
fileStream.Close();
tcpClient.Close();
networkStream.Close();
return true;
}
catch (Exception ex)
{
logger.Info(ex.Message);
return false;
}
finally
{
}
}
protected override void OnStop()
{
}
}
I have to note something that my windows service (server) is multithreaded.
On the receiving end, set up a while loop to listen until there's no more data, then exit gracefully: close the stream and client. The framework TCP libs consider it an issue to drop a connection cold on thread exit and will therefore throw the exception you're seeing.
This will also save you from an intermittent problem you'll likely see once you correct the current one: Stream.Read with a length specifier won't always give you your full buffer each time. It looks like you're sending (up to) 2kb chunks and receiving into a (single-shot) 1kb buffer anyhow so you may start to get XML exceptions as well.
If that's not enough detail, ask and I'll dig up some old TcpClient code.

Threading issue in C#

can somebody tell me why my code is not working?
class Connection
{
public static StreamWriter writer;
public static string SERVER;
private static int PORT;
private static string USER;
private static string NICK;
private static string CHANNELS;
private Thread connection;
private Thread ping;
public Connection()
{
connection = new Thread(new ThreadStart(this.Run));
ping = new Thread(new ThreadStart(this.Ping));
}
public void Start(string server, int port, string ident, string realname, string nick, string channels)
{
SERVER = server;
PORT = port;
USER = "USER " + ident + " 8 * :" + realname;
NICK = nick;
CHANNELS = channels;
connection.Start();
}
public void Ping()
{
while (true)
{
try
{
Connection.writer.WriteLine("PING :" + SERVER);
Connection.writer.Flush();
Thread.Sleep(15000);
}
catch (Exception e) { Console.WriteLine(e.ToString()); }
}
}
public void Run()
{
NetworkStream stream;
TcpClient irc;
string inputLine;
StreamReader reader;
try
{
irc = new TcpClient(SERVER, PORT);
stream = irc.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
writer.WriteLine(USER);
writer.Flush();
writer.WriteLine("NICK " + NICK);
writer.Flush();
Thread.Sleep(5000);
writer.WriteLine("JOIN " + CHANNELS);
writer.Flush();
while (true)
{
while ((inputLine = reader.ReadLine()) != null)
{
Console.WriteLine(inputLine);
}
writer.Close();
reader.Close();
irc.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
Run();
}
}
}
It connects to the server fine, but the ping Thread and voids seem to not functioning at all! and i dont know why, everything seems correct unless im missing something very obviousC
You haven't started your ping thread. Call Start method of it.
Another note - don't use Thread.Sleep for threads/process synchronization. From my experience, code using it is usually slow, unreliable and hard to maintain. Use Monitor class or various WaitHandle implementations (e.g. AutoResetEvent) or whatever. For client/server communication try to wait until server response to your request (if such is defined in protocol), not just timeout.
Also, if you are starting new threads either make this threads stop (e.g. in Dispose method of your class) or set IsBackground property, or, preferrably, both. Otherwise these threads will block your process from stopping.

Categories

Resources