Przejdź do treści stopki
POMOC .NET

C# WebRTC (jak to działa dla programistów)

WebRTC to skrót od Web Real-Time Communication, czyli technologii umożliwiającej bezpośrednią komunikację w czasie rzeczywistym między przeglądarkami internetowymi a innymi platformami bez konieczności korzystania z serwerów pośredniczących w transferze danych, z wyjątkiem początkowego nawiązania połączenia. Obsługuje ona przesyłanie obrazu, dźwięku i danych ogólnych między użytkownikami, co czyni ją potężnym narzędziem do tworzenia aplikacji do komunikacji w czasie rzeczywistym.

W tym samouczku przedstawiono sposób tworzenia rozwiązania WebRTC przy użyciu języka C#, ze szczególnym uwzględnieniem platformy .NET Core, a także omówiono konfigurację serwera sygnalizacyjnego, działanie serwerów TURN oraz integrację WebRTC z aplikacjami IronPDF napisanymi w języku C#.

Konfiguracja środowiska

Aby rozpocząć tworzenie aplikacji WebRTC w języku C#, należy skonfigurować środowisko programistyczne. Wymaga to zainstalowania .NET Core, czyli wieloplatformowej wersji .NET do tworzenia stron internetowych, usług i aplikacji konsolowych. Możesz pobrać i zainstalować .NET Core z oficjalnej strony Microsoftu. Po zainstalowaniu możesz używać Visual Studio, popularnego zintegrowanego środowiska programistycznego (IDE) do tworzenia w C#, albo dowolnego innego edytora, żeby pisać swój kod.

Tworzenie nowej aplikacji konsolowej

Zacznij od utworzenia nowego projektu aplikacji konsolowej. Otwórz terminal lub interfejs wiersza poleceń i przejdź do katalogu, w którym planujesz utworzyć swój projekt. Następnie wykonaj poniższe polecenie:

dotnet new console -n WebRTCSample
dotnet new console -n WebRTCSample
SHELL

To polecenie tworzy nowy katalog o nazwie WebRTCSample z prostą aplikacją konsolową "Hello World". Przejdź do katalogu projektu i możesz rozpocząć pisanie kodu aplikacji WebRTC.

Zrozumienie WebRTC i sygnalizacji

WebRTC umożliwia komunikację w czasie rzeczywistym, ale wymaga mechanizmu koordynującego komunikację i wysyłającego komunikaty sterujące, czyli procesu znanego jako sygnalizacja. Sygnalizacja służy do wymiany metadanych dotyczących sesji komunikacyjnej, takich jak opisy sesji i informacje o kandydatach do nawiązania połączenia. Aplikacje napisane w języku C# mogą realizować sygnalizację za pośrednictwem dowolnego mechanizmu transportu komunikatów, takiego jak WebSockets lub interfejsy API REST.

Wdrażanie serwera sygnalizacyjnego w .NET Core

Serwer sygnalizacyjny pełni rolę pośrednika w wymianie komunikatów między węzłami przed nawiązaniem bezpośredniego połączenia peer-to-peer. Możesz zaimplementować serwer sygnalizacyjny przy użyciu .NET Core, tworząc prostą aplikację internetową obsługującą połączenia WebSocket.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class Startup
{
    // Configures services for the web application.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options => options.AddDefaultPolicy(
            builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));
        services.AddSignalR();
    }

    // Configures the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseCors();
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<SignalingHub>("/signal");
        });
    }
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public class Startup
{
    // Configures services for the web application.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options => options.AddDefaultPolicy(
            builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));
        services.AddSignalR();
    }

    // Configures the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseCors();
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<SignalingHub>("/signal");
        });
    }
}
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Hosting

Public Class Startup
	' Configures services for the web application.
	Public Sub ConfigureServices(ByVal services As IServiceCollection)
		services.AddCors(Function(options) options.AddDefaultPolicy(Function(builder) builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()))
		services.AddSignalR()
	End Sub

	' Configures the HTTP request pipeline.
	Public Sub Configure(ByVal app As IApplicationBuilder, ByVal env As IWebHostEnvironment)
		If env.IsDevelopment() Then
			app.UseDeveloperExceptionPage()
		End If
		app.UseCors()
		app.UseRouting()
		app.UseEndpoints(Sub(endpoints)
			endpoints.MapHub(Of SignalingHub)("/signal")
		End Sub)
	End Sub
