일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- Spring
- oracle
- GPS
- jsr 296
- jQuery
- MySQL
- tomcat
- Android
- 전자정부프레임워크
- swingx
- Ajax
- Google Map
- PLSQL
- ibsheet
- sencha touch
- 가우스
- rowspan
- Struts
- 선택적조인
- iBATIS
- appspresso
- Eclipse
- node.js
- WebLogic
- dock
- PHP
- phonegap
- JSON
- JDOM
- MFC
Archives
- Today
- Total
Where The Streets Have No Name
android + node.js에서 websocket을 이용한 파일전송 본문
안드로이드에서 최신 websocket 스펙을 지원하는 라이브러리를 선정하는데 시간이 좀 걸렸습니다.
여러가지 테스트중 http://autobahn.ws/android 에서 구한걸로 테스트했습니다.
여러 websocket 라이브러리 비교는 http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations 여기
를 참조하세요.
node.js에서 사용된 websocket 모듈은 http://einaros.github.com/ws/ 에서 구한걸로 테스트했습니다.
node.js소스
var WebSocketServer = require('ws').Server
, express = require('express')
, fs = require('fs')
, http = require('http')
, util = require('util')
, path = require('path')
, app = express()
, events = require('events')
, ansi = require('ansi')
, cursor = ansi(process.stdout);
function BandwidthSampler(ws, interval) {
interval = interval || 2000;
var previousByteCount = 0;
var self = this;
var intervalId = setInterval(function() {
var byteCount = ws.bytesReceived;
var bytesPerSec = (byteCount - previousByteCount) / (interval / 1000);
previousByteCount = byteCount;
self.emit('sample', bytesPerSec);
}, interval);
ws.on('close', function() {
clearInterval(intervalId);
});
}
util.inherits(BandwidthSampler, events.EventEmitter);
function makePathForFile(filePath, prefix, cb) {
if (typeof cb !== 'function') throw new Error('callback is required');
filePath = path.dirname(path.normalize(filePath)).replace(/^(\/|\\)+/, '');
var pieces = filePath.split(/(\\|\/)/);
var incrementalPath = prefix;
function step(error) {
if (error) return cb(error);
if (pieces.length == 0) return cb(null, incrementalPath);
incrementalPath += '/' + pieces.shift();
fs.exists(incrementalPath, function(exists) {
if (!exists) fs.mkdir(incrementalPath, step);
else process.nextTick(step);
});
}
step();
}
cursor.eraseData(2).goto(1, 1);
app.use(express.static(__dirname + '/public'));
var clientId = 0;
var wss = new WebSocketServer({host:'192.168.0.59', port: 8081});
wss.on('connection', function(ws) {
var thisId = ++clientId;
cursor.goto(1, 4 + thisId).eraseLine();
console.log('Client #%d connected', thisId);
var sampler = new BandwidthSampler(ws);
sampler.on('sample', function(bps) {
cursor.goto(1, 4 + thisId).eraseLine();
//console.log('WebSocket #%d incoming bandwidth: %d MB/s', thisId, Math.round(bps / (1024*1024)));
});
var filesReceived = 0;
var currentFile = null;
ws.on('message', function(data, flags) {
if (!flags.binary) {
try{
currentFile = JSON.parse(data);
console.log(currentFile);
}catch(e){
console.log(e);
}
// note: a real-world app would want to sanity check the data
}
else {
if (currentFile == null) return;
makePathForFile(currentFile.path, __dirname + '/uploaded', function(error, path) {
if (error) {
console.log(error);
ws.send(JSON.stringify({event: 'error', path: currentFile.path, message: error.message}));
return;
}
fs.writeFile(path + '/' + currentFile.name, data, function(error) {
++filesReceived;
console.log('received %d bytes long file, %s', data.length, currentFile.path);
ws.send(JSON.stringify({event: 'complete', path: currentFile.path}));
currentFile = null;
});
});
}
});
ws.on('close', function() {
cursor.goto(1, 4 + thisId).eraseLine();
console.log('Client #%d disconnected. %d files received.', thisId, filesReceived);
});
ws.on('error', function(e) {
cursor.goto(1, 4 + thisId).eraseLine();
console.log('Client #%d error: %s', thisId, e.message);
});
});
fs.mkdir(__dirname + '/uploaded', function(error) {
// ignore errors, most likely means directory exists
console.log('Uploaded files will be saved to %s/uploaded.', __dirname);
console.log('Remember to wipe this directory if you upload lots and lots.');
app.listen(8080);
console.log('Listening on http://localhost:8080');
});
안드로이드 소스
package com.example.websocket2;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import net.neocorea.android.util.ExceptionUtil;
import net.neocorea.android.util.FileUtil;
import org.codehaus.jackson.map.ObjectMapper;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import de.tavendo.autobahn.WebSocketConnection;
import de.tavendo.autobahn.WebSocketException;
import de.tavendo.autobahn.WebSocketHandler;
import de.tavendo.autobahn.WebSocketMessage;
import de.tavendo.autobahn.WebSocketOptions;
public class MainActivity extends Activity {
public static final String TAG = "WebSocket2";
private final CustomConnection mConnection = new CustomConnection();
public static final String wsuri = "ws://192.168.0.59:8081";
private static final int FILE_SELECT_CODE = 0;
private static String FILE_SELECT_NAME = "";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSelect = (Button) findViewById(R.id.btnSelect);
btnSelect.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "파일 선택"), FILE_SELECT_CODE);
}
});
Button btnSend = (Button) findViewById(R.id.btnSend);
btnSend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 전송될 파일크기제한 설정
if ("".equals(FILE_SELECT_NAME)) {
Log.d(TAG, "선택된 파일이 없습니다.");
return;
}
if (mConnection.isConnected()){
mConnection.fileSend(FILE_SELECT_NAME);
}else{
try {
mConnection.connect(wsuri, new CustomHandler(mConnection, FILE_SELECT_NAME));
} catch (Exception e) {
ExceptionUtil.WriteStack(TAG, e);
}
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_SELECT_CODE:
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
Log.d(TAG, "File Uri: " + uri.toString());
try {
FILE_SELECT_NAME = FileUtil.getPath(this, uri);
Log.d(TAG, "File Path: " + FILE_SELECT_NAME);
} catch (URISyntaxException e) {
ExceptionUtil.WriteStack(TAG, e);
}
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
package com.example.websocket2;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import net.neocorea.android.util.ExceptionUtil;
import net.neocorea.android.util.FileUtil;
import org.codehaus.jackson.map.ObjectMapper;
import android.util.Log;
import de.tavendo.autobahn.WebSocketConnection;
import de.tavendo.autobahn.WebSocketHandler;
import de.tavendo.autobahn.WebSocketOptions;
public class CustomHandler extends WebSocketHandler {
public static final String TAG = MainActivity.TAG;
private CustomConnection conn;
private String filePath;
public CustomHandler(CustomConnection conn, String filePath) {
super();
this.conn = conn;
this.filePath = filePath;
}
@Override
public void onClose(int code, String reason) {
Log.d(TAG, "Status: Disconnected");
}
@Override
public void onOpen() {
Log.d(TAG, "Status: Connected");
conn.fileSend(filePath);
}
@Override
public void onTextMessage(String payload) {
Log.d(TAG, "Got echo: " + payload);
}
}
package com.example.websocket2;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import net.neocorea.android.util.ExceptionUtil;
import net.neocorea.android.util.FileUtil;
import org.codehaus.jackson.map.ObjectMapper;
import de.tavendo.autobahn.WebSocketConnection;
import de.tavendo.autobahn.WebSocketOptions;
public class CustomConnection extends WebSocketConnection {
public static final String TAG = MainActivity.TAG;
public void fileSend(String filePath){
try {
byte[] fileData = FileUtil.getBytesFromFile(new File(filePath));
mOptions.setMaxMessagePayloadSize(fileData.length);
Map dummyData1 = new HashMap();
dummyData1.put("name", (new File(filePath)).getName());
dummyData1.put("path", "");
ObjectMapper om = new ObjectMapper();
this.sendTextMessage(om.writerWithDefaultPrettyPrinter().writeValueAsString(dummyData1));
this.sendBinaryMessage(fileData);
} catch (Exception e) {
ExceptionUtil.WriteStack(TAG, e);
}
}
}