TCP/IP Socket๊ณผ Socket io ์ฌ์ฉ๋ฒ
์์ฑ์ : ์ก์ง์ฐ
Present Time : 2018-09-28
- https://m.blog.naver.com/goldenkingll/70106915167
- https://d2.naver.com/helloworld/1336
- http://woowabros.github.io/woowabros/2017/09/12/realtime-service.html
- https://github.com/socketio/socket.io-client-java
๋ ํ๋ก๊ทธ๋จ์ด ๋คํธ์ํฌ๋ฅผ ํตํด ์๋ก ํต์ ์ ์ํ ํ ์ ์๋๋ก ์์ชฝ์ ์์ฑ๋๋ ๋งํฌ์ ๋จ์์ ๋๋ค.
- ๋ฐ์ดํฐ๋ฅผ ์บก์ํํ์ฌ ์ ๋ฌ ๊ฐ๋ฅ
- UNIX์์์ ์ ์ถ๋ ฅ ๋ฉ์๋์ ํ์ค์ธ ๊ฐ๋ฐฉ/์ฝ๊ธฐ/์ฐ๊ธฐ/๋ซ๊ธฐ ๋ฉ์ปค๋์ฆ
TCP ๋ ๋ ํ๋ก๊ทธ๋จ ๊ฐ์ ํต์ ์ด ์ฒ์ ์์๋ ๋๋ถํฐ ๋๋ ๋๊น์ง ๊ณ์ ์ฐ๊ฒฐ์ ์ ์งํ๋ ์ฐ๊ฒฐ์งํฅ(Connection oriented) ๋ฐฉ์์ ๋๋ค.
- ์คํธ๋ฆผ ์์ผ ๋ฐฉ์
- ์์ชฝ ์ดํ๋ฆฌ์ผ์ด์ ๋ชจ๋ ๋ฐ์ดํฐ ์ฃผ๊ณ ๋ฐ๊ธฐ ๊ฐ๋ฅ
- ํ๋ฆ์ ์ด๋ฑ์ ๋ณด์ฅํด ์ฃผ๋ฉฐ ์ก์ ๋ ์์์ ๋ฐ๋ฅธ ์ค๋ณต๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์์ ๊ฐ๋ฅ
- IP์ ํฌํธ ๋ฒํธ๋ก ์์ผ์ ์ฐ๊ฒฐํ๋ฉด ํต์ ์์
- byte ์๋ฃํ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋
- TCP Client
- ์์ผ์ ์์ฑํฉ๋๋ค.
- ์๋ฒ๋ก connect() ํฉ๋๋ค.
- ์ ์์ด ์ฑ๊ณต๋๋ค๋ฉด read ๋ฐ write ํจ์๋ฅผ ํตํด ์๋ฒ์ ํต์ ์ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ์ ๋ง์น๋ฉด close๋ก ์์ผ์ ๋ซ์ต๋๋ค.
- TCP Server
- ๋ฃ๊ธฐ ์์ผ์ ์์ ํฉ๋๋ค.
- bindํฉ๋๋ค. (๋ด์ ๋ถ์ฌ)
- listenํฉ๋๋ค. (๋ด์ ์ฐ๊ฒฐ)
- accept() ํด๋ผ์ด์ธํธ๊ฐ connectํ ๊ฒฝ์ฐ ์์ผ์ ์์ฑ ํ๊ณ ์ฐ๊ฒฐํฉ๋๋ค.
- read์ write ํจ์๋ฅผ ์ด์ฉํด ๋ฉ์์ง๋ฅผ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ๋ ์ฐ๊ฒฐ ์์ผ์ ๋ซ์ต๋๋ค.
- ์ฌ์ฉ์ ๋ง์ณค์ ๊ฒฝ์ฐ ๋ฃ๊ธฐ ์์ผ์ ๋ซ์ต๋๋ค.
- Socket ๊ฐ์ฒด๋ฅผ ์์ฑ
private static Socket socket;
socket = new Socket();
- ์๋ฒ์ ์์ดํผ์ ํฌํธ๋ฒํธ๋ฅผ ์ ๊ณ connect()๋ก ์ฐ๊ฒฐํฉ๋๋ค.
socket.connect(new InetSocketAddress("localhost", 'ํฌํธ๋ฒํธ'));
3. ์ ์์ด ์ฑ๊ณตํ๋ค๋ฉด read ๋ฐ write ํจ์๋ฅผ ํตํด ์๋ฒ์ ํต์ ์ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
- ์คํธ๋ฆผ ์์ผ์ผ๋ก ํต์ ํ๊ธฐ ๋๋ฌธ์ InputStream๊ณผ OutputStream์ ๋ง๋ญ๋๋ค.
- ๋ํ ๋ฐ์ดํธ ๋ฐฐ์ด๋ก ์๋ฒ์ ํต์ ์ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
- OutputStream์ write() ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ต๋๋ค.
- InputStream์ read() ๋ก ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ต๋๋ค.
- ๋ฐ์ดํฐ ์ก์์ ์ ๋ฐ์ดํฐ๋ฅผ Charset์ผ๋ก UTF ๋ฑ์ ์ค์ ํ ์ ์์ต๋๋ค.
private static InputStream is;
private static OutputStream os;
is = socket.getInputStream();
os = socket.getOutputStream();
byte[] byteArr = null;
String msg = "Hello Server";
byteArr = msg.getBytes("UTF-8");
os.write(byteArr);
os.flush();
System.out.println("Data Transmitted OK!");
byteArr = new byte[512];
int readByteCount = is.read();
if(readByteCount == -1)
throw new IOException();
msg = new String(byteArr, 0, readByteCount, "UTF-8");
System.out.println("Data Received OK!");
System.out.println("Message : " + msg);
- ํต์ ์ด ๋๋๋ฉด ์คํธ๋ฆผ ์์ผ๊ณผ ์์ผ์ close() ํจ์๋ก ๋ซ์ต๋๋ค.
is.close();
os.close();
socket.close();
private static ServerSocket serverSocket;
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(3880));
ํด๋ผ์ด์ธํธ์์ ์์ฒญ์ด ์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค!!!!
private static Socket socket;
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
byte[] byteArr = new byte[512];
String msg = null;
int readByteCount = is.read(byteArr);
if(readByteCount == -1)
throw new IOException();
msg = new String(byteArr, 0, readByteCount, "UTF-8");
System.out.println("Data Received OK!");
System.out.println("Message : " + msg);
msg = "Hello Client";
byteArr = msg.getBytes("UTF-8");
os.write(byteArr);
System.out.println("Data Transmitted OK!");
os.flush();
is.close();
os.close();
socket.close();
if(!serverSocket.isClosed()) {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
- ์ค์๊ฐ ์ด๋ฒคํธ ์๋ฒ๋ฅผ ๊ฐ๋ฐ ํ ์ ์๋ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๋๋ค.
- WebSocket์ ๊ธฐ๋ฐ์ผ๋ก FlashSocket, AJAX Long Polling๋ฑ ๋ค์ํ ๋ฐฉ์์ ์ค์๊ฐ ์น ๊ธฐ์ ๋ค์ ํ๋์ API๋ก ์ถ์ํํ node.js ๋ชจ๋(MIT ๋ผ์ด์ผ์ค ์คํ์์ค)
- ๋ฉํฐ ๋๋ฐ์ด์ค(web, android, ios, windows)๋ฅผ ์ง์ํฉ๋๋ค.
- ํต์ ๊ตฌํ์ ์ฝ๋๊ฐ ๋งค์ฐ ๊ฐ์ํฉ๋๋ค.
- Socket์ ์ฑ๊ฒฉ๊ณผ ๊ฐ์ด ์ค์๊ฐ ํต์ ๊ฐ๋ฅ
- http๋ฅผ ํตํด ํต์ ์ด ๊ฐ๋ฅํ๊ณ JsonObject๋ ์ผ๋ฐ Object๋ก ํต์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ์ ์น ์๋ฒ์ ์ข ๋ฅ์ ๋ฒ์ ์ ํ์ ํ์ฌ ๊ฐ์ฅ ์ ํฉํ ๊ธฐ์ ์ ์ ํํ์ฌ ์ฌ์ฉํ๋ ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ ๋ธ๋ผ์ฐ์ ์ ์ข ๋ฅ์ ์๊ด์์ด ์ค์๊ฐ ์น ๊ตฌํ ๊ฐ๋ฅ
- Socket.io๋ Javascript์ ์ด์ ์ด ๋ง๋ค์ด์ก์ต๋๋ค.
- ๋ค์ํ ์ธ์ด์ ์๋ฒ์ ํต์ ์ ํ๊ธฐ์๋ ์ ์ฝ์ด ์์ต๋๋ค.
- Gradle์ socket.io๋ฅผ ์ถ๊ฐํฉ๋๋ค.
dependencies {
...์๋ต
implementation ('com.github.nkzawa:socket.io-client:1.0.0'){
exclude group: 'org.json', module: 'json'
}
}
- TCP/IP์ ๋์ผํ๊ฒ ์์ผ์ ๋ง๋ญ๋๋ค.
- http๋ก ์ฐ๊ฒฐ์ด ๊ฐ๋ฅํ๋ฉฐ, ์๋ฒ์ ์ฃผ์์ ํฌํธ ๋ฒํธ๋ฅผ ์ด๊ธฐํ ํด์ค๋๋ค.
- URI ์ด๊ธฐํ ๊ณผ์ ์ ์์ธ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
private Socket socket;
{
try{
socket = IO.socket("http://***.***.***.***:***");
} catch (URISyntaxException ue) {
ue.printStackTrace();
}
}
- connect() ํจ์๋ก ์์ผ์ ์ฐ๊ฒฐํฉ๋๋ค.
socket.connect();
- ํด๋ผ์ด์ธํธ๋ ์ด๋ค ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์ด๋ฒคํธ๋ฅผ ์๋ฒ๋ก ์ก์ ํ ์ ์์ต๋๋ค.
- emit() ํจ์๋ฅผ ํตํด ๋ฐ์ดํฐ ๋๋ ๋ฉ์์ง๋ฅผ ์๋ฒ์ ์ ๋ฌํฉ๋๋ค.
- ์๋ฒ๋ ์ด๋ฅผ ์ด๋ฒคํธ์ ์ด๋ฆ์ผ๋ก ๊ตฌ๋ถํ์ฌ ์์ ํฉ๋๋ค.
socket.emit("EVENT_NANE", DATA);
- ์๋ฒ๋ ๋ค๋ฅธ ์ธ๋ถ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด๋ ์๋ฒ์ ์ด๋ฒคํธ ๋ฐ์ ์ ํด๋ผ์ด์ธํธ์ ์ด๋ฒคํธ๋ฅผ ์ก์ ํ ์ ์์ต๋๋ค.
- on() ํจ์๋ฅผ ํตํด ํด๋น ์ด๋ฒคํธ ๋ช ์ ์ด์ฉํด ๊ตฌ๋ถํ๊ณ ์๋ฒ์ emit์ ๋ฐ์ํ๋ ๋ฆฌ์ค๋๋ฅผ ๊ตฌํํฉ๋๋ค.
- ๋ฆฌ์ค๋ ์์ call ํจ์ ์์๋ ์ด๋ฒคํธ ์์ ํ ์คํํ ๋ด์ฉ์ ๋ด์ต๋๋ค.
socket.on("EVENT_NAME", '๋ฆฌ์ค๋ ์ต๋ช
๊ตฌํ ๊ฐ์ฒด');
Emitter.Listener '๋ฆฌ์ค๋ ์ต๋ช
๊ตฌํ ๊ฐ์ฒด' = new Emitter.Listener() {
@Override
public void call(Object... args) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// ์ด๋ฒคํธ ์์ ์ ์คํํ ๋ด์ฉ๋ค
}
});
- ์๋ฒ์์ ํต์ ์ด ๋ ์ด์ ํ์ ์๋ ๊ฒฝ์ฐ disconnect() ํจ์๋ฅผ ์ด์ฉํด connect๋ฅผ ๋์ต๋๋ค.
- ๊ทธ๋ฆฌ๊ณ on ์์ผ ๋์๋ ์์ผ๋ off() ํจ์๋ก ๋ซ์ต๋๋ค.
protected void onDestroy() {
super.onDestroy();
socket.disconnect();
socket.off("EVENT_NAME", '๋ฆฌ์ค๋ ์ต๋ช
๊ตฌํ ๊ฐ์ฒด');
}
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
console.log("user connect");
socket.on('๋ฐ์ ์ด๋ฒคํธ ๋ช
', function(){
console.log("๋ฐ์ ์ด๋ฒคํธ ๋ช
");
io.emit('๋ณด๋ผ ์ด๋ฒคํธ ๋ช
', "๋ฉ์์ง๋ ๋ฐ์ดํฐ");
});
});
http.listen('ํฌํธ ๋ฒํธ!', function(){
console.log("server on ํฌํธ๋ฒํธ");
});
- TCP/IP์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ ํ์ ์ byte๋ฐฐ์ด๋ก ํด์ผํ๊ณ Charset์ ํด์ผ ๋ฐ์ดํฐ๊ฐ ๊บ ์ง์ง ์์ต๋๋ค.
- ์์ผ์ ์์ฑํ๊ณ ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉ์ ํ๊ณ ๋๋ฉด ๊ผญ ์ ์์ ์ผ๋ก ์์ผ์ ์ฐ๊ฒฐ์ ๋๊ณ ์์ผ์ ๋ซ์์ค์ผ ํฉ๋๋ค.
- ์์ผ๋ ํต์ ์ด๊ธฐ ๋๋ฌธ์ ๋ฉํฐ ์ค๋ ๋๋ฅผ ํ์ฉํ์ฌ ์์ ์ ํด์ค์ผ ์ฑ๋ฅ ๊ฐ์ ๋ฐ ๋ก์ง์ด ์ํค๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
- Socket.io๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ด๋ฒคํธ ๋ช ์ด ํท๊ฐ๋ฆฌ์ง ์๋๋ก ์ ์ค์ ํด์ผ ํฉ๋๋ค. ์ด๋ฒคํธ๊ฐ ์๊ฐ๋ฆด ๊ฒฝ์ฐ ์ผ์ผ์ด ํ์ธํด์ผํ๋ ๋ถ์์ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
- static์ด ์๋๋ผ Kotlin์์๋ companion object๋ก socket์ ๋ง๋ค์ด์ค๋๋ค.
companion object {
private lateinit var socket : Socket
fun get(): Socket {
try {
socket = IO.socket("http://127.0.0.0:3000")
} catch (e: URISyntaxException) {
e.printStackTrace()
}
return socket
}
}
- ๊ทธ ์ธ ๋๋คํํ์์ ์ข ๋ ๊ฐํธํ๊ฒ ์ฌ์ฉํ ์ ์๋ค๋ ์ ์ธ์๋ ๋ค๋ฅธ ์ ์ด ์์ต๋๋ค.
class MainActivity : AppCompatActivity() {
lateinit var Text : TextView
lateinit var lighton_btn: Button
lateinit var lightoff_btn: Button
lateinit var socket: Socket
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
lighton_btn = findViewById(R.id.lighton_button)
lightoff_btn = findViewById(R.id.lightoff_button)
Text = findViewById(R.id.message)
socket = SocketApplication.get()
Text.setText("์์ผ ์์ฑ")
socket.connect()
lighton_btn.setOnClickListener { v ->
socket.emit("lightOn")
Text.setText("Light on Emit ์ฑ๊ณต")
}
lightoff_btn.setOnClickListener { v ->
socket.emit("lightOff")
Text.setText("Light off Emit ์ฑ๊ณต")
}
}
}
class MainActivity : AppCompatActivity() {
lateinit var Text : TextView
lateinit var Receive_Text: TextView
lateinit var socket: Socket
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Text = findViewById(R.id.message)
Receive_Text = findViewById(R.id.receive_Text)
socket = SocketApplication.get()
socket.on("lightOn",light_on)
socket.on("lightOff", light_off)
socket.connect()
}
var light_on = Emitter.Listener { args ->
runOnUiThread({
Text.setText("์์ผ on ์ฑ๊ณต")
Receive_Text.setText(args[0].toString())
})
}
var light_off = Emitter.Listener { args ->
runOnUiThread({
Text.setText("์์ผ on ์ฑ๊ณต")
Receive_Text.setText(args[0].toString())
})
}
}