• Flask란?
  • Socket이란?
    • flask-socketIO
  • 채팅어플리케이션 개발



Flask란?


Socket이란?

  • 한 컴퓨터가 다른 컴퓨터와 상호 작용할 수있는 경로를 설정
  • 게이트가 열려있을 때, 즉 소켓이 열려있는 경우에만 통신을 가능하게하는 게이트로 생각할 수 있다.
  • 채팅은 통신이 있어야 가능하므로 소켓이 필수적이다.


SocketIO

  • 실제 전송 프로토콜에서 클라이언트 응용 프로그램을 추상화하는 브라우저 간 Javascript기반 라이브러리.
  • SocketIO Javascript 라이브러리에 의해 노출 된 메시지 전달 프로토콜을 구현함
  • SocketIO를 사용하면 브라우저가 응용 프로그램에 연결할 수 있다.


flask에서 socket 만들기

  • Flask-SocketIO를 사용하면 플라스크 응용 프로그램이 클라이언트와 서버 간의 양방향 통신에 액세스 할 수 있다.
  • 클라이언트 측 애플리케이션은 Javascript, C ++, Java 및 Swift의 모든 SocketIO 공식 클라이언트 라이브러리 또는 호환 가능한 클라이언트를 사용하여 서버에 영구적으로 연결할 수 있다.
  • pip로 ‘flask-socketio’ 패키지를 설치할 수 있다.
pip install flask-socketio


  • 기본 코드
from flask import Flask
from flask_socketio import SocketIO

app = Flask(__name__)
app.config['SECRET_KEY'] = '비밀번호 설정'
socketio = SocketIO(app)

if __name__ == '__main__':
    socketio.run(app, debug=True)
  • name’ 주위에 Flask를 배치하여 app이라는 변수를 만든다.
  • 암호화를 활성화하기 위해 SECRET_KEY를 선언.
  • SocketIO는 ‘앱’에 적용되고 있으며 나중에 애플리케이션을 실행할 때 앱 대신 socketio를 사용할 수 있도록 socketio 변수에 저장된다.
  • socketio는 웹 서버를 캡슐화한다.
  • run() 메소드는 기본적으로 Flask의 개발 웹 서버와 같은 localhost:5000에서 대기한다.
  • debug = True를 사용하면 쉽게 오류를 정렬 할 수 있다.(필수는 아님)


Writing Flask view

@app.route('/')
def sessions():
    return render_template('session.html')
  • 홈페이지 (경로 데코레이터‘/’로 표시)를 방문하면 그 아래에 선언 된 세션보기가 트리거된다.
  • 언급 된 URL을 열 때 호출된다.
  • 위의 경우 session.html 실행


render_template 사용

  • /main.py
from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
app.config['SECRET_KEY'] = '비밀번호 설정'
socketio = SocketIO(app)

@app.route('/')
def sessions():
    return render_template('session.html')

def messageReceived(methods=['GET', 'POST']):
    print('message was received!!!')

@socketio.on('my event')
def handle_my_custom_event(json, methods=['GET', 'POST']):
    print('received my event: ' + str(json))
    socketio.emit('my response', json, callback=messageReceived)

if __name__ == '__main__':
    socketio.run(app, debug=True)
  • HTML 페이지를 렌더링하는 데 도움이 된다.
  • 템플릿 폴더에 포함되어야한다.


  • /templates/session.html
<html>
    <head>
        <title>Session</title>
    </head>
    <body>
        <p>Hello</p>
    </body>
</html>
  • 위와 같이 templates폴더에 session.html 파일을 만든 후 command line에서 실행한다.
python main.py //경우에 따라서 python3 main.py로 실행

size_main


Flask-Socket Handling

  • 서버가 클라이언트가 보낸 메시지를 받는 방법, 클라이언트의 메시지를 확인하는 방법
  • 클라이언트에서 WebSocket 메시지를 수신하기 위해 애플리케이션은 socketio.on 데코레이터(@socketio.on())를 사용하여 이벤트 핸들러를 정의
  • send() 및 emit() 함수를 사용하여 연결된 클라이언트에 응답 메시지를 보낼 수 있다.


@socketio.on('my event')
def handle_my_custom_event(json, methods=['GET', 'POST']):
    print('received my event: ' + str(json))
    socketio.emit('my response', json, callback=messageReceived)

‘my event’를 트리거할 때 ‘handle_my_custom_event’ 함수는 먼저 json 객체를 수신하여 print 한 후, 나중에 ‘my response’ 이벤트로 전송한다. callback(콜백)은 서버에 의해 메시지가 수신되는지 여부를 알 수 있도록 도와주는 디버깅 기법의 일종이다.(위의 경우 messageRecevied함수를 불러옴)


SocketJS in Flask Templates

  • HTML 파일에 jquery와 socket.js 스크립트를 포함
    • 그러기 위해서는 JS 기능을 작성하기 전에 아래와 같은 스크립트를 가져와야 한다.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
  • 채팅어플리케이션의 사용자가 메시지를 입력할 때 화면에 표현이 되어야한다.(html로 표시)
