教你怎么用java实现客户端与服务器一问一答
短信预约 -IT技能 免费直播动态提醒
运行效果
开启多个客户端
服务端效果:
客户端效果:
当一个客户端断开连接:
代码
因为代码中有注释,我就直接贴上来了
服务端:
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;
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);
}
}
}
}
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);
}
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();
}
}
}
到此这篇关于教你怎么用java实现客户端与服务器一问一答的文章就介绍到这了,更多相关java实现客户端与服务器一问一答内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341