Sayfalar

5 Mayıs 2017 Cuma

C++ SignalR İstemci Uygulaması


SignalR, bağlı olan istemciler arasında gerçek zamanlı haberleşme altyapısı sağlayan bir frameworkdür. Http tabanlı çalışır ve asenkron haberleşmenin kalıcı olmasını/kopmadan devam etmesini sağlar. SignalR ile bağlantı kurulumu için konfigürasyon ve bağlantı durumunu sorgulamak gibi işler kolaylaşır ve bu gibi temel işler kütüphane tarafından otomatik gerçekleştirilir .NET uygulamaları ve Javascript ile SignalR kullanımına dair örnekler internette bir hayli mevcut. Ben bu yazı kapsamında SignalR'ı C++ ile kullanarak C# uygulaması ile haberleşme sağlayan bir örnek gerçekleştireceğim.

C++ SignalR Client uygulaması için kurulumun nasıl yapıldığı ve örnek uygulamalar için : https://github.com/aspnet/SignalR-Client-Cpp





İlk olarak server olarak çalışacak C# console uygulamasının kodlarını paylaşıyorum.

using System;
using System.Collections.Generic;
using System.Linq;
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Hosting;
using Owin;
using Microsoft.Owin.Cors;

class Program
{
static void Main(string[] args)
{
   string url = "http://localhost:8080";
   using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}

Console.ReadKey();
}
}

class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub Hub
{
public void Method1(string name, string message, float x)
{
Console.WriteLine("Method1 called from remote name: {0} message: {1}",name,message );

if (message == "kare")
x = x * x;
else if (message == "karekok")
x = (float)Math.Sqrt(x);

Clients.All.Send("server", message, x);
}
}


İstemciler ile bağlantı kuracağımız adres http://localhost:8080 . Her iki uygulamada da bağlantı kurulumu için bu adresi kullanacağız.

C# console uygulamamızdaki  MyHub sınıfı sunucu ile istemci arasında iletişimi sağlayacak olan sınıfımız. C++ uygulaması ile sunucuya erişmek istediğimizde Hub sınıfından türetilmiş bu sınıfın adı ile sınıf içerisindeki metodlara erişeceğiz. MyHub sınıfında Method1 isimli bir metod tanımladık. Bu metod 3 parametre alıyor ve string tipindeki message değişkeninin değerine bakarak 3. parametre olan int x değerinin karekök ya da karesini alıp istemcilere (yani C++ uygulamasına) gönderiyor!

Dilerseniz şimdi C++ uygulamasının kodlarına geçelim. Kod üzerinde önemli gördüğüm yerlere kısa açıklamalar ekledim ve program çıktısına dair bir örneği yazının sonunda paylaştım.

#include "signalrclient\hub_connection.h"

#include<iostream>
#include<string>

void send_message(signalr::hub_proxy proxy, const utility::string_t& name, const utility::string_t& message, float x)
{
web::json::value args{};
args[0] = web::json::value::string(name);
args[1] = web::json::value(message);
args[2] = web::json::value(x);


// json formatina cevrilen verileri, sunucudaki(C# uygulamasi) MyHub.Method1 metodunu cagirirken
// parametre olarak gonderiyoruz.
proxy.invoke<void>(U("Method1"), args/*, [](const web::json::value&){}*/)
.then([](pplx::task<void> invoke_task) // fire and forget but we need to observe exceptions
{
try
{
invoke_task.get();
}
catch (const std::exception &e)
{
ucout << U("Error while sending data: "<< e.what();
}
});
}


utility::string_t methodname;

int main()
{
// standart C++ string i  C++ rest SDK string formatına çeviriyoruz...
utility::string_t name(utility::conversions::to_string_t("ibrahim"));

// Baglanacagimiz adres, *****C# uygulamasındaki ile ayni olmali*****
signalr::hub_connection connection{ U("http://localhost:8080") };

// MyHub-> C# uygulamasındaki sınıf adi
auto proxy = connection.create_hub_proxy(U("MyHub"));

// Method1 -> cagiracagimiz metod adi
methodname = utility::conversions::to_string_t("Method1");

// C# uygulamasindan verileri aldigimiz kisim
// veriler json formatında geliyor, donusturme islemi uyguluyoruz
proxy.on(U("Send"), [](const web::json::value& m)
{
std::cout << "***newmessage*** ";
ucout << std::endl << m.at(0).as_string() << U(" wrote:");

std::string id(utility::conversions::to_utf8string(m.at(1).as_string()));

float x = m.at(2).as_double();
std::cout << " x = " << << std::endl;

});


connection.start()
.then([proxy, name]()
{

for (;;)
{
std::string str;
utility::string_t message;
float x;

ucout << U("Enter the number:");
std::cin >> x;

ucout << U("Enter your message: ");
std::cin >> str;
message = utility::conversions::to_string_t(str);

if (message == U(":q"))
{
break;
}

send_message(proxy, name, message, x );
}
})
.then([&connection]() // fine to capture by reference - we are blocking so it is guaranteed to be valid
{
return connection.stop();
})
.then([](pplx::task<void> stop_task)
{
try
{
stop_task.get();
ucout << U("connection stopped successfully"<< std::endl;
}
catch (const std::exception &e)
{
ucout << U("exception when starting or stopping connection: "<< e.what() << std::endl;
}
}).get();


std::cout << "NO CONNECTION ESTABLISHED";

return 0;
}


Bu örnekte C++ uygulaması ile C# uygulamasındaki bir metodu, istemci yani C++ uygulaması tarafından gönderilen parametre değerleri ile çağırmış olduk ve sunucudan gönderdiğimiz mesaja bir cevap aldık. Basit olarak; C++ ile girdiğimiz bir sayının karesini ya da karekökünü hesaplayan bir program yazdık, Fakat bu işlemi  C# uygulamasındaki metodu çağırarak yaptık!!!!

Aşağıdaki ekran çıktısını incelerseniz;

C++ uygulamasında sayı ve mesaj değerleri kullanıcıdan alınıyor ve bu değerler ile C# uygulamasındaki metod çağrılıyor. 

SignalRCpp.exe: number : 25  mesaj : huhu   girilince, C# metodu bu parametreler ile çağrıldı ve gelen mesajı ekrana yazdı:

Method1 called from remote  name: ibrahim message: huhu

ConsoleApp1.exe tarafından gönderilen cevap mesajı ise C++ uygulamasında ekrana yazdırıldı: 

server  wrote: x = 25 


Eğer mesaj olarak karekok ya da kare girildiyse int x değeri güncellenip gönderiliyor, aksi halde gönderilen int x değeri değişmeden geri geliyor.





Hiç yorum yok:

Yorum Gönder