UDP broadcast of WCF Service address - wcf

Im have a lab-environment in VMware with a WS2008R2-server and a W7-client. Im trying to broadcast a WCF-service-address from the server and receive this in the client. Im using System.Net.Sockets in C# .NET and I can successfuly send data from the server. I looks okay with WinDump at least. But when I try to receive this on the client it fails. I cant understand where the problem is..? The client can communicate with the server in other ways and with my WCF-service if I manually enter its address. I have turned of my firewalls in the lab-environment just in case.
[Update]
I checked WinDump on my client-vm and the same udp-message showes up here as well so it seem to be able to receive the broadcast. But why arent the ReceieveFrom-method returning anything? Have I setup the client socket wrong? Should it bind to the Any-address or to its local ip? Neither works...
[/Update]
Heres the server-code:
public static class MulticastServer
{
static Socket socket;
static IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 9050);
public static void Open()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
}
public static void Send(string message)
{
socket.SendTo(Encoding.ASCII.GetBytes(message), ep);
}
public static void Close()
{
socket.Close();
}
}
And the client:
public static class MulticastClient
{
public static string ReceiveOne()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 9050);
socket.Bind(ep);
byte[] data = new byte[1024];
EndPoint e = (EndPoint)ep;
int i = socket.ReceiveFrom(data, ref e);
socket.Close();
return Encoding.ASCII.GetString(data, 0, i);
}
}

I'm not sure where your current problem is but by reading your question I immediately knew that you are reinventing a wheel. Upgrade to .NET 4.0 and use WCF Discovery which is exactly for this purpose - UDP based searching for service with given contract and UDP based announcements about services. Moreover it is based on WS-Discovery protocol so I guess it should be interoperable. Isn't it better than custom solution?

Related

Fail to connect to WCF Service on my Localhost

I got the below error when trying to connect to WCF service running on my localhost using the WCF Test Client tool. I entered the end-point address as "net.tcp://localhost:19998/MyWCFService". MyWCFService is launched within Visual Studio 2017 on my local PC.
"There was no endpoint listening at net.tcp://localhost:19998/MyWCFService that
could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details."
I can verify the port 19998 is listening on my PC using the netstat.
TCP 0.0.0.0:19998 LISTENING
I have disabled all the firewall on my PC.
It turns out that my WCF service has some runtime errors that prohibits any clients to connect to it.. I have fixed the errors and i can connect now. Thanks.
It seems that the error is caused by that the service address is wrong. How do you host the service on the server side? I would like you could post more details about the server side so that give you an effective reply.
Here is my example about using NetTCPBinding, wish it is useful to you.
Server
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("net.tcp://localhost:1500");
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
using (ServiceHost sh = new ServiceHost(typeof(Calculator), uri))
{
sh.AddServiceEndpoint(typeof(ICalculator), binding,"");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
//smb.HttpGetEnabled = true;
sh.Description.Behaviors.Add(smb);
}
Binding mexbinding = MetadataExchangeBindings.CreateMexTcpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "MEX");
sh.Open();
Console.Write("Service is ready....");
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
public interface ICalculator
{
[OperationContract]
int Test(int a);
}
public class Calculator : ICalculator
{
public int Test(int a)
{
return a * 2;
}
}
Result.
Feel free to let me know if there is anything I can help with.

Spring Integration two way communication with gps devices