<form action="" method="POST">
      <input type="text" class="username" style='font-size:15px;' placeholder="User Name"/>
      <input type="text" class="message" style='font-size:15px;' placeholder="Messages"/>
      <input type="submit"/>
</form>


var socket = io.connect('http://' + document.domain + ':' + location.port);
  • 연결 설정 및 세션 생성에 io.connect()를 사용
  • 두 사용자 모두를 http://127.0.1:5000이라는 동일한 URL에 연결하여 세션 생성
  • 아래 코드의 document.domain은 작업 중인 컴퓨터의 IP 주소를 나타낸다.
  • location.port는 포트를 나타내며, 기본값은 5000이다.


socket.on( 'connect', function() {
  socket.emit( 'my event', {
    data: 'User Connected'
  })
  var form = $( 'form' ).on( 'submit', function( e ) {
    e.preventDefault()
    let user_name = $( 'input.username' ).val()
    let user_input = $( 'input.message' ).val()
    socket.emit( 'my event', {
      user_name : user_name,
      message : user_input
    })
    $( 'input.message' ).val( '' ).focus()
  })
})
  • socket.on()에 대한 첫 번째 인수는 이벤트 이름
    • ‘connect’, ‘disconnect’, ‘message’, ‘json’은 socketIO에 의해 생성된 특수 이벤트.
    • 다른 모든 이벤트 이름은 사용자 정의 이벤트로 간주된다.
      • ‘message’ : 형식 문자열의 페이로드(payload)를 전달
      • ‘json’ : json 사용자 정의 이벤트는 파이썬 사전의 형태로 JSON 페이로드(payload)를 전달
  • 이벤트를 보내기 위해 flask server는 flask socketIO에서 제공하는 send(), emit() 기능을 사용할 수 있다.
  • send() 함수는 문자열 또는 JSON 유형의 표준 메시지를 클라이언트로 보낸다.
  • emit() 함수는 데이터와 함께 사용자 정의 이벤트 이름(위 코드에서는 ‘my event’)으로 메시지를 전송한다.
  • POST 메소드를 호출한 후 이벤트 ‘e’가 인수로 전달되며, 여기서 preventDefault() 메서드가 호출되어 전달이 금지된다. 그리고 나중에 입력 필드, 사용자 이름 및 메시지에서 값을 가져온다.
  • 그런 다음 emit()을 통해 이전에 ‘main.py’에서 정의한 ‘my event’로 전달된다.
  • 그 후 메시지 필드에는 전달했던 값이 사라지고 빈칸으로 변경된다.(focus()사용)


socket.on( 'my response', function( msg ) {
  console.log( msg )
  if( typeof msg.user_name !== 'undefined' ) {
    $( 'h3' ).remove()
    $( 'div.message_holder' ).append('<div><b style="color:#000">'+msg.user_name+'</b>'+msg.message+'</div>' )
  }
})
  • 일단 메시지를 이벤트를 통해 보내면, 수신된 메시지를 HTML 페이지에 렌더링해야 한다.
  • 응답으로 메시지가 수신되는 즉시 메시지를 “message_holder” 클래스 (h3 태그의 텍스트 (“No message yet”)가 제거됨)로 전달한다. 여기서 메시지는 이전 메시지에 추가된다.


<!DOCTYPE html>
  <html lang="en">
  <head>
    <title>Flask_Chatting_Application</title>
  </head>
  <body>
    <h3 style='color: #ccc;font-size: 30px;'>No message yet..</h3>
    <div class="message_holder"></div>
    <form action="" method="POST">
      <input type="text" class="username" style='font-size:15px;' placeholder="User Name"/>
      <input type="text" class="message" style='font-size:15px;' placeholder="Messages"/>
      <input type="submit"/>
    </form>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
    <script type="text/javascript">
      var socket = io.connect('http://' + document.domain + ':' + location.port);

      socket.on( 'connect', function() {
        socket.emit( 'my event', {
          data: 'User Connected'
        } )
        var form = $( 'form' ).on( 'submit', function( e ) {
          e.preventDefault()
          let user_name = $( 'input.username' ).val()
          let user_input = $( 'input.message' ).val()
          socket.emit( 'my event', {
            user_name : user_name,
            message : user_input
          } )
          $( 'input.message' ).val( '' ).focus()
        } )
      } )
      socket.on( 'my response', function( msg ) {
        console.log( msg )
        if( typeof msg.user_name !== 'undefined' ) {
          $( 'h3' ).remove()
          $( 'div.message_holder' ).append( '<div><b style="color: #000">'+msg.user_name+'</b> '+msg.message+'</div>' )
        }
      })
    </script>

  </body>
  </html>
  • 위처럼 코드를 작성하여 실행하면 통신이 되는 것을 확인할 수 있다.
  • flask-socketIO를 이용하여 간단하게 채팅어플리케이션을 만들 수 있다.

size_main

size_main


참고