2010-04-21 2 views
5

Java를 배우려고합니다. 나는 채팅 기능뿐만 아니라 간단한 네트워크 연결 게임을 구현하고 싶다.Java ServerSocketChannel SocketChannel (콜백)

내 네트워크 논리를 차단하지 않기를 바란다. 많은 연구 끝에 SocketChannel이 내 요구를 회피 한 후에 무엇인지 찾아 냈다.

SocketChannels에서 콜백 기능이 부족하다는 점을 감안하지 못했습니다. C#에서와 마찬가지입니다.

내 시간은 다음과 같습니다.받은 데이터를 채팅 또는 게임 양식 (JFrame)으로 어떻게 전송합니까?

일부 안내를 환영합니다.

+0

비 차단 입출력 대신 다중 스레드를 사용하는 것이 좋습니다. –

답변

13

선택기를 사용해야합니다. 먼저 이벤트를 수신하는 선택기를 만들 :

SelectionKey acceptKey = server.register(selector, SelectionKey.OP_ACCEPT); 

그런 다음 당신은 그들이에서 와서 (당신이 이벤트를 처리하기 위해 선택기를 사용해야합니다

Selector selector = Selector.open() 

그런 다음 당신은 선택과 ServerSocketChannel을 등록해야 프로세스의 "콜백"부분으로 생각할 수 있습니다

while(true){ 
    //how many channel keys are available 
    int available = selector.select(); 
    //select is blocking, but should only return if available is >0, this is more of a sanity check 
    if(available == 0) continue; 

    Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); 
    while(keys.hasNext()){ 
    SelectionKey key = keys.next(); 
    keys.remove(); 
    //someone is trying to connect to the server socket 
    if(key.isAcceptable()) doAccept(key); 
    //someone is sending us data 
    else if(key.isReadable()) doRead(key); 
    //we are trying to (and can) send data 
    else if(key.isWritable()) doWrite(key); 
} 

는 선택 키가 INF가 포함됩니다 키 동의를 들어 고기가 doAccept(), doRead() 및 doWrite()에있을 것입니다. 새로운 소켓을 만들기위한 오리온. 선택기에서받은 이벤트가 연결 (예를 들어,이 게임의 선수가 될 수 있음)에 기인 할 수 있도록

doAccept(SelectionKey key){ 

//create the new socket 
SocketChannel socket = ((ServerSocketChannel)key.channel()).accept(); 
//make it non-blocking as well 
socket.configureBlocking(false); 

... 
//here you would likely have some code to init your game objects/communication protocol, etc. and generate an identifier object (used below). 
//and be able to find the socket created above 
... 

//Since it is non blocking it needs a selector as well, and we register for both read and write events 
SelectionKey socketKey = socket.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE); 
// so we can identify the events as they come in 
socketKey.attach(someSocketIndentifier); 
} 

마지막 줄은 키에 어떤 객체를 추가합니다. 이제 새로운 연결을 수락 할 수 있으며 읽고 쓰는 것이 필요합니다. 쓰기에 대한 유사

doRead(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.readTheData(); 
} 

doWrite(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.getSocketHandler().writePendingData(); 
} 

독서는 단지의 데이터를 준비하는 SocketChannel에는이 (의 ByteBuffer)을 읽는 (그 변종 또는 하나)를 호출 한 후 ByteBuffer를 생성하고, 정직하고 공정하게하다 채널이 비어있을 때까지. 당신이 클래스에 버퍼를 관리하기 위해 적절한 코드가 필요합니다

class MyNetworkClass{ 
    ByteBuffer writeBuffer = ByteBuffer.allocate(1024); 
    SocketChannel commchannel; //from the server accept processing 

    ... 

    public void write(byte[] data){ 
    //here the class writeBuffer object is filled with the data 
    //but it isn't actually sent over the socket 
    ... 
    } 

    public void writePendingData(){ 
    //here actually write the data to the socket 
    commchannel.write(writeBuffer); 
    } 
} 

참고 : 일반적으로는 쓰기 이벤트를받을 때까지 데이터가 기록되는 버퍼 할 것 같은

쓰기에는 약간 까다 롭습니다 처리 중에 throw 될 수있는 각종의 예외 뿐만이 아니라, 버퍼 내의 모든 데이터가 소켓에 기입 해지지 않은 경우, 기입 해 대기 중의 메소드로 적절하게 변경하는 이벤트 희망이 당신을 시작하는 데 도움이됩니다.

+0

이것은 매우 유용합니다. 이제 프로세스가 더 잘 이해됩니다. – iTEgg