End Class
$vbLabelText   $csharpLabel

Ten fragment kodu konfiguruje podstawową aplikację .NET Core z wykorzystaniem SignalR, biblioteki służącej do dodawania funkcji internetowych działających w czasie rzeczywistym do aplikacji. SignalR upraszcza proces dodawania funkcji internetowych działających w czasie rzeczywistym do aplikacji, co czyni go dobrym wyborem dla naszego serwera sygnalizacyjnego.

Łączenie użytkowników za pomocą WebRTC

Po skonfigurowaniu serwera sygnalizacyjnego następnym krokiem jest nawiązanie połączenia peer-to-peer między klientami przy użyciu WebRTC. Obejmuje to tworzenie obiektów RTCPeerConnection na każdym kliencie, wymianę komunikatów ofert i odpowiedzi oraz negocjowanie szczegółów połączenia.

Tworzenie połączenia równorzędnego

W aplikacji napisanej w języku C# będziesz przede wszystkim zarządzać częścią sygnalizacyjną i ewentualnie współpracować z interfejsami API WebRTC za pośrednictwem przeglądarki lub innych platform, takich jak React Native dla aplikacji mobilnych. Poniżej znajduje się przykład zainicjowania połączenia peer-to-peer z klienta internetowego:

// Create a new RTCPeerConnection instance
const peerConnection = new RTCPeerConnection();

// Listen for ICE candidates and send them to the signaling server
peerConnection.onicecandidate = event => {
  if (event.candidate) {
    sendMessage('new-ice-candidate', event.candidate);
  }
};

// Handle incoming media streams
peerConnection.ontrack = event => {
  // Display the video or audio stream
};
// Create a new RTCPeerConnection instance
const peerConnection = new RTCPeerConnection();

// Listen for ICE candidates and send them to the signaling server
peerConnection.onicecandidate = event => {
  if (event.candidate) {
    sendMessage('new-ice-candidate', event.candidate);
  }
};

// Handle incoming media streams
peerConnection.ontrack = event => {
  // Display the video or audio stream
};
JAVASCRIPT

Ten fragment kodu JavaScript pokazuje tworzenie nowego połączenia peer-to-peer, obsługę kandydatów ICE oraz konfigurację wywołania zwrotnego w celu wyświetlania przychodzących strumieni multimedialnych.

Wymiana ofert i odpowiedzi

Aby nawiązać połączenie, jeden z uczestników tworzy ofertę, a drugi odpowiada na nią. Są one wymieniane za pośrednictwem wdrożonego wcześniej serwera sygnalizacyjnego.

// Create an offer for the peer connection
async function createOffer() {
  const offer = await peerConnection.createOffer();
  await peerConnection.setLocalDescription(offer);
  sendMessage('offer', offer);
}

// Create an answer after receiving an offer
async function createAnswer(offer) {
  await peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
  const answer = await peerConnection.createAnswer();
  await peerConnection.setLocalDescription(answer);
  sendMessage('answer', answer);
}
// Create an offer for the peer connection
async function createOffer() {
  const offer = await peerConnection.createOffer();
  await peerConnection.setLocalDescription(offer);
  sendMessage('offer', offer);
}

// Create an answer after receiving an offer
async function createAnswer(offer) {
  await peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
  const answer = await peerConnection.createAnswer();
  await peerConnection.setLocalDescription(answer);
  sendMessage('answer', answer);
}
JAVASCRIPT

Integracja WebRTC z aplikacjami .NET

