Is there any way i get the reference of ChannelPipeline created when i a client connect to server on serverside? - tcp

In case of synchronous TCP server when ever a client connects i get a reference of Client example :
int serverPortNum = 9000;
socket while(true) {
ServerSocket connectionSocket = new ServerSocket(serverPortNum);
Socket dataSocket = connectionSocket.accept( );
// pass this reference(dataSocket ) to other part of program to read or write depending on app logic
}
Now i want to use asynchronous TCP Server using Netty so is there any way i can get the reference of ChannelPipeline or ChannelHandler created when a new client is connected.
On Client Side I can do it easily : sample code :
NioClientSocketChannelFactory ncscf = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
ClientBootstrap clientBootstrap = new ClientBootstrap(ncscf);
final DummyHandler dummy = new DummyHandler();
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(dummy);
}
});
InetAddress inetaddress = InetAddress.getByName(host);
ChannelFuturecf=clientBootstrap.connect(newInetSocketAddress(inetaddress,port));
So every time i create a new client i have new DummyHandler reference
On Server Side : sample Code :
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new DummyServerHandler());
}
});
bootstrap.bind(new InetSocketAddress(port));
So when client request connection new DummyServerHandler object is created but i cannot get reference of this.

I may missunderstood the question but wouldn't this work.
Channel.getpipeline()

Related

How to make a Blazor page update the content of one html tag with incoming data from gRPC service

So i'm testing with Blazor and gRPC and my dificulty at the moment is on how to pass the content of a variable that is on a class, specifically the gRPC GreeterService Class to the Blazor page when new information arrives. Notice that my aplication is a client and a server, and i make an initial comunication for the server and then the server starts to send to the client data(numbers) in unary mode, every time it has new data to send. I have all this working, but now i'm left it that final implementation.
This is my Blazor page
#page "/greeter"
#inject GrpcService1.GreeterService GreeterService1
#using BlazorApp1.Data
<h1>Grpc Connection</h1>
<input type="text" #bind="#myID" />
<button #onclick="#SayHello">SayHello</button>
<p>#Greetmsg</p>
<p></p>
#code {
string Name;
string Greetmsg;
async Task SayHello()
{
this.Greetmsg = await this.GreeterService1.SayHello(this.myID);
}
}
The method that later receives the communication from the server if the hello is accepted there is something like this:
public override async Task<RequestResponse> GiveNumbers(BalconyFullUpdate request, ServerCallContext context)
{
RequestResponse resp = new RequestResponse { RequestAccepted = false };
if (request.Token == publicAuthToken)
{
number = request.Number;
resp = true;
}
return await Task.FromResult(resp);
}
Every time that a new number arrives i want to show it in the UI.
Another way i could do this was, within a while condition, i could do a call to the server requesting a new number just like the SayHello request, that simply awaits for a server response, that only will come when he has a new number to send. When it comes the UI is updated. I'm just reluctant to do it this way because i'm afraid that for some reason the client request is forgotten and the client just sit's there waiting for a response that will never come. I know that i could implement a timeout on the client side to handle that, and on the server maybe i could pause the response, with a thread pause or something like that, and when the method that generates the new number has a new number, it could unpause the response to the client(no clue on how to do that). This last solution looks to me much more difficult to do than the first one.
What are your thoughts about it? And solutions..
##################### UPDATE ##########################
Now i'm trying to use a singleton, grab its instance in the Blazor page, and subcribe to a inner event of his.
This is the singleton:
public class ThreadSafeSingletonString
{
private static ThreadSafeSingletonString _instance;
private static readonly object _padlock = new object();
private ThreadSafeSingletonString()
{
}
public static ThreadSafeSingletonString Instance
{
get
{
if (_instance == null)
{
lock(_padlock)
{
if (_instance == null)
{
_instance = new ThreadSafeSingletonString();
_instance.number="";
}
}
}
return _instance;
}
set
{
_instance.number= value.number;
_instance.NotifyDataChanged();
}
}
public int number{ get; set; }
public event Action OnChange;
private void NotifyDataChanged() => OnChange?.Invoke();
And in Blazor page in code section i have:
protected override void OnInitialized()
{
threadSafeSingleton.OnChange += updateNumber();
}
public System.Action updateNumber()
{
this.fromrefresh = threadSafeSingleton.number + " que vem.";
Console.WriteLine("Passou pelo UpdateNumber");
this.StateHasChanged();
return StateHasChanged;
}
Unfortunatly the updatenumber function never gets executed...
To force a refresh of the ui you can call the StateHasChanged() method on your component:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.componentbase.statehaschanged?view=aspnetcore-3.1
Notifies the component that its state has changed. When applicable, this will cause the component to be re-rendered.
Hope this helps
Simple Request
After fully understanding that your problem is just to Update the Page not to get unsyncronous messages from the server with a bi directional connection. So jou just have to change your page like (please not there is no need to change the files generated by gRPC, I called it Number.proto so my service is named NumberService):
async Task SayHello()
{
//Request via gRPC
var channel = new Channel(Host + ":" + Port, ChannelCredentials.Insecure);
var client = new this.NumberService.NumberServiceClient(channel);
var request = new Number{
identification = "ABC"
};
var result = await client.SendNumber(request).RequestAccepted;
await channel.ShutdownAsync();
//Update page
this.Greetmsg = result;
InvokeAsync(StateHasChanged);//Required to refresh page
}
Bi Directional
For making a continious bi directional connection you need to change the proto file to use streams like:
service ChatService {
rpc chat(stream ChatMessage) returns (stream ChatMessageFromServer);
}
This Chant sample is from the https://github.com/meteatamel/grpc-samples-dotnet
The main challenge on this is do divide the task waiting for the gRPC server from the client. I found out that BackgroundService is good for this. So create a Service inherited from BackgroundService where place the while loop waiting for the server in the ExecuteAsyncmethod. Also define a Action callback to update the page (alternative you can use an event)
public class MyChatService : BackgroundService
{
Random _random = new Random();
public Action<int> Callback { get; set; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Replace next lines with the code request and wait for server...
using (_call = _chatService.chat())
{
// Read messages from the response stream
while (await _call.ResponseStream.MoveNext(CancellationToken.None))
{
var serverMessage = _call.ResponseStream.Current;
var otherClientMessage = serverMessage.Message;
var displayMessage = string.Format("{0}:{1}{2}", otherClientMessage.From, otherClientMessage.Message, Environment.NewLine);
if (Callback != null) Callback(displayMessage);
}
// Format and display the message
}
}
}
}
On the page init and the BackgroundService and set the callback:
#page "/greeter"
#using System.Threading
<p>Current Number: #currentNumber</p>
#code {
int currentNumber = 0;
MyChatService myChatService;
protected override async Task OnInitializedAsync()
{
myChatService = new MyChatService();
myChatService.Callback = i =>
{
currentNumber = i;
InvokeAsync(StateHasChanged);
};
await myChatService.StartAsync(new CancellationToken());
}
}
More information on BackgroundService in .net core can be found here: https://gunnarpeipman.com/dotnet-core-worker-service/

