2012. 7. 26. 04:34

멤버십 과제중 안드로이드로 게임통신을 해야하는 부분에서 자바에 WSASelect 가 없으므로 비동기 소켓을 보내고 받는것이 익숙치 않았다. IOCP 소켓이란 것이 이미 윈도우의 이벤트를 이용 하는 것이기 때문에, 자바에서는 100% 맞는 통신은 없지만, 아래와 같이 channel selector 를 이용하여 비슷한 효과로 비동기 소켓을 처리 할 수 있다. 


자바는 WSAselect 가 없기 때문에 IOCP 통신을 해주기위해서 select 개념을 사용해야 한다. 


MainActivity.java


 import android.os.Bundle;

import android.app.Activity;


public class MainActivity extends Activity {


    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

    

SimpleChatClient scc = new SimpleChatClient();

scc.initServer();

scc.startServer();

    }

}




SimpleChatClient.java

 

package com.example.iocpclient;


import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.SocketChannel;

import java.nio.charset.CharacterCodingException;

import java.nio.charset.Charset;

import java.nio.charset.CharsetDecoder;

import java.util.Iterator;


import android.util.Log;


public class SimpleChatClient {


private static final String HOST = "210.118.64.148";

private static final int PORT = 5056;


private Selector selector = null;

private SocketChannel sc = null;


private Charset charset = null;

private CharsetDecoder decoder = null;

public SimpleChatClient(){//Handler MainAct) {


charset = Charset.forName("EUC-KR");

decoder = charset.newDecoder();

}


public void initServer() {


try {


// open Selector

selector = Selector.open();

// 소켓채널을 생성한다.

sc = SocketChannel.open(new InetSocketAddress(HOST, PORT));

// 비 블록킹 모드로 설정한다.

sc.configureBlocking(false);

// 서버소켓 채널을 셀렉터에 등록한다.

sc.register(selector, SelectionKey.OP_READ);

} catch (IOException ex) {


Log.e("aaa", "_____________________1" + ex.toString());

System.exit(0);

// log(Level.WARNING, "SimpleChatClient.initServer()", ex);

}

}


public void startServer() {

//startWriter();

Thread tWriter = new WriteThread(sc);

tWriter.start();

/*쓰레드 추가 */

ReaderThread tReader = new ReaderThread();

tReader.start();

}

public class ReaderThread extends Thread {

public ReaderThread(){

}

public void run() {

try {

while (true) {

// info("요청을 기다리는중...");

// 셀렉터의 select() 메소드로 준비된 이벤트가 있는지 확인한다.

selector.select();

// 셀렉터의 SelectoedSet에 저장된 준비된 이벤트들(SelectionKey)을 하나씩 처리한다.

Iterator it = selector.selectedKeys().iterator();

while (it.hasNext()) {

SelectionKey key = (SelectionKey) it.next();

if (key.isReadable()) {

// 이미 연결된 클라이언트가 메시지를 보낸경우...

read(key);

}

// 이미 처리한 이벤트므로 반드시 삭제해준다.

it.remove();

}

}

} catch (Exception ex) {

// log(Level.WARNING ,"SimpleChatClient.startServer()", ex);

}

}

}class WriteThread extends Thread {


private SocketChannel sc = null;


public WriteThread(SocketChannel sc) {

this.sc = sc;

}


public void run() {


ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

String message =null;


try {

sleep(400); //소켓 연결하는 동안 잠깐 대기. 

while (!Thread.currentThread().isInterrupted()) {

sleep(5); //초당 프레임 체크 

buffer.clear();

message=singletonMove.movement;  //싱글톤으로 가져온 변수값 


if (message.length() <2 || message==null) {

//Log.e("============","===============error NULL"+message);


} else {

if (message.equals("quit")|| message.equals("shutdown")) {

System.exit(0);

}


buffer.put(message.getBytes());

buffer.flip();

sc.write(buffer);

message = null;

}

}


} catch (Exception ex) {

ex.printStackTrace();

System.exit(0);

// log(Level.WARNING, "MyThread.run()", ex);

} finally {

System.exit(0);

clearBuffer(buffer);

}

}

}


private void read(SelectionKey key) {


// SelectionKey로부터 소켓채널을 얻어온다.


SocketChannel sc = (SocketChannel) key.channel();

// ByteBuffer를 생성한다.

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

int read = 0;


try {


// 요청한 클라이언트의 소켓채널로부터 데이터를 읽어들인다.

read = sc.read(buffer);


// info(read + " byte를 읽었습니다.");

} catch (IOException ex) {

try {

sc.close();

} catch (IOException ex1) {


}

}


buffer.flip();


String data = new String();


try {

data = decoder.decode(buffer).toString();

} catch (CharacterCodingException ex) {


// log(Level.WARNING, "SimpleChatClient.read()", ex);

}


System.out.println("Message - " + data);


// 버퍼 메모리를 해제한다.

clearBuffer(buffer);

}


private void clearBuffer(ByteBuffer buffer) {


if (buffer != null) {

buffer.clear();

buffer = null;

}


}



}



Posted by k1rha