상세 컨텐츠

본문 제목

Html5의 네트워크 | Node.JS, WebSocket, Socket.io, Tcp, Udp 관련

WEB/html5

by AlrepondTech 2018. 4. 10. 17:21

본문

반응형
728x170

 

 

=================================

=================================

=================================

 

 

 

 

출처: https://nesoy.github.io/articles/2017-04/Nodejs-Network

 

 

 
 
 

 

TCP Module

  • var net = require('net');

클래스

  • net.Server
  • net.Socket

서버 생성

  • var server = net.createServer(option)
  • server.listen(port)
  • server.close()
  • server.getConnections(callback) : 연결갯수
  • server.address() : 서버 주소

Server Event

  • listening : 포트 바인딩, 접속 가능한 상태 이벤트
  • connection : 클라이언트 접속 이벤트
  • close : 서버 닫기(연결된 소켓이 없을 때만 발생)
  • error : 에러
var net = require('net'); var server = net.createServer(function(socket) {     // connection event     console.log('클라이언트 접속');     socket.write('Welcome to Socket Server');      socket.on('data', function(chunk) {         console.log('클라이언트가 보냄 : ',         chunk.toString());     });      socket.on('end', function() {         console.log('클라이언트 접속 종료');     }); });  server.on('listening', function() {     console.log('Server is listening'); });  server.on('close', function() {     console.log('Server closed'); });  server.listen(3000); 

Client event

  • connect : 소켓 연결 이벤트
  • data : 읽을 수 있는 데이터 도착
  • end : 소켓 종료
  • timeout : 제한 시간 지남
  • error : 에러
var net = require('net');  var ip = '127.0.0.1'; var port = 3000;  var socket = new net.Socket(); socket.connect({host:ip, port:port}, function() {    console.log('서버와 연결 성공');     socket.write('Hello Socket Server\n');    socket.end();      socket.on('data', function(chunk) {         console.log('서버가 보냄 : ',         chunk.toString());             });      socket.on('end', function() {         console.log('서버 연결 종료');     }); }); 

Udp

  • require('dgram')
  • dgram.Socket

event

  • listening : 데이터 도착 감시
  • message : 데이터 도착 이벤트
  • close : 소켓 연결 종료 이벤트
  • error : 에러 발생 이벤트

Send

var dgram = require('dgram'); var socket = dgram.createSocket('udp4');  var msg = new Buffer('Hello UDP Receiver'); socket.send(msg, 0, msg.length, 3000, '127.0.0.1',     function(err) {         console.log(err);         if ( err ) {             console.log('UDP message send error', err);             return;         }         console.log('메세지 전송 성공');         socket.close();             } ); 

Receive

var dgram = require('dgram'); var socket = dgram.createSocket('udp4'); socket.bind(3000);  socket.on('listening', function() {     console.log('listening event'); });  socket.on('message', function(msg, rinfo) {     console.log('메세지 도착', rinfo.address, msg.toString()); });  socket.on('close', function() {     console.log('close event'); }); 

Multicast

  • socket.addMembership

 

 

 

=================================

=================================

=================================

 

 

출처: https://gist.github.com/tedmiston/5935757

 

 

Node.js TCP client and server example
  /*
  In the node.js intro tutorial (http://nodejs.org/), they show a basic tcp
  server, but for some reason omit a client connecting to it. I added an
  example at the bottom.
   
  Save the following server in example.js:
  */
   
  var net = require('net');
   
  var server = net.createServer(function(socket) {
  socket.write('Echo server\r\n');
  socket.pipe(socket);
  });
   
  server.listen(1337, '127.0.0.1');
   
  /*
  And connect with a tcp client from the command line using netcat, the *nix
  utility for reading and writing across tcp/udp network connections. I've only
  used it for debugging myself.
   
  $ netcat 127.0.0.1 1337
   
  You should see:
  > Echo server
   
  */
   
  /* Or use this example tcp client written in node.js. (Originated with
  example code from
  http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html.) */
   
  var net = require('net');
   
  var client = new net.Socket();
  client.connect(1337, '127.0.0.1', function() {
  console.log('Connected');
  client.write('Hello, server! Love, Client.');
  });
   
  client.on('data', function(data) {
  console.log('Received: ' + data);
  client.destroy(); // kill client after server's response
  });
   
  client.on('close', function() {
  console.log('Connection closed');
  });

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------

And i try "Echo server" here:

//server:

var net = require('net'); var textChunk = ''; var server = net.createServer(function(socket) { 	socket.write('Echo server\r\n'); 	socket.on('data', function(data){ 		console.log(data); 		textChunk = data.toString('utf8'); 		console.log(textChunk); 		socket.write(textChunk); 	}); }); server.listen(52275, '127.0.0.1'); 

//client:

var net = require('net'); var client = new net.Socket(); client.connect(52275, '127.0.0.1', function() { 	console.log('Connected'); 	client.write('Hello, server! Love, Client.'); }); var i = 0; client.on('data', function(data) { 	console.log('Received: ' + data); 	i++; 	if(i==2) 		client.destroy();  }); client.on('close', function() { 	console.log('Connection closed'); });

 

 

=================================

=================================

=================================

 

 

 

 

출처: http://ssmlim.tistory.com/46

 

 

 

원래 서버와 클라이언트(브라우저)가 통신을 할때는 HTTP(Hyper Text Transfer Protocol)을 이용하고 1개의 요청이 가면 1개의 응답이 오는 것이 일반적이다.

 

 

 

1. 만약 네이버(www.naver.com)를 주소창에 입력하면 브라우저는 인터넷에 접속하여 DNS서버를 거친 뒤 네이버 서버에 도달하게 되고 www.naver.com 주소가 가리키는 파일을 요청한다. 

 

2. 이 요청을 받은 네이버의 서버는 url 분석후index.html(네이버 메인 화면을 index.html라고 가정) 파일을 브라우저에 전송하게 된다.

 

3. 브라우저는 파일을 받고 화면에 띄울 준비를 한다. 위에서부터 문서를 읽다보면 참조 주소가 네이버인 css파일이 있다. 그렇다면 네이버 서버에 다시 접근 후 요청하여 css파일을 받고 캐시에 넣는다.

 

4. 그다음에 내려갔더니 이번엔 js파일이 필요하다. 3번의 작업을 반복한다.

 

5. 페이지 로드가 끝날 때까지 이런 모든 파일을 받아오는데에 1요청(리소스요청) 1응답(파일받음)으로 처리가 된다.

 

 

 

html5 icon

 

그러다 모바일 환경의 등장으로 웹의 활용도가 높아졌고, 굳이 웹에서는 실시간 전송에 대한 필요성이 없었으나(있어도 거의 어도비 플래시로 처리했다. 내가 알기로는) 그리고 HTML5버전에서 web socket이 등장했다.

 

 

 

 

 

웹소켓의 개념 자체는 별거 없다. 응답 하나에 요청 하나만 처리하면 해당 응답에 대한 작업은 땡치던 것을 이제 통로하나 뚫어놓고 기다리는 것이다. 

 

서버는 (서버)소켓을 가지고 있고 클라이언트가 요청하면 서버소켓중 하나가 해당 클라이언트의 몫이 된다. 서버의 통신 대역폭 일부를 점유하게 된다.

 

아무래도 최근에 적용된 기술이다보니 지원을 안하는 브라우저나 버전이 있을 수 있다. 특히 IE라던가 IE라던가 IE라던가............. 

 

본인이 사용하는 브라우저가 웹소켓을 지원하는지는 http://www.websocket.org/echo.html 이곳에서 확인할 수 있다. 최신 브라우저라면 왠만하면 될 것...

 

 

 

그리고 내가 이 포스팅을 쓰는 이유는............. 이전에 학원에서 다른팀이 했던 프로젝트를 구현해보고 싶어서이다. 

 

canvas와 web socket을 이용하여 실시간으로 그림을 그릴 수 있는 것..

 

다른 언어(java?)도 웹소켓을 지원하긴 하는데 node.js를 한번 써보고 싶어서 java는 제외시켰다.

 

 

 

1.

 

- node.js는 https://nodejs.org/ko/에서 받아서 설치한뒤 시스템 PATH에 설치경로만 추가해주면 설정이 끝난다. 매우 간단

 

 

 

2.

 

- socket.io 패키지를 받는다. cmd창을 열고 > npm install socket.io를 입력하면 패키지 설치가 완료된다.

 

 

 

3.

 

socketio.js

 

var http = require('http');

var fs = require('fs');

var socketio = require('socket.io');

 

var server = http.createServer(function(req, res){

        fs.readFile('index.html', function(err, data){

        res.writeHead(200, {'Content-Type':'text/html'});

        res.end(data);

    });

}).listen(8080, function(){

    console.log('Running ~~~~~~~~~~~~');

});

 

var io = socketio.listen(server);

io.sockets.on('connection', function(socket){

        socket.on('sMsg', function(data){

        io.sockets.emit('rMsg', data);

    });

});

 

- 자바는 클래스나 패키지를 참조할 때 import를 사용하지만 node.js는 require함수를 사용하여 패키지를 불러온다. 위의 코드에서 http는 웹 서버를 구성하기 위해 필요하고, fs는 file system의 약자로 파일을 읽어들일 때 사용한다. 

- 우선 http을 이용하여 서버를 생성한다. 생성 후 콜백함수에는 무엇을 할지가 들어가있는데, 위의 코드에선 index.html을 파일시스템에서 읽어와 응답으로 보낸다. server객체의 listen함수를 이용하면 그 순간부터 웹서버로 동작하기 시작한다. listen함수의 첫번째 파라미터는 포트넘버이고 두번째는 콜백함수로 난 그냥 서버가 켜졌음을 표시했다.

- socket.io 패키지를 불러온 뒤, listen함수에 기동할 웹서버 객체를 파라미터로 넘기고 io.sockets.on는 해당 서버소켓 전체에게 이벤트를 적용시킨다.

- 'connection' 이벤트가 발생하면 콜백함수에 연결 후의 이벤트 설정을 지정한다. 위의 코드에서는 개별 소켓에 sMsg라는 이벤트가 발생하면 받은 데이터를 전체 서버소켓에 rMsg라는 이벤트를 발생시키고 데이터를 전달한다.

 

 

index.html

 

<!DOCTYPE>

<html>

<head>

    <style>

        #container {

            width: 400px;

        border: 1px dotted #000;

        padding: 10px;

        height: 328px;

        }

        #chatBox {

            border: 1px solid #000;

        width: 400px;

        height: 300px;

            margin-bottom: 5px;

        }

        #chat li {

            padding: 5px 0px;

        }

        #name {

        width: 78px;

        }

        #msg {

        width: 256px;

        }

 

    </style>

    <script type="text/javascript" src="https://cdn.socket.io/socket.io-1.0.0.js"></script>

    <script type="text/javascript">

        window.onload = function(){

            var socket = io.connect();

            if(socket != null && socket != undefined){

                var welcome = document.createElement('li');

                welcome.innerHTML = '<system> 채팅을 시작합니다.';

                document.getElementById('chat').appendChild(welcome);

 

                socket.on('rMsg', function(data){

                    var li = document.createElement('li');

                    li.innerHTML = data.name + ' : ' + data.msg;

                    document.getElementById('chat').appendChild(li);

                });

 

                document.getElementById('submit').onclick = function(){

                    var val = document.getElementById('msg').value;

                    var name = document.getElementById('name').value;

                    socket.emit('sMsg', {

                        name : name,

                        msg : val

                    });

                    document.getElementById('msg').value = '';

                };

 

            }

        };

    </script>

