Saya akhirnya menemukan ini. Inilah yang saya pelajari sejak memulai pertanyaan ini:
Latar belakang: Kami sedang membangun aplikasi iOS menggunakan Xamarin / Monotouch dan klien .NET SignalR 2.0.3. Kami menggunakan protokol SignalR default - dan tampaknya menggunakan SSE, bukan soket web. Saya belum yakin apakah mungkin menggunakan soket web dengan Xamarin / Monotouch. Semuanya dihosting menggunakan situs web Azure.
Kami membutuhkan aplikasi untuk terhubung kembali ke server SignalR kami dengan cepat, tetapi kami terus mengalami masalah di mana koneksi tidak terhubung kembali dengan sendirinya - atau menghubungkan kembali membutuhkan waktu tepat 30 detik (karena waktu tunggu protokol yang mendasarinya).
Ada tiga skenario yang akhirnya kami uji:
Skenario A - menghubungkan pertama kali aplikasi dimuat. Ini bekerja dengan sempurna sejak hari pertama. Koneksi selesai dalam waktu kurang dari 0,25 detik bahkan melalui koneksi seluler 3G. (dengan asumsi radio sudah menyala)
Skenario B - menyambungkan kembali ke server SignalR setelah aplikasi menganggur / ditutup selama 30 detik. Dalam skenario ini, klien SignalR pada akhirnya akan menyambung kembali ke server sendiri tanpa pekerjaan khusus - tetapi tampaknya menunggu tepat 30 detik sebelum mencoba menyambung kembali. (terlalu lambat untuk aplikasi kita)
Selama masa tunggu 30 detik ini, kami mencoba memanggil HubConnection.Start () yang tidak berpengaruh. Dan memanggil HubConnection.Stop () juga membutuhkan waktu 30 detik. Saya menemukan bug terkait di situs SignalR yang tampaknya telah diselesaikan , tetapi kami masih mengalami masalah yang sama di v2.0.3.
Skenario C - menghubungkan kembali ke server SignalR setelah aplikasi menganggur / ditutup selama 120 detik atau lebih. Dalam skenario ini, protokol transport SignalR telah habis waktunya sehingga klien tidak pernah terhubung kembali secara otomatis. Ini menjelaskan mengapa klien terkadang tetapi tidak selalu menyambung kembali sendiri. Kabar baiknya adalah, memanggil HubConnection.Start () berfungsi hampir secara instan seperti skenario A.
Jadi, perlu beberapa saat bagi saya untuk menyadari bahwa kondisi penyambungan kembali berbeda berdasarkan apakah aplikasi ditutup selama 30 detik vs 120+ detik. Dan meskipun log pelacakan SignalR menerangi apa yang terjadi dengan protokol yang mendasarinya, saya tidak percaya ada cara untuk menangani peristiwa tingkat pengangkutan dalam kode. (Peristiwa Closed () menyala setelah 30 detik dalam skenario B, langsung dalam skenario C; properti Negara menyatakan "Tersambung" selama periode tunggu penghubung kembali ini; tidak ada peristiwa atau metode relevan lainnya)
Solusi:
Solusinya jelas. Kami tidak menunggu SignalR melakukan keajaiban penyambungan kembali. Sebaliknya, ketika aplikasi diaktifkan atau ketika koneksi jaringan ponsel dipulihkan, kami hanya membersihkan acara dan membatalkan referensi HubConnection (tidak dapat membuangnya karena membutuhkan waktu 30 detik, semoga pengumpulan sampah akan menanganinya ) dan membuat instance baru. Sekarang semuanya bekerja dengan baik. Untuk beberapa alasan, saya pikir kita harus menggunakan kembali koneksi yang ada dan menghubungkan kembali daripada hanya membuat contoh baru.
Menyetel pengatur waktu pada peristiwa terputus untuk secara otomatis mencoba menyambungkan kembali adalah satu-satunya metode yang saya ketahui.
Dalam javascript dilakukan seperti ini:
$.connection.hub.disconnected(function() { setTimeout(function() { $.connection.hub.start(); }, 5000); // Restart connection after 5 seconds. });
Ini adalah pendekatan yang direkomendasikan dalam dokumentasi:
sumber
reconnecting
acara, yang dijalankan setelah hub kehilangan koneksi dan mengatur variabel itu (misalnyashouldReconnect
) ke true. Jadi saya mengadaptasi contoh Anda untuk memeriksa variabel itu. Ini terlihat bagus.Sejak OP meminta klien .NET (implementasi winform di bawah),
private async Task<bool> ConnectToSignalRServer() { bool connected = false; try { Connection = new HubConnection("server url"); Hub = Connection.CreateHubProxy("MyHub"); await Connection.Start(); //See @Oran Dennison's comment on @KingOfHypocrites's answer if (Connection.State == ConnectionState.Connected) { connected = true; Connection.Closed += Connection_Closed; } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } return connected; } private async void Connection_Closed() { // A global variable being set in "Form_closing" event // of Form, check if form not closed explicitly to prevent a possible deadlock. if(!IsFormClosed) { // specify a retry duration TimeSpan retryDuration = TimeSpan.FromSeconds(30); DateTime retryTill = DateTime.UtcNow.Add(retryDuration); while (DateTime.UtcNow < retryTill) { bool connected = await ConnectToSignalRServer(); if (connected) return; } Console.WriteLine("Connection closed") } }
sumber
Saya menambahkan beberapa pembaruan untuk jawaban ibubi . Mungkin seseorang membutuhkannya. Saya menemukan bahwa dalam beberapa kasus signalr tidak naik acara "tertutup" setelah menghubungkan kembali dihentikan. Saya menyelesaikannya menggunakan acara "StateChanged". Metode yang terhubung ke server SignalR:
private async Task<bool> ConnectToSignalRServer() { bool connected = false; try { var connection = new HubConnection(ConnectionUrl); var proxy = connection.CreateHubProxy("CurrentData"); await connection.Start(); if (connection.State == ConnectionState.Connected) { await proxy.Invoke("ConnectStation"); connection.Error += (ex) => { Console.WriteLine("Connection error: " + ex.ToString()); }; connection.Closed += () => { Console.WriteLine("Connection closed"); }; connection.StateChanged += Connection_StateChanged; Console.WriteLine("Server for Current is started."); connected = true; } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } return connected; }
Metode untuk menghubungkan kembali:
private async void Connection_StateChanged(StateChange obj) { if (obj.NewState == ConnectionState.Disconnected) { await RestartConnection(); } }
Metode upaya tanpa henti untuk terhubung ke server (Juga saya menggunakan metode ini untuk membuat koneksi tinju):
public async Task RestartConnection() { while (!ApplicationClosed) { bool connected = await ConnectToSignalRServer(); if (connected) return; } }
sumber
Anda dapat mencoba memanggil metode server dari android Anda sebelum status koneksi ulang mulai untuk mencegah masalah koneksi ulang sihir.
SignalR Hub C #
public class MyHub : Hub { public void Ping() { //ping for android long polling } }
Di Android
private final int PING_INTERVAL = 10 * 1000; private boolean isConnected = false; private HubConnection connection; private ClientTransport transport; private HubProxy hubProxy; private Handler handler = new Handler(); private Runnable ping = new Runnable() { @Override public void run() { if (isConnected) { hubProxy.invoke("ping"); handler.postDelayed(ping, PING_INTERVAL); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); System.setProperty("http.keepAlive", "false"); ..... ..... connection.connected(new Runnable() { @Override public void run() { System.out.println("Connected"); handler.postDelayed(ping, PING_INTERVAL); }); }
sumber