node.js 개발 (3-2)

2013년 9월 4일 수요일

Server 구현

아래와같이 net 모듈로 쉽게 서버를 구성할 수 있다.

var server = net.createServer()
server.on('connection', function (socket) {
  console.log('connection')
})
server.on('error', function (err) {
  console.log('error')
})
server.on('close', function () {
  console.log('close')
})
server.listen(4001)

생성한 서버에 클라이언트가 접속하면 connection 이벤트가 호출되고 socket을 전단받는다. socket으로 Connection을 생성하여서 패킷 주고 받을 준비를 한다.

var server = net.createServer()
server.on('connection', function (socket) {
  console.log('connection')
  var conn = new Connection(socket)

  conn.on('packet', function (header, data) {
    console.log('packet receive')
  })
  conn.on('packet_error', function (err) {
    console.log('packet receive')
  })
  conn.on('error', function (err) {
    console.log('socket error')
  })
  conn.on('close', function () {
    console.log('socket close')
  })
})
server.on('error', function (err) {
  console.log('error')
})
server.on('close', function () {
  console.log('close')
})
server.listen(4001)

이제 packet이벤트 안에서 클라이언트에서 보낸 패킷을 처리할 수 있다. 실제 패킷을 처리하고 데이터를 담아둘 User 클래스를 만들어보자.

var User = function (conn) {
  this.conn = conn

  this.name = ''
  this.id = ''
}

User.prototype = {
  send: function (header, data) {
    this.conn.send(header, data)
  },

  // connection
  onPacket: function (header, data) {
    console.log('User:parsePacket', data)
  },
  onPacketError: function (err) {
    console.log('packet_error:', err)
    this.conn.close(proto.PK_CRITICALERROR)
    this.conn.pause()
  },
  onError: function (err) {
    console.log('socket error:', err)
    if (err.code != 'ECONNRESET') {
      this.conn.close(proto.PK_CRITICALERROR)
    }
    this.conn.pause()
  },
  onClose: function () {
    console.log('socket closed')
    this.conn = null
  },
}

이 클래스를 이용해서 Connection 이벤트를 User에서 처리하도록 한다.

server.on('connection', function (socket) {
  console.log('connection')
  var conn = new Connection(socket)

  var user = new User(conn)
  user.name = 'anonymous'

  conn.on('packet', function (header, data) {
    user.onPacket(header, data)
  })
  conn.on('packet_error', function (err) {
    user.onPacketError(err)
  })
  conn.on('error', function (err) {
    user.onError(err)
  })
  conn.on('close', function () {
    user.onClose()
  })
})

살을 붙여서 Server 클래스를 만들어보자.

소스

world.js

/**
 * world.js
 * 서버
 *
 * @require net
 */

// module
var net = require('net')
var util = require('util')

// include
var Connection = require('../common/connection')
var User = require('./user')

var World = function () {
  // 기본옵션
  this.option = {
    port: 8080,
    maxConnection: 10000,
    maxUser: 10000,
  }

  // 소켓서버
  this.server = net.createServer()

  // 유저목록
  this.users = []

  // server-event
  var self = this
  this.server.on('connection', function (socket) {
    self.onConnection(socket)
  })
  this.server.on('error', function (err) {
    console.log('err:', err.message)
    self.onError(err)
  })
  this.server.on('close', function () {
    self.onClose()
  })
}

util.inherits(World, require('events').EventEmitter)

util._extend(World.prototype, {
  config: function (option) {
    if (option) {
      util._extend(this.option, option)
    }
    console.log('## Setting ################################')
    console.log(this.option)
  },
  start: function () {
    console.log('## Start #################################')
    console.log('Welcome to the world~')

    this.server.listen(this.option.port)
    console.log('Listen:', this.option.port)
  },
  enter: function (user) {
    this.users.push(user)
    console.log('current user:' + this.users.length)
  },
  leave: function (user) {
    var index = this.users.indexOf(user)
    this.users.splice(index, 1)
    console.log('current user:' + this.users.length)
  },

  onConnection: function (socket) {
    var conn = new Connection(socket)
    if (this.option.maxConnection <= this.users.length) {
      conn.close(proto.PK_CRITICALERROR, 'max connection error')
      return
    }

    var user = new User(this, conn)
    this.enter(user)

    // socket-event
    var self = this
    conn.on('packet', function (header, data) {
      user.onPacket(header, data)
    })
    conn.on('packet_error', function (err) {
      user.onPacketError(err)
    })
    conn.on('error', function (err) {
      user.onError(err)
    })
    conn.on('close', function () {
      user.onClose()
    })
  },
  onError: function (err) {
    console.log('server error:', err.message)
  },
  onClose: function (close) {
    console.log('server close')
  },
})

module.exports = new World()

포트번호, 최대이용자수등 간단한 옵션과 사용자목록 관리내용을 추가하였다.

require('./world').start()