</head>

<body>

<div id="container">

    <div id="chatBox">

        <ul id="chat"></ul>

    </div>

    <input type="text" id="name"/>

    <input type="text" id="msg"/>

    <button id="submit">보내기</button>

</div>

</body>

</html>

- socket.io.js 파일을 링크시킨다. 내가 본 책에서는 서버단에서 socket.io를 포함시키면 자동으로 추가되어있을거라고 하는데 걍 별도로 추가해야됨..

- io.connect를 통해 서버소켓에 연결 후, 소켓을 통해 rMsg가 발생하면 채팅창에 메세지를 뿌린다.

- 보내기 버튼에 클릭이벤트를 설정하여 sMsg이벤트를 발생시키고 사용자 이름과 메세지를 객체 형식으로 서버에 전송한다.

 

- emit은 이벤트를 발생시키고 on은 이벤트를 기다린다.

 

 

 

 

4. 

 

 

 

localhost:8080으로 첫 진입하면 이렇게 뜬다. 브라우저를 2개 띄운 후 하나는 이름부분을 1, 다른 하나는 2로 설정한 후 채팅 메세지를 전송하였다.

 

 

 

 

 

 

 

 

일단은 간단한거라 적용은 잘 됐다... 사실 책에 나와있는건데 간단하지만 걍 복습할겸 써봄

 

 

 

