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 = " << 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
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