Podczas gdy podstawowa implementacja WebRTC jest zazwyczaj obsługiwana w przeglądarce lub innych środowiskach po stronie klienta, aplikacje .NET mogą ułatwiać proces sygnalizacji, zarządzać kontrolą sesji oraz współpracować z innymi usługami, takimi jak serwery TURN, w celu pokonywania ograniczeń NAT. W przypadku aplikacji desktopowych lub serwerowych biblioteki takie jak Pion WebRTC (biblioteka open source dla języka Go) mogą być opakowane lub używane w połączeniu z językiem C# do obsługi ruchu WebRTC.

Uruchamianie aplikacji

Aby uruchomić aplikację .NET Core, przejdź do katalogu projektu w terminalu i wykonaj:

dotnet run
dotnet run
SHELL

To polecenie kompiluje i uruchamia aplikację, uruchamiając zaimplementowany serwer sygnalizacyjny. Twoi klienci internetowi mogą teraz połączyć się z tym serwerem, aby rozpocząć wymianę komunikatów sygnalizacyjnych.

Wprowadzenie do IronPDF

C# WebRTC (jak to działa dla programistów): Rysunek 1 – strona internetowa IronPDF

IronPDF to wszechstronna biblioteka, która zapewnia aplikacjom .NET możliwości generowania i manipulowania plikami PDF, umożliwiając programistom tworzenie, odczytywanie i edytowanie dokumentów PDF za pomocą kodu. IronPDF obsługuje szereg zadań, w tym generowanie plików PDF z HTML, wypełnianie formularzy, wyodrębnianie tekstu i zabezpieczanie dokumentów. Dzięki temu jest niezwykle przydatne do generowania raportów, faktur i dokumentów dynamicznych na podstawie danych użytkownika lub wyników aplikacji.

Kluczową funkcją IronPDF jest możliwość konwersji HTML do PDF z zachowaniem układów i stylów. Generuje pliki PDF na podstawie treści internetowych, dzięki czemu idealnie nadaje się do tworzenia raportów, faktur i dokumentacji. Możesz łatwo konwertować pliki HTML, adresy URL i ciągi znaków HTML do formatu PDF.

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

		' 1. Convert HTML String to PDF
		Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
		Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
		pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")

		' 2. Convert HTML File to PDF
		Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
		Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
		pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
$vbLabelText   $csharpLabel

Instalacja IronPDF

Zanim zaczniesz używać IronPDF w swoim projekcie, musisz dodać go do swojej aplikacji .NET. Można to zrobić za pomocą menedżera pakietów NuGet, który upraszcza proces zarządzania bibliotekami zewnętrznymi w projektach. Aby zainstalować IronPDF, można użyć następującego polecenia w konsoli NuGet Package Manager Console:

Install-Package IronPdf

Przykład zastosowania: Generowanie protokołów spotkań w formacie PDF w aplikacji WebRTC za pomocą IronPDF

Wyobraź sobie, że tworzysz aplikację do komunikacji w czasie rzeczywistym z wykorzystaniem WebRTC, przeznaczoną do spotkań online lub wirtualnych sal lekcyjnych. Ta aplikacja pozwala użytkownikom na prowadzenie rozmów audio i wideo, udostępnianie ekranów oraz współpracę nad dokumentami w czasie rzeczywistym. Cenioną funkcją tej aplikacji byłaby możliwość automatycznego generowania i dystrybucji protokołów spotkań lub podsumowań sesji, zawierających kluczowe omówione kwestie, podjęte decyzje i działania do wykonania, w formacie PDF. W tym miejscu do gry wkracza IronPDF.

Etapy realizacji

  1. Rejestrowanie treści spotkań: Podczas sesji WebRTC rejestrowane są treści tekstowe, takie jak wiadomości czatu, udostępnione notatki lub zaznaczone zadania do wykonania. Treść ta może być sformatowana jako HTML, co pozwala na łatwą stylizację i organizację (np. użycie list dla punktów do wykonania i nagłówków dla kluczowych tematów).
  2. Wygeneruj szablon HTML: Pod koniec sesji zebrana treść jest formatowana do postaci szablonu HTML. Ten szablon zawiera tytuł spotkania, datę, listę uczestników oraz uporządkowane sekcje dla różnych rodzajów treści (punkty dyskusji, decyzje, działania do wykonania).
  3. Konwersja HTML do PDF: Po zakończeniu spotkania i przygotowaniu szablonu HTML używa się IronPDF do konwersji tej treści HTML na dokument PDF. Ta konwersja gwarantuje, że styl i układ zdefiniowane w HTML zostaną zachowane w pliku PDF, dzięki czemu dokument będzie czytelny i będzie miał profesjonalny wygląd.

