ecsimsw
소켓 통신 연습 / Node.js, C# 본문
Node.js 소켓 통신 연습
C#으로만 소켓 서버와 클라이언트를 구성하여 통신해오다가, node.js를 공부하면서 훨씬 쉽게 서버, 클라이언트를 구성할 수 있었다. 공부한 것을 연습하고자 간단하게 채팅 앱을 만들어 보았다.
Node.js 로 server 제작
node.js socket 모듈의 이벤트 처리를 이용하면 보다 쉽게 소켓으로 데이터를 받고 이를 연결된 모든 소켓에 뿌리는 서버를 만들 수 있다.
1) net.createServer를 호출하므로서 socket 객체를 생성한다. 생성된 소켓은 clients 배열에 push 한다. socket 객체를 통해 소켓으로 직접 연결된 클라이언트를, clients 배열을 통해 연결된 전체 클라이언트들(소켓들)을 관리할 수 있다.
2) 'data' 이벤트 핸들러를 통해 한 socket을 통해 data가 들어오면 write 메소드를 통해 clients의 모든 객체에 데이터를 뿌린다.
3) 'end' 이벤트 핸들러를 정의하여 클라이언트가 연결을 종료하면 clients 배열에서 해당 소켓의 인덱스를 확인하여 제거하고 splice한다.
winform 으로 client 제작
클라이언트는 c# 윈폼으로 만들어보았다. C#으로는 서버/ 클라이언트르 만들어본 경험이 있어, 일단 node.js를 공부하기 위한 프로젝트기 때문에 자세한 설명 없이, 문제가 될 수 있는 부분만 언급한다.
1) 멀티 스레딩 : 수신 함수를 만들어 Receive_thread에 델리게이트의 인자로 넣으므로써 비동기 송수신을 가능하도록 하였다.
2) string을 byte로 encoding 하여 write 메소드를 통해 데이터를 전송하고, 수신 시엔 반대로 byte를 string으로 encoding 하여 수신 데이터를 얻었다.
3) form 종료 시 NetworkStream과 TcpClient를 종료하므로써 end 이벤트를 서버에 발생시켰다. 이를 빼먹을 시 클라이언트 종료 시 에러가 발생하여 서버가 아예 닫히는 상황이 발생한다. Sleep(2000)은 2초의 딜레이를 주고 다음 동작을 실행 시킨다. close가 너무 빠르면 서버에서 에러가 나서 일부러 딜레이를 주었다. 서버에서의 data 이벤트가 처리되는 도중에 클라이언트가 close로 닫혀버리면 서버가 사라진 클라이언트를 찾을 수 없어서 나는 오류 같았다.
stream.write의 동기/ 비동기를 고민했으나 어차피 클라이언트는 write를 다 마치고 close를 호출하고, 그때 서버가 데이터를 보내고 있나, 데이터 전송을 종료했나의 문제지 클라이언트의 write 속도 문제는 아니라고 판단하였고,
서버에서 end 이벤트를 처리함과 동시에 ~ is left 를 나머지 클라이언트에 뿌리는 방식이 가장 좋다고 생각했으나 그럼 서버 입장에서 모든 클라이언트의 데이터를 클라이언트 id+message 형식으로 관리해줘야하므로 딜레이를 주는 것으로 해결 했으나,
클라이언트가 엄청 많아져 데이터 전송에 2초 이상의 시간이 걸리거나, data 이벤트 처리에서 다른 처리가 추가 될 경우 등, Sleep()으로 딜레이를 주는 것에는 분명히 한계가 있어 다음번 채팅 어플리케이션은 이를 해결할 방법을 고민할 생각이다.
스크린 샷
윈폼 클라이언트가 Node.js 서버를 통해 통신하는 모습
pug+express 로 만든 클라인트
"client.html"
<head>
<meta charset="utf-8">
<title>Chat</title>
<style>
.logBox{ width: 350px; height: 400px; }
.name{ width: 44px; }
.message{ width: 300px; }
.submit{ display: none; }
#textBox{padding-bottom: 10px;}
</style>
</head>
<script src="/socket.io/socket.io.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
$('#textBox').on('submit', function(event){
var msg={
name:$('#name').val(),
message:$('#message').val()
};
socket.emit('submit_by_client', msg);
$('#message').val('');
$('#message').focus();
event.preventDefault();
//.val() : to get or set value of the form
// preventDefault : for cancelling refresh attempt that is by submit event
});
socket.on('emit_by_server', function(msg){
$('#logBox').append(msg.name+' : '+msg.message+'\n');
$('#logBox').scrollTop($('#logBox')[0].scrollHeight);
});
</script>
<h4>Client</h4>
<div>
<form id="textBox">
<input id="name" class="name" type="text">
<input id="message" class="message" type="text">
<input type="submit" class="submit" value="submit">
</form>
</div>
<div>
<textarea id="logBox" class="logBox" readonly></textarea>
</div>
'KimJinHwan > Project' 카테고리의 다른 글
Spring boot, JPA / Giggle (0) | 2020.10.05 |
---|---|
JSP, Servlet / 익명 질문과 답변 (1) | 2020.05.20 |
영화 추천 서비스 / TF-IDF, NLP (0) | 2020.03.14 |
Python / Google image crawler (5) | 2019.12.01 |
유전 알고리즘 시뮬레이션 (9) | 2019.11.28 |