안녕하세요. 명월입니다.
이 글은 C#의 MVC Framework에서 WebSocket을 사용하는 방법(SignalR)에 대한 글입니다.
예전에 Java에서 WebSocket을 사용하는 방법에 대해 소개한 적이 있습니다.
Java의 WebSocket보다는 SignalR이 살짝 복잡하네요.. 그러나 처음 설정만 잘하면 사용하기는 오히려 더 편할 수도 있습니다.
MVC Framework를 생성하는 것은 아래의 링크를 참조해 주세요.
링크 - [C# 강좌 - 67] MVC Framework 프로젝트 생성하기
그럼 MVC Framework를 하나 생성하겠습니다.
그리고 SignalR 라이브러리를 Nuget을 통해 다운로드 받습니다.
그리고 검색 창에 SignalR라고 검색을 하면 여러가지가 뜨는 데 우리는 Microsoft.AspNet.SignalR를 다운 받습니다.
주의점은 우리는 Net Core를 사용하는 것이 아니기 때문에 Microsoft.AspNetCore.SignalR가 아닌 Microsoft.AspNet.SignalR를 다운 받아야 합니다.
라이브러리 추가가 끝났으면 Startup파일에 app.MapSignalR()를 추가해야 합니다.
using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(WebSocketExample.Startup))]
namespace WebSocketExample
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
이번에는 웹 소켓을 사용할 Hub클래스를 만듭니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace WebSocketExample
{
public class TestHub : Hub
{
public void Send(string message)
{
// 전 유저에게 송신된다.
Clients.All.Receive("echo - " + message);
}
}
}
저는 TestHub라는 이름으로 작성했습니다. 일단 위 예제는 제가 Send함수를 넣었습니다. 이 설정은 javascript을 작성할 때 설명하겠습니다.
여기까지가 SignalR 설정이 완료되었습니다.
이제는 Home/Index 화면에 웹 소켓을 사용할 화면을 만들겠습니다.
@{
Layout = null;
}
<!DOCTYPE>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<input id="textMessage" type="text">
<input id="sendmessage" value="Send" type="button">
<br />
<textarea id="messageTextArea" rows="10" cols="50"></textarea>
<!-- jquery 링크 -->
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<!-- signalR 링크 -->
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(document).ready(function () {
// $.connection에서 뒤 testHub는 위에서 제가 작성한 TestHub 클래스란 의미입니다. C#에서 첫글자 대문자로 클래스를 작성하면 여기서는 첫글자를 소문자로 변환하는 것으로 확인이 됩니다.
var $ws = $.connection.testHub;
// client receive함수 설정은 Clients.All.Receive로 호출될 때 불리는 함수이다.
$ws.client.receive = function (message) {
document.getElementById("messageTextArea").value += "Recieve From Server => " + message + "\n";
};
// 이 함수는 웹 소켓이 개시되면 호출된다.
$.connection.hub.start().done(function () {
// sendmessage 클릭 이벤트 등록이다.
$('#sendmessage').click(function () {
var message = document.getElementById("textMessage");
document.getElementById("messageTextArea").value += "Send to Server => " + message.value + "\n";
// TestHub 클래스의 Send함수가 호출된다. 역시 함수명의 첫글자는 대문자이지만 여기서는 소문자로 치환되서 호출할 수 있다.
$ws.server.send(message.value);
message.value = "";
});
});
});
</script>
</body>
</html>
작성이 완료되었습니다. 이제 실행해 보겠습니다.
ASP.Net은 Jsp와 다르게 내부적으로 어떻게 돌아가는지 보이지가 않아서 에러가 발생했을 때 찾기가 참 힘드네요. 특히 저같은 경우는 자바스크립트에서 server.send와 connection.testHub가 어떻게 돌아가는지 이해가 잘 안되서 한참을 헤맸습니다.
첨부 파일 - WebSocketExample.zip
참조 - https://docs.microsoft.com/ko-kr/aspnet/core/fundamentals/websockets?view=aspnetcore-3.0
참조 - https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-3.0
참조 - https://stackoverflow.com/questions/17395201/call-a-hub-method-from-a-controllers-action
여기까지 C#의 MVC Framework에서 WebSocket을 사용하는 방법(SignalR)에 대한 설명이었습니다.
-----추가 2020년 6월 3일-----
MVC에서 Controller에서 SingalR을 호출해서 웹 브라우저로 메시지를 보내는 방법에 대한 질문을 추가합니다.
Controller에서 TestHub를 사용하기 위해서는 Controller에 Context를 바인딩하거나 기타 여러가지의 방법이 있습니다. 그러나 가장 간단한 방법은 GlobalHost.ConnectionManager를 이용하는 게 가장 간단합니다.
using System.Web.Mvc;
using Microsoft.AspNet.SignalR;
namespace WebSocketExample.Controllers
{
// Home 컨트럴러
public class HomeController : Controller
{
// Index 페이지
public ActionResult Index()
{
return View();
}
// Send 페이지
public void Send(string message)
{
// TestHub를 취득
var ws = GlobalHost.ConnectionManager.GetHubContext<TestHub>();
// Receive함수로 에코를 보냅니다.
ws.Clients.All.Receive("echo - " + message);
}
}
}
Home/Send를 호출해서 파라미터로 message를 넣었습니다.
Send 함수에서는 Websocket를 접속한 클라이언트에 echo 메시지를 보냅니다.
두번째, SignalR이 끊겼을 때 재 접속 하는 방법에 대한 질문입니다.
기본적으로 SingalR은 접속이 끊기면 재 접속 시도를 합니다만, 어느 정도 시간이 지나면 그대로 접속 끊김을 선언합니다.
@{
Layout = null;
}
<!DOCTYPE>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<input id="textMessage" type="text">
<input id="sendmessage" value="Send" type="button">
<br />
<textarea id="messageTextArea" rows="10" cols="50"></textarea>
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
// 페이지 로드가 끝나면 함수 실행
$(function () {
// SignalR 커넥션 가져오기
var $ws = $.connection;
// Receive함수 설정
$ws.testHub.client.receive = function (message) {
// 메시지 박스에 출력한다.
document.getElementById("messageTextArea").value += "Recieve From Server => " + message + "\n";
};
// 버튼을 누를 때 이벤트
$('#sendmessage').click(function () {
// 텍스트 박스 취득
var message = document.getElementById("textMessage");
// 메시지 박스에 출력
document.getElementById("messageTextArea").value += "Send to Server => " + message.value + "\n";
// 웹 소켓에 메시지 송신
$ws.testHub.server.send(message.value);
// 텍스트 박스 초기화
message.value = "";
});
// 접속이 끊기면 호출
$ws.hub.disconnected(function () {
// 병렬 식으로 웹 소켓을 다시 실행
setTimeout(function () {
$ws.hub.start();
});
});
// 웹 소켓 실행
$ws.hub.start();
});
</script>
</body>
</html>
접속 될 때까지 계속 호출합니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Development note > C#' 카테고리의 다른 글
[C#] Command(cmd) 명령어 실행하는 방법(Process 클래스) (3) | 2020.02.11 |
---|---|
[C#] Python을 사용하기 위한 방법(pythonnet) (2) | 2020.02.07 |
[C#] 비동기 소켓 통신(IOCP) - APM 패턴 (0) | 2020.02.02 |
[C#] 비동기 소켓 통신(IOCP) - EAP 패턴 (36) | 2020.01.31 |
[C#] ASP.NET의 MVC Framework에서 DI 의존성 주입을 하는 방법 (0) | 2019.11.28 |
[C#] dynamic타입의 동적 파라미터 - DynamicObject (WinForm에서 ASP.MVC의 ViewBag 오브젝트를 사용하는 방법) (0) | 2019.11.25 |
[C#] 로그 라이브러리(log4net) (2) | 2019.08.23 |
[C#] 날짜 포맷 (2) | 2019.08.06 |