Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Tworzenie środowiska w czasie rzeczywistym, takiego jak funkcja współtworzenia w programie Microsoft Word , może być trudne.
Dzięki łatwym w użyciu interfejsom API Socket.IO okazała się biblioteką komunikacji w czasie rzeczywistym między klientami a serwerem. Jednak Socket.IO użytkownicy często zgłaszają trudności ze skalowaniem połączeń Socket.IO. Dzięki usłudze Web PubSub dla Socket.IO deweloperzy nie muszą już martwić się o zarządzanie połączeniami trwałymi.
Ważne
Nieprzetworzone parametry połączenia są wyświetlane tylko w tym artykule w celach demonstracyjnych.
parametry połączenia zawiera informacje autoryzacyjne potrzebne Twojej aplikacji, aby uzyskać dostęp do usługi Azure Web PubSub. Klucz dostępu w parametry połączenia działa jak hasło root dla Twojej usługi. W środowiskach produkcyjnych zawsze chroń klucze dostępu. Użyj usługi Azure Key Vault, aby bezpiecznie zarządzać kluczami i obracać je oraz zabezpieczać połączenie za pomocą usługi WebPubSubServiceClient.
Unikaj dystrybuowania kluczy dostępu do innych użytkowników, kodowania ich lub zapisywania ich w dowolnym miejscu w postaci zwykłego tekstu, który jest dostępny dla innych użytkowników. Obracanie kluczy, jeśli uważasz, że mogły one zostać naruszone.
Omówienie
W tym artykule pokazano, jak zbudować aplikację, która umożliwia programiście transmitowanie na żywo swojej pracy programistycznej do publiczności. Tworzysz tę aplikację przy użyciu:
- Edytor Monaco, edytor kodu, który obsługuje program Visual Studio Code.
- Express— platforma internetowa Node.js.
- Interfejsy API udostępniane przez bibliotekę Socket.IO, służące do komunikacji w czasie rzeczywistym.
- Hostowanie połączeń Socket.IO korzystających z usługi Web PubSub na potrzeby Socket.IO.
Zakończona aplikacja
Gotowa aplikacja umożliwia użytkownikowi edytora kodu udostępnianie linku internetowego, za pomocą którego użytkownicy mogą obserwować wpisywanie.
Aby procedury były zwięzłe i łatwe do przyswojenia w około 15 minut, w tym artykule zdefiniowano dwie role użytkownika oraz to, co mogą one robić w edytorze:
- Autor, który może pisać w edytorze online, a treść jest przesyłana strumieniowo
- Przeglądający, którzy otrzymują w czasie rzeczywistym treść wpisywaną przez autora i nie mogą jej edytować
Architektura
| Towar | Cel | Świadczenia |
|---|---|---|
| biblioteka Socket.IO | Zapewnia mechanizm wymiany danych dwukierunkowych o małych opóźnieniach między aplikacją zaplecza a klientami | Łatwe w użyciu interfejsy API, które obejmują większość scenariuszy komunikacji w czasie rzeczywistym |
| Web PubSub dla Socket.IO | Hostuje połączenia trwałe protokołu WebSocket lub oparte na sondach z klientami Socket.IO | Obsługa 100 000 połączeń współbieżnych; uproszczona architektura aplikacji |
Wymagania wstępne
Aby wykonać wszystkie kroki opisane w tym artykule, potrzebne są następujące elementy:
- Konto platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto platformy Azure.
- Interfejs Azure CLI (wersja 2.29.0 lub nowsza) lub Azure Cloud Shell do zarządzania zasobami platformy Azure.
- Podstawowa znajomość interfejsów API Socket.IO.
Tworzenie usługi Web PubSub dla zasobu Socket.IO
Użyj interfejsu wiersza polecenia platformy Azure, aby utworzyć zasób:
az webpubsub create -n <resource-name> \
-l <resource-location> \
-g <resource-group> \
--kind SocketIO \
--sku Free_F1
Pobierz ciąg połączenia
Parametr połączenia umożliwia połączenie z usługą Web PubSub przy użyciu Socket.IO.
Uruchom następujące polecenia. Zachowaj gdzieś zwrócony ciąg połączenia, ponieważ będzie potrzebny później w tym artykule, gdy uruchomisz aplikację.
az webpubsub key show -n <resource-name> \
-g <resource-group> \
--query primaryKey \
-o tsv
Pisanie kodu po stronie serwera aplikacji
Zacznij pisać kod aplikacji, pracując po stronie serwera.
Tworzenie serwera HTTP
Utwórz projekt Node.js:
mkdir codestream cd codestream npm initZainstaluj zestaw SDK serwera i platformę Express:
npm install @azure/web-pubsub-socket.io npm install expressZaimportuj wymagane pakiety i utwórz serwer HTTP do obsługi plików statycznych:
/*server.js*/ // Import required packages const express = require('express'); const path = require('path'); // Create an HTTP server based on Express const app = express(); const server = require('http').createServer(app); app.use(express.static(path.join(__dirname, 'public')));Zdefiniuj punkt końcowy o nazwie
/negotiate. Klient modułu zapisywania najpierw osiąga ten punkt końcowy. Ten punkt końcowy zwraca odpowiedź HTTP. Odpowiedź zawiera punkt końcowy, którego klient powinien użyć do nawiązania trwałego połączenia. Zwraca również wartość przypisanąroomprzez klienta./*server.js*/ app.get('/negotiate', async (req, res) => { res.json({ url: endpoint room_id: Math.random().toString(36).slice(2, 7), }); }); // Make the Socket.IO server listen on port 3000 io.httpServer.listen(3000, () => { console.log('Visit http://localhost:%d', 3000); });
Tworzenie usługi Web PubSub dla serwera Socket.IO
Zaimportuj usługę Web PubSub dla zestawu SDK Socket.IO i zdefiniuj opcje:
Nieprzetworzone parametry połączenia są wyświetlane tylko w tym artykule w celach demonstracyjnych. W środowiskach produkcyjnych zawsze chroń klucze dostępu. Użyj usługi Azure Key Vault, aby bezpiecznie zarządzać kluczami i obracać je oraz zabezpieczać połączenie za pomocą usługi
WebPubSubServiceClient./*server.js*/ const { useAzureSocketIO } = require("@azure/web-pubsub-socket.io"); const wpsOptions = { hub: "codestream", connectionString: process.argv[2] }Utwórz web pubSub dla serwera Socket.IO:
/*server.js*/ const io = require("socket.io")(); useAzureSocketIO(io, wpsOptions);
Te dwa kroki różnią się nieco od sposobu tworzenia serwera Socket.IO zgodnie z opisem w tej dokumentacji Socket.IO. Dzięki tym dwóm krokom kod po stronie serwera może przenieść zarządzanie połączeniami stałymi do usługi platformy Azure. Za pomocą usługi platformy Azure serwer aplikacji działa tylko jako lekki serwer HTTP.
Implementowanie logiki biznesowej
Po utworzeniu serwera Socket.IO hostowanego przez usługę Web PubSub można zdefiniować sposób komunikowania się klientów i serwerów przy użyciu interfejsów API Socket.IO. Ten proces jest nazywany implementowanie logiki biznesowej.
Po nawiązaniu połączenia klient aplikacji informuje klienta, że jest zalogowany, wysyłając zdarzenie niestandardowe o nazwie
login./*server.js*/ io.on('connection', socket => { socket.emit("login"); });Każdy klient emituje dwa zdarzenia, na które serwer może reagować:
joinRoomisendToRoom. Gdy serwer otrzyma wartośćroom_id, do którego klient chce dołączyć, użyj metodysocket.joinz interfejsu API Socket.IO, aby dodać docelowego klienta do określonego pokoju./*server.js*/ socket.on('joinRoom', async (message) => { const room_id = message["room_id"]; await socket.join(room_id); });Po dołączeniu klienta serwer informuje klienta o pomyślnym wyniku, wysyłając
messagezdarzenie. Gdy klient otrzymuje zdarzeniemessagetypuackJoinRoom, może poprosić serwer o przesłanie najnowszego stanu edytora./*server.js*/ socket.on('joinRoom', async (message) => { // ... socket.emit("message", { type: "ackJoinRoom", success: true }) });/*client.js*/ socket.on("message", (message) => { let data = message; if (data.type === 'ackJoinRoom' && data.success) { sendToRoom(socket, `${room_id}-control`, { data: 'sync'}); } // ... });Gdy klient wysyła zdarzenie
sendToRoomdo serwera, serwer rozsyła do wskazanego pokoju zmiany stanu edytora kodu. Wszyscy klienci w tym pokoju mogą teraz otrzymywać najnowsze aktualizacje.socket.on('sendToRoom', (message) => { const room_id = message["room_id"] const data = message["data"] socket.broadcast.to(room_id).emit("message", { type: "editorMessage", data: data }); });
Napisz kod aplikacji po stronie klienta
Po zakończeniu procedur po stronie serwera można pracować po stronie klienta.
Konfiguracja początkowa
Aby komunikować się z serwerem, należy utworzyć klienta Socket.IO. Pytanie brzmi, z którym serwerem klient powinien nawiązać trwałe połączenie. Ponieważ używasz usługi Web PubSub dla Socket.IO, serwer jest usługą platformy Azure. Pamiętaj, że zdefiniowano przez Ciebie trasę /negotiate, aby udostępniać klientom punkt końcowy usługi Web PubSub dla Socket.IO.
/*client.js*/
async function initialize(url) {
let data = await fetch(url).json()
updateStreamId(data.room_id);
let editor = createEditor(...); // Create an editor component
var socket = io(data.url, {
path: "/clients/socketio/hubs/codestream",
});
return [socket, editor, data.room_id];
}
Funkcja initialize(url) organizuje kilka operacji konfiguracji razem:
- Pobiera punkt końcowy usługi platformy Azure z serwera HTTP
- Tworzy instancję edytora Monaco
- Ustanawia trwałe połączenie z usługą Web PubSub dla Socket.IO
Klient modułu zapisywania
Jak wspomniano wcześniej, masz po stronie klienta dwie role użytkownika: edytor i przeglądający. Wszystko, co wpisuje autor, jest przesyłane strumieniowo na ekran odbiorcy.
Pobierz punkt końcowy usługi Web PubSub dla Socket.IO oraz wartość
room_id:/*client.js*/ let [socket, editor, room_id] = await initialize('/negotiate');Gdy klient zapisujący jest połączony z serwerem, serwer wysyła do niego zdarzenie
login. Moduł zapisujący może odpowiedzieć, prosząc serwer o dołączenie do określonego pokoju. Co 200 ms klient edytora wysyła do pokoju najnowszy stan edytora. Funkcja o nazwieflushorganizuje logikę wysyłania./*client.js*/ socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); setInterval(() => flush(), 200); // Update editor content // ... });Jeśli program zapisujący nie wprowadzi żadnych zmian,
flush()nic nie robi i po prostu kończy działanie. W przeciwnym razie zmiany stanu edytora są wysyłane do pokoju./*client.js*/ function flush() { // No changes from editor need to be flushed if (changes.length === 0) return; // Broadcast the changes made to editor content sendToRoom(socket, room_id, { type: 'delta', changes: changes version: version++, }); changes = []; content = editor.getValue(); }Po nawiązaniu połączenia nowego klienta przeglądarki przeglądarka musi uzyskać najnowszy pełny stan edytora. Aby to osiągnąć, do klienta zapisującego wysyłany jest komunikat zawierający dane
sync. Komunikat prosi klienta modułu zapisywania o wysłanie pełnego stanu edytora./*client.js*/ socket.on("message", (message) => { let data = message.data; if (data.data === 'sync') { // Broadcast the full content of the editor to the room sendToRoom(socket, room_id, { type: 'full', content: content version: version, }); } });
Klient przeglądarki
Podobnie jak klient zapisujący, klient wyświetlający tworzy swojego klienta Socket.IO za pośrednictwem
initialize(). Gdy klient wyświetlający jest połączony i otrzymuje z serwera zdarzenielogin, prosi serwer o dołączenie go do określonego pokoju. Zapytanieroom_idokreśla pomieszczenie./*client.js*/ let [socket, editor] = await initialize(`/register?room_id=${room_id}`) socket.on("login", () => { updateStatus('Connected'); joinRoom(socket, `${room_id}`); });Gdy klient wyświetlający odbiera z serwera zdarzenie
message, a typ danych toackJoinRoom, prosi klienta edytującego w danym pokoju o przesłanie pełnego stanu edytora./*client.js*/ socket.on("message", (message) => { let data = message; // Ensures the viewer client is connected if (data.type === 'ackJoinRoom' && data.success) { sendToRoom(socket, `${id}`, { data: 'sync'}); } else //... });Jeśli typ danych to
editorMessage, klient przeglądarki aktualizuje edytor zgodnie z rzeczywistą zawartością./*client.js*/ socket.on("message", (message) => { ... else if (data.type === 'editorMessage') { switch (data.data.type) { case 'delta': // ... Let editor component update its status break; case 'full': // ... Let editor component update its status break; } } });Zaimplementuj
joinRoom()isendToRoom(), korzystając z interfejsów API Socket.IO:/*client.js*/ function joinRoom(socket, room_id) { socket.emit("joinRoom", { room_id: room_id, }); } function sendToRoom(socket, room_id, data) { socket.emit("sendToRoom", { room_id: room_id, data: data }); }
Uruchamianie aplikacji
Znajdź repozytorium
W poprzednich sekcjach omówiono główną logikę związaną z synchronizowaniem stanu edytora między użytkownikami przeglądającymi a użytkownikiem edytującym. Pełny kod można znaleźć w repozytorium przykładów.
Sklonuj repozytorium
Możesz sklonować repozytorium i uruchomić polecenie npm install, aby zainstalować zależności projektu.
Uruchamianie serwera
node server.js <web-pubsub-connection-string>
To są parametry połączenia, które otrzymano we wcześniejszym kroku.
Wypróbuj edytor kodu w czasie rzeczywistym
Otwórz http://localhost:3000 w karcie przeglądarki. Otwórz inną kartę z adresem URL wyświetlanym na pierwszej stronie.
Jeśli piszesz kod w pierwszej karcie, powinieneś widzieć w drugiej karcie w czasie rzeczywistym to, co wpisujesz. Usługa Web PubSub dla Socket.IO ułatwia przekazywanie komunikatów w chmurze. Serwer express obsługuje tylko plik statyczny index.html i /negotiate punkt końcowy.