I have a simple application which sends and receives data.
ZSocketExample client = new ZSocketExample("127.0.0.1:5555");
client.send("test");
This is my client class:
public class ZSocketExample:IDisposable
{
public delegate void ReceiveEventHandler(object sender, SocketEventArgs e);
public event ReceiveEventHandler ReceiveEvent;
private ZmqContext zmqContext;
private ZmqSocket zmqSocket;
private string host;
private bool isRunning;
private bool disposed = false;
public ZSocketExample(string host)
{
try
{
zmqContext = ZmqContext.Create();
zmqSocket = zmqContext.CreateSocket(SocketType.DEALER);
ZHelpers.SetID(zmqSocket, Encoding.UTF8);
zmqSocket.Connect(host);
this.isRunning = true;
zmqSocket.ReceiveReady += new EventHandler<SocketEventArgs>(zmqSocket_ReceiveReady);
zmqSocket.SendReady += new EventHandler<SocketEventArgs>(zmqSocket_SendReady);
Poller poller = new Poller(new List<ZmqSocket> { zmqSocket });
while (isRunning)
{
poller.Poll(TimeSpan.FromSeconds(5));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
void zmqSocket_ReceiveReady(object sender, SocketEventArgs e)
{
Console.WriteLine("Receive Ready");
}
void zmqSocket_SendReady(object sender, SocketEventArgs e)
{
Console.WriteLine("Send Ready");
}
public void send(string msg)
{
zmqSocket.Send(msg, Encoding.UTF8);
if (ReceiveEvent != null)
ReceiveEvent(this, null);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
close();
}
disposed = true;
}
public void close()
{
isRunning = false;
zmqSocket.Linger = TimeSpan.FromSeconds(1);
zmqSocket.Close();
zmqContext.Terminate();
}
}
But somehow it doesnot send or receive. Can someone tell me what do I do wrong? And this example blocks the main application. how can I make it non blocking?
ZeroMQ socket is not thread safe, you can't use it from multiple threads without using some kind of synchronization.
In your example you call the close which set a variable and then immediately close the socket, this is wrong, you should close the socket when you are out of the while loop.
Regarding receive/send ready, you rarely need to register for send ready, send ready will let you know when you can send a message, in the dealer socket if you are connected you always will be ready to send (unless the highwater has reached).
Receive Ready will be invoked when there is message ready to be received, if other side send you a message the receive ready will be invoked.
For the last part, blocking, you need a dedicate thread to handle zeromq sockets, you can have one thread that handle multiple sockets using the poller.
Related
I have this example as a server.
The question that only works well for me on console.
I want to pass it to windows Form. And I don't know how to apply it.
Because I understand that it is bad practice from another class such as creating a Form1 Method and using a Form1 object in the Server class.
As if in the Server class I call the textbox or things like that.
The question that I think I would have to adapt all the code back for windows Form?
Or stop using the classes and use the typical TcpClient, TpcListener as in the videos that declare it at the moment in Form1.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Chatroom
{
delegate void MessageEventHandler(object sender, MessageEventArgs e);
class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
this.Message = message;
}
}
class Server
{
private TcpListener serverSocket;
private List<Worker> workers = new List<Worker>();
public Server(int port)
{
//serverSocket = new TcpListener(port);// deprecated
// the same way
serverSocket = new TcpListener(IPAddress.Any, port);
serverSocket.Start();
}
private void WaitForConnection()
{
while (true)
{
TcpClient socket = serverSocket.AcceptTcpClient();
Worker worker = new Worker(socket);
AddWorker(worker);
worker.Start();
}
}
private void Worker_MessageReceived(object sender, MessageEventArgs e)
{
BroadcastMessage(sender as Worker, e.Message);
}
private void Worker_Disconnected(object sender, EventArgs e)
{
RemoveWorker(sender as Worker);
}
private void AddWorker(Worker worker)
{
lock (this)
{
workers.Add(worker);
worker.Disconnected += Worker_Disconnected;
worker.MessageReceived += Worker_MessageReceived;
}
}
private void RemoveWorker(Worker worker)
{
lock (this)
{
worker.Disconnected -= Worker_Disconnected;
worker.MessageReceived -= Worker_MessageReceived;
workers.Remove(worker);
worker.Close();
}
}
private void BroadcastMessage(Worker from, String message)
{
lock (this)
{
message = string.Format("{0}: {1}", from.Username, message);
for (int i = 0; i < workers.Count; i++)
{
Worker worker = workers[i];
if (!worker.Equals(from))
{
try
{
worker.Send(message);
}
catch (Exception)
{
workers.RemoveAt(i--);
worker.Close();
}
}
}
}
}
class Worker
{
public event MessageEventHandler MessageReceived;
public event EventHandler Disconnected;
private readonly TcpClient socket;
private readonly Stream stream;
public string Username { get; private set; } = null;
public Worker(TcpClient socket)
{
this.socket = socket;
this.stream = socket.GetStream();
}
public void Send(string message)
{
byte[] buffer = Encoding.UTF8.GetBytes(message);
stream.Write(buffer, 0, buffer.Length);
}
public void Start()
{
new Thread(Run).Start();
}
private void Run()
{
byte[] buffer = new byte[2018];
try
{
while (true)
{
int receivedBytes = stream.Read(buffer, 0, buffer.Length);
if (receivedBytes < 1)
break;
string message = Encoding.UTF8.GetString(buffer, 0, receivedBytes);
if (Username == null)
Username = message;
else
MessageReceived?.Invoke(this, new MessageEventArgs(message));
}
}
catch (IOException) { }
catch (ObjectDisposedException) { }
Disconnected?.Invoke(this, EventArgs.Empty);
}
public void Close()
{
socket.Close();
}
}
static void Main(string[] args)
{
try
{
Server server = new Server(3393);
server.WaitForConnection();
}
catch (IOException) { }
}
}
}
The problem is this. If I have Form1.
As I relate it, as I do eg. Every time a new Client is created it is added by a ListBox from the Server class. In theory you can't or if you can or is it bad practice?
Class Server{
private void RemoveWorker(Worker worker)
{
lock (this)
{
**textbox.text +="Cliente desconectado";**
worker.Disconnected -= Worker_Disconnected;
worker.MessageReceived -= Worker_MessageReceived;
workers.Remove(worker);
worker.Close();
}
}
}
How could it be done without being in the main WinForm class?
Here are steps to help you start.
Create a new WinForms project in VisualStudio.
You project should build and show the form right away without you having to do anything.
You should have Program.cs that contains the Main() method. You do not need to change it. This is what causes the Form1 to load and display.
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
You can right-click on the Form1.cs and select View Code to see the code behind page.
There you will have the constructor that has InitializeComponent() method that creates all of your GUI "stuff".
Add a listener to run when the Form loads. This is where you can add your server stuff.
Open your GUI designer, go to Form1->Properties and add a new function to the Load
This is where you will write your code. For example, you can create and start the server.
private void Form1_Load(object sender, EventArgs e)
{
try
{
Server server = new Server(3393);
server.WaitForConnection();
}
catch (IOException) { // Put something here like a log }
}
Your server can go to a new Class that can be in a new file like Server.cs. Just make sure that WaitForConnection() is public.
This should get you started. When you run into an issue, just create a new question on SO and make sure to add your latest code.
Some suggestions:
Use a delegate to communicate between Server and the GUI
You may want to run the Server in another thread. Test it first to get it working and see if this is what you need/want
You don't normally want to run a server as WinForms project. If you accidently close the form, you kill your server.
Make sure to have a Form1_Close event and shut down your server there correctly
I have three class, Main, UserSerial, Communication
In Main
Communication Comm;
Thread CoTH;
UserSerial Serial;
private void btnStart_Click(object sender, EventArgs e)
{
CoTH = new Thread(() =>
{
commJob();
});
CoTH.Start();
}
private void commJob()
{
Serial.Setting();
Serial.Open();
Comm = new Communication(Serial);
Comm.StartConnection();
}
In Communication
UserSerial Serial;
public Communication(UserSerial Serial)
{
this.Serial = Serial;
}
public void Read()
{
lock(Serial.Synchronous)
{
while(condition...)
{
Serial.Receive();
// ....
}
}
}
And UserSerial is not my code, so I don't know detail..
Anyway, When I want serial communication force terminate, I Use Thread.Abort() in Main.
private void btnStop_Click(object sender, EventArgs e)
{
try
{
if (Serial != null)
Serial.Close();
if (CoTH != null)
CoTH.Abort();
}
catch
{
}
}
But sometimes it occur 'Safe Handle been Closed', so program is abnormal termination.
How Can I communication force terminate without 'Safe Handle been Closed'?
It seems you should stop CoTH first and then Serial. Or you will brutally terminate CoTH since it's using Serial while not knowing it has been disposed.
In your class Communication. It's keep calling Serial.Receive().
public void Read()
{
lock(Serial.Synchronous)
{
while(condition...)
{
Serial.Receive();
// ....
}
}
}
However your Stop method is disposing resource Serial before closing the communication logic CoTH.
if (Serial != null)
Serial.Close();
if (CoTH != null)
CoTH.Abort();
You close Serial first. What if Communication.Read() wants to call Serial.Receive() after you closed it?
My suggestion:
Let Communication handle the resource, or a supervisor take care of their construction and destruction.
I am developing a Windows Phone 8.1 chat app and discovered multiple difficulties during programming a socket interoperability.
The main issue are 'events' on a socket, and main question is: How to subscribe to OnData event, e.g. how to detect the event, when data came from the server?
I tried to solve it by direct way: infinite reading from InputStream, and that works with 50/50 luck: sometimes that method freeze the UI stream (even the reading method is async).
I googled for that issue, because it's a very strange behavior for that important component, and didn't found any solutions for this even on MSDN. At SO I found only same solutions like mine, but they also freeze UI flow.
For reference, my app infrastructure is the main app that uses facade class from shared library, the facade class get a generic, that specify concrete behavior (this was done for reason of multiple data transports). For TCP transport, I wrote that:
public class TCPTransport : ITransportProvider
{
private bool _connected { get; set; }
private StreamSocket _socket { get; set; }
private DataReader _input { get; set; }
public TCPTransport()
{
_socket = new StreamSocket();
}
public async Task<bool> Connect(string host, int port)
{
try
{
await _socket.ConnectAsync(new HostName(host), port.ToString());
if (OnConnect != null)
OnConnect();
_connected = true;
_input = new DataReader(_socket.InputStream)
{
InputStreamOptions = InputStreamOptions.Partial
};
_read();
return _connected;
}
catch(Exception e)
{
Debug.WriteLine("[warn] cant conect to " + host + ":" + port + ". Additional: " + e.Message);
return false;
}
}
async private void _read()
{
while (true)
{
if (!_connected || _socket == null) break;
uint buffer = await _input.LoadAsync(2048);
string data = _input.ReadString(buffer);
if (OnData != null && data.Length != 0)
OnData(data);
}
}
public async Task<bool> Send(string data)
{
if (!_connected) return false;
try
{
await _socket.OutputStream.WriteAsync(Encoding.UTF8.GetBytes(data).AsBuffer());
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("[warn] Exception send: " + e.Message);
}
return true;
}
public bool Close()
{
if (!_connected) return false;
_socket.Dispose();
return true;
}
public Action OnConnect { get; set; }
public Action<string> OnData { get; set; }
public Action OnClose { get; set; }
}
I suppose that I am wrong about using that solution, but how can I listen to data from server?
For better or worse, the StreamSocket API is not designed as an event-driven API; it is designed as an asynchronous API. If you want to raise an event when data is available, use an event, not a delegate:
Here is a trivial example (hard-coded to www.microsoft.com and with no error handling) showing how to simulate the event:
Note that if you run with the debugger attached, it will temporarily freeze the UI thread. This doesn't occur when not debugging
// Create your own class to hold the data
public class DataReceivedEventArgs : EventArgs
{
public uint DataCount { get; private set; }
public DataReceivedEventArgs(uint dataCount)
{
DataCount = dataCount;
}
}
// Now inside your MainPage...
bool m_keepReading = false;
bool m_eventHandled = false;
public event TypedEventHandler<MainPage, DataReceivedEventArgs> DataReceived;
// Hook this up to (eg) a Button
private async void StartSockets(object sender, RoutedEventArgs e)
{
if (!m_eventHandled)
DataReceived += (s, args) => Debug.WriteLine(args.DataCount);
m_eventHandled = true;
m_keepReading = true;
DoSocketTestAsync();
}
// Hook this up to (eg) a Button
private void StopSockets(object sender, RoutedEventArgs e)
{
m_keepReading = false;
}
private async Task DoSocketTestAsync()
{
var socket = new StreamSocket();
await socket.ConnectAsync(new HostName("www.microsoft.com"), "http");
var writer = new DataWriter(socket.OutputStream);
writer.WriteString("GET /en-us HTTP/1.1\r\nHOST: www.microsoft.com\r\n\r\n");
await writer.StoreAsync();
ReadSocketAsync(socket);
}
private async void ReadSocketAsync(StreamSocket socket)
{
while (m_keepReading)
{
const uint size = 2048;
IBuffer buffer = new Windows.Storage.Streams.Buffer(size);
buffer = await socket.InputStream.ReadAsync(buffer, size,
InputStreamOptions.Partial);
var handler = DataReceived;
if (handler != null && buffer.Length > 0)
handler(this, new DataReceivedEventArgs(buffer.Length));
}
}
Now when you click the "start" button, assuming you have a network connection you will see some numbers start appearing in the Debug Output window.
(Also note that using private auto-implemented properties doesn't really buy you anything; just make them fields).
So i know there are a lot of articles out there on this topic and i did read a lot of them i would say but for some reason im sure my code is not doing what it is supposed to do.
I want to close a connection between my Server and my Client.
Now on the serverside i start the disconnect with this code
public void shutdown()
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
And on the Client side i have some troubles understanding how i get to the disconnect what i believe is happening is the following: in my async receive callback i should get an error since the server started a shutdown sequence and i have to handle that (right???) so my code for the client looks like this:
ReceiveCallback:
private void ReceiveCallback(IAsyncResult result)
{
int bytesRecieved = 0;
byte[] tempBuff;
//Try to receive But if a Socket error occures disconnect otherwise start Receiving again
try
{
bytesRecieved = _socket.EndReceive(result);
}
catch (SocketException sockEx)
{
Disconnect(sockEx);
return;
}
catch (ObjectDisposedException disposeEx)
{
Disconnect(disposeEx);
return;
}
catch (Exception ex)
{
StartReceive();
return;
}
if (bytesRecieved == 0)
{
StartReceive();
return;
}
tempBuff = new byte[bytesRecieved];
Buffer.BlockCopy(_buffer, 0, tempBuff, 0, bytesRecieved);
StartReceive();
_packHandler.handlePacket(tempBuff);
}
Disconnect:
public void Disconnect()
{
if (!_socket.Connected)
{
return;
}
_socket.BeginDisconnect(false, DisconnectCallback, null);
}
DisconnectCallback
private void DisconnectCallback(IAsyncResult result)
{
_socket.EndDisconnect(result);
_socket.Close();
}
(The Disconnect Method is overloaded so if i get an exception it puts up a messageBox and then also calls Disconnect. Just so i know what happened.)
Where am i wrong and what can i improve uppon ???
I tried the code and it seemed to work but i then looked with netstat if all sockets are closed and the client socket was not. It was in FIN_WAIT_2 which means that it (or the server???) did not yet send the FIN packet right ?
Oh and then i tried it again with this line changed:
if (bytesRecieved == 0)
{
StartReceive();
return;
}
TO
if (bytesRecieved == 0)
{
Disconnect;
return;
}
which then threw an exception on the serverside and on the clientside the client said that the connection was closed by the server ???
EDIT: Even when i have closed both Programs Netstat still shows the port in a WAITING status. what does that tell me ?
Your normal disconnect has a shutdown which will clear the socket so it can disconnect properly but your async style never calls shutdown. I added it in a convenient location below.
public void Disconnect()
{
if (!_socket.Connected)
{
return;
}
_socket.Shutdown(SocketShutdown.Both); // Make sure to do this
_socket.BeginDisconnect(false, DisconnectCallback, null);
}
EDIT:
From the sounds of it you don't have a reason to be using the Async Method? The async methods are so you can send data in a separate execution thread freeing up your thread to do some data processing for instance while that occurs.
I don't see any processing going on so I suggest you change disconnect like this and see if it resolves the problem. Because I don't think you are waiting on the Async methods which will not work out well.
public void Disconnect()
{
if (!_socket.Connected)
{
return;
}
shutdown(); //Your standard disconnect that you showed up top. Scoping might be required.
}
A bit of data on Async can be scrounged up here: http://msdn.microsoft.com/en-us/library/38dxf7kt(v=vs.110).aspx
Important is:
If a server starts a shutdown sequence you DO have to handle it
Both sides have to call shutdown on their socket
You need a way to notice the disconnect (it does not give you an error, or least it didnt for me)
Therefor I created my own class customSocket which inherits from Socket
public class customSocket : Socket
{
#region Properties
private readonly Timer _timer;
private const int _interval = 1000;
private bool Connected
{
get
{
bool part1 = Poll(1000, SelectMode.SelectRead);
bool part2 = (Available == 0);
if (part1 && part2)
return false;
else
return true;
}
}
public bool EventsEnabled
{
set
{
if (value)
{
_timer.Start();
}
else
_timer.Stop();
}
}
#endregion
#region Constructors
public customSocket(AddressFamily addressFamily, SocketType sockType, ProtocolType protocolType)
: base(addressFamily, sockType, protocolType)
{
_timer = new Timer { Interval = _interval };
_timer.Elapsed += TimerTick;
}
public customSocket(SocketInformation sockInfo)
: base(sockInfo)
{
_timer = new Timer { Interval = _interval };
_timer.Elapsed += TimerTick;
}
#endregion
#region Events
public event EventHandler<EventArgs> Socket_disconected;
public void Raise_Socket_disconnected()
{
EventHandler<EventArgs> handler = Socket_disconected;
if (handler != null)
{
handler(this,new EventArgs());
}
}
private void TimerTick(object sender, EventArgs e)
{
if (!Connected)
{
Raise_Socket_disconnected();
}
}
#endregion
}
This version of a socket has an Event for a disconnect.
Now if you create an instance of your socket class you have to connect the handler and set the EventsEnabled true.
This handler then calls the shutdown and your socket does not stay in FIN_WAIT_2
I'm testing SignalR (0.4.0 via nuget) and can't find any way to have the server forcefully disconnect a client. I assume I'm missing something obvious.
My test code is below and I've tried both Close() and Timeout() in pretty much every place and combination I can think of with no success. The client continues to receive pulse messages, though I do always get 2 reconnections within the first 4-5 seconds that appear to come from return Connection.Close() in OnReceivedAsync()
Server:
internal class SignalRServer
{
private Server server;
public SignalRServer()
{
server = new Server("http://localhost:13170/");
server.MapConnection<EchoConnection>("/echo");
server.Start();
Timer timer = new Timer(1000);
timer.Elapsed += OnTimer;
timer.Enabled = true;
}
void OnTimer(object sender, ElapsedEventArgs e)
{
IConnectionManager manager = server.DependencyResolver.GetService(typeof(IConnectionManager)) as IConnectionManager;
IConnection connection = manager.GetConnection<EchoConnection>();
connection.Broadcast("pulse");
connection.Close();
connection.Timeout();
}
}
internal class EchoConnection : PersistentConnection
{
protected override Task OnConnectedAsync(IRequest request, IEnumerable<string> groups, string connectionId)
{
Connection.Timeout();
Connection.Close();
return Connection.Broadcast(String.Format("{0} connection", connectionId));
}
protected override Task OnReconnectedAsync(IRequest request, IEnumerable<string> groups, string connectionId)
{
return Connection.Broadcast(String.Format("{0} reconnection", connectionId));
}
protected override Task OnReceivedAsync(string connectionId, string data)
{
Console.WriteLine(data);
Connection.Close();
Connection.Timeout();
Connection.Broadcast(data);
return Connection.Close();
}
}
Client:
internal class SignalRClient
{
private readonly Connection connection;
public SignalRClient()
{
connection = new Connection("http://localhost:13170/echo");
connection.Received += OnReceive;
connection.Closed += OnClosed;
connection
.Start()
.ContinueWith(t =>
{
if (!t.IsFaulted)
connection.Send("Hello");
else
Console.WriteLine(t.Exception);
});
Console.WriteLine(connection.ConnectionId);
}
void OnClosed()
{
// never called
connection.Stop();
}
void OnReceive(string data)
{
Console.WriteLine(data);
}
}
Sample Client output:
d7615b15-f80c-4bc5-b37b-223ef96fe96c connection
Hello
pulse
pulse
d7615b15-f80c-4bc5-b37b-223ef96fe96c reconnection
pulse
pulse
d7615b15-f80c-4bc5-b37b-223ef96fe96c reconnection
pulse
pulse
pulse
pulse
pulse
pulse
...
In .Net Core use
Context.Abort();
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.signalr.hubcallercontext.abort
Send a specific string to the client to force the disconnect:
void OnReceive(string data)
{
if(data.Equals("exit"))
{
connection.Stop();
return;
}
Console.WriteLine(data);
}