最近在学netty 复习了一下java高级的io,多线程,网络编程
今天分享一下我练得小综合项目
NI/O是I/O的加强版 ,IO就是人机或机机交互的接口
三大特性:channel(通道),buffer(缓存),selector(选择器)
上代码
Server
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class ChatServer {
private ServerSocketChannel channel;
private Selector selector;
public ChatServer() {
try {
channel = ServerSocketChannel.open();
selector = Selector.open();
SocketAddress address = new InetSocketAddress(6666);
channel.socket().bind(address);
channel.configureBlocking(false);
//注册通道的可接收事件
channel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
//监听客户端
public void listenClient() throws Exception {
System.out.println("服务器启动监听");
//轮询选择器
while (true) {
int num = selector.select();
if (num == 0) continue;
//接收连接
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> it = set.iterator();
//处理连接
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
/*
* 识别key对应的事件
*/
if (key.isAcceptable()) {
SocketChannel clientChannel = channel.accept();
//设置线程非阻塞
clientChannel.configureBlocking(false);
//注册监听下次的读事件
clientChannel.register(selector, SelectionKey.OP_READ);
//提示
System.out.println("user " + clientChannel.socket().getRemoteSocketAddress() + " 登录");
continue;
}
if (key.isReadable()) {
//接收客户端消息
readData(key);
}
}
}
}
/*
* 接收msg
*/
private void readData(SelectionKey key) throws Exception {
SocketChannel channel = null;
try {
//接收channel抽象类 要强转
channel = (SocketChannel) key.channel();
//给缓冲区 分配内存
ByteBuffer buffer = ByteBuffer.allocate(1024);
int num = channel.read(buffer);
if (num > 0) {
String msg = new String(buffer.array());
msg=msg+" from>> "+channel.socket().getRemoteSocketAddress();
System.out.println("msg : " + msg);
//广播消息
sendToOther(msg, channel);
}
} catch (Exception e) {
//channel置空则用户下线
System.out.println("user : "+ channel.socket().getRemoteSocketAddress()+"下线");
//注销selector
key.cancel();
//关闭通道
try {
channel.close();
}catch (Exception e1){
e1.printStackTrace();
}
}
}
/*
* 广播消息给其他用户
*/
private void sendToOther(String msg, SocketChannel selfChannel)throws Exception {
Set<SelectionKey> set = selector.keys();
for (SelectionKey key : set) {
Channel channel = key.channel();
//判断管道是否属于除发消息外其他用户
if (channel instanceof SocketChannel && channel != selfChannel) {
SocketChannel socketChannel = (SocketChannel) channel;
//直接把数据分到缓冲区
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
//写入
socketChannel.write(buffer);
}
}
}
public static void main(String[] args) throws Exception {
//初始化服务器
ChatServer server=new ChatServer();
server.listenClient();
}
}
客户端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class ChatClient {
private SocketChannel channel;
private Selector selector;
//构造器
public ChatClient() {
try {
selector = Selector.open();
SocketAddress address = new InetSocketAddress("127.0.0.1", 6666);
channel = SocketChannel.open(address);
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
System.out.println("user " + channel.getLocalAddress() + "上线");
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 写数据
*/
public void sendData(String msg) {
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
try {
channel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 读数据
*/
public void readData() {
try {
int num = selector.select();
if (num > 0) {
//接收连接
Set<SelectionKey> set = selector.selectedKeys();
Iterator<SelectionKey> it = set.iterator();
//处理连接
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isReadable()) {
//接收服务器消息
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer);
String msg =new String (buffer.array());
System.out.println(msg);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final ChatClient chatClient=new ChatClient();
new Thread(){
public void run(){
while (true){
chatClient.readData();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
//处理用户输入
Scanner scanner=new Scanner(System.in);
while(scanner.hasNextLine()){
String str=scanner.next();
chatClient.sendData(str);
}
}
}
演示一下
服务器:
俩用户:
发消息:
发消息用户角度
另一个用户
服务器:
下线
这种项目综合三个重难点,难度和益处都是挺发大的 ,希望大家能从中受益