We are using spring integration application for data receiption from gps devices. For current configuration we are able to receive data from device also respose sent back to device through same connection
current configuration is as
#SpringBootApplication
#IntegrationComponentScan
public class SpringIntegrationApplication extends SpringBootServletInitializer{
private Integer TIMEOUT=1000*60*10;
#Value("${TCP_PORT}")
private Integer TCP_PORT;
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringIntegrationApplication.class, args);
System.in.read();
ctx.close();
}
#Bean
TcpNetServerConnectionFactory cf(){
TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(TCP_PORT);
connectionFactory.setSerializer(new CustomSerializerDeserializer());
connectionFactory.setDeserializer(new CustomSerializerDeserializer());
connectionFactory.setSoTimeout(TIMEOUT);
return connectionFactory;
}
#Bean
TcpInboundGateway tcpGate(){
TcpInboundGateway gateway=new TcpInboundGateway();
gateway.setConnectionFactory(cf());
gateway.setRequestChannel(requestChannel());
gateway.setRequestTimeout(TIMEOUT);
return gateway;
}
#Bean
public MessageChannel requestChannel(){
return new DirectChannel();
}
}
and message end point
#MessageEndpoint
public class Echo {
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#SuppressWarnings("deprecation") #Header("ip_address") String ip){
//here we receive packet data in bytes from gps device
return "".getBytes();//string will contains expected result for device.
}
Above configuartion works fine for one way communication. but we want to implement two way communication. What we want after connection established between server and device we want to send message explicitely.To send command through server we dont know ip and port of device, so how can we send command through server to connected device.
I am trying following solution
created oubound channel adapter
#Bean
public TcpSendingMessageHandler tcpSendingMessageHandler() {
System.out.println("Creating outbound adapter");
TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
return outbound;
}
then created gateway for explicite message send, this will be called from service where we want to send data explicitely
#MessagingGateway(defaultRequestChannel="toTcp")
public static interface tcpSendService {
public byte [] send(String string);
}
After calling gate way following service activator invoked where we are setting connection ip and port, these ip and ports will be from connection established while receiving data from device
#ServiceActivator(inputChannel="toTcp", outputChannel="fromTcp")
public String send(String in){
System.out.println(new String(in));
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(ip_extracted_from_inbound_connection, port_extarcted_from_inbound_connection);
factory.start();
tcpSendingMessageHandler.setConnectionFactory(factory);
return in;
}
// for ip and port extraction i am using following service which is inbound sevice
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#Header("ip_address") String ip){
System.out.println(new String(in)+ " ; IP : "+ip);
for (String connectionId : factory.getOpenConnectionIds()) {
if(!lastConection.contains(ip))
lastConection = connectionId;
}
return "hello".getBytes();
}
For service activator i am setting new TcpNetClientConnectionFactory every time service called. Ip and port are extracted from TcpNetServerConnectionFactory. whenever device connects with server i am saving its connection ip and port, using these ip and port for data transmission through server but i am getting connection timeout issue.
Kindly help me out and suggest me a solution over it.
Thank you.
Replace the gateway with a pair of Collaborating Outbound and Inbound Channel Adapters.
In order to send arbitrary messages to a connection, you must set the ip_connectionId header.
The challenge, though, is how to direct the reply to the gateway. You would need to capture the replyChannel header from the request and, when a reply is received for that ip_connectionId, set the replyChannel headers.
This will only work, though, if you have only one request/reply outstanding to each device at a time, unless there is some data in the reply that can be used to correlate it to a request.
Another challenge is race conditions, where the device and the server initiate a request at the same time. You would need to look at data in the inbound message to see if it's a request or reply.

Ninject is not generating WSDL

