Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting up TCP on Azure Service Fabric

I have a requirement to set up a Stateful Service Fabric app that listens for TCP requests and then pops the messages on to a Reliable Queue.

There's plenty of examples around for HTTP and WCF endpoints, but i can find nothing for simple TCP.

In my ServiceManifest.xml I have this

 <Endpoints>
  <!-- This endpoint is used by the communication listener to obtain the port on which to 
       listen. Please note that if your service is partitioned, this port is shared with 
       replicas of different partitions that are placed in your code. -->
  <Endpoint Name="ServiceEndpoint" />

  <!-- This endpoint is used by the replicator for replicating the state of your service.
       This endpoint is configured through a ReplicatorSettings config section in the Settings.xml
       file under the ConfigPackage. -->
  <Endpoint Name="ReplicatorEndpoint" />
  <Endpoint Name="tcpEndpoint" Protocol="tcp" Port="10100"/>
</Endpoints>

I have a listener that implements ICommunicationListenercalled TcpCommunicationListener

 public class TcpCommunicationListener : ICommunicationListener
{
    private readonly ServiceEventSource eventSource;
    private readonly ServiceContext serviceContext;
    private readonly string endpointName;
    private string listeningAddress;
    private string hostAddress;


    public TcpCommunicationListener(ServiceContext serviceContext, ServiceEventSource eventSource, string endpointName)
    {

        if (serviceContext == null)
        {
            throw new ArgumentNullException(nameof(serviceContext));
        }

        if (endpointName == null)
        {
            throw new ArgumentNullException(nameof(endpointName));
        }

        if (eventSource == null)
        {
            throw new ArgumentNullException(nameof(eventSource));
        }

        this.serviceContext = serviceContext;
        this.endpointName = endpointName;
        this.eventSource = eventSource;
    }

    public Task<string> OpenAsync(CancellationToken cancellationToken)
    {
        var serviceEndpoint = this.serviceContext.CodePackageActivationContext.GetEndpoint(this.endpointName);
        var protocol = serviceEndpoint.Protocol;
        int port = serviceEndpoint.Port;


        //StatefulServiceContext statefulServiceContext = this.serviceContext as StatefulServiceContext;

        this.hostAddress = FabricRuntime.GetNodeContext().IPAddressOrFQDN;

        this.listeningAddress = string.Format(
            CultureInfo.InvariantCulture,
            "{0}://{1}:{2}",
            protocol,
            hostAddress,
            port
           );

        try
        {
            this.eventSource.Message("Starting tcp listener " + this.listeningAddress);

            return Task.FromResult(this.hostAddress);
        }
        catch (Exception ex)
        {
            this.eventSource.Message("Tcp Listener failed to open endpoint {0}. {1}", this.endpointName, ex.ToString());

            throw;
        }
    }

    public Task CloseAsync(CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

    public void Abort()
    {
        throw new NotImplementedException();
    }
}

I also have a StatefulService called ListenerService

internal sealed class ListenerService : StatefulService
{

    public ListenerService(StatefulServiceContext context)
        : base(context)
    {

    }


    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
    {
        var endpoints = Context.CodePackageActivationContext.GetEndpoints()
                              .Where(endpoint => endpoint.Protocol == EndpointProtocol.Tcp)
                              .Select(endpoint => endpoint.Name);

        return endpoints.Select(endpoint => new ServiceReplicaListener(
            serviceContext => new TcpCommunicationListener(serviceContext, ServiceEventSource.Current, endpoint), endpoint));
    }


    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

       //do i spin up a TcpListener here?
    }
}

So my question is how do I get the messages that are being received?

Do I have to create a TcpListener in the RunAsync method of my ListenerService? If that's the case then what's the point of specifying an endpoint in the ServiceManifest.xml?

OR

Do I need to do something in the OpenAsync method of the TcpCommunicationListener?

like image 396
MrBliz Avatar asked Oct 18 '22 04:10

MrBliz


1 Answers

Right now your communication listener code only publishes a Uri when OpenAsync is called. You'll also need to actually start listening on that endpoint. So for instance, you could open a Socket at that time. You can also use WCF with a NetTcpBinding.

like image 74
LoekD Avatar answered Oct 27 '22 23:10

LoekD