728x90
반응형
출처 : https://dotnetplaybook.com/which-is-best-websockets-or-signalr/
Http, XMLHttpRequest & WebSockets 개념
Http
Request / Response Cycle
동기 Synchronous
Stateless : 요청하고 응답받고의 반복이며, 어떠한 연결을 유지하거나 상태값을 관리하지 않는다.
XMLHttpRequest (Ajax)
부분 UI 업데이트가 가능하다.
비동기 Asynchronous
Long Polling에서 사용된다.
WebSockets
Http "upgrade" 요청으로 시작한다.
양방향 통신이 가능하다. Bi-directional
Server와 Client의 연결이 유지된다. Persistent
WebSocket API
- Method
- Send
- Close
- Events
- Open
- Message
- Error
- Close
SignalR
WebSocket을 감싸는 프레임워크이다.
1. SignalR Server
- vscode terminal에 아래 명령어를 실행하여, web project를 생성한다.
dotnet new web -n SignalRServer
PS C:\Users\admin\source\repos> dotnet new web -n SignalRServer
"ASP.NET Core Empty" 템플릿이 성공적으로 생성되었습니다.
생성 후 작업 처리 중...
C:\Users\admin\source\repos\SignalRServer\SignalRServer.csproj에서 'dotnet restore' 실행 중 ...
복원할 프로젝트를 확인하는 중...
C:\Users\admin\source\repos\SignalRServer\SignalRServer.csproj을(를) 80 ms 동안 복원했습니다.
복원에 성공했습니다.
- 프로젝트 폴더에 Hubs 폴더를 만듭니다.
- Hubs 폴더에서 다음 코드로 ChatHub 클래스를 만듭니다. (연결, 그룹 및 메시징 관리)
using System;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SignalRServer
{
public class ChatHub : Hub
{
public override Task OnConnectedAsync()
{
Console.WriteLine("--> Connection Established" + Context.ConnectionId); //Guid로 id를 생성할 필요가 없다.
Clients.Client(Context.ConnectionId).SendAsync("ReceiveConnID", Context.ConnectionId);
return base.OnConnectedAsync();
}
public async Task SendMessageAsync(string message)
{
var routeOb = JsonConvert.DeserializeObject<dynamic>(message);
string toClient = routeOb.To;
Console.WriteLine("Message Received on: " + Context.ConnectionId);
if(toClient == string.Empty)
{
await Clients.All.SendAsync("ReceiveMessage", message);
}
else
{
await Clients.Client(toClient).SendAsync("ReceiveMessage", message);
}
}
}
}
- Program.cs 파일에 SignalR 서버 구성
using SignalRServer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors();
builder.Services.AddSignalR();
var app = builder.Build();
app.UseCors(builder => builder
.WithOrigins("null")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
app.MapGet("/", () => "Hello World!");
app.MapHub<ChatHub>("/chatHub");
app.Run();
- 서버실행 dotnet run!!!
2. SignalR Client
- SignalRClient 폴더 생성
- Signalr.js 파일 추가
PS C:\Users\admin\source\repos\SignalRClient> libman --version
libman : 'libman' 용어가 cmdlet, 함수, 스크립트 파일 또는 실행할 수 있는 프로그램 이름으로 인식되지 않습니다. 이름이 정확한지 확인하고 경로가 포함된 경우
경로가 올바른지 검증한 다음 다시 시도하십시오.
위치 줄:1 문자:1
+ libman --version
+ ~~~~~~
+ CategoryInfo : ObjectNotFound: (libman:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Users\admin\source\repos\SignalRClient> dotnet tool install -g Microsoft.Web.LibraryManager.cli
다음 명령을 사용하여 도구를 호출할 수 있습니다. libman
'microsoft.web.librarymanager.cli' 도구('2.1.161' 버전)가 설치되었습니다.
PS C:\Users\admin\source\repos\SignalRClient> libman --version
2.1.161+abc97ecc7d.RR
PS C:\Users\admin\source\repos\SignalRClient> libman install @aspnet/signalr@next -p unpkg -d lib/signalr --files dist/browser/signalr.js
https://unpkg.com/@aspnet/signalr@next/dist/browser/signalr.js 파일을 다운로드하는 중...
lib/signalr/dist/browser/signalr.js이(가) 디스크에 기록되었습니다.
"@aspnet/signalr@next" 라이브러리를 "lib/signalr"에 설치했습니다.
- signalRClient.html 파일 추가
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>SignalR JavaScript Client</title>
</head>
<script src="lib/signalr/dist/browser/signalr.js"></script>
<body>
<h1>SignalR JavaScript Client</h1>
<p id="stateLabel">Ready to connect</p>
<p id="connIDLabel">ConnID: N/a</p>
<div>
<label for="connectionUrl">SignalR Server URL:</label>
<input id="connectionUrl" />
<button id="connectButton" type="submit">Connect</button>
<button id="closeButton" disabled>Close Socket</button>
</div>
<p></p>
<div>
<label for="sendMessage">Message:</label>
<input id="sendMessage" disabled />
<button id="sendButton" type="submit" disabled>Send</button>
</div>
<p></p>
<div>
<label for="recipients">Recipient IDs:</label>
<input id="recipients" disabled />
</div>
<p></p>
<h2>Communication Log</h2>
<table style="width: 800px">
<thead>
<tr>
<td style="width: 100px">From</td>
<td style="width: 100px">To</td>
<td>Data</td>
</tr>
</thead>
<tbody id="commsLog">
</tbody>
</table>
<p></p>
</body>
<script>
var connectionUrl = document.getElementById("connectionUrl");
var connectButton = document.getElementById("connectButton");
var stateLabel = document.getElementById("stateLabel");
var sendMessage = document.getElementById("sendMessage");
var sendButton = document.getElementById("sendButton");
var commsLog = document.getElementById("commsLog");
var closeButton = document.getElementById("closeButton");
var recipients = document.getElementById("recipients");
var connID = document.getElementById("connIDLabel");
connectionUrl.value = "http://localhost:5000/chatHub";
var hubConnection = new signalR.HubConnectionBuilder().withUrl(connectionUrl.value).build();
connectButton.onclick = function () {
stateLabel.innerHTML = "Attempting to connect...";
hubConnection.start().then(function () {
updateState();
commsLog.innerHTML += '<tr>' +
'<td colspan="3" class="commslog-data">Connection opened</td>' +
'</tr>';
});
};
closeButton.onclick = function () {
if (!hubConnection || hubConnection.state !== "Connected") {
alert("Hub not connected!");
}
hubConnection.stop().then(function () {
console.debug("Requested stop on hub");
});
hubConnection.onclose(function (event) {
updateState();
commsLog.innerHTML += '<tr>' +
'<td colspan="3" class="commslog-data">Connection Stopped.</td>' +
'</tr>';
});
};
sendButton.onclick = function () {
var message = constructJSON();
hubConnection.invoke("SendMessageAsync", message);
commsLog.innerHTML += '<tr>' +
'<td class="commslog-server">Client</td>' +
'<td class="commslog-client">Server</td>' +
'<td class="commslog-data">' + htmlEscape(message) + '</td></tr>';
};
hubConnection.on("ReceiveConnID", function (connid) {
connID.innerHTML = connid;
commsLog.innerHTML += '<tr>' +
'<td colspan="3" class="commslog-data">Connection ID Received from Hub</td>' +
'</tr>';
});
hubConnection.on("ReceiveMessage", function (message) {
commsLog.innerHTML += '<tr>' +
'<td class="commslog-server">Server</td>' +
'<td class="commslog-client">Client</td>' +
'<td class="commslog-data">' + htmlEscape(message) + '</td></tr>';
});
function constructJSON() {
return JSON.stringify({
"From": connID.innerHTML.substring(8, connID.innerHTML.length),
"To": recipients.value,
"Message": sendMessage.value
});
}
function htmlEscape(str) {
return str.toString()
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
function updateState() {
function disable() {
sendMessage.disabled = true;
sendButton.disabled = true;
closeButton.disabled = true;
recipients.disabled = true;
}
function enable() {
sendMessage.disabled = false;
sendButton.disabled = false;
closeButton.disabled = false;
recipients.disabled = false;
}
connectionUrl.disabled = true;
connectButton.disabled = true;
if (!hubConnection) {
disable();
} else {
switch (hubConnection.state) {
case "Disconnected":
stateLabel.innerHTML = "Closed";
connID.innerHTML = "ConnID: N/a";
disable();
connectionUrl.disabled = false;
connectButton.disabled = false;
break;
case "Connecting":
stateLabel.innerHTML = "Connecting...";
disable();
break;
case "Connected":
stateLabel.innerHTML = "Connected";
enable();
break;
default:
stateLabel.innerHTML = "Unknown WebSocket State - unknown";
disable();
break;
}
}
}
</script>
</html>
- signalRClient.html 파일 브라우저에서 열기
Connect 클릭!
메시지 Send 클릭!!
728x90
반응형
'ASP.NET Core' 카테고리의 다른 글
.NET 6] user-secrets(secrets.json) 사용하여 ConnectionStrings 계정 관리하기 (0) | 2022.06.16 |
---|---|
.NET 6] Minimal APIs VS MVC APIs 차이점 (0) | 2022.06.15 |
.NET Core] Request Pipeline - Run, Map, Use (0) | 2022.05.23 |
.NET 6 API with Redis] 4. API using Hashes Data Type (0) | 2022.05.18 |
.NET 6 API with Redis] 3. Model , Repository, Controller구성 (0) | 2022.05.18 |
댓글