Oto przykładowy kod w formacie PDF:

using IronPdf;

public class MeetingMinutesGenerator
{
    public static void GenerateMeetingMinutesPdf(string htmlContent, string outputPath)
    {
        // Initialize the HTML to PDF converter
        var renderer = new HtmlToPdf();
        renderer.PrintOptions.MarginTop = 40;
        renderer.PrintOptions.MarginBottom = 40;
        renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
        {
            CenterText = "{pdf-title}",
            DrawDividerLine = true,
            FontSize = 12
        };
        renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
        {
            LeftText = "{date} {time}",
            RightText = "Page {page} of {total-pages}",
            DrawDividerLine = true,
            FontSize = 12
        };
        // Convert the HTML content to a PDF document
        var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
        // Save the PDF document
        pdfDocument.SaveAs(outputPath);
        Console.WriteLine("Meeting minutes PDF generated.");
    }
}
using IronPdf;

public class MeetingMinutesGenerator
{
    public static void GenerateMeetingMinutesPdf(string htmlContent, string outputPath)
    {
        // Initialize the HTML to PDF converter
        var renderer = new HtmlToPdf();
        renderer.PrintOptions.MarginTop = 40;
        renderer.PrintOptions.MarginBottom = 40;
        renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
        {
            CenterText = "{pdf-title}",
            DrawDividerLine = true,
            FontSize = 12
        };
        renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
        {
            LeftText = "{date} {time}",
            RightText = "Page {page} of {total-pages}",
            DrawDividerLine = true,
            FontSize = 12
        };
        // Convert the HTML content to a PDF document
        var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
        // Save the PDF document
        pdfDocument.SaveAs(outputPath);
        Console.WriteLine("Meeting minutes PDF generated.");
    }
}
Imports IronPdf

Public Class MeetingMinutesGenerator
	Public Shared Sub GenerateMeetingMinutesPdf(ByVal htmlContent As String, ByVal outputPath As String)
		' Initialize the HTML to PDF converter
		Dim renderer = New HtmlToPdf()
		renderer.PrintOptions.MarginTop = 40
		renderer.PrintOptions.MarginBottom = 40
		renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter() With {
			.CenterText = "{pdf-title}",
			.DrawDividerLine = True,
			.FontSize = 12
		}
		renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter() With {
			.LeftText = "{date} {time}",
			.RightText = "Page {page} of {total-pages}",
			.DrawDividerLine = True,
			.FontSize = 12
		}
		' Convert the HTML content to a PDF document
		Dim pdfDocument = renderer.RenderHtmlAsPdf(htmlContent)
		' Save the PDF document
		pdfDocument.SaveAs(outputPath)
		Console.WriteLine("Meeting minutes PDF generated.")
	End Sub
End Class
$vbLabelText   $csharpLabel

Wnioski

C# WebRTC (jak to działa dla programistów): Rysunek 2 – Strona licencyjna IronPDF

W tym artykule omówiliśmy, jak stworzyć podstawową aplikację WebRTC przy użyciu języka C# i platformy .NET Core. Omówiliśmy konfigurację środowiska programistycznego, tworzenie nowej aplikacji konsolowej, implementację serwera sygnalizacyjnego oraz nawiązywanie połączeń peer-to-peer w celu komunikacji w czasie rzeczywistym. WebRTC otwiera wiele możliwości dla aplikacji do komunikacji w czasie rzeczywistym, a dzięki C# i .NET Core można tworzyć solidne, skalowalne rozwiązania, które działają na różnych platformach i urządzeniach. Aby uzyskać informacje na temat licencji i zakupu, odwiedź stronę licencyjną IronPDF. Po podjęciu decyzji o zakupie licencja zaczyna obowiązywać od $799.