How can I write message from server to an IP/Port using Netty 3.8 ServerBootstrap (TCP)

I want to send a message from server to an IP/Port but it's not working when I write the channel. I'm not sure what I'm doing wrong.
private Channel channel;
private void createConnection() {
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
this.bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SimpleChannelHandler());
}
});
bootstrap.setOption("localAddress", new InetSocketAddress("localhost", 0));
bootstrap.setOption("reuseAddress", true);
bootstrap.setOption("child.sendBufferSize", 65536);
bootstrap.setOption("child.receiveBufferSize", 65536);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
this.channel = bootstrap.bind();
}
I'm writing a component using apache camel. When my component proccess, I want it sends a message to an IP/Port.
public void send(Exchange exchange) {
String ip = exchange.getIn().getHeader("ip", String.class);
int port = exchange.getIn().getHeader("port", Integer.class);
Object msg = exchange.getIn().getBody();
InetSocketAddress inetSocketAddress = new InetSocketAddress(ip, port);
this.channel.write(msg, inetSocketAddress);
}
I'm getting a "getUnsupportedOperationFuture". I'm not sure what I'm doing wrong. I'm using Netty 3.8 and I think the connection is set correctly. Any help?

How to define a custom port for the WebDAV server using sardine?

In Sardine how do I change the port number to something different from port 80 (for HTTP) and 443 (for HTTPS)?
The User guide states that I have to "override SardineImpl#createDefaultSchemeRegistry() or provide your own configured HTTP client instance by instantiating SardineImpl#SardineImpl(org.apache.http.impl.client.HttpClientBuilder)" but I can't find how to define the port.
When I instantiate SardineImpl using:
HttpClientBuilder builder = HttpClientBuilder.create();
SardineImpl sardine = new SardineImpl(builder, "user", "password");
byte[] data;
data = FileUtils.readFileToByteArray(new File("test.txt"));
sardine.put("http://webdav-server:8095/projects/", data);
I obtain:
org.apache.http.NoHttpResponseException: webdav-server:8095 failed to respond
The server is accessible via browser so the problem must be with the definition of the port and I could not find an example on how to do this.
Can someone help me on this? Thanks in advance.
This is what I figured out after racking my brain trying to find a solution. Hopefully it helps someone else:
HttpClientBuilder builder = new HttpClientBuilder(){
#Override
public CloseableHttpClient build() {
SchemePortResolver spr = new SchemePortResolver() {
#Override
public int resolve(HttpHost httpHost) throws UnsupportedSchemeException {
return 8443; // SSL port to use
}
};
CloseableHttpClient httpclient = HttpClients.custom()
.useSystemProperties()
.setSchemePortResolver(spr)
.build();
return httpclient;
}
};
Sardine sardine = new SardineImpl(builder, "user", "passwd");
List<DavResource> resources = null;
resources = sardine.list("https://ftp-site.com/path/");
resources.forEach(resource -> {
System.out.println(resource.getName());
}
Hope that helps somebody.

JavaFX UI freezes on web service call

I have a JavaFX application that consumes web services via Jersey Client API, every once in a while parts of the application(screens) freeze while executing a call to a web service.
There is no thread that i used to make the web service calls.
The following is the Jersey Client Code:
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
public class WSClient{
WebResource webResource;
ClientResponse response;
protected Client getWSClient() {
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(
JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client wsClient = Client.create(clientConfig);
return wsClient;
}
public ArrayList<String> getNames(){
ArrayList<String> names= new ArrayList<>();
try{
webResource = getWSClient().resource("http://localhost:8080/names");
response = webResource.type("application/json").accept("application/json").get(ClientResponse.class);
}catch(Exception ex){
log.error("Failed : " + ex.getMessage());
return null;
}
if(response.getStatus() != 200){
return null;
}
String output = response.getEntity(String.class);
names= getGson().fromJson(output,
new TypeToken<ArrayList<String>>() {
}.getType());
return names;
}
}
The Following is the JavaFX controller class:
private ComboBox<String> cmbNames = new ComboBox<>();
cmbNames.setItems(FXCollections.observableList(new WSClient().getNames()));
your help is really appreciated!
Retrieving data from a server is, or at least has the potential to be, a long-running operation. You should not perform such operations on the FX Application Thread, as the UI will be unresponsive during the operation.
Create a Task to perform the operation, and execute it in a background thread:
Task<List<String>> getNamesTask = new Task<List<String>>() {
#Override
public List<String> call() {
return new WSClient().getNames();
}
};
getNamesTask.setOnSucceeded(e ->
cmbNames.getItems().setAll(getNamesTask.getValue()));
To execute the task in a background thread, you can either do so "by hand":
Thread thread = new Thread(getNamesTask);
thread.setDaemon(true);
thread.start();
Or (better), use an Executor which will manage a thread pool for you:
// declared at class level:
private final Executor exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
// ...
exec.execute(getNamesTask);
For more strategies on integrating client-server communication with JavaFX, have a look at Adam Bien's excellent article.

Is there a notification when ASP.NET Web API completes sending to the client

I'm using Web API to stream large files to clients, but I'd like to log if the download was successful or not. That is, if the server sent the entire content of the file.
Is there some way to get a a callback or event when the HttpResponseMessage completes sending data?
Perhaps something like this:
var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// This doesn't exist, but it illustrates what I'm trying to do.
response.OnComplete(context =>
{
if (context.Success)
Log.Info("File downloaded successfully.");
else
Log.Warn("File download was terminated by client.");
});
EDIT: I've now tested this using a real connection (via fiddler).
I inherited StreamContent and added my own OnComplete action which checks for an exception:
public class StreamContentWithCompletion : StreamContent
{
public StreamContentWithCompletion(Stream stream) : base (stream) { }
public StreamContentWithCompletion(Stream stream, Action<Exception> onComplete) : base(stream)
{
this.OnComplete = onComplete;
}
public Action<Exception> OnComplete { get; set; }
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var t = base.SerializeToStreamAsync(stream, context);
t.ContinueWith(x =>
{
if (this.OnComplete != null)
{
// The task will be in a faulted state if something went wrong.
// I observed the following exception when I aborted the fiddler session:
// 'System.Web.HttpException (0x800704CD): The remote host closed the connection.'
if (x.IsFaulted)
this.OnComplete(x.Exception.GetBaseException());
else
this.OnComplete(null);
}
}, TaskContinuationOptions.ExecuteSynchronously);
return t;
}
}
Then I use it like so:
var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContentWithCompletion(stream, ex =>
{
if (ex == null)
Log.Info("File downloaded successfully.");
else
Log.Warn("File download was terminated by client.");
});
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;
I am not sure if there is direct signaling that all is ok, but you can use a trick to find out that the connection is exist just before you end it up, and right after you fully send the file.
For example the Response.IsClientConnected is return true if the client is still connected, so you can check something like:
// send the file, make a flush
Response.Flush();
// and now the file is fully sended check if the client is still connected
if(Response.IsClientConnected)
{
// log that all looks ok until the last byte.
}
else
{
// the client is not connected, so maybe have lost some data
}
// and now close the connection.
Response.End();
if the server sent the entire content of the file
Actually there is nothing to do :)
This might sound very simplistic but you will know if an exception is raised - if you care about server delivering and not client cancelling halfway. IsClientConnected is based on ASP.NET HttpResponse not the WebApi.

Resources