출처: http://ssmlim.tistory.com/46 [그럴 수도 있지]

 

 

 

=================================

=================================

=================================

 

 

 

출처:  http://ohgyun.com/370

 

Daylogs/Javascript

node.js로 소켓서버 구축하기

 

문제:

지난 주말엔 회사에서 주최하는 해커톤(hackathon) 행사에 참석했었다.

 

이번엔 모바일 브라우저에서 PC 브라우저의 마우스를 컨트롤 할 수 있는 리모트 컨트롤러를 만들었다.

 

컨트롤러는 트위터 부트스트랩과 Raphael.js로 꾸미고, require.js로 모듈화했고,

통신은 웹소켓으로 하고, 소켓 서버는 node.js를 사용했다.

 

작업한 코드는 github에 넣어뒀다.

 

https://github.com/ohgyun/remote-controller

 

 

여기까지 작업하는데 대략 10시간 정도 걸린 것 같다. 비몽사몽이라 기억이.. @_@

 

여튼, 작업 중간중간 메모해둔 게 있어 옮겨둔다.

 

 

해결책:

 

 

node.js 웹소켓 서버

     https://npmjs.org/package/websocket

 

 

웹서버 프레임워크는 express를 쓴다.

     https://npmjs.org/package/express

 

 

express 사용법

     http://expressjs.com/api.html

 

 