Często Zadawane Pytania

Jakie są zalety korzystania z WebRTC w C# i .NET Core?

WebRTC w połączeniu z C# i .NET Core pozwala programistom tworzyć aplikacje do komunikacji w czasie rzeczywistym, które wykorzystują potężne funkcje zarówno WebRTC, jak i środowiska programistycznego C#. To połączenie obsługuje bezpośredni transfer danych peer-to-peer i może być zintegrowane z bibliotekami .NET, takimi jak IronPDF for .NET, w celu uzyskania dodatkowych funkcji.

Jak skonfigurować środowisko programistyczne dla WebRTC w języku C#?

Aby skonfigurować środowisko programistyczne dla WebRTC w języku C#, należy zainstalować pakiet .NET Core SDK z oficjalnej strony internetowej firmy Microsoft. Do efektywnego zarządzania i pisania kodu należy używać środowiska IDE, takiego jak Visual Studio. Taka konfiguracja pozwoli na tworzenie aplikacji konsolowych i integrację funkcji WebRTC.

Jaką rolę pełni serwer sygnalizacyjny w aplikacji WebRTC?

Serwer sygnalizacyjny ma kluczowe znaczenie w aplikacji WebRTC, ponieważ ułatwia wymianę komunikatów sterujących i metadanych między węzłami w celu nawiązania połączenia. Pomaga w negocjowaniu opisów sesji i informacji o kandydatach przed nawiązaniem bezpośredniego połączenia peer-to-peer.

Jak mogę stworzyć serwer sygnalizacyjny przy użyciu .NET Core?

Możesz stworzyć serwer sygnalizacyjny przy użyciu .NET Core, tworząc prostą aplikację internetową, która zarządza połączeniami WebSocket. Wykorzystanie SignalR, biblioteki dodającej funkcje internetowe działające w czasie rzeczywistym, może usprawnić proces wdrażania serwera sygnalizacyjnego.

W jaki sposób można wykorzystać IronPDF do generowania plików PDF w aplikacjach WebRTC?

IronPDF można zintegrować z aplikacjami WebRTC w celu generowania plików PDF na podstawie treści HTML. Jest to szczególnie przydatne przy tworzeniu dokumentów, takich jak protokoły spotkań lub podsumowania sesji, co zwiększa funkcjonalność aplikacji do komunikacji w czasie rzeczywistym.

Jakie kroki są wymagane do nawiązania połączenia peer-to-peer w WebRTC?

Nawiązanie połączenia peer-to-peer w WebRTC wymaga utworzenia obiektów RTCPeerConnection, wymiany komunikatów ofert i odpowiedzi oraz negocjacji szczegółów połączenia przy użyciu kandydatów ICE. Proces ten jest niezbędny do umożliwienia bezpośredniej komunikacji między peerami.

W jaki sposób serwery TURN ułatwiają połączenia WebRTC?

Serwery TURN pomagają w nawiązywaniu połączeń WebRTC, przekazując dane multimedialne między węzłami, gdy bezpośrednie połączenie nie jest możliwe, szczególnie w restrykcyjnych środowiskach sieciowych. Zapewnia to łączność nawet w przypadkach, gdy wymagane jest przekierowanie NAT.

Czy w aplikacjach .NET można konwertować HTML na PDF?

Tak, w aplikacjach .NET można konwertować HTML na PDF przy użyciu bibliotek takich jak IronPDF. Metody takie jak RenderHtmlAsPdf mogą służyć do konwersji treści HTML na dokument PDF przy zachowaniu oryginalnego stylu i układu.

Jacob Mellor, Dyrektor Technologiczny @ Team Iron
Dyrektor ds. technologii

Jacob Mellor jest Chief Technology Officer w Iron Software i wizjonerskim inżynierem, pionierem technologii C# PDF. Jako pierwotny deweloper głównej bazy kodowej Iron Software, kształtuje architekturę produktów firmy od jej początku, przekształcając ją wspólnie z CEO Cameron Rimington w firmę liczą...

Czytaj więcej

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie