2010-04-21 20 views
5

Java'yı öğrenmeye çalışıyorum. Basit bir ağ bağlantılı 4 oyunun yanı sıra sohbet özelliği uygulamak istiyorum.Java ServerSocketChannel SocketChannel (Geri Arama)

Ağ mantığımın engellenmesini istemiyorum, bu yüzden çok çalıştıktan sonra SocketChannel'in gereksinimlerimi yeniden düzenledikten sonra olduğumu buldum.

Mantıksız olan şey, hala SocketChannels'ta CallBack işlevlerinin olmamasıdır. C# 'da olduğu gibi.

Bu saat için sorgum: Chat veya Oyun formuna (JFrame) alınan verileri nasıl teslim edebilirim?

Bazı yönlendirme memnuniyetle karşılanır.

+0

Bloke edici olmayan G/Ç yerine çoklu iş parçacığı kullanmanızı öneririz. –

cevap

13

Seçici kullanmanız gerekir. İlk olayları almak için bir Seçici oluşturun:

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

Sonra geldikleri gibi (seni olayları işlemek için Selector'ü kullanmak gerekir:

Selector selector = Selector.open() 

Sonra seçici ile ServerSocketChannel kaydetmeniz gerekir sürecin "geri arama" bölümü olarak bu düşünebilirsiniz:

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); 
} 

bir seçim tuşu inf içerecektir anahtar kabul için et doAccept(), doRead() ve doWrite() olacaktır. yeni Soket oluşturmak için ormation. seçicinin alınan olaylar bağlantı (örneğin sizin oyununda bir oyuncu olabilir) isnat edilebilir, böylece

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); 
} 

son satırı anahtarına bazı nesne ekler. Şimdi yeni bağlantıları kabul edebilir ve sadece okumak ve yazmanız gerekir. yazmak için benzer

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(); 
} 

Okuma sadece veri hazır olmak için SocketChannels (ByteBuffer) okumak (varyantları veya bir) diyoruz sonra ByteBuffer oluşturmak ve yalındır oldukça olduğunu Kanal boş olana kadar. sınıfta içinde tampon yönetmek için uygun kod gerekir

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); 
    } 
} 

Not: genellikle yazma olayını alma dek yazılacak verileri tampon isteyeceksiniz olarak

Yazma biraz daha zordur olay dolu olduğunda veya tamponda bulunan tüm veriler sokete yazılmamışsa, işlem sırasında atılabilecek çeşitli istisnalar dışında, yazma bekletme yönteminde uygun şekilde değiştirilir. Umarım başlamana yardım eder.

+0

Bu çok yararlı oldu, şimdi süreci daha iyi anlıyorum. – iTEgg