教你怎么用java實(shí)現(xiàn)客戶(hù)端與服務(wù)器一問(wèn)一答
運(yùn)行效果
開(kāi)啟多個(gè)客戶(hù)端
服務(wù)端效果:

客戶(hù)端效果:

當(dāng)一個(gè)客戶(hù)端斷開(kāi)連接:

代碼
因?yàn)榇a中有注釋?zhuān)揖椭苯淤N上來(lái)了
服務(wù)端:
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 {
//創(chuàng)建一個(gè)服務(wù)端channel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//設(shè)置為非阻塞
serverSocketChannel.configureBlocking(false);
//獲取服務(wù)器socket
ServerSocket socket = serverSocketChannel.socket();
//綁定ip和端口
socket.bind(new InetSocketAddress(NioServer.PORT));
//創(chuàng)建多路復(fù)用選擇器,并保持打開(kāi)狀態(tài),直到close
selector = Selector.open();
//將服務(wù)器管道注冊(cè)到selector上,并監(jiān)聽(tīng)accept事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server start on port: " + NioServer.PORT);
start();
}
public void start() throws IOException {
//selector是阻塞的,直到至少有一個(gè)客戶(hù)端連接。
while (selector.select() > 0) {
//SelectionKey是channel想Selector注冊(cè)的令牌,可以通過(guò)chancel取消(不是立刻取消,會(huì)放進(jìn)一個(gè)cancel list里面,下一次select時(shí)才會(huì)把它徹底刪除)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
//當(dāng)這個(gè)key的channel已經(jīng)準(zhǔn)備好接收套接字連接
if(selectionKey.isAcceptable()) {
connectHandle(selectionKey);
}
//當(dāng)這個(gè)key的channel已經(jīng)準(zhǔn)備好讀取數(shù)據(jù)時(shí)
if(selectionKey.isReadable()) {
readHandle(selectionKey);
}
}
}
}
/**
* 處理連接
* @param selectionKey
*/
private void connectHandle(SelectionKey selectionKey) throws IOException {
//注意,服務(wù)端用的是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("客戶(hù)端連接成功,當(dāng)前總數(shù):" + (++count));
writeBuffer.clear();
writeBuffer.put("連接成功".getBytes(StandardCharsets.UTF_8));
writeBuffer.flip();
socketChannel.write(writeBuffer);
}
/**
* 讀取數(shù)據(jù)
* @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("收到客戶(hù)端消息: " + 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("客戶(hù)端斷開(kāi)了連接~~");
count--;
}
}
}
客戶(hù)端
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();
//終端監(jiān)聽(tīng)用戶(hù)輸入
new Thread(nioClient::terminal).start();
//這個(gè)方法是阻塞的,要放在最后
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后要?jiǎng)h除,否則會(huì)重復(fù)處理
iterator.remove();
if(selectionKey.isReadable()) {
handleRead(selectionKey);
}
//只要連接成功,selectionKey.isWritable()一直為true
if(selectionKey.isWritable()) {
handleWrite(selectionKey);
}
}
}
}
/**
* 監(jiān)聽(tīng)寫(xiě)操作
*/
private void handleWrite(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// writeBuffer有數(shù)據(jù)就直接寫(xiě)入,因?yàn)榱黹_(kāi)了線程監(jiān)聽(tīng)用戶(hù)讀取,所以要上鎖
synchronized (writeBuffer) {
writeBuffer.flip();
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
writeBuffer.compact();
}
}
/**
* 監(jiān)聽(tīng)讀操作
*/
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("收到服務(wù)器發(fā)來(lái)的消息: " + res);
readBuffer.clear();
}
/**
* 監(jiān)聽(tīng)終端的輸入
*/
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();
}
}
}
到此這篇關(guān)于教你怎么用java實(shí)現(xiàn)客戶(hù)端與服務(wù)器一問(wèn)一答的文章就介紹到這了,更多相關(guān)java實(shí)現(xiàn)客戶(hù)端與服務(wù)器一問(wèn)一答內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloudAlibaba Nacos開(kāi)啟鑒權(quán)解決跳過(guò)登錄頁(yè)面問(wèn)題
對(duì)于Nacos,如果需要開(kāi)啟權(quán)限控制,可以在 Nacos 控制臺(tái)上進(jìn)行配置,本文主要介紹了SpringCloudAlibaba Nacos開(kāi)啟鑒權(quán)解決跳過(guò)登錄頁(yè)面問(wèn)題,感興趣的可以了解一下2023-10-10
淺談java Iterator.remove()方法的用法(詳解)
下面小編就為大家?guī)?lái)一篇淺談java Iterator.remove()方法的用法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
MyBatis中執(zhí)行相關(guān)SQL語(yǔ)句的方法
本文主要介紹了MyBatis中執(zhí)行相關(guān)SQL語(yǔ)句的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Java求字符串中出現(xiàn)次數(shù)最多的字符串以及出現(xiàn)次數(shù)
這篇文章主要為大家詳細(xì)介紹了Java統(tǒng)計(jì)字符串中出現(xiàn)次數(shù)最多的字符串以及出現(xiàn)次數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
Java語(yǔ)言實(shí)現(xiàn)掃雷游戲(1)
這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言實(shí)現(xiàn)的掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
SpringBoot實(shí)現(xiàn)Word轉(zhuǎn)PDF和TXT的實(shí)踐分享
研發(fā)工作中難免會(huì)遇到一些奇奇怪怪的需求,就比如最近,客戶(hù)提了個(gè)新需求:上傳一個(gè)WORD文檔,要求通過(guò)系統(tǒng)把該文檔轉(zhuǎn)換成PDF和TXT,所以本文給大家分享了SpringBoot實(shí)現(xiàn)Word轉(zhuǎn)PDF和TXT的實(shí)踐,感興趣的朋友可以參考下2024-08-08

