I'm kind of new to this ask-answer thing, please let me know if I've done any mistakes. I have this server program, running on my laptop. Server is a console application;
class Program
{
static void Main(string[] args)
{
Server sv = new Server("192.168.2.69", 52025);
sv.OnClientAccept += new ClientAcceptHandler(sv_OnClientAccept);
sv.OnClientMessage += new ClientMessageHandler(sv_OnClientMessage);
sv.Start();
}
static void sv_OnClientMessage(Server s, System.Net.Sockets.TcpClient client, string message)
{
Console.WriteLine("Message received from client " + GetClientIp(client) + ": \"" + message + "\"");
string msgToAll = message;
s.SendToAllClients(msgToAll);
Console.WriteLine("Message sent: \"" + message + "\" to the clients:");
foreach (TcpClient cl in s.Clients)
{
Console.WriteLine(GetClientIp(cl));
}
}
static void sv_OnClientAccept(Server s, System.Net.Sockets.TcpClient client)
{
Console.WriteLine("Client Accepted : " + GetClientIp(client));
}
static string GetClientIp(TcpClient Client)
{
return ((IPEndPoint)Client.Client.RemoteEndPoint).Address.ToString();
}
}
The Server class;
public delegate void ClientAcceptHandler(Server s, TcpClient client);
public delegate void ClientMessageHandler(Server s, TcpClient client, string message);
public class Server
{
private List<TcpClient> clients = new List<TcpClient>();
object lockObjc;
private TcpListener server;
private string ip;
private int port;
private Thread accepter, listener;
public List<TcpClient> Clients { get { return this.clients; } set { this.clients = value; } }
public event ClientAcceptHandler OnClientAccept;
public event ClientMessageHandler OnClientMessage;
public Server(string IP, int Port)
{
ip = IP;
port = Port;
}
private void ClientAccepted(TcpClient Client)
{
if (OnClientAccept != null)
{
OnClientAccept.Invoke(this, Client);
}
}
private void ClientMessaged(TcpClient Client, string Message)
{
if (OnClientMessage != null)
{
OnClientMessage.Invoke(this, Client, Message);
}
}
public void Start()
{
lockObjc = new object();
IPAddress ipAddress = IPAddress.Parse(ip);//127.0.0.1 -> local || "192.168.2.69" -> laptop
server = new TcpListener(ipAddress, port);//2014 -> local || 52025
server.Start();
accepter = new Thread(AcceptClients);
accepter.Start();
listener = new Thread(Listen);
listener.Start();
}
private void AcceptClients()
{
while (true)
{
TcpClient attachedCl = server.AcceptTcpClient();
if (attachedCl != null)
{
lock (lockObjc)
{
if (!clients.Contains(attachedCl))
{
clients.Add(attachedCl);
ClientAccepted(attachedCl);
}
}
}
}
}
private void Listen()
{
while (true)
{
for (int i = 0; i < clients.Count; i++)
{
TcpClient client = clients[i];
lock (lockObjc)
{
try
{
StreamReader clientIn = new StreamReader(client.GetStream());
string msg = clientIn.ReadLine();
if (msg != string.Empty)
{
ClientMessaged(client, msg);
}
}
catch
{
}
}
}
}
}
private bool send(TcpClient Client, string Msg)
{
bool b = true;
try
{
TcpClient client = Client;
StreamWriter clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
clientOut.WriteLine(Msg);
}
catch
{
b = false;
}
return b;
}
public bool SendToACLient(TcpClient Client, string Message)
{
return send(Client, Message);
}
public bool SendToAClient(int i, string Message)
{
return send(clients[i], Message);
}
public bool SendToAllClients(string Message)
{
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
b = b && send(clients[i], Message);
}
return b;
}
public bool SendToAllClientsExcept(TcpClient Client, string Message)
{
int x = clients.IndexOf(Client);
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
if (i != x)
{
b = b && send(clients[i], Message);
}
}
return b;
}
}
Since I'm really new to server-client relationships, I don't know if the server part is OK, but it seems OK to me programmatically (But I'm also amateur programer, no real education).
And the client part is;
public delegate void ServerMessageHandler(Client Receiver, string Message);
public class Client
{
private StreamReader clientIn;
private StreamWriter clientOut;
private TcpClient client;
private Thread listener;
private object lockObj;
public event ServerMessageHandler OnServerMessage;
public bool Connected { get { return (client != null && client.Connected); } }
public Client()
{
lockObj = new object();
client = new TcpClient();
listener = new Thread(Listen);
}
private void ServerMessaged(string Message)
{
if (OnServerMessage != null)
{
OnServerMessage.Invoke(this, Message);
}
}
private void Listen()
{
string serverMsg;
while (true)
{
try
{
serverMsg = clientIn.ReadLine();
if (serverMsg != string.Empty)
{
ServerMessaged(serverMsg);
}
}
catch
{
}
}
}
private void start()
{
listener.Start();
}
public bool Connect(string Ip, int Port)
{
client.Connect(Ip, Port);//"192.168.2.69", 52025
if (client.Connected)
{
clientIn = new StreamReader(client.GetStream());
clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
start();
}
return client.Connected;
}
public void Send(string Message)
{
if (client.Connected)
{
clientOut.WriteLine(Message);
}
}
}
Here's the form that I run Client class;
public partial class Form1 : Form
{
string s;
Client c;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
c = new Client();
c.OnServerMessage += new ServerMessageHandler(c_OnServerMessage);
bool b = c.Connect("192.168.2.69", 52025);
if (b)
{
s += "Connected to the server: 192.168.2.69:52025\r\n";
}
timer1.Start();
}
void c_OnServerMessage(Client Receiver, string Message)
{
s += "Server: " + Message + "\r\n";
}
private void button1_Click(object sender, EventArgs e)
{
c.Send(textBox1.Text);
}
private void timer1_Tick(object sender, EventArgs e)
{
textBox2.Text = s;
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
c.Send(textBox1.Text);
}
}
}
This form has two textboxes, first one is the one which takes user input (textBox1), the second one is the one which shows server responds. Why I'm not using Console? Because I've tried it in a way which I was waiting an input from user (Console.ReadLine) which as far as I know locks the console until user presses enter, even tough I'm using a thread for listening the server, I wasn't able to show the server answer on console.
So, I decided to create my own console (sort-of). The reason I run a timer to show messages is I get an error when I try to change the textbox text from a method that is being called by a thread (which is the c_OnServerMessage method, being called, indirectly, from the Listener thread from Client class)
But the problem I get here is this: I run the server on my laptop, I also run one client on my laptop which goes perfectly fine until I open up another client on another computer. At that point things go this way: I send a message from a client, the message reaches the server and is sent back. When I send another message, that message does not reach the server until I send a message from Client 2. And when I send a message from Client 2, the server gets the message from Client 2 even tough I sent the message from Client 1 first.
So basically what happens is, if I run 2 clients, I cannot send 2 messages in a row from a client, it kind of acts like a chess game where there is a turn for playing. I really don't understand the reason.
This problem is probably from a basic mistake but I had to write this whole message to be able to express myself. Thank you for your patient and your helps.
EDIT:
Problem solved thanks to this: TCP server with multiple Clients
My problem was the Listen method from Server class. The Listen method is being called by a thread, but still it runs a for loop in itself. Which if loop stops and waits for something, thread wouldn't make any difference. Thanks again, i think i will keep question, because i do not know what should happen to solved problems.
Related
I'm currently developing a server that deals with clients using a consumer/producer approach with threads and a blocking collection as shown below:
public class NetworkClient
{
private bool _started = false;
private int _clientId;
private readonly Socket _socket;
private static AutoResetEvent _lastMessageWasAckd = new AutoResetEvent(true);
private static BlockingCollection<byte[]> _messageQueue = new BlockingCollection<byte[]>();
public NetworkClient(Socket socket, int clientId)
{
this._socket = socket;
this._clientId = clientId;
}
public int getClientID() {
return _clientId;
}
public void SendMessage(string message)
{
Console.WriteLine("Adding to player's sending queue " + _clientId);
_messageQueue.Add(Encoding.ASCII.GetBytes(message));
}
public void Start()
{
Thread receiver = new Thread(new ThreadStart(ReceivingThreadProc));
Thread sender = new Thread(new ThreadStart(SendingThreadProc));
receiver.Start();
sender.Start();
this._started = true;
}
public void Stop()
{
this._started = false;
}
private void ReceivingThreadProc()
{
byte[] bytes = new byte[1024];
string data;
try
{
while (_started && _socket.Connected)
{
int numByte = this._socket.Receive(bytes);
data = Encoding.ASCII.GetString(bytes, 0, numByte);
if (numByte == 0)
{
break;
}
if (data == "ACK")
{
_lastMessageWasAckd.Set();
continue;
}
// Acknowledge the message
_socket.Send(Encoding.ASCII.GetBytes("ACK"));
ServerReceiver.onEvent(this._clientId, data);
}
}
catch (Exception e)
{
this._socket.Close();
}
}
private void SendingThreadProc()
{
while (_started && _socket.Connected)
{
_lastMessageWasAckd.WaitOne();
byte[] message = _messageQueue.Take();
Console.WriteLine("Sending the following message to client number: " + _clientId);
Console.WriteLine(System.Text.Encoding.ASCII.GetString(message));
_socket.Send(message);
_lastMessageWasAckd.Reset();
}
}
}
There will be an instance of NetworkClient created for every client that connects for the server. The issue is that sometimes a message is queued to be sent to client 1 (this is confirmed by the Console.Writeline in the SendMessage method) however that message is sent to client 0 (Shown by the console writeline in the SendingThreadProc method) instead. Is this due to a thread safety issue, or am I missing something entirely? This typically happens when two messages are sent right after one another.
Any help would be greatly appreciated.
EDIT:
As many people rightly pointed out I haven't added where I call SendMessage I'll put this class down below:
class NetworkServer
{
private int latestClient = 0;
private ServerReceiver _serverReceiver;
private static readonly Dictionary<int, NetworkClient> clients = new Dictionary<int, NetworkClient>();
public NetworkServer()
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 5656);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._serverReceiver = new ServerReceiver();
this._serverReceiver.start();
try
{
listener.Bind(endpoint);
listener.Listen(10);
while (true)
{
Socket clientSocket = listener.Accept();
this.OnClientJoin(clientSocket);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void SendClientMessage(int clientId, string package, CommandType commandType,
Dictionary<string, object> data = null)
{
if (data == null)
{
data = new Dictionary<string, object>();
}
SendClientMessageRaw(clientId, new NetworkCommand(clientId, package, commandType, data).ToJson());
}
public static void SendClientMessageRaw(int id, string message)
{
Console.WriteLine("Supposed to send to client number " + clients[id].getClientID());
clients[id].SendMessage(message);
}
private void OnClientJoin(Socket socket)
{
// Add client to array, perform handshake?
NetworkClient networkClient = new NetworkClient(socket, latestClient);
clients.Add(latestClient, networkClient);
Console.WriteLine("player added :" + latestClient);
networkClient.Start();
latestClient++;
if (latestClient == 2)
{
SendClientMessage(1, "Test", CommandType.Ping, null);
}
}
Could it be because your message queue is static and therefore shared between all NetworkClients? Meaning client A can pick up a message for client B?
Might be as easy as removing static from the properties.
I have been given the task to create a interface where I receive data through socket from the sender, for this purpose I am using NetMQ PushSocket for the sender side and then I receive the data at client side sung PullSocket and I have to update the UI (WPF app) when data is received so I receive data using poller in ReceiveReady event of the PullSocket when I do this in a seperate service class and call that class in UI ViewModel the UI thread hangs, so I use Poller.Run in a task, now the problem is that when I stop the poller and then restart it again it doesn't call the ReceiveReady event
Here is the ReceiverService for receiving the data.
public class ReceiverService
{
string msg;
string _address;
int _port;
PullSocket receiver;
NetMQPoller poller;
private MapViewModel ViewModel { get; set; }
public ReceiverService(MapViewModel mapViewModel, int port = 5555)
{
_address = GetComputerLanIP();
_port = port;
receiver = new PullSocket($"tcp://{_address}:{_port}");
receiver.Options.Linger = TimeSpan.Zero;
this.ViewModel = mapViewModel;
poller = new NetMQPoller { receiver };
receiver.ReceiveReady += receiver_ReceiveReady;
}
public void Start()
{
receiver.Connect($"tcp://{_address}:{_port}");
poller.Run();
}
public void Stop()
{
receiver.Disconnect($"tcp://{_address}:{_port}");
poller.Stop();
}
private void receiver_ReceiveReady(object sender, NetMQSocketEventArgs e)
{
// receive won't block as a message is ready
msg = e.Socket.ReceiveFrameString();
// send a response
if (!string.IsNullOrEmpty(msg))
{
try
{
//Updaing the ViewModel here
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
private string GetComputerLanIP()
{
string strHostName = Dns.GetHostName();
IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
foreach (var ipAddress in ipEntry.AddressList)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
{
return ipAddress.ToString();
}
}
return "";
}
private string GetValueFromMessage(string identifier)
{
msg.Replace("{", "");
msg.Replace("}", "");
identifier = /*" " + */identifier + " = ";
try
{
int index = msg.IndexOf(identifier) + identifier.Length;
if (index != -1)
{
int index2 = msg.IndexOf(";", index);
if (index2 == -1)
{
index2 = msg.Length;
}
return msg.Substring(index, index2 - index);
}
}
catch (IndexOutOfRangeException ex)
{
return null;
}
return null;
}
}
and in my ViewModel I have set commands for these
private void StartReceiver()
{
Task.Run(() => ReceiverService.Start());
}
private void StopReceiver()
{
Task.Run(() => ReceiverService.Stop());
}
What am I doing wrong? I am new to NetMQ and WPF. TIA
at first it would be good to make a task inside ReceiverService, kind of an ActorModel, because in the end if You would like to reuse it anywhere You need to remember that You should creat a Task first.
always it would be good to have socket in using statement, because You should always close socket if You are not using it
public async Task StartAsync() {
await Task.Run(() => ThreadBody())
}
public void Stop()
{
_poller.Stop();
}
private void ThreadBody()
{
using (PullSocket receiverSocket = new PullSocket())
using (_poller = new NetMQPoller())
{
receiverSocket.Connect($"tcp://{_address}:{_port}");
receiverSocket.ReceiveReady += receiver_ReceiveReady;
_poller.Add(receiverSocket);
_poller.Run();
}
}
I know, the title might be confusing, but I can't really express it better in short.
Basically, I'm writing a TCP Server. I don't have a Windows Form to show, the only thing the user sees is a TrayIcon.
My TCP Server class creates a thread for listening for clients, and then additional thread for every client handling communication. When all communication is done, I want to call a method on the main thread.
I've done it by firing a event from the client communication thread which gets handled on the main thread, and all worked fine until I wanted to add desktop notifications to my application. I've build a notification using WPF (iControlNotification) and wanted to show it in the event handler I mentioned before, but I'm getting a error message saying something like "The calling thread has to be a STA Thread".
Here's some code (I removed unnecessary party):
static class Program {
[...]
[STAThread]
static void Main() {
Log("iControlServerApplication started.");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
trayIcon = new TrayIcon();
trayIcon.Display();
NotificationManager = new iControlNotificationManager();
server = new TCPServer();
server.CommandReceived += new TCPServer.CommandReceivedEventHandler(tcpServer_CommandReceived);
if (server.Start()) {
NotificationManager.ShowNotfication("iControl Server Application", "Server started. " + plugins.Count + " plugins loaded.");
Application.Run();
} else {
MessageBox.Show("Port " + server.Port + " is already in use. Server could not be started.", ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
[...]
static void tcpServer_CommandReceived(object source, TCPServer.CommandReceivedEventArgs e) {
string toolTipText = "[" + e.Client.IPAddress + "] >> " + e.Command;
NotificationManager.ShowNotfication("iControl Server Application", toolTipText);
foreach (IiControlPlugin plugin in plugins) {
plugin.Handle(e.SplittedCommands, e.Client);
}
}
[...]
}
-
class TCPServer {
public delegate void CommandReceivedEventHandler(object source, CommandReceivedEventArgs e);
public event CommandReceivedEventHandler CommandReceived;
public class CommandReceivedEventArgs : EventArgs {
private string _command;
private string[] _splittedCommands;
private iControlClient _client;
public CommandReceivedEventArgs(string command, iControlClient client) {
_command = command;
_splittedCommands = command.Split(new Char[]{' '});
_client = client;
}
public string Command { get { return _command; } }
public string[] SplittedCommands { get { return _splittedCommands; } }
public iControlClient Client { get { return _client; } }
}
public TCPServer() {
this.tcpListener = new TcpListener(IPAddress.Any, Port);
this.icClients = new Dictionary<String, iControlClient>();
}
public Boolean Start() {
if (PortIsAvailable(Port)) {
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
Program.Log("ListeningThread started.");
return true;
} else {
return false;
}
}
private void ListenForClients() {
this.tcpListener.Start();
TcpClient client;
while (this.keepListening) {
try {
client = this.tcpListener.AcceptTcpClient();
} catch {
break;
}
iControlClient icClient = new iControlClient(client);
icClient.Thread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
icClient.Thread.Start(icClient);
}
Program.Log("Stop listening.");
}
private void HandleClientCommunication(object client) {
iControlClient icClient = (iControlClient)client;
NetworkStream clientStream = icClient.TCP.GetStream();
clientStream.ReadTimeout = 10;
int bufflen = 4096;
byte[] message = new byte[bufflen];
int bytesRead;
while (this.keepReceiving && icClient.keepConnected) {
bytesRead = 0;
try {
bytesRead = clientStream.Read(message, 0, bufflen);
} catch {
break;
}
if (bytesRead == 0) {
break;
}
ProcessReceivedData(icClient, ParseData(message, bytesRead));
}
Program.Log("[" + icClient.IPAddress + "] Connection closed.");
icClient.TCP.Close();
this.icClients.Remove(icClient.IPAddress);
}
private void ProcessReceivedData(iControlClient icClient, String[] commands) {
Program.Log("[" + icClient.IPAddress + "] >> " + String.Join(" ", commands));
if (this.CommandReceived != null) {
CommandReceived(this, new CommandReceivedEventArgs(String.Join(" ", commands), icClient));
}
NetworkStream clientStream = icClient.TCP.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("::ok");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
icClient.keepConnected = false;
}
}
-
public class iControlNotificationManager {
private iControlNotifications _notifications;
public void ShowNotfication(string caption, string message) {
if ((Boolean)Program.GetSetting("notifications", true) == false) return;
Dispatcher.CurrentDispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
() => {
iControlNotification noti = new iControlNotification(caption, message);
noti.Show();
}));
}
}
-
public class iControlNotification : Window {
private iControlNotificationModel _notification;
public iControlNotification(string caption, string message) { // Here's the error
InitializeComponent();
_notification = new iControlNotificationModel() {
Caption = caption,
Message = message
};
this.DataContext = _notification;
}
}
So how should I call tcpServer_CommandReceived so that the Notification Window can be shown the right way?
I'm really stuck here, I really appreciate any help on this!
//How to call a method from another thread :
a) You can invoke it in other thread by passing SynchronizationContext object to it:
void Method(object s)
{
SynchronizationContext sync = s as SynchronizationContext;
sync.Post(delegate { // what to do in other thread}, null);
}
Then in code you run this method in new task, passing your sync context as object (for example):
Task t = Task.Factory.StartNew(Method, SynchronizationContext.Current);
b) You can create extension method for this purpose (here is example that i used in win forms application to update UI):
public static class ControlExtensions
{
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
public static void UIThread(this Control #this, Action code)
{
if (#this.InvokeRequired)
{
#this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
Im trying to forward an event OnClientMessage from my class Client over the class Server to outside my libary.
Client.cs
public class Client
{
private TcpClient tcpClient;
private StreamWriter writer;
private Boolean alive = true;
private int id;
public delegate void OnClientMessageHandler(Client sender, String message);
public delegate void OnClientDisconnectHandler(Client sender);
public event OnClientMessageHandler OnClientMessage;
public event OnClientDisconnectHandler OnClientDisconnect;
public Client(TcpClient tcpClient, int id)
{
this.tcpClient = tcpClient;
this.id = id;
writer = new StreamWriter(tcpClient.GetStream());
new Thread(() =>
{
Listen(new StreamReader(tcpClient.GetStream()));
}).Start();
}
void Listen(StreamReader reader)
{
while (tcpClient.GetStream().DataAvailable && alive)
{
OnClientMessage(this, reader.ReadLine());
Thread.Sleep(150);
}
}
public void Write(String message)
{
writer.WriteLine(message);
writer.Flush();
}
public int GetID()
{
return id;
}
public void Close()
{
alive = false;
writer.Close();
tcpClient.Close();
OnClientDisconnect(this);
}
}
Server.cs
public class Server
{
private IPAddress serverIP;
private short serverPort;
private TcpListener serverListener;
private int serverClientCount;
public List<Client> serverClients = new List<Client>();
private Boolean running;
public delegate void OnClientMessageHandler(Client sender, String message);
public delegate void OnClientDisconnectHandler(Client sender);
public event OnClientMessageHandler OnClientMessage;
public event OnClientDisconnectHandler OnClientDisconnect;
public Server(IPAddress ip, short port, Boolean autoStart = true)
{
this.serverIP = ip;
this.serverPort = port;
if(autoStart)
OpenServer();
}
public void OpenServer()
{
serverListener = new TcpListener(serverIP, serverPort);
serverListener.Start();
running = true;
while (running)
{
if (serverListener.Pending())
{
TcpClient tcpClient = serverListener.AcceptTcpClient();
new Thread(() =>
{
Client client;
client = new Client(tcpClient, serverClientCount);
client.OnClientMessage += new Client.OnClientMessageHandler(OnClientMessage);
client.OnClientDisconnect += new Client.OnClientDisconnectHandler(OnClientDisconnect);
serverClients.Add(client);
serverClientCount++;
}).Start();
}
else
{
Thread.Sleep(150);
}
}
}
public void WriteToClient(Client client, String message)
{
client.Write(message);
}
public void WriteToAll(String message)
{
serverClients.ForEach(client => client.Write(message));
}
public void Shutdown()
{
running = false;
serverClients.ForEach(client => client.Close());
serverListener.Stop();
}
}
Now when the event is firing the application crashes with Delegate to an instance method cannot have null 'this'.
Are I'm doing something wrong or isn't this the right way to forward an event?
This is pretty unique, never once seen anybody do this. It is a regression in the .NET Framework, 3.5 gives you a much better exception. Basic problem is that you made the event subscribe itself. A simple version to repro that crash:
using System;
class Program {
public static event Action Kaboom;
static void Main(string[] args) {
Kaboom += new Action(Kaboom); // 3.5 raises an exception here
var handler = Kaboom;
if (handler != null) handler(); // kaboom
}
}
You are not actually "forwarding" the event. Untangle your names and code. Add, say, a Fire() method.
I have got a windows forms project than copying files and folders to clients in my domain. When copying file or copying directory process to [x]clients in my domain. I want to send it a Messagebox that says "There is a new folder or file in your [xdirectory]".
I can't do it by Messenger service because of Messenger service is does not working in XP Sp2 so I need another way for this. Maybe a client/server side application could be make. There will be a listener app in client then I will send it a messagebox.show code then it will show us a messagebox. etc.
I did something similar once before. I got most of this code from somewhere else, but I cannot remember from where.
First the Server Code:
public class HSTcpServer
{
private TcpListener m_listener;
private IPAddress m_address = IPAddress.Any;
private int m_port;
private bool m_listening;
private object m_syncRoot = new object();
public event EventHandler<TcpMessageReceivedEventArgs> MessageReceived;
public HSTcpServer(int port)
{
m_port = port;
}
public IPAddress Address
{
get { return m_address; }
}
public int Port
{
get { return m_port; }
}
public bool Listening
{
get { return m_listening; }
}
public void Listen()
{
try
{
lock (m_syncRoot)
{
m_listener = new TcpListener(m_address, m_port);
// fire up the server
m_listener.Start();
// set listening bit
m_listening = true;
}
// Enter the listening loop.
do
{
Trace.Write("Looking for someone to talk to... ");
// Wait for connection
TcpClient newClient = m_listener.AcceptTcpClient();
//Trace.WriteLine("Connected to new client");
// queue a request to take care of the client
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessClient), newClient);
}
while (m_listening);
}
catch (SocketException se)
{
Trace.WriteLine("SocketException: " + se.ToString());
}
finally
{
// shut it down
StopListening();
}
}
public void StopListening()
{
if (m_listening)
{
lock (m_syncRoot)
{
// set listening bit
m_listening = false;
// shut it down
m_listener.Stop();
}
}
}
private void sendMessage(string message)
{
// Copy to a temporary variable to be thread-safe.
EventHandler<TcpMessageReceivedEventArgs> messageReceived = MessageReceived;
if (messageReceived != null)
messageReceived(this, new TcpMessageReceivedEventArgs(message));
}
private void ProcessClient(object client)
{
TcpClient newClient = (TcpClient)client;
try
{
// Buffer for reading data
byte[] bytes = new byte[1024];
StringBuilder clientData = new StringBuilder();
// get the stream to talk to the client over
using (NetworkStream ns = newClient.GetStream())
{
// set initial read timeout to 1 minute to allow for connection
ns.ReadTimeout = 60000;
// Loop to receive all the data sent by the client.
int bytesRead = 0;
do
{
// read the data
try
{
bytesRead = ns.Read(bytes, 0, bytes.Length);
if (bytesRead > 0)
{
// Translate data bytes to an ASCII string and append
clientData.Append(Encoding.ASCII.GetString(bytes, 0, bytesRead));
// decrease read timeout to 1 second now that data is
// coming in
ns.ReadTimeout = 1000;
}
}
catch (IOException ioe)
{
// read timed out, all data has been retrieved
Trace.WriteLine("Read timed out: {0}", ioe.ToString());
bytesRead = 0;
}
}
while (bytesRead > 0);
bytes = Encoding.ASCII.GetBytes("clowns");
// Send back a response.
ns.Write(bytes, 0, bytes.Length);
sendMessage(clientData.ToString());
}
}
finally
{
// stop talking to client
if (newClient != null)
newClient.Close();
}
}
}
public class TcpMessageReceivedEventArgs : EventArgs
{
private string m_message;
public TcpMessageReceivedEventArgs(string message)
{
m_message = message;
}
public string Message
{
get
{
return m_message;
}
}
}
The Client Code:
class HSTcpClient
{
private TcpClient _client;
private IPAddress _address;
private int _port;
private IPEndPoint _endPoint;
private bool _disposed;
public HSTcpClient(IPAddress address, int port)
{
_address = address;
_port = port;
_endPoint = new IPEndPoint(_address, _port);
}
public void SendForwardedClientMessage(int senderId, int receiverId, int hsId)
{
SendMessage(senderId.ToString() + ":" + receiverId.ToString() + ":" + hsId.ToString());
}
public void SendUpdatedCGBMessage()
{
SendMessage("Update your CGB you clowns");
}
public void SendMessage(string msg)
{
try
{
_client = new TcpClient();
_client.Connect(_endPoint);
// Get the bytes to send for the message
byte[] bytes = Encoding.ASCII.GetBytes(msg);
// Get the stream to talk to the server on
using (NetworkStream ns = _client.GetStream())
{
// Send message
Trace.WriteLine("Sending message to server: " + msg);
ns.Write(bytes, 0, bytes.Length);
// Get the response
// Buffer to store the response bytes
bytes = new byte[1024];
// Display the response
int bytesRead = ns.Read(bytes, 0, bytes.Length);
string serverResponse = Encoding.ASCII.GetString(bytes, 0, bytesRead);
Trace.WriteLine("Server said: " + serverResponse);
}
}
catch (SocketException se)
{
Trace.WriteLine("There was an error talking to the server: " +
se.ToString());
}
finally
{
Dispose();
}
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_client != null)
_client.Close();
}
_disposed = true;
}
}
#endregion
}
Then to use, create a server variable in your form code:
private HSTcpServer m_server;
and I created a background worker thread:
private System.ComponentModel.BackgroundWorker hsTcpServerThread;
handled the DoWork event:
private void hsTcpServerThread_DoWork(object sender, DoWorkEventArgs e)
{
m_server = new HSTcpServer(<pick your port>);
m_server.MessageReceived += new EventHandler<TcpMessageReceivedEventArgs>(m_server_MessageReceived);
m_server.Listen();
}
Then handle the message recieved event:
void m_server_MessageReceived(object sender, TcpMessageReceivedEventArgs e)
{
//<your code here> - e contains message details
}
Then to send a message to the server:
HSTcpClient client = new HSTcpClient(<ip address>, <port you picked>);
client.SendForwardedClientMessage(<message details>);
Hopefully I got everything in there.
You can use the FileSystemWatcher in the client. That way you do not have to deal with remoting or listening on ports.
If you really want to communicate between the two machines you can do using remoting, or via the TcpListener.