Java Socket编程实例(五)- NIO UDP实践

时间:2021-07-14 16:13:02

一、回传协议接口和UDP方式实现:

1.接口:

?
1
2
3
4
5
6
7
8
import java.nio.channels.SelectionKey;
import java.io.IOException;
 
public interface EchoProtocol {
 void handleAccept(SelectionKey key) throws IOException;
 void handleRead(SelectionKey key) throws IOException;
 void handleWrite(SelectionKey key) throws IOException;
}

2.实现:

?
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
29
30
31
32
33
34
35
36
37
38
39
40
import java.net.SocketAddress;
import java.nio.channels.*;
import java.nio.ByteBuffer;
import java.io.IOException;
 
public class UDPEchoSelectorProtocol implements <span style="font-size: 1em; line-height: 1.5;">EchoProtocol </span><span style="font-size: 1em; line-height: 1.5;">{</span>
  private static final int ECHOMAX = 255; // Maximum size of echo datagram
 
  static class ClientRecord {
    public SocketAddress clientAddress;
    public ByteBuffer buffer = ByteBuffer.allocate(ECHOMAX);
  }
 
  public void handleAccept(SelectionKey key) throws IOException {
     
  }
 
  public void handleRead(SelectionKey key) throws IOException {
    DatagramChannel channel = (DatagramChannel) key.channel();
    ClientRecord clntRec = (ClientRecord) key.attachment();
    clntRec.buffer.clear(); // Prepare buffer for receiving
    clntRec.clientAddress = channel.receive(clntRec.buffer);
    if (clntRec.clientAddress != null) { // Did we receive something?
      // Register write with the selector
      key.interestOps(SelectionKey.OP_WRITE);
    }
  }
 
  public void handleWrite(SelectionKey key) throws IOException {
    DatagramChannel channel = (DatagramChannel) key.channel();
    ClientRecord clntRec = (ClientRecord) key.attachment();
    clntRec.buffer.flip(); // Prepare buffer for sending
    int bytesSent = channel.send(clntRec.buffer, clntRec.clientAddress);
    if (bytesSent != 0) { // Buffer completely written?
      // No longer interested in writes
      key.interestOps(SelectionKey.OP_READ);
    }
  }
 
}

二、NIO UDP客户端:

?
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
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
 
public class UDPEchoClientNonblocking {
 
  private static final int TIMEOUT = 3000; // Resend timeout (milliseconds)
  private static final int MAXTRIES = 255; // Maximum retransmissions
   
  public static void main(String args[]) throws Exception {
    // Convert input String to bytes using the default charset
    byte[] bytesToSend = "0123456789abcdefghijklmnopqrstuvwxyz".getBytes();
 
    // Create channel and set to nonblocking
    DatagramChannel datagramChannel = DatagramChannel.open();
    datagramChannel.configureBlocking(false);
    datagramChannel.socket().setSoTimeout(TIMEOUT);
     
    ByteBuffer writeBuf = ByteBuffer.wrap(bytesToSend);
    ByteBuffer readBuf = ByteBuffer.allocate(MAXTRIES);
     
    datagramChannel = datagramChannel.connect(new InetSocketAddress("127.0.0.1", 5500));
 
    int totalBytesRcvd = 0; // Total bytes received so far
    int bytesRcvd; // Bytes received in last read
    while (totalBytesRcvd < bytesToSend.length) {
      if (writeBuf.hasRemaining()) {
        datagramChannel.write(writeBuf);
      }
      if ((bytesRcvd = datagramChannel.read(readBuf)) == -1) {
        throw new SocketException("Connection closed prematurely");
      }
      totalBytesRcvd += bytesRcvd;
      System.out.print("."); // Do something else
    }
 
    System.out.println("Received: " + new String(readBuf.array(), 0, totalBytesRcvd));
    datagramChannel.close();
  }
}

三、NIO UDP服务端:

?
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
 
public class UDPEchoServerSelector {
 
  private static final int TIMEOUT = 3000; // Wait timeout (milliseconds)
 
  public static void main(String[] args) throws IOException {
    // Create a selector to multiplex client connections.
    Selector selector = Selector.open();
 
    DatagramChannel channel = DatagramChannel.open();
    channel.configureBlocking(false);
    channel.socket().bind(new InetSocketAddress(5500));
    channel.register(selector, SelectionKey.OP_READ, new UDPEchoSelectorProtocol.ClientRecord());
 
    UDPEchoSelectorProtocol echoSelectorProtocol = new UDPEchoSelectorProtocol();
    while (true) { // Run forever, receiving and echoing datagrams
      // Wait for task or until timeout expires
      if (selector.select(TIMEOUT) == 0) {
        System.out.print(".");
        continue;
      }
 
      // Get iterator on set of keys with I/O to process
      Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
      while (keyIter.hasNext()) {
        SelectionKey key = keyIter.next(); // Key is bit mask
 
        // Client socket channel has pending data?
        if (key.isReadable())
          echoSelectorProtocol.handleRead(key);
 
        // Client socket channel is available for writing and
        // key is valid (i.e., channel not closed).
        if (key.isValid() && key.isWritable())
          echoSelectorProtocol.handleWrite(key);
 
        keyIter.remove();
      }
    }
  }
 
}

以上就是本文的全部内容,查看更多Java的语法,也希望大家多多支持服务器之家。