教你怎么用java實現(xiàn)客戶端與服務(wù)器一問一答
更新時間:2021年04月30日 10:39:18 作者:小樓夜聽雨QAQ
這篇文章主要介紹了教你怎么用java實現(xiàn)客戶端與服務(wù)器一問一答,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
運(yùn)行效果
開啟多個客戶端
服務(wù)端效果:

客戶端效果:

當(dāng)一個客戶端斷開連接:

代碼
因為代碼中有注釋,我就直接貼上來了
服務(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)建一個服務(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ù)用選擇器,并保持打開狀態(tài),直到close
selector = Selector.open();
//將服務(wù)器管道注冊到selector上,并監(jiān)聽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取消(不是立刻取消,會放進(jìn)一個cancel list里面,下一次select時才會把它徹底刪除)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
//當(dāng)這個key的channel已經(jīng)準(zhǔn)備好接收套接字連接
if(selectionKey.isAcceptable()) {
connectHandle(selectionKey);
}
//當(dāng)這個key的channel已經(jīng)準(zhǔn)備好讀取數(shù)據(jù)時
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("客戶端連接成功,當(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("收到客戶端消息: " + 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();
//終端監(jiān)聽用戶輸入
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后要刪除,否則會重復(fù)處理
iterator.remove();
if(selectionKey.isReadable()) {
handleRead(selectionKey);
}
//只要連接成功,selectionKey.isWritable()一直為true
if(selectionKey.isWritable()) {
handleWrite(selectionKey);
}
}
}
}
/**
* 監(jiān)聽寫操作
*/
private void handleWrite(SelectionKey selectionKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// writeBuffer有數(shù)據(jù)就直接寫入,因為另開了線程監(jiān)聽用戶讀取,所以要上鎖
synchronized (writeBuffer) {
writeBuffer.flip();
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
writeBuffer.compact();
}
}
/**
* 監(jiān)聽讀操作
*/
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ā)來的消息: " + res);
readBuffer.clear();
}
/**
* 監(jiān)聽終端的輸入
*/
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實現(xiàn)客戶端與服務(wù)器一問一答的文章就介紹到這了,更多相關(guān)java實現(xiàn)客戶端與服務(wù)器一問一答內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Win10 Java jdk14.0.2安裝及環(huán)境變量配置詳細(xì)教程
這篇文章主要介紹了Win10 Java jdk14.0.2安裝及環(huán)境變量配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
springboot如何配置嵌套map和list參數(shù)
這篇文章主要介紹了springboot如何配置嵌套map和list參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03
如何利用Java使用AOP實現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換
這篇文章主要介紹了如何利用Java使用AOP實現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換,AOP也是我們常說的面向切面編程,AOP在我們開發(fā)過程中應(yīng)用也比較多,在這里我們就基于AOP來實現(xiàn)一個數(shù)據(jù)字典轉(zhuǎn)換的案例2022-06-06

