Похоже, есть несколько похожих вопросов, но через несколько дней я не нахожу правильного ответа. Мой вопрос в том, как узнать, закрыл ли сервер веб-узел, и как попытаться восстановить соединение. Я видел несколько примеров, но ни один из них не работал должным образом, когда я хотел реализовать функциональность закрытия веб-сокета от клиента при изменении представления.
Затем я нашел этот пример, лучший из тех, что я видел до сих пор, и с небольшими изменениями я смог добавить функцию закрытия, которая работает довольно хорошо.
Закрытие веб-сокета от клиента больше не проблема, однако я не могу знать, когда веб-сокет закрыт сервером и как снова переподключить.
Мой код очень похож на вопрос это, но я прошу другое. Кроме того, у меня были проблемы с повторным использованием веб-сокета, пока я не увидел функцию общего доступа, о которой они говорят в указанной мной ссылке, поэтому в опубликованном мною классе служба веб-сокета и служба, которая использовала службу веб-сокета, объединены в один
Моя служба веб-сокетов
import { Injectable } from '@angular/core';
import { Observable, Observer, Subscription } from 'rxjs';
import { Subject } from 'rxjs/Subject';
import { ConfigService } from "../config.service";
@Injectable()
export class WSEtatMachineService {
public messages: Subject<any> = new Subject<any>();
private url: string = '';
static readonly ID = 'machine';
private _subject: Subject<MessageEvent>;
private _subjectData: Subject<number>;
private _ws: any;
constructor(private configService: ConfigService) {
console.info('constructyor ws machine service')
this.setUrl(WSEtatMachineService.ID)
}
public setUrl(id:string) {
const host = this.configService.getConfigReseau().ipServer;
const port = this.configService.getConfigReseau().portServer;
this.url = `ws://${host}:${port}/` + id
}
public connect() {
console.info('connect ws machine service ', this.url)
this.messages = <Subject<any>>this._connect(this.url)
.map((response: any): any => {
console.info('ws etat machine service: ', response)
return JSON.parse(response.data);
})
}
public close() {
console.info('on closing WS');
this._ws.close()
this._subject = null
}
public send(msg: any) {
this.messages.next(JSON.stringify(msg));
}
// Private methods to create the websocket
public _connect(url: string): Subject<MessageEvent> {
if (!this._subject) {
this._subject = this._create(url);
}
return this._subject;
}
private _create(url: string): Subject<MessageEvent> {
this._ws = new WebSocket(url);
let observable = Observable.create(
(obs: Observer<MessageEvent>) => {
this._ws.onmessage = obs.next.bind(obs);
this._ws.onerror = obs.error.bind(obs);
this._ws.onclose = obs.complete.bind(obs);
return this._ws.close.bind(this._ws);
}).share();
let observer = {
next: (data: Object) => {
if (this._ws.readyState === WebSocket.OPEN) {
this._ws.send(JSON.stringify(data));
}
}
};
return Subject.create(observer, observable);
}
} // end class
Затем в компоненте я делаю:
constructor( private wsMachineService: WSMachineService) { ... }
ngOnInit() {
...
this.wsMachineService.connect();
// connexion du web socket
this.wsMachineService.messages.subscribe(
machine => {
console.info(" wsMachineService open and alive", machine);
},
err => {
// This code is never executed
console.info(" wsMachineService closed by server!!", err);
}
);
}
ngOnDestroy() {
//let tmp = this.synoptiqueSocketSubscription.unsubscribe();
this.wsMachineService.messages.unsubscribe();
this.wsMachineService.close()
}
Думаю, мне что-то не хватает в функции _create, потому что я пытаюсь уловить тему функции подключения, но она не работает.
Есть идеи, как я могу узнать, закрывается ли он, и попытаться снова подключиться?
Спасибо
Редактировать: Я думаю, что моя проблема связана с предметом / наблюдаемыми, поскольку я не контролирую их полностью. У меня был старый подход, когда я мог знать, когда сервер был мертв, и он пытался повторно подключиться каждые X секунд, но, к сожалению, я не смог закрыть соединение от клиента, так как у меня не было доступа к объекту websocket. Я тоже добавляю код:
public messages: Observable<any>;
private ws: Subject<any>;
private url: string;
public onclose = new Subject();
public connect(urlApiWebSocket: string): Observable<any> {
if (this.messages && this.url === urlApiWebSocket) {
return this.messages;
}
this.url = urlApiWebSocket;
this.ws = Observable.webSocket({
url: urlApiWebSocket,
closeObserver: this.onclose
});
return this.messages = this.ws.retryWhen(errors => errors.delay(10000)).map(msg => msg).share();
}
send(msg: any) {
this.ws.next(JSON.stringify(msg));
}
Посмотрим, сможем ли мы объединить оба решения.





У вас нет никакого способа узнать, когда сервер закрывает соединение с клиентом.
Как вы уже заметили, this._ws.onclose = obs.complete.bind(obs); сработает только тогда, когда клиент выполнит действие «закрыть».
Обычный способ поиграть:
В вашем примере вы не можете сделать this.ws.unsubscribe (); заставить Observable закрыть соединение от клиента?
Если вы говорите о первом подходе, который я использовал, когда я отказывался от подписки, иногда он закрывал соединение, а иногда нет. С новым делаю закрытие работает всегда
Что ж, я нашел способ. Я использую старый подход с Observable.websocket
@Injectable()
export class WSMyService {
private url: string = '';
static readonly ID = 'mytestwebsocket';
readonly reload_time = 3000;
public messages: Observable<any>;
private ws: Subject<any>;
public onclose = new Subject();
constructor(private configService: ConfigService) {
console.info('constructor ws synop service')
this.setUrl(WSActionFrontService.ID)
}
public setUrl(id:string) {
...
this.url = `ws://${host}:${port}/` + id
}
public connect(): Observable<any> {
this.ws = Observable.webSocket({
url: this.url,
closeObserver: this.onclose
});
return this.messages = this.ws.retryWhen(errors => errors.delay(this.reload_time)).map(msg => msg).share();
}
send(msg: any) {
this.ws.next(JSON.stringify(msg));
}
public close() {
console.info('on closing WS');
this.ws.complete();
}
и когда я его использую:
constructor(
private wsMyService: WSMyService,
ngOnInit():
...
this.mySocketSubscription = this.wsMyService.connect().subscribe(message => {
... }
this.wsMyService.onclose.subscribe(evt => {
// the server has closed the connection
})
ngOnDestroy() {
this.wsMyService.close();
this.mySocketSubscription.unsubscribe();
...
}
Похоже, все, что мне нужно было сделать, это вызвать функцию complete (), которая сообщает серверу, что клиент завершил работу. Я уверен, что есть способ получше, но это единственный способ, который мне подходит.
Спасибо за помощь.
Привет, спасибо, что ответили. Раньше у меня был код вроде этого
this.ws = Observable.webSocket({ url: myUrl, closeObserver: this.onclose }); return this.messages = this.ws.retryWhen(errors => errors.delay(10000)).map(msg => msg).share();, и я мог знать, когда сервер был мертв, и когда ws пытался повторно подключиться, пока он не стал доступным. Однако при таком подходе я не мог получить доступ к самому ws (он использует наблюдаемый веб-сокет), поэтому я не мог закрыть его от клиента. Я думаю, что моя проблема связана с наблюдаемым и предметом, но я этого не вижу.