WebSocket과 Socket.io의 차이점

     http://helloworld.naver.com/helloworld/1336

 

 

통신 방법을 websocket으로만 제한하고 싶다면.

     transports 옵션을 webscoket으로만 넣는다.

     https://github.com/LearnBoost/socket.io/wiki/Configuring-Socket.IO

 

 

socket.io.js 파일 어디에 있나?

     express 3.x 버전에서 socket.io를 사용했기 때문.

     https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x

     

     3.x에 맞게 바꾸고,

     express의 app.listen()이 아니라, http 서버의 server.listen() 이다.

 

 

socket.io로 방(채널) 만들기

     https://github.com/LearnBoost/socket.io/wiki/Rooms

 

 

방 여러개 쓰기 튜토리얼

     http://psitsmike.com/2011/10/node-js-and-socket-io-multiroom-chat-tutorial/

 

 

__dirname 과 상대경로 ./ 의 차이

     http://stackoverflow.com/questions/8131344/what-is-the-difference-between-dirname-and-in-node-js

 

 

require.js로 부트스트랩이 로드되지 않을 때

     http://stackoverflow.com/questions/11389715/requirejs-use-autoloading-deps-with-shim

 

 

require.js로 raphael이 로드되지 않을 때

     https://github.com/DmitryBaranovskiy/raphael/issues/524

     https://github.com/DmitryBaranovskiy/raphael/pull/540

 

 

 

 

반응형

 

728x90

 

 

 

 

=================================

=================================

=================================

 

 

 

NodeJS에서 TCP/IP Socket과 WebSocket

 

현재 노드를 사용중이고, 소켓을 처음 사용해봅니다.

사용중인 모듈은 socket.io 이며, 서버-클라 모두 제가 구현하여 잘 사용중입니다.

 

제가 사용중인 socket.io는 WebSocket인걸 알고있습니다.

외부에서 소켓연동에 대한 이슈가 발생하여 소켓연결 지원을 해야하는데,

TCP/IP 소켓이라고 되어있어 제가 사용하는 WebScoket과는 다른걸로 생각됩니다.

 

질문

1. TCP/IP Socket 과 WebSocket은 다른건가요? (다른거같습니다만)

2. node js에서 socket.io와 socket.io-client를 사용중인데 이 모듈로 TCP/IP 소켓이 가능한가요?

3. socket.io로 구현이 안된다면, TCP/IP 소켓을 구현하는 서버/클라이언트 모듈이 있나요?

4. 구글링을 못해서.. 모두 웹소켓에 대한 정보만 나오네요.. 키워드가 있을까요?

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

자답)

 

TCP 소켓 서버/클라이언트 구현은

https://mylko72.gitbooks.io/node-js/content/chapter8/chapter8_3.html 

에서 설명하는것이 맞는건가요?

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

1. TCP/IP => HTTP => WebSocket => Socket.IO

커다란 의미로 TCP/IP 에 Socket.IO 가 포함 됩니다.

TCP/IP 를 이용해서 HTTP 프로토콜로 웹소켓을 구현한 것을 사용하기 쉽게 프레임워크 화 한 것이 Socket.IO 입니다.

 

2. 말이 잘못되었습니다. TCP/IP 로 여전히 통신하고 있습니다. 다만 사용중인 프로토콜이 텍스트 기반의 HTTP 일 뿐입니다. 물론 원하시는 답으로 말하자면 "가능하지 않습니다. "

3. net 모듈을 쓰시면 됩니다. 위 댓글의 예제가 맞습니다.

4. 구글 키워드 nodejs socket server 로 보시면 될 것 같습니다.

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

답변감사합니다.


