NIO实现的服务端与客户端之间的简单通信
程序员文章站
2022-06-06 08:36:13
...
1 服务端启动类
public class TimeServer {
public static void main(String[] args) {
int port = 8080;
//这个类负责轮询多路复用器 selector
MultiplexerTimerServer mts = new MultiplexerTimerServer(port);
//单独开启一个线程来执行mts服务
new Thread(mts,"NIO-MultiplexerTimerServer-001").start();
}
}
2:服务端请求处理类
public class MultiplexerTimerServer implements Runnable{
private Selector selector;
private ServerSocketChannel serverSocketChannel;
private volatile boolean stop;
public MultiplexerTimerServer(int port) {
try {
//创建多路复用器 selector
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
//将serverSocketChannel设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//serverSocketChannel的socket绑定服务端口 并设置TCP参数
serverSocketChannel.socket().bind(new InetSocketAddress(port), 1024);
//将serverSocketChannel 注册到selector上,并让selector监听SelectionKey 的OP_ACCEPT操作位
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("============MultiplexerTimerServer is start in port "+port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
/**
* 关闭MultiplexerTimerServer服务
*/
public void stop() {
stop = true;
}
@Override
public void run() {
while (!stop) {
try {
//休眠1秒 无论是否有读写事件发生 selector每隔1秒被唤醒
selector.select(1000);
//获取注册在selector上的所有的就绪状态的serverSocketChannel中发生的事件
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterators = selectedKeys.iterator();
SelectionKey key = null;
while (iterators.hasNext()) {
key = iterators.next();
iterators.remove();
try {
handleInput(key);
} catch (Exception e) {
if (key != null) {
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (selector != null) { //服务停止 关闭selector
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 处理客户端新接入的请求
* @param key 请求信息
* @throws IOException
*/
private void handleInput(SelectionKey key) throws IOException{
if (key.isValid()) {
//处理新接入的请求消息
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
}
if (key.isReadable()) {
//获取SocketChannel实例后,相当于完成了TCP三次握手,TCP物理链路正式建立
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
//读取客户端传过来的请求参数
int readBytes = sc.read(readBuffer);
if (readBytes > 0) {//获取到了请求数据,对字节进行编解码
readBuffer.flip();
byte[] bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String requestMessage = new String(bytes, Charset.forName("UTF-8"));
System.out.println("============MultiplexerTimerServer receive message:"+requestMessage);
doWrite(sc,"responseMessage");
} else if (readBytes < 0) {//没有获取到请求数据,需要关闭SocketChannel(C/S 连接链路)
key.cancel();
sc.close();
}
}
}
}
/**
* 将请求的响应 异步返回给客户端
* @param sc (C/S 连接链路)
* @param response 响应数据
* @throws IOException
*/
private void doWrite(SocketChannel sc, String response) throws IOException {
if (response != null && !response.isEmpty()) {
byte[] bytes = response.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
buffer.flip();
sc.write(buffer);
}
}
}
3:客户端启动类
public class TimeClient {
public static void main(String[] args) {
//服务器端的端口
int port = 8080;
//这个类负责轮询多路复用器 selector
TimeClientHandle tch = new TimeClientHandle("127.0.0.1",port);
//单独开启一个线程来执行tch服务
new Thread(tch,"NIO-TimeClient-001").start();
}
}
4:客户端实现类
public class TimeClientHandle implements Runnable {
private String ip;
private int port;
private Selector selector;
private SocketChannel socketChannel;
private volatile boolean stop;
public TimeClientHandle (String ip,int port) {
this.ip = ip == null ? "127.0.0.1" : ip;
this.port = port;
try {
selector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
@Override
public void run() {
try {
doConnect(); //请求建立连接
} catch (IOException e) {
e.printStackTrace();
}
while (!stop) {
try {
//休眠1秒 无论是否有读写事件发生 selector每隔1秒被唤醒
selector.select(1000);
//获取注册在selector上的所有的就绪状态的serverSocketChannel中发生的事件
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> it = set.iterator();
SelectionKey key = null;
while (it.hasNext()) {
key = it.next();
it.remove();
try {
handleInput(key);
} catch (Exception e) {
if (key != null) {
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
if (selector != null) {
try {
selector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void handleInput(SelectionKey key) throws IOException {
if (key.isValid()) {
SocketChannel sc = (SocketChannel) key.channel();
if (key.isConnectable()) { //处于连接状态
if (sc.finishConnect()) {//客户端连接成功
sc.register(selector, SelectionKey.OP_READ);
doWrite(sc);
} else { //连接失败
System.exit(1);
}
}
if (key.isReadable()) {//如果客户端接收到了服务器端发送的应答消息 则SocketChannel是可读的
ByteBuffer bf = ByteBuffer.allocate(1024);
int bytes = sc.read(bf);
if (bytes > 0) {
bf.flip();
byte[] byteArray = new byte[bf.remaining()];
bf.get(byteArray);
String resopnseMessage = new String(byteArray, "UTF-8");
System.out.println("=======The response message is:"+resopnseMessage);
this.stop = true;
} else if (bytes < 0) {
key.cancel();
sc.close();
}
}
}
}
private void doConnect() throws IOException {
//如果直连接连接成功,则注册到多路复用器上,并注册SelectionKey.OP_READ操作
if (socketChannel.connect(new InetSocketAddress(ip, port))) {
socketChannel.register(selector, SelectionKey.OP_READ);
//发送请求消息 读应答
doWrite(socketChannel);
} else {//如果直连接连接未成功,则注册到多路复用器上,并注册SelectionKey.OP_CONNECT操作
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
}
private void doWrite(SocketChannel sc) throws IOException {
byte[] requestBytes = "request message from client".getBytes();
ByteBuffer bf = ByteBuffer.allocate(requestBytes.length);
bf.put(requestBytes);
bf.flip();
sc.write(bf);
if (!bf.hasRemaining()) {//如果缓冲区里面的所有内容全部发送完毕
System.out.println("=======client send requst message to server successed!");
}
}
}
上一篇: 申扎县