I have 2 applications: 1 dispatcher and second receiver.
I'm using Name pipe server and client to send to message from dispatcher to receiver
public partial class DispatcherForm : Form
{
public DispatcherForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
var pipe = new NamedPipeServerStream("DispatcherPipe", PipeDirection.InOut);
pipe.WaitForConnection();
Task.Run(async () =>
{
var buffer = Encoding.UTF8.GetBytes("Hello from dispacther");
await pipe.WriteAsync(buffer, 0, buffer.Length);
pipe.Dispose();
Application.Exit();
});
base.OnLoad(e);
}
}
public partial class ReceiverForm : Form
{
private NamedPipeClientStream m_pipe;
public ReceiverForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
startProcess();
base.OnLoad(e);
}
private void startProcess()
{
string processName = "DispatcherEventTester.exe";
var process = new Process();
process.StartInfo.FileName = processName;
process.Start();
m_pipe = new NamedPipeClientStream("DispatcherPipe");
startConnecting(new CancellationTokenSource().Token);
}
private Task startConnecting(CancellationToken token)
{
var buffer = new byte[8096];
return m_pipe.ConnectAsync(token)
.ContinueWith(async t =>
{
while(m_pipe.IsConnected)
{
if (t.IsCanceled)
{
m_pipe.Close();
break;
}
var ret = await m_pipe.ReadAsync(buffer, 0, buffer.Length);
this.Invoke(new Action(() =>
{
richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)+Environment.NewLine);
}));
m_pipe.Close();
break;
}
},token);
}
private void button1_Click(object sender, EventArgs e)
{
startProcess();
}
}
the application works but weird things happen sometimes.
The application throws System.IO.IOException: All pipe instances are busy.
if pressing on button1 few times
what is this error and how do I clear the pipe instances?
there were also few times I received in ReadAsync method 0 values
Related
I'm learning to code and I'm currently making a server and a client with two-way communication. Is there a way to make the received message appear on the left side of the textbox and the sent message on the right side of the textbox just like in a real chat service. Is there also a way to add the timestamp, when the message was received and when it was sent?
I will attach all the code that I have written and images of the client and server windows.
Server
Client
Server code:
namespace Full_Chatt_Server
{
public partial class Form1 : Form
{
TcpListener listener;
TcpClient klient;
int port;
public Form1()
{
InitializeComponent();
}
private void btnStartServer_Click(object sender, EventArgs e)
{
btnTaEmot.Enabled = false;
port = int.Parse(tbxPort.Text);
try
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartAccepting();
}
public async void StartAccepting()
{
try
{
klient = await listener.AcceptTcpClientAsync();
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartReading(klient);
}
public async void StartReading(TcpClient k)
{
byte[] buffer = new byte[1024];
int n = 0;
try
{
n = await k.GetStream().ReadAsync(buffer, 0, 1024);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
tbxMessage.AppendText(Encoding.Unicode.GetString(buffer, 0, n) + "\r\n");
StartReading(k);
}
private void btnSend_Click(object sender, EventArgs e)
{
string chatt = tbxChatt.Text;
StartSending(chatt);
tbxChatt.Clear();
tbxMessage.AppendText(chatt + "\r\n");
}
public async void StartSending(string message)
{
if (klient.Connected)
{
byte[] OutStream = Encoding.Unicode.GetBytes(message);
try
{
await klient.GetStream().WriteAsync(OutStream, 0, OutStream.Length);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
}
}
}
Client code:
namespace Full_Chatt_Klient
{
public partial class Form1 : Form
{
TcpClient klient = new TcpClient();
int port;
public Form1()
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)
{
if (!klient.Connected)
{
Connect();
}
}
public async void Connect()
{
IPAddress address = IPAddress.Parse(tbxIP.Text);
port = int.Parse(tbxPort.Text);
try
{
await klient.ConnectAsync(address, port);
StartReading(klient);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
btnSkicka.Enabled = true;
btnAnslut.Enabled = false;
}
private void btnSend_Click(object sender, EventArgs e)
{
string chatt = tbxChatt.Text;
StartSending(chatt);
tbxChatt.Clear();
tbxMessage.AppendText(chatt + "\r\n");
}
public async void StartSending(string message)
{
if (klient.Connected)
{
byte[] OutStream = Encoding.Unicode.GetBytes(message);
try
{
await klient.GetStream().WriteAsync(OutStream, 0, OutStream.Length);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
}
}
public async void StartReading(TcpClient k)
{
byte[] buffer = new byte[1024];
int n = 0;
try
{
n = await k.GetStream().ReadAsync(buffer, 0, 1024);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
tbxMessage.AppendText(Encoding.Unicode.GetString(buffer, 0, n) + "\r\n");
StartReading(k);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (klient != null)
{
klient.Close();
}
}
}
}
I'm writing an android app in c#, which communicates with a server.
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.button1);
TextView txt = FindViewById<TextView>(Resource.Id.textView1);
Client client = new Client();
client.Setup("ws://192.168.0.14:8001", "basic", WebSocketVersion.Rfc6455);
client.Start();
...
On start up, it should display a message on the TextView.
class Client : Activity{
private WebSocket websocketClient;
...
public void Setup(string url, string protocol, WebSocketVersion version)
{
...
websocketClient.Opened += new EventHandler(websocketClient_Opened);
}
private void websocketClient_Opened(object sender, EventArgs e){
txt.Text = ("Client successfully connected."); // this line is wrong
websocketClient.Send("Hello World!");
}
}
The problem is, I have no idea, how to access the TextView. I found this, but I don't know how should I use it in my case.
I don't know what library WebSocket you a using. I using websocket-sharp. It is example use:
protected override void OnCreate(Bundle bundle)
{
TextView txt = FindViewById<TextView>(Resource.Id.My);
using (var ws = new WebSocket("ws://dragonsnest.far/Laputa"))
{
ws.OnError += (sender, e) =>
{
txt.Text = e.Message;
};
..........
}
It is work. I see error message in my TextView.
If you get error, try use RunOnUiThread.Example:
private void websocketClient_Opened(object sender, EventArgs e)
{
this.RunOnUiThread(() =>
{
txt.Text = "your message";
});
}
Hope this help.
Just make WebsocketClient a property it a instead of a class variable and then you can access it from you activity.
public class MainActivity : Activity
{
private TextView txt;
private Client client;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
txt = FindViewById<TextView>(Resource.Id.textView1);
client = new Client();
client.WebsocketClient.Opened += websocketClient_Opened;
client.Setup("ws://192.168.0.14:8001", "basic", WebSocketVersion.Rfc6455);
client.Start();
}
protected override void OnDestroy()
{
client.WebsocketClient.Opened -= websocketClient_Opened;
base.OnDestroy();
}
private void websocketClient_Opened(object sender, EventArgs e)
{
txt.Text = ("Client successfully connected.");
// maybe have to be wrapped in a RunOnUiThread(() =>{ ... });
}
}
class Client
{
public WebSocket WebsocketClient { get; set; }
public void Setup(string url, string protocol, WebSocketVersion version)
{
// WebsocketClient = new ...
WebsocketClient.Opened += websocketClient_Opened;
}
private void websocketClient_Opened(object sender, EventArgs e)
{
WebsocketClient.Send("Hello World!");
}
}
Everything is going fine with connection , except when i close the connection and reopen (everything fine till now , data is received fine).
The error pops up when I try to write in the stream :
Cannot access a disposed object: 'System.Net.Sockets.NetworkStream' !!
I have tried using a new instance of client each time I connect
When closing connection : i have tried all these things like _client.GetStream().Close();
_client.Close();
but everything fail
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myform = this;
}
public static Form1 myform;
Client c1;
public void ConnectButton_Click(object sender, EventArgs e)
{
c1 = new Client();
try
{ c1.Connect(IPADRESStext.Text, PORTNUMBERtext.Text); }
catch (Exception ex)
{ MessageBox.Show(ex.ToString()); }
}
private void CloseButton_Click(object sender, EventArgs e)
{
c1.Disconnect();
}
}
public sealed partial class Client
{
public void SendData(byte[] data)
{ _sender.SendData(data); }
public event EventHandler<DataReceivedEventArgs> DataReceived;
public void Connect(string IPADRESStxt, string PORTNUMBERtxt)
{
sq = new sequence();
_client = new TcpClient(IPADRESStxt, Int32.Parse(PORTNUMBERtxt));
_stream = _client.GetStream();
_sender = new Sender(_stream);
_receiver = new Receiver(_stream);
_receiver.DataReceived += OnDataReceived;
}
public void Disconnect()
{
_stream.Close();
_client.Close();
//_client.Client.Disconnect(false);
//tcpClient.GetStream().Close();
//tcpClient.Close();
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
public sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
_stream.Write(data, 0, data.Length); /// 2 When trying to execute this instruction
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// Code Code Code
SendData(Sframe); /// 1 Error pops up here
}
private NetworkStream _stream;
private Thread _thread;
}
}
onrecvdChanged is an event (of Server Class) once occured I want it to change the text of label1 of the form1 class. I've been stuck here for a long time. I tried a few tricks but I get a cross thread exception.
namespace TCPServerTutorial
{
public partial class Form1 : Form
{
Server a;
public Form1()
{
InitializeComponent();
label1.Text = "Ready";
a=new Server(this);
}
private void Start_btn_Click(object sender, EventArgs e)
{
a.StartTcpServer();
label1.Text = "Listening...";
}
private void Stop_Btn_Click(object sender, EventArgs e)
{
a.StopListenForClients();
label1.Text = "Stopped...";
}
}
class Server
{
public event EventHandler recvdChanged;
private TcpListener tcpListener;
private Thread listenThread;
private string recvd;
Form1 _f1parent;
public Server(Form1 par)
{
_f1parent = par;
}
public string getsetrecvd
{
get { return this.recvd; }
set
{
this.recvd = value;
if (this.recvdChanged != null)
this.recvdChanged(this, new EventArgs());
}
}
public void StartTcpServer()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
if(client.Connected)
{
MessageBox.Show(client.Client.RemoteEndPoint + " Has Connected.");
}
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
public void StopListenForClients()
{
tcpListener.Stop();
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
recvdChanged += new EventHandler(onrecvdChanged);
byte[] message = new byte[4096];
int bytesRead;
Form1 p = new Form1();
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
getsetrecvd=encoder.GetString(message, 0, bytesRead);
if (recvd != "e")
{
}
else
{
break;
}
}
tcpClient.Close();
}
void onrecvdChanged(object sender, EventArgs e)
{
MessageBox.Show("event: " + recvd);
}
}
}
You already have an event that is fired when the string is changed, recvdChanged. Just have the form add an event handler to that event and then invoke to the UI thread:
public Form1()
{
InitializeComponent();
label1.Text = "Ready";
a=new Server(this);
a.recvdChanged += (_,args) => Invoke(new MethodInvoker(
()=>label1.Text = a.getsetrecvd));
}
There is no need for the event handler for that event inside of the Server class itself.
A cross thread exception is usually fixed by the use of Invoke.
I find the simplest way is to use a MethodInvoker cast and a Lambda expression...something like:
Invoke((MethodInvoker)( () => Form1.Label1.Text = "some string" ) );
I want to implement this function: when receive a http request, then create a new window form, and waiting for user inputing response text and write to the http response stream. The quesition is, I can not write response text to the stream in thread even I useing the Action<> delegate. Some code like this:
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//startup web server
Dispatcher.BeginInvoke(new Action(Start));
}
private void Start()
{
var server = new HttpServer();
try
{
server.EndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 80);
server.Start();
server.RequestReceived += DataProcess;
}
catch (Exception ex)
{
return;
}
}
private void DataProcess(object sender, HttpRequestEventArgs e)
{
//create a new window in which user can input the response for the http request e.
var pw = (PrivateWindow)Dispatcher.Invoke(new Func<HttpRequestEventArgs, PrivateWindow>(CreatePrivateWindow), e);
}
public PrivateWindow CreatePrivateWindow(string windowKey, HttpRequestEventArgs e)
{
var pw = new PrivateWindow();
pw.httpRequest = e;//pass the stream to thread here.
windows.Add(pw);
return pw;
}
}
public partial class PrivateWindow : Window
{
private void btnSendMessage_Click(object sender, RoutedEventArgs e)
{
string messageText = new TextRange(txtWriteMessage.Document.ContentStart, txtWriteMessage.Document.ContentEnd).Text.Trim();
//write the response in thread
Dispatcher.BeginInvoke(new Action<HttpRequestEventArgs, string>(WriteToStream), httpRequest, messageText);
}
private void WriteToStream(HttpRequestEventArgs e, string str)
{
//**here occurs "stream can not be written" error.**
using (var writer = new StreamWriter(e.Response.OutputStream))
{
writer.Write(str);
}
}
}