TCP/IP => HTTP => WebSocket => Socket.IO (npm 모듈)

                            => Sokcet 등

             => FTP 등

 

로 머릿속에 정리가되었습니다. 친절한 설명 감사드립니다.

말씀하신것을 토대로 자료를 찾아보니 이해가되는부분이 많네요.

다시한번 감사드립니다.

 

 

=================================

=================================

=================================

 

 

 

출처: http://myeonguni.tistory.com/1389

 

 

[Node.js] websocket 모듈을 통한 에코 서버 구축하기

 

* 사전에 미리 node.js가 설치되어 있어야 합니다.

* 참고 : http://myeonguni.tistory.com/1388

 

 

1. websocket 모듈 설치하기

 

-> websocket 모듈을 설치할 폴더를 생성해줍니다. (ex - c:\wsServer)

 

-> 시작(윈도우키) + R -> cmd 입력 후 엔터

 

 

 

-> websocket 모듈을 설치할 폴더로 포커스를 이동 - "cd c:\wsServer"

 

-> websocket 모듈 설치 명령어 입력 - "npm install websocket"

(모듈을 인스톨하는 과정이 5초?정도 걸립니다)

 

 

 

여기까지 하셨으면 websocket 모듈은 설치가 완료되었습니다.

 

설치한 폴더로 가서 확인해봅시다 !

 

 

 

비어있던 wsServer 폴더에 node_modules \ websocket \ docs...등 하위 폴더 및 파일이 생성되신걸 확인할 수 있습니다.

 

자 그럼 이제 에코 서버(Echo Server)를 만들어 볼 차례입니다.

 

 

2. 에코 서버(Echo Server) 만들기

 

우선 서버를 만들어 봅시다 @.@

 

 

2. 1 서버(Server) - EchoServer.js

 

