
TCP socket의 추상화 클래스이다.
net.Socket은 net.createConnection()로 생성해서 서버와 통신하는 데 사용하면 된다.
소켓 서버 상에서 Socket 객체는 클라이언트가 서버에 연결하는 시점이나 연결 이벤트 핸들러에 전달되는 시점에 생성한다. 서버에서는 Socket 객체를 사용해 클라이언트 연결과 클라이언트와 주고받는 데이터도 모니터링한다.
Socket 객체가 생성되면 서버에 연결된 기간 동안 다양한 이벤트들을 발생시킨다.
소켓 서버를 구현한다면 소켓 연결 수립과 종료, 데이터 읽기 쓰기 과정에서 방출되는 다양한 이벤트를 처리하는 콜백을 등록할 수 있다.
다음 코드는 클라이언트의 Socket 객체 기본 구현을 보여준다.
var net = require('net');
var client = net.connect({port:8107, host:'localhost'}, function(){
console.log('Client connected');
client.write('Some Data \r\n');
});
client.on('data', function(data){
console.log(data.toString());
client.end();
});
client.on('end', function(){
console.log('Client disconnected');
});
connect의 콜백 함수는 메시지를 남긴 후 일부 데이터를 서버에 쓴다. 서버에서 수신한 데이터를 처리하기 위해 on.data() 이벤트 핸들러가 구현됐다. 소켓 닫힘 처리를 위해 on('end') 이벤트 핸들러가 구현됐다.
close: 소켓이 완전히 닫히면 발생한다.connect: 소켓 연결이 성공적으로 설정되면 발생한다.data: 데이터를 수신할 때 발생한다.drain: 쓰기 버퍼가 비었을 때 발생한다. 업로드를 조절하는데 사용한다.end: 소켓의 다른 쪽 끝이 전송 종료 신호를 보낼 때 발생한다.error: 오류가 발생할 때 발생한다. 이 이벤트 직후에 close가 발생한다.lookup: 호스트 이름을 확인한 후 연결하기 전에 내보낸다.ready: 소켓을 사용할 준비가 되면 발생한다.timeout: 소켓이 비활성 상태에서 시간 초과되면 발생한다.TCP 소켓 서버를 생성하고 데이터를 읽기/쓰기가 가능한 연결을 만들기 위해 net.Serber 객체를 사용한다. Server 객체는 net.createServer() 호출 시 내부적으로 생성된다.
이 객체는 소켓 서버를 나타내고, 연결을 위한 수신 처리 후 서버 연결을 통한 데이터 송신/수신을 한다.
var net = require('net');
var server = net.createServer(function(client) {
console.log('Client connected');
client.on('data', function(data) {
console.log('Client sent ' + data.toString());
});
client.on('end', function() {
console.log('Client disconnected');
});
client.write('Hello');
});
server.listen(8107, function(){
console.log('Server listening for connection');
});
먼저 net.connect()를 호출해서 소켓 클라이언트를 생성한다.
연결할 port와 host를 전달하고, 연결 이벤트를 처리할 콜백 함수도 구현한다.
net.connect({port: 8107, host: 'localhost'}, function() {
// 이 안에는 연결 속성 설정
this.setTimeout(500);
this.setEncoding('utf8');
});
data 이벤트를 처리해 서버로부터 받은 데이터를 읽어오려면, 다음 핸들러를 추가한다.
this.on('data', function(data){
console.log("Read from server: " + data.toString());
...
this.end();
});
서버에 데이터를 쓰려면 write() 명령을 실행한다. 서버에 많은 데이터를 쓰거나 쓰기가 실패한 경우, drain 이벤트 핸들러를 구현해 버퍼가 비어있을 경우 다시 쓰기를 수행한다.
다음은 쓰기 실패시 처리를 위한 drain 핸들러를 구현하는 예제다. 클로저를 사용해 함수가 종료되더라도 소켓과 데이터 값들을 보존한다.
function writeData(socket, data){
var success = !socket.write(data);
if(!success){
(function(socket, data){
socket.once('drain', function(){
writeData(socket, data);
});
})(socket, data)
}
}
다음은 기본 TCP 소켓 클라이언트의 전체 구현을 보여준다.
서버에 3개의 다른 소켓이 열려있고 동시에 통신을 하고 있다. 각 클라이언트는 서로 다른 랜덤 포트 번호를 받아 생성된다.
var net = require('net');
function getConnection(connName){
var client = net.connect({port: 8107, host:'localhost'}, function() {
console.log(connName + ' Connected: ');
console.log(' local = %s:%s', this.localAddress, this.localPort);
console.log(' remote = %s:%s', this.remoteAddress, this.remotePort);
this.setTimeout(500);
this.setEncoding('utf8');
this.on('data', function(data) {
console.log(connName + " From Server: " + data.toString());
this.end();
});
this.on('end', function() {
console.log(connName + ' Client disconnected');
});
this.on('error', function(err) {
console.log('Socket Error: ', JSON.stringify(err));
});
this.on('timeout', function() {
console.log('Socket Timed Out');
});
this.on('close', function() {
console.log('Socket Closed');
});
});
return client;
}
function writeData(socket, data){
var success = !socket.write(data);
if (!success){
(function(socket, data){
socket.once('drain', function(){
writeData(socket, data);
});
})(socket, data);
}
}
var Dwarves = getConnection("Dwarves");
var Elves = getConnection("Elves");
var Hobbits = getConnection("Hobbits");
writeData(Dwarves, "More Axes");
writeData(Elves, "More Arrows");
writeData(Hobbits, "More Pipe Weed");
소켓 서버는 Server 객체의 close 와 error 이벤트와 클라이언트 Socket 객체의 연결 이벤트를 처리해야 한다.
Server 객체를 사용해 소켓 서버를 구현하는 첫 단계는 아래와 같이 net.createServer() 호출을 통해 소켓 서버를 생성한다. 연결 콜백 핸들러를 제공하고 listen() 호출을 통해 포트 수신을 시작한다.
var server = net.createServer(function(client){
...
});
server.listen(8107, function(){
...
});
listen 콜백 핸들러 안에서 서버 객체의 close와 error 이벤트를 지원할 핸들러를 추가한다.
server.on('close', function(){
console.log('Server Terminated');
});
server.on('error', function(err){
...
});
connection 이벤트 호출 내에서는 연결 속성을 설정한다. 아래와 같이 타임아웃이나 인코딩 설정을 할 수 있다.
this.setTimeout(500);
this.setEncoding('utf8');
data 이벤트 핸들러를 사용해 클라이언트에서 받은 데이터를 읽어오려면, 다음 핸들러를 추가한다.
this.on('data', function(data){
console.log("Reeived from client: " + data.toString());
...
});
다음은 기본 TCP 소켓 서버의 전체 구현을 보여준다.
소켓 서버는 8107 포트로 연결을 받고, 데이터를 읽은 후 클라이언트에 문자열을 쓴다.
var net = require('net');
var server = net.createServer(function(client) {
console.log('Client connection: ');
console.log(' local = %s:%s', client.localAddress, client.localPort);
console.log(' remote = %s:%s', client.remoteAddress, client.remotePort);
client.setTimeout(500);
client.setEncoding('utf8');
client.on('data', function(data) {
console.log('Received data from client on port %d: %s',
client.remotePort, data.toString());
console.log(' Bytes received: ' + client.bytesRead);
writeData(client, 'Sending: ' + data.toString());
console.log(' Bytes sent: ' + client.bytesWritten);
});
client.on('end', function() {
console.log('Client disconnected');
server.getConnections(function(err, count){
console.log('Remaining Connections: ' + count);
});
});
client.on('error', function(err) {
console.log('Socket Error: ', JSON.stringify(err));
});
client.on('timeout', function() {
console.log('Socket Timed out');
});
});
server.listen(8107, function() {
console.log('Server listening: ' + JSON.stringify(server.address()));
server.on('close', function(){
console.log('Server Terminated');
});
server.on('error', function(err){
console.log('Server Error: ', JSON.stringify(err));
});
});
function writeData(socket, data){
var success = !socket.write(data);
if (!success){
(function(socket, data){
socket.once('drain', function(){
writeData(socket, data);
});
})(socket, data);
}
}