java实现客户端与服务器一问一答 教你怎么用java实现客户端与服务器一问一答

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

java实现客户端与服务器一问一答 教你怎么用java实现客户端与服务器一问一答

小楼夜听雨QAQ   2021-04-30 我要评论
想了解教你怎么用java实现客户端与服务器一问一答的相关内容吗,小楼夜听雨QAQ在本文为您仔细讲解java实现客户端与服务器一问一答的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:java实现客户端与服务器一问一答,java客户端与服务器通信,下面大家一起来学习吧。

运行效果

开启多个客户端

服务端效果:

客户端效果:

当一个客户端断开连接:

代码

因为代码中有注释,我就直接贴上来了

服务端:

package com.dayrain.server;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
 
public class NioServer {
    /**端口**/
    private static final int PORT = 8081;
    /**buffer大小**/
    private static final int DEFAULT_BUFFER_SIZE = 1024;
    private final Selector selector;
    private final ByteBuffer readBuffer = ByteBuffer.allocate(NioServer.DEFAULT_BUFFER_SIZE);
    private final ByteBuffer writeBuffer = ByteBuffer.allocate(NioServer.DEFAULT_BUFFER_SIZE);
 
    private static int count = 0;
 
    public static void main(String[] args) throws IOException {
        new NioServer().start();
    }
 
    public NioServer() throws IOException {
        //创建一个服务端channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
 
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
 
        //获取服务器socket
        ServerSocket socket = serverSocketChannel.socket();
        //绑定ip和端口
        socket.bind(new InetSocketAddress(NioServer.PORT));
 
        //创建多路复用选择器,并保持打开状态,直到close
        selector = Selector.open();
 
        //将服务器管道注册到selector上,并监听accept事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("server start on port: " + NioServer.PORT);
        start();
    }
 
    public void start() throws IOException {
 
        //selector是阻塞的,直到至少有一个客户端连接。
        while (selector.select() > 0) {
            //SelectionKey是channel想Selector注册的令牌,可以通过chancel取消(不是立刻取消,会放进一个cancel list里面,下一次select时才会把它彻底删除)
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                iterator.remove();
                //当这个key的channel已经准备好接收套接字连接
                if(selectionKey.isAcceptable()) {
                    connectHandle(selectionKey);
                }
 
                //当这个key的channel已经准备好读取数据时
                if(selectionKey.isReadable()) {
                    readHandle(selectionKey);
                }
            }
        }
    }
 
    /**
     * 处理连接
     * @param selectionKey
     */
    private void connectHandle(SelectionKey selectionKey) throws IOException {
        //注意,服务端用的是ServerSocketChannel,BIO中是ServerSocket
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        SocketChannel socketChannel = serverSocketChannel.accept();
        if(socketChannel == null) {
            return;
        }
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
 
        System.out.println("客户端连接成功,当前总数:" + (++count));
 
        writeBuffer.clear();
        writeBuffer.put("连接成功".getBytes(StandardCharsets.UTF_8));
        writeBuffer.flip();
        socketChannel.write(writeBuffer);
    }
 
    /**
     * 读取数据
     * @param selectionKey
     */
    private void readHandle(SelectionKey selectionKey){
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        try {
            readBuffer.clear();
            int read = socketChannel.read(readBuffer);
            if(read > 0) {
                readBuffer.flip();
                String receiveData = StandardCharsets.UTF_8.decode(readBuffer).toString();
 
                System.out.println("收到客户端消息: " + receiveData);
 
                writeBuffer.clear();
                writeBuffer.put(receiveData.getBytes(StandardCharsets.UTF_8));
                writeBuffer.flip();
                socketChannel.write(writeBuffer);
            }
 
        }catch (Exception e) {
            try {
                socketChannel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
            System.out.println("客户端断开了连接~~");
            count--;
        }
    }
}

客户端

package com.dayrain.client;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
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.StandardCharsets;
import java.util.Iterator;
 
public class NioClient {
 
    private static final int PORT = 8081;
    private static final int DEFAULT_BUFFER_SIZE = 1024;
    private final Selector selector;
    private final ByteBuffer readBuffer = ByteBuffer.allocate(NioClient.DEFAULT_BUFFER_SIZE);
    private final ByteBuffer writeBuffer = ByteBuffer.allocate(NioClient.DEFAULT_BUFFER_SIZE);
 
    public static void main(String[] args) throws IOException {
        NioClient nioClient = new NioClient();
 
        //终端监听用户输入
        new Thread(nioClient::terminal).start();
 
        //这个方法是阻塞的,要放在最后
        nioClient.start();
    }
 
    public NioClient() throws IOException {
        selector = Selector.open();
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), NioClient.PORT));
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
    }
 
    public void start() throws IOException {
        while (selector.select() > 0) {
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //拿到selectionKey后要删除,否则会重复处理
                iterator.remove();
                if(selectionKey.isReadable()) {
                    handleRead(selectionKey);
                }
 
                //只要连接成功,selectionKey.isWritable()一直为true
                if(selectionKey.isWritable()) {
                    handleWrite(selectionKey);
                }
            }
        }
    }
 
    /**
     * 监听写操作
     */
    private void handleWrite(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
 
        // writeBuffer有数据就直接写入,因为另开了线程监听用户读取,所以要上锁
        synchronized (writeBuffer) {
            writeBuffer.flip();
            while (writeBuffer.hasRemaining()) {
                socketChannel.write(writeBuffer);
            }
            writeBuffer.compact();
        }
 
    }
 
    /**
     * 监听读操作
     */
    private void handleRead(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        readBuffer.clear();
        socketChannel.read(readBuffer);
 
        readBuffer.flip();
        String res = StandardCharsets.UTF_8.decode(readBuffer).toString();
        System.out.println("收到服务器发来的消息: " + res);
        readBuffer.clear();
    }
 
    /**
     * 监听终端的输入
     */
    private void terminal() {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        try {
            String msg;
            while ((msg = bufferedReader.readLine()) != null) {
                synchronized (writeBuffer) {
                    writeBuffer.put((msg + "\r\n").getBytes(StandardCharsets.UTF_8));
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
}

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们