c语言sscanf函数的用法是什么
253
2023-01-18
教你怎么用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
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);
writepksJFkBuffer.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
whhttp://ile (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();
}
}
}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~