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.
Related
In the ClientClass, I have two threads; one for TCP-IP connection to a localhost and another to keep receiving messages from the localhost.
In case the connection gets broken, I close the connection using m_DeviceClientSocket.Close() inside the catch block of the method ConnectToDeviceAndMonitorConnection().
PROBLEM: Since I close the socket connection, therefore, the whole m_DeviceClientSocket object is dereferenced. This leads to another error inside the catch block of the method GetMessagesFromDevice() and the error says (as shown in the catch block of the code):
"Cannot access a disposed object.\r\nObject name:
'System.Net.Sockets.NetworkStream'
QUESTION: How should I create the m_DeviceClientSocket object, which can be closed, reconnected and is available to both the threads?
class ClientClass
{
Thread t1_DeviceConnectionMonitor, t2_receiveDeviceMessages;
static readonly object m_IsConnectedToDevice_Locker = new object();
bool m_IsConnectedToDevice = false;
//Device - Communication Variables
string m_DeviceURL = "127.0.0.1";
int m_DevicePort = 23;
TcpClient m_DeviceClientSocket = new TcpClient();
NetworkStream m_DeviceServerStream = default(NetworkStream);
public ClientClass()
{
//Thread for CONNECTION Monitoring
t1_DeviceConnectionMonitor = new Thread(ConnectToDeviceAndMonitorConnection);
t_DeviceConnectionMonitor.Start();
//Thread to RECEIVE messages
t2_receiveDeviceMessages = new Thread(GetMessagesFromDevice);
t2_receiveDeviceMessages.Start();
}
//Connect to Device
void ConnectToDeviceAndMonitorConnection()
{
while (true)
{
if (!m_IsConnectedToDevice)
{
try
{
//Connect to device server
m_DeviceClientSocket.Connect(m_DeviceURL, m_DevicePort);
m_DeviceServerStream = m_DeviceClientSocket.GetStream();
SetDeviceConnectionStatus(true);
}
catch (SocketException se)
{
if (m_DeviceClientSocket.Connected)
m_DeviceClientSocket.Close(); //This Close() statement dereference the complete "m_DeviceClientSocket" object
}
}
}
}
//RECEIVE messages from the device
public void GetMessagesFromDevice()
{
string messageReceivedFromDevice;
while (true)
{
try
{
var buffersize = m_DeviceClientSocket.ReceiveBufferSize;
byte[] instream = new byte[buffersize];
int status = m_DeviceServerStream.Read(instream, 0, buffersize);
if (status == 0)
{
SetDeviceConnectionStatus(false);
}
messageReceivedFromDevice = System.Text.Encoding.ASCII.GetString(instream);
}
catch (Exception e)
{
//I ENETER HERE AND THE EXCEPTIONS SAYS: ""Cannot access a disposed object.\r\nObject name: 'System.Net.Sockets.NetworkStream'"
}
}
}
//Thread Safety is needed to set the device connection status
public void SetDeviceConnectionStatus(bool status)
{
lock (m_IsConnectedToDevice_Locker)
{
m_IsConnectedToDevice = status;
}
}
}
I'm trying to use SqlBulkCopy to import data into a temp table.
private bool CreateTempTable(IDbConnection conn, byte[] fileByteArray, string tempTableName)
{
try
{
Stream stream = new MemoryStream(fileByteArray);
using (var reader = new CsvReader(stream, false, System.Text.Encoding.UTF8))
{
// Bulk insert the data into a temporary table.
using (SqlBulkCopy bulkCopy = new SqlBulkCopy((SqlConnection)conn))
{
// Import the data into the temp table
bulkCopy.DestinationTableName = tempTableName;
bulkCopy.EnableStreaming = true;
bulkCopy.BatchSize = 20000;
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(reader);
}
}
}
catch (Exception ex)
{
Logger.Error(ex, $"CreateTempTable(): Exception while creating the TempTable \"{tempTableName}\" - {ex.Message}");
return false;
}
return true;
}
This method is called within another method that runs as async. The connection is passed and maintained by code that looks similar to this:
private async Task<bool> ConsumeAsyn(byte[] fileByteArray, string tempTableName)
{
using (var conn = (SqlConnection)OpenConnection())
{
if (CreateTempTable(conn, fileByteArray, tempTableName))
{
// success
}
else
{
// fail
}
}
}
This is basically how the ConsumeAsync is being called:
public async Task<bool> ProcessNextAsync2()
{
try
{
isIdle = false;
string filePath = ImportFilePickupPath + "\\" + Filename;
byte[] inStream = await LoadImportFileAsync(filePath);
bool consumeSuccess = await Consume(inStream, "##TempTable");
if (consumeSuccess)
{
// Delete the file
DeleteImportFile(filePath);
}
else
{
// Rescedule job
}
isIdle = true;
}
catch (Exception ex)
{
isIdle = true;
}
return isIdle;
}
If I use a small record set, of about a 100 rows in my csv, then everything works. The problem is if I have thousands of records, then the connection gets terminated during the bulk import process.
How can I pass the connection to the method and ensure that it remains open till the bulk import completes?
Maybe an answer, maybe not, but perhaps need to keep your IDisposables (at least/especially the SqlConnection) outside of the async tasks.
This answer over here makes it sound like .NET considers the IDiposables to be out of scope and so disposes them while you're still trying to use them:
SqlBulkCopy.WriteToServer() keep getting "connection is closed"
I were able to fix my problem by dropping support on a third party nuget lib that were dropping my connections. While it's unclear as to why it was happening, getting rid of all async calls and managing the connections myself seemed to have fixed my issue. Bulk imports was working fine however processing the data from the ##Temp table was slow. I decided to keep it all in memory and process it from there.
private bool Consume(byte[] fileByteArray, IDataProcess dataConsumer)
{
try
{
using (var conn = OpenConnection())
{
// Convert byte Array to a stream
Stream stream = new MemoryStream(fileByteArray);
// Create a reader from the stream
using (var reader = new CsvReader(stream, false, System.Text.Encoding.UTF8))
{
RecordEnumerator enumerator = reader.GetEnumerator();
enumerator.MoveNext();
do
{
// Proccess enumerator.Current with dataConsumer
} while (enumerator.MoveNext());
}
}
}
catch (Exception ex)
{
return false;
}
return true;
}
We run the risk of running out of memory but until we get a faster approach, this will have to do.
I have an issue with my application,
I have a TCPListener which listen let's say on port 14000
After the application is being closed I can see on the CMD that the listener is still listening.
At the second run of the application as expected I cant start the listener on the same port (14000) because it is already taken, I am changing the application port to 15000 on the second running, work wonderful and the listener is being CLOSED after the application is being shut down,
I assume that on the first run, the first listener on port 14000 stays open after the app is dead, on the second run the application closed/open the listener on port 15000 very well, why is this happen? I thought maybe it is about the port 14000 I've switched the orders of the opening ports (first opened 15000) and saw that the 15000 stays open and the 14000 (on the second run) closed and open correctly, Why at the first run the listener not being closed??
The code to my server:
class Server : IDisposable
{
private const int TIMER_PERIOD = 60 * 1000; // ms
private string servePort;
private string serverIP;
byte[] DataReceived = new byte[1024];
Action<string> MssageReceiveCallback;
private bool isListening = false;
static Timer serverTimer = null;
private TcpListener _Server;
private Dictionary<int, TcpClient> clientsList = new Dictionary<int, TcpClient>();
private bool serverListening = true;
private static int ClientInstance = 0;
public Server(string _serverIP, string _serverPORT, Action<string> messageReceiveCallback)
{
serverIP = _serverIP;
servePort = _serverPORT;
MssageReceiveCallback = messageReceiveCallback;
// InitilizeServer();
}
private void InitilizeServer()
{
_Server = new TcpListener(IPAddress.Parse(serverIP), int.Parse(servePort));
// if (serverTimer == null)
// serverTimer = new Timer(new TimerCallback(OnTimerCallback), null, TIMER_PERIOD, TIMER_PERIOD);
Task.Run(() =>
{
try
{
_Server.Start();
while (_Server != null)
{
TcpClient tcpClient;
try
{
tcpClient = _Server.AcceptTcpClient();
}
catch
{
continue;
}
Task.Run(() =>
{
ClientInstance++;
int currentinstance = ClientInstance;
clientsList.Add(currentinstance, tcpClient);
try
{
while (tcpClient.Connected && serverListening)
{
if (tcpClient.GetStream().DataAvailable)
{
int actualBufferlength = tcpClient.GetStream().Read(DataReceived, 0, DataReceived.Length);
byte[] data = new byte[actualBufferlength];
Buffer.BlockCopy(DataReceived, 0, data, 0, actualBufferlength);
string asciiMessage = Encoding.ASCII.GetString(data);
MssageReceiveCallback(asciiMessage);
}
else
{
Thread.Sleep(5);
}
}
}
catch (Exception ex)
{
}
finally
{
clientsList[currentinstance].Close();
clientsList.Remove(currentinstance);
}
});
}
}
catch (Exception ex)
{
}
});
}
public void StartServer()
{
InitilizeServer();
isListening = true;
}
public void SendMessage(string msg)
{
byte[] data = ASCIIEncoding.ASCII.GetBytes(msg);
foreach (TcpClient client in clientsList.Values)
{
client.GetStream().Write(data, 0, data.Length);
}
}
public void Dispose()
{
serverListening = false;
foreach (var item in clientsList.Values)
{
if (item.Connected)
item.Close();
}
_Server.Server.Close();
}
}
UPDATE:
I've check in TCPView to see which application the listener bind to and found this:
It looks like the listener available for un exist process
The biggest problem here, I think (I've pointed out other problems in the comments) is that TCP shutdown requires network communications and by default prevents socket reuse for a period of time.
The function you need to get to is Socket.SetSocketOption, specifically the ReuseAddress option. You should be able to get at it via the Server property on the TcpListener. Pay attention that it needs to be done before you actually start the listener listening.
You could try putting:
_Server.Server =null;
After close.
I wrote the simplified version of my program below. Process A launches a child process (Process B). I use an anonymous pipe to write information about the progress of a method running on process B. Meanwhile I have a function in process A that continually reads from a stream to see if there is a new update coming in from the pipe. If there is, the form on process A is updated to reflect the progress. This works as expected, however I am wondering if there is a better way to accomplish this without having to continually check the stream to see if there are any new updates to the progress.
/////////////////
///Process A ////
/////////////////
public void LaunchProcessB()
{
using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In,
HandleInheritability.Inheritable))
{
var _Process = new Process();
_Process.StartInfo.FileName = exeString;
_Process.StartInfo.Arguments = pipeServer.GetClientHandleAsString()
_Process.StartInfo.RedirectStandardOutput = true;
_Process.StartInfo.RedirectStandardInput = true;
_Process.StartInfo.CreateNoWindow = true;
_Process.StartInfo.UseShellExecute = false;
_Process.Start(); //launches process B
pipeServer.DisposeLocalCopyOfClientHandle();
using (StreamReader sr = new StreamReader(pipeServer))
{
try
{
while (true)
{
string temp = sr.ReadLine();
if (temp == null) break;
int result;
if (Int32.TryParse(temp, out result))
ShowDocumentProgress(result);
else ShowProgress(temp);
}
}
catch (Exception)
{
//error occured when reading from stream.
}
}
if (!_Process.Responding && !_Process.HasExited)
{
_Process.Kill();
return;
}
_Process.WaitForExit(10000);
}
}
private void ShowProgressPercent(int percentage)
{
if (percentage > currentPercentage)
{
progressBar.Value = percentage;
}
}
private void ShowProgress(string progressString)
{
labelMessage.Text = progressString;
}
/////////////////
///Process B ////
/////////////////
private StreamWriter _progressWriter;
private PipeStream _progressPipe;
static int Main(string[] args)
{
using (progressPipe = new AnonymousPipeClientStream(PipeDirection.Out, args[0]))
using (_progressWriter = new StreamWriter(_progressPipe))
{
RunLongProcess()
}
}
private void RunLongProcess()
{
//attaches events to PercentProgress and StageProgress methods.
}
private void PercentProgress(int percentage)
{
_progressWriter.WriteLine(percentage.ToString());
_progressPipe.WaitForPipeDrain();
}
private void StageProgress(string stage)
{
_progressWriter.WriteLine(stage);
_progressPipe.WaitForPipeDrain();
}
The while condition is not necessary. Simply read until temp is null. That's the end signal of the stream.
Make this a while(true) loop.
I think you also need to add exception handling to catch the process terminating and severing the pipe. !_Process.HasExited && pipeServer.IsConnected is not enough because it might be true but immediately switch to false after the test.
I also would add a WaitForExit at the end to make sure the system is quiesced before you continue.
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.