var WebSocketServer = require('websocket').server; var http = require('http');   var server = http.createServer(function(request, response) {     console.log((new Date()) + ' Received request for ' + request.url);     response.writeHead(404);     response.end(); }); server.listen(8080, function() {     console.log((new Date()) + ' Server is listening on port 8000'); });   wsServer = new WebSocketServer({     httpServer: server,     // You should not use autoAcceptConnections for production     // applications, as it defeats all standard cross-origin protection     // facilities built into the protocol and the browser.  You should     // *always* verify the connection's origin and decide whether or not     // to accept it.     autoAcceptConnections: false });   function originIsAllowed(origin) {   // put logic here to detect whether the specified origin is allowed.   return true; }   wsServer.on('request', function(request) {     if (!originIsAllowed(request.origin)) {       // Make sure we only accept requests from an allowed origin       request.reject();       console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');       return;     }       var connection = request.accept(null, request.origin);     console.log((new Date()) + ' Connection accepted.');     connection.on('message', function(message) {         if (message.type === 'utf8') {             console.log('Received Message: ' + message.utf8Data);             connection.sendUTF(message.utf8Data);         }         else if (message.type === 'binary') {             console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');             connection.sendBytes(message.binaryData);         }     });     connection.on('close', function(reasonCode, description) {         console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');     }); }); 

 

2. 2 클라이언트(Client) - EchoClient.html

 

  Send
closed 

 

-> 서버와 클라이언트 파일을 작성하셨으면 다음과 같이 준비가 되셨습니다.

 

 

 

 

2. 3 자 그럼 작성된 에코 서버를 구동하여 줍니다.

 

우선 명령 프롬프트 창을 띄어줍니다.

 

(-> 시작(윈도우키) + R -> cmd 입력 후 엔터)

 

-> 작성된 에코 서버 실행 : "node EchoServer"

 

 

 

다음과 같이 뜨시면 성공 !

 

 

2. 4 작성된 클라이언트 페이지를 통하여 에코 테스트를 해봅시다.

 

Client.html 파일을 열어주시고 텍스트박스에 내용을 입력하신 후 Send 버튼 클릭.

 

 

 

위와 같이 서버로 전송한 내용이 되돌아와서 출력된 걸 볼 수 있습니다 .

 

여기까지 해서 node.js 의 websocket 모듈을 이용한 간단한 에코서버 및 클라이언트 통신 구축하기를 진행해보았습니다.

 

간단하지만 여기서 응용하면 멋진 프로그램을 만들 수 있을 것 같네요 ~ @.@

 

 

(+ EchoServer.js, EchoClient.html 파일을 첨부합니다)

 

EchoClient.html
다운로드
EchoServer.js
다운로드


출처: http://myeonguni.tistory.com/1389 [명우니닷컴]

 

 

 

=================================

=================================

=================================

 

 

 

 

출처: https://code.i-harness.com/ko/q/9a4cb2

 

socket.io와 websocket의 차이점 [node.js]

Answers

 

오해

WebSocket 및 Socket.IO에 관한 몇 가지 일반적인 오해가 있습니다.

  1. 첫 번째 오해는 Socket.IO를 사용하는 것이 WebSocket을 사용하는 것보다 훨씬 쉽다는 것입니다. 아래 예를 참조하십시오.
  2. 두 번째 오해는 WebSocket이 브라우저에서 널리 지원되지 않는다는 것입니다. 자세한 내용은 아래를 참조하십시오.
  3. 세 번째 오해는 Socket.IO가 오래된 브라우저에서 연결을 다운 그레이드하는 것입니다. 실제로 브라우저가 오래되었다고 가정하고 서버에 AJAX 연결을 시작합니다.이 연결은 나중에 트래픽이 교환 된 후 WebSocket을 지원하는 브라우저에서 업그레이드됩니다. 자세한 내용은 아래를 참조하십시오.

내 실험

WebSocket과 Socket.IO의 차이를 보여주기 위해 npm 모듈을 작성했습니다.

이것은 서버 측 및 클라이언트 측 코드의 간단한 예입니다. 클라이언트는 WebSocket 또는 Socket.IO를 사용하여 서버에 연결하고 서버는 클라이언트가 DOM에 추가하는 1 초 간격으로 3 개의 메시지를 보냅니다.

서버 측

Express.js 앱에서 WebSocket과 Socket.IO를 사용하는 서버 측 예제를 비교해보십시오.

웹 소켓 서버

Express.js를 사용하는 WebSocket 서버 예제 :

var path = require('path'); var app = require('express')(); var ws = require('express-ws')(app); app.get('/', (req, res) => {   console.error('express connection');   res.sendFile(path.join(__dirname, 'ws.html')); }); app.ws('/', (s, req) => {   console.error('websocket connection');   for (var t = 0; t < 3; t++)     setTimeout(() => s.send('message from server', ()=>{}), 1000*t); }); app.listen(3001, () => console.error('listening on http://localhost:3001/')); console.error('websocket example');

출처 : https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.js

Socket.IO 서버

Express.js를 사용하는 Socket.IO 서버 예제 :

var path = require('path'); var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); app.get('/', (req, res) => {   console.error('express connection');   res.sendFile(path.join(__dirname, 'si.html')); }); io.on('connection', s => {   console.error('socket.io connection');   for (var t = 0; t < 3; t++)     setTimeout(() => s.emit('message', 'message from server'), 1000*t); }); http.listen(3002, () => console.error('listening on http://localhost:3002/')); console.error('socket.io example');

출처 : https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.js

고객 측

WebSocket과 Socket.IO를 사용하는 클라이언트 측 예제를 브라우저에서 동일하게 비교하십시오.

WebSocket 클라이언트

바닐라를 사용하는 WebSocket 클라이언트 예제 JavaScript :

var l = document.getElementById('l'); var log = function (m) {     var i = document.createElement('li');     i.innerText = new Date().toISOString()+' '+m;     l.appendChild(i); } log('opening websocket connection'); var s = new WebSocket('ws://'+window.location.host+'/'); s.addEventListener('error', function (m) { log("error"); }); s.addEventListener('open', function (m) { log("websocket connection open"); }); s.addEventListener('message', function (m) { log(m.data); });

출처 : https://github.com/rsp/node-websocket-vs-socket.io/blob/master/ws.html

Socket.IO 클라이언트

바닐라를 사용하는 Socket.IO 클라이언트 예제 JavaScript :

var l = document.getElementById('l'); var log = function (m) {     var i = document.createElement('li');     i.innerText = new Date().toISOString()+' '+m;     l.appendChild(i); } log('opening socket.io connection'); var s = io(); s.on('connect_error', function (m) { log("error"); }); s.on('connect', function (m) { log("socket.io connection open"); }); s.on('message', function (m) { log(m); });

출처 : https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html

네트워크 트래픽

네트워크 트래픽의 차이를 보려면 내 테스트를 실행할 수 있습니다. 내가 얻은 결과는 다음과 같습니다.

WebSocket 결과

2 요청, 1.50KB, 0.05 초

그 2 개의 요구에서 :

  1. HTML 페이지 자체
  2. WebSocket으로의 연결 업그레이드

(연결 업그레이드 요청은 개발자 도구에서 101 Switching Protocols 응답으로 볼 수 있습니다.)

Socket.IO 결과

6 요청, 181.56KB, 0.25 초

그 6 개의 요구에서 :

  1. HTML 페이지 자체
  2. Socket.IO의 자바 스크립트 (180 킬로바이트)
  3. 첫 번째 긴 폴링 AJAX 요청
  4. 두 번째 긴 폴링 AJAX 요청
  5. 세 번째로 긴 폴링 AJAX 요청
  6. WebSocket으로의 연결 업그레이드

스크린 샷

localhost에있는 WebSocket 결과 :

 

 

=================================

=================================

=================================

 

 

 

Socket.io를 이용한 실시간 웹 구현

TCP/IP 소켓프로그래밍이라는 도서가 생각나는가? 인터넷의 다른 컴퓨터와 연결할 수 있다는 사실에 몇번이고 다시 읽었던 책이다. 이러한 소켓을 웹 프로토콜에서도 사용할수 있다. 80번 포트를 그대로 사용하면서 http 핸드쉐이크 과정 없이 데이터를 주고 받을 수 있다. 물론 초기 핸드쉐이크는 한 번 있어야 한다.

웹소켓의 개념과 socket.io의 예제 코드는 이쪽(링크1링크2) 설명을 참고하자. 웹소켓 이전에 실시간 웹을 구현하기 위해서 polling, streaming 방식의 ajax 코드를 이용했다. 문제는 각 브라우져마다 구현 방법이 달라 개발이 어렵다는 것. 그래서 웹소켓이란 표준이 나왔고 이것를 구현한 것이 socket.io 모듈이다. socket.io는 하나의 인터페이스로 실시간 웹을 작성할 수 있다.

본 글에서는 angular-fullstack 프레임웍을 사용하여 socket.io를 이용한 실시간 웹을 구현해 본다.

백엔드

yo angular-fullstack으로 앵귤러 풀스택을 설치한다. 기본적으로 백엔드에는 GET /api/things라는 프로토콜을 제공하고 프론트에서 이것을 호출하여 /에서 보여주는 샘플 코드이다. new thing을 추가하는 POST /app/things와 name으로 삭제하는 DELETE /api/things/:name을 추가하자.

// server/api/thing/index.js router.get('/', controller.index); router.post('/', controller.create); router.delete('/:name', controller.destroy);  // server/api/thing/thing.controller.js // Get list of things exports.index = function(req, res) {   res.json(db); };  // Create new thing exports.create = function(req, res) {   var newThing = {name: req.body.name, info: req.body.info};   db.push(newThing);   res.json(201, newThing); };  // Remove a thing exports.destroy = function(req, res) {   _.remove(db, function (n) {     return n.name === req.params.name   });   res.send(204); };  

각 리소스가 변경되는 이벤트마다 소켓으로 브로드캐스팅 하는 것이 실시간 API의 핵심이다. 이를 구현하기 위해서는 리소스 변경시 이벤트를 후킹할수 있어야한다. Mongoose, Sequeilize 처럼 데이터베이스를 추상화 해놓은 DAO 모듈에는 CRUD 작업에 대한 이벤트를 제공하므로 이벤트 핸들러에서 소켓 통신을 하면된다.

본 글에서는 임시 데이터베이스 클래스를 만들어 이벤트를 발생할 것이다. 이를 위해서는 노드의 EventEmitter 를 상속하여 MyDatabase를 먼저 작성해보자.

// server/api/thing/db.js 'use strict';  var _ = require('lodash'); var util = require('util'); var events = require('events').EventEmitter;  // EventImitter를 상속하는 MyDatabase 클래스를 정의한다 function MyDatabase() {   events.call(this);    this.db = [{       name : '...',       info : '...'   }]; } util.inherits(MyDatabase, events);  // 데이터베이스 조회 메쏘드 MyDatabase.prototype.findAll = function () {   return this.db; };  // 신규 데이터 추가 메쏘드 MyDatabase.prototype.create = function (newThing) {   this.db.push(newThing);   this.emit('create', newThing);   return newThing; };  // 데이터 삭제 메쏘드 MyDatabase.prototype.destroy = function (name) {   _.remove(this.db, function (thing) {     return thing.name === name;   });   this.emit('destroy', name);   return name; };  // 객체를 미리 생성하여 싱글톤으로 구현한다. var db = new MyDatabase(); exports = module.exports = db;

데이터베이스에서 이벤트를 발생하도록 만들었다. 각 이벤트마다 헨들러 함수를 등록하고 이 함수 안에서 소켓 통신을 구현하면 된다. 그전에 소켓 통신을 위해서 socket.io 모듈을 설치하자. npm install --save socket.io socket.io-client로 서버와 클라이언트에서 사용할 socket.io 모듈을 설치한다. socket.io 모듈은 노드의 http 모듈과 연동하여 사용할 수 있다.

// server/app.js // 소켓과 http 인스턴스(server)을 연결한다. var socketio = require('socket.io')(server, {   path: '/socket.io-client' }); require('./config/socketio')(socketio);  // server/config/socketio.js module.exports = function (socketio) {   // 소켓연결이 되었을때 thing 리소스에 대한 소켓 설정을 등록한다.   // 데이터베이스 이벤트 핸들러에 소켓 통신을 구현하는 것이다.   socketio.on('connection', function (socket) {     require('../api/thing/thing.socket').register(socket);   }); };  // server/api/thing/thing.socket.js var db = require('./db');  exports.register = function(socket) {   db.on('create', function (newThing) {     // 디비에 엔트리가 추가되었을 경우 소켓으로 thing:create 이벤트를 보낸다.     socket.emit('thing:create', newThing);   });    db.on('destroy', function (removedName) {     // 디비에서 엔트리가 삭제되었을 경우 소켓으로 thing:destroy 이벤트를 보낸다.     socket.emit('thing:destroy', removedName);   }); }; 

프론트엔드

앵귤러를 사용한 프로트엔드에서는 bower install --save angular-socket-io 로 앵귤러용 socket.io를  설치하고 angular.module('...', [... 'btford.socket-io']);로 모듈을 주입한다. index.html에서는 백엔드 서버로 부터 socket.io 라이브러리를 다운로드한다.

<!-- index.html --> <script src="socket.io-client/socket.io.js"></script>

소켓 통신을 위한 전용 앵귤러 서비스를 만들자.  이 서비스는 백엔드와 소켓으로 연결한 뒤 그 객체를 반환하는 역할을 한다.

// client/components/services/socket/socket.service.js  angular.module('realTimeWebBySocketioApp')     .factory('socket', function (socketFactory) {       // 백앤드와 소켓으로 연결한다.       var ioSocket = io('', {         path: '/socket.io-client'       });        // 소켓 서비스 객체를 생성한다.       var socket = socketFactory({         ioSocket: ioSocket       });        return socket;     }); 

마지막으로 컨트롤러에서 이 앵귤러 서비스를 사용해 백엔드와 소켓 통신을 구현해 보자.

// client/app/main/main.controller.js  angular.module('realTimeWebBySocketioApp')     .controller('MainCtrl', function ($scope, $http, socket) {       // socket 서비스를 주입한다.        // 서버로부터 리소스를 받아온다.       $http.get('/api/things').success(function (awesomeThings) {         $scope.awesomeThings = awesomeThings;       });        // 서버에 리소스를 추가하는 프로토콜을 요청한다.       $scope.create = function (name) {         var thing = {name: name, info: ''};         $http.post('/api/things', thing);         $scope.name = '';       };        // 서버는 리소스 추가가 완료되면 'thing:create' 이벤트를 보낸다.       socket.on('thing:create', function (newThing) {         // 브라우져에서는 이 이벤트를 캐치하여 새로운 리소스를 브라우져에 추가할 수 있다.         $scope.awesomeThings.push(newThing);       });        // 리소스 삭제도 동일한 구조다.       $scope.destroy = function (thing) {         $http.delete('/api/things/' + thing.name);       };        socket.on('thing:destroy', function (removedName) {         _.remove($scope.awesomeThings, function (thing) {           return thing.name === removedName;         });       });     }); 

테스트

실제 두 세션으로 연동하여 소켓 동작을 확인할 수 있다.

소스코드: 링크

https://github.com/jeonghwan-kim/real-time-web-by-socket.io

 

 

 

=================================

=================================

=================================

 

 

 

기타관련링크:

 

- https://www.youtube.com/watch?v=HyGtI17qAjM

 

https://www.slideshare.net/kiyoungmoon144/nodejs-78654536

 

https://www.zerocho.com/category/NodeJS/post/57df854f5f0b02001505fef2

 

https://www.slideshare.net/Paprikhan/nodejs-websocket-59636014

 

https://github.com/mattschultz/Socket.IO-node-example/blob/master/client.html

 

https://openclassrooms.com/courses/ultra-fast-applications-using-node-js/socket-io-let-s-go-to-real-time

 

 

=================================

=================================

=================================

 

 

반응형
그리드형


관련글 더보기

댓글 영역