I just started playing with Ninject for self hosted WCF services.
I ran into a problem where it isnt generating a wsdl (url?wsdl or url?singleWsdl).
I start up the service with this :
private static void StartNinjectSelfHost()
{
var someWcfService = NinjectWcfConfiguration.Create<CalculatorService, NinjectWebServiceSelfHostFactory>();
_selfHost = new NinjectSelfHostBootstrapper(CreateKernel,someWcfService);
_selfHost.Start();
}
If I revert to the standard way with this:
private static void LoadWcf()
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(CalculatorService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
Then I get the wsdl just fine at this URL:
http://localhost:8000/ServiceModelSamples/service?singleWsdl
I'm guessing I have to tell Ninject to do this, but I'm struggling to find any good info by searching.
Any help on enabling the wsdl is appreciated.
Nevermind I'm dumb. I wanted to use "NinjectServiceSelfHostFactory" instead, now it works

singleton WCF service in C#

I'm developing an application in C#. I have created ServiceHost app which will host the wcf service.
client will call ServiceHost.exe by passing some argument.
I have tried by below way.
static class ServiceHost
{
private static ITest channel = null;
static void Main(string[] args)
{
if (String.Compare(args[0], "dooperation", true) == 0)
{
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.MaxValue;
EndpointAddress ep = new EndpointAddress(address);
channel = ChannelFactory<ITest>.CreateChannel(binding, ep);
channel.DoOpertion1();
channel.Close() // close service
// Make sure the application runs!
Application.Run();
GC.KeepAlive(m_singleInstance);
}
else if (String.Compare(args[0], "stop", true) == 0)
{
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.MaxValue;
EndpointAddress ep = new EndpointAddress(address);
channel = ChannelFactory<ITest>.CreateChannel(binding, ep);
channel.DoOpertion2();
channel.Close() // close service
// Exit Appli
Application.Exit();
}
}
}
So here I'm creating communication channel, calling method and closing the channel.
but creating namepipe, then communication channel and service channel consuming more time, so i want to optimize the call so that it will create single instance of WCF service communication channel whenever client calls ServiceHost.exe.
is there any way to create single instance of channel?
is there any side effect if we keep open the namepine/communication channel.
Reusing a WCF channel is an anti pattern, the channel is not thread safe and you have to handle the fault state. The creation of the channel is not time consuming, the creation of the factory is. So you should reuse your ChannelFactory.
MSDN Middle-Tier Client Applications

Cross domain policy file over net.tcp for WCF servicehost and Silverlight 5

I have a locally hosted WCF service and a silverlight 5 app that communicates with it. By default silverlight tries to obtain the cross domain policy file over HTTP when making calls to the WCF service. I need to change this so that the policy file is served over net.tcp port 943 instead.
I have setup a local tcp listener that serves up the policy file over port 943 and i have followed this technique whereby i make a dummy socket connection in order to obtain the policy file over tcp as it is only retrieved once per application lifetime. The tcp server is being hit as expected and i am getting SocketError property value as Success (though i must note, the first time i hit the tcp server after starting the listener, the result is always access denied).
From what i can tell, the policy file is either invalid as the silverlight application as still unable to connect or the above mentioned technique does not work with silverlight 5.
What i would like to know is if what i am doing is possible & im doing it correctly, otherwise if there is an alternative means to have the policy file successfully downloaded over tcp and removing the need for retrieving it over HTTP.
Thanks
I wrote a long post about hosting silverlight in WPF - and using WCF with a http listener here:
How can I host a Silverlight 4 application in a WPF 4 application?
Now while not directly answering your question, it does show how to create a http version of the policy file.
I have also written something that serves up a policy listener over port 943, but I can't find where I posted the source - so I'll keep digging. As far as I remember though, silverlight does a cascade find of the policy file, if it doesn't get a connection on port 80, it'll then look on port 943.
I hope this is of some help somewhere.
Ok, here is the policy listener I had for net.TCP transport i.e. not HTTP based. I presume you have sorted this by now, sorry for the delay. It may well be of use to someone else now.
I was looking for the MS thing that said they cascade from HTTP to TCP, however, I can't, and therefore have to assume it was bunk and then changed.
Either way, if you call using a net.TCP service, and want a listener for it, this code should help:
#region "Policy Listener"
// This is a simple policy listener
// that provides the cross domain policy file for silverlight applications
// this provides them with a network access policy
public class SocketPolicyListener
{
private TcpListener listener = null;
private TcpClient Client = null;
byte[] Data;
private NetworkStream netStream = null;
private string listenaddress = "";
// This could be read from a file on the disk, but for now, this gives the silverlight application
// the ability to access any domain, and all the silverlight ports 4502-4534
string policyfile = "<?xml version='1.0' encoding='utf-8'?><access-policy><cross-domain-access><policy><allow-from><domain uri='*' /></allow-from><grant-to><socket-resource port='4502-4534' protocol='tcp' /></grant-to></policy></cross-domain-access></access-policy>";
// the request that we're expecting from the client
private string _policyRequestString = "<policy-file-request/>";
// Listen for our clients to connect
public void Listen(string ListenIPAddress)
{
listenaddress = ListenIPAddress;
if (listener == null)
{
listener = new TcpListener(IPAddress.Parse(ListenIPAddress), 943);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger,lo);
}
listener.Start();
WaitForClientConnect();
}
private void WaitForClientConnect()
{
listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), listener);
}
public void StopPolicyListener()
{
if (Client.Connected)
{
// Should never reach this point, as clients
// are closed if they request the policy
// only clients that open the connection and
// do not submit a policy request will remain unclosed
Client.Close();
}
listener.Stop();
}
public void RestartPolicyListener()
{
listener.Start();
}
// When a client connects:
private void OnClientConnected(IAsyncResult ar)
{
if (ar.IsCompleted)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
// End the operation and display the received data on
// the console.
Client = listener.EndAcceptTcpClient(ar);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
// Set our receive callback
Data = new byte[1024];
netStream = Client.GetStream();
netStream.BeginRead(Data, 0, 1024, ReceiveMessage, null);
}
WaitForClientConnect();
}
// Read from clients.
public void ReceiveMessage(IAsyncResult ar)
{
int bufferLength;
try
{
bufferLength = Client.GetStream().EndRead(ar);
// Receive the message from client side.
string messageReceived = Encoding.ASCII.GetString(Data, 0, bufferLength);
if (messageReceived == _policyRequestString)
{
// Send our policy file, as it's been requested
SendMessage(policyfile);
// Have to close the connection or the
// silverlight client will wait around.
Client.Close();
}
else
{
// Continue reading from client.
Client.GetStream().BeginRead(Data, 0, Data.Length, ReceiveMessage, null);
}
}
catch (Exception ex)
{
throw new Exception(Client.Client.RemoteEndPoint.ToString() + " is disconnected.");
}
}
// Send the message.
public void SendMessage(string message)
{
try
{
byte[] bytesToSend = System.Text.Encoding.ASCII.GetBytes(message);
//Client.Client.Send(bytesToSend,SocketFlags.None);
Client.GetStream().Write(bytesToSend,0, bytesToSend.Length);
Client.GetStream().Flush();
}
catch (Exception ex)
{
throw ex;
}
}
}
#endregion