用到了ServerSocket的(服务端),Socket(客户端);
服务端:
客户端:
哪些操作是阻塞的?
接收(),连接(),读(),写();
下面的代码是基于BIOS实现的一个简单的客户端和服务端一直通话的代码,服务端代码中用到了线程池,你也可以看作这是一个伪异步IO的代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName TestDemo4
* @Description 服务端 持久通话
* @Author lzq
* @Date 2019/5/18 17:54
* @Version 1.0
**/
/**
* 读线程,服务端
*/
class SendServer extends Thread {
private DataInputStream dis;
private Socket socket;
public SendServer(Socket socket) {
try {
this.socket = socket;
dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
close();
}
}
/**
* 读
*/
private void read() {
try {
String s = dis.readUTF();
System.out.print("<客户端>:"+s);
} catch (IOException e) {
close();
}
}
@Override
public void run() {
while (true) {
read();
}
}
private void close() {
try {
socket.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 写线程,服务端
*/
class ReceptionServer extends Thread {
private DataOutputStream dos;
private Socket socket;
private BufferedReader bufferedReader;
public ReceptionServer(Socket socket) {
try {
this.socket = socket;
dos = new DataOutputStream(socket.getOutputStream());
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 写
*/
private void writer() {
try {
String s = bufferedReader.readLine();
dos.writeUTF(s+"\n");
dos.flush();
} catch (IOException e) {
close();
}
}
@Override
public void run() {
while (true) {
writer();
}
}
private void close() {
try {
socket.close();
dos.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class TestDemo4 {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端已启动......");
int count = 1;
ExecutorService threadPoolExecutor = Executors.newCachedThreadPool();
while (true) {
Socket socket = serverSocket.accept();
System.out.println("有新客户端连接......"+count+++"......");
threadPoolExecutor.submit(new SendServer(socket));
threadPoolExecutor.submit(new ReceptionServer(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* @ClassName TestDemo3
* @Description 客户端 持久通话
* 要实现持久通话,必须把它的读写操作分离出来,交给特定的线程去处理
* @Author lzq
* @Date 2019/5/18 17:54
* @Version 1.0
**/
/**
* 处理发送数据的线程
*/
class Send extends Thread{
private Socket socket;
private DataOutputStream dos;
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
public Send(Socket socket) {
try {
this.socket = socket;
this.dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
close();
}
}
/**
* 获取控制台数据
* @return
*/
private String getData() {
String s = "";
try {
s = reader.readLine();
} catch (IOException e) {
close();
}
return s;
}
/**
* 发送数据
*/
private void send() {
String s = getData();
if(s != null && !s.equals("")) {
try {
dos.writeUTF(s+"\n");
dos.flush();
} catch (IOException e) {
close();
}
}
}
@Override
public void run() {
while (true) {
send();
}
}
private void close() {
try {
socket.close();
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 读取数据
*/
class Reception extends Thread {
private Socket socket;
private DataInputStream dis;
public Reception(Socket socket) {
try {
this.socket = socket;
this.dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
close();
}
}
/**
* 读取数据的方法
*/
private void reception() {
try {
String s = dis.readUTF();
System.out.print("<服务端>:"+s);
} catch (IOException e) {
close();
}
}
@Override
public void run() {
while (true) {
reception();
}
}
private void close() {
try {
socket.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class TestDemo3 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.0.1",8888));
System.out.println("已连接服务器......");
new Send(socket).start();
new Reception(socket).start();
}
}
用到ServerSocketChannel(服务端)、SocketChannel(客户端);
channel(通道) 、Buffer(缓存)、selector(IO复用器或选择器)
服务端:
客户端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName TestDemo7
* @Description 服务端
* @Author lzq
* @Date 2019/5/22 21:20
* @Version 1.0
**/
public class TestDemo7 {
private static Charset charset = Charset.forName("UTF-8");
private static ExecutorService executor = Executors.newCachedThreadPool();
public static void main(String[] args) {
new TestDemo7().start();
}
private void start() {
ServerSocketChannel server = null;
Selector selector = null;
try {
//创建ServerSocketChannel实例
server = ServerSocketChannel.open();
//将它设置为非阻塞
server.configureBlocking(false);
//绑定端口
server.bind(new InetSocketAddress(8888));
//实例化选择器
selector = Selector.open();
//将ServerSocketChannel实例添加到选择器,并关注可接收事件
server.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务端已启动......");
while (selector.select() > 0) { //select()这是一个阻塞方法
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey next = iterator.next();
iterator.remove();
if (next.isAcceptable()) { //有可连接事件发生
System.out.println("有客户端连接......");
ServerSocketChannel channel = (ServerSocketChannel) next.channel();
SocketChannel socketChannel = channel.accept(); //到这是不会阻塞的
socketChannel.configureBlocking(false); //设置为非阻塞
socketChannel.register(selector, SelectionKey.OP_READ); //添加到选择器,关注可读事件
}
if (next.isReadable()) { //有可读事件发生
SocketChannel channel = (SocketChannel) next.channel(); //获取通道
//读
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
StringBuilder stringBuilder = new StringBuilder();
while (channel.read(byteBuffer) > 0) {
byteBuffer.flip();
stringBuilder.append(charset.decode(byteBuffer));
}
if(stringBuilder.length() > 0) {
System.out.println("<客户端>" + stringBuilder.toString());
}
//写
String msg = "欢迎";
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(msg.getBytes()); //将数据放到缓冲区
buffer.flip(); //调换读写指针
channel.write(buffer);
}
}
}
} catch (ClosedChannelException e) {
} catch (IOException e) {
} finally {
try {
if(server != null) {
server.close();
}
if(selector != null) {
selector.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* @ClassName TestDemo8
* @Description 客户端
* @Author lzq
* @Date 2019/5/23 12:48
* @Version 1.0
**/
public class TestDemo8 {
public static void main(String[] args) {
SocketChannel socketChannel = null;
Selector selector = null;
try {
//创建SocketChannel实例的
socketChannel = SocketChannel.open();
//将创建的SocketChannel实例设置为非阻塞
socketChannel.configureBlocking(false);
//创建选择器
selector = Selector.open();
//将创建的实例添加到选择器,并选择关注连接事件
socketChannel.register(selector, SelectionKey.OP_CONNECT);
//连接服务器,只写这句代码是连接不上服务端的,还需要后面的finishConnect()操作
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888));
while (selector.select() > 0) {
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey next = iterator.next();
iterator.remove();
if (next.isConnectable()) { //有可连接事件发生
SocketChannel channel = (SocketChannel) next.channel(); //获取通道
if (channel.isConnectionPending()) { //判断此通道上是否在进行连接操作
channel.finishConnect(); //完成套接字通道的连接过程
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_WRITE); //添加到选择器,关注可写事件
}
if (next.isWritable()) {//有可写事件发生
SocketChannel channel = (SocketChannel) next.channel(); //获取通道
//写
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("----------------");
String s = bufferedReader.readLine();
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(s.getBytes());
buffer.flip();
channel.write(buffer);
channel.register(selector, SelectionKey.OP_READ); //关注读事件
}
if (next.isReadable()) {
SocketChannel channel = (SocketChannel) next.channel(); //获取通道
//读
ByteBuffer buffer1 = ByteBuffer.allocate(1024);
channel.read(buffer1); //将数据读到缓冲区
buffer1.flip();
System.out.println("<服务端>" + new String(buffer1.array()));
channel.register(selector, SelectionKey.OP_WRITE);
}
}
}
} catch (ClosedChannelException e) {
} catch (IOException e) {
} finally {
try {
if(socketChannel != null) {
socketChannel.close();
}
if(selector != null) {
selector.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这个一般不会用,直接上代码:
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Future;
/**
* @ClassName Server
* @Description 服务端
* @Author lzq
* @Date 2019/5/30 12:40
* @Version 1.0
**/
public class Server {
public static void main(String[] args) {
try {
Server server = new Server();
} catch (Exception e) {
e.printStackTrace();
}
}
public Server() throws Exception {
AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 80);
serverSocketChannel.bind(inetSocketAddress);
Future accept;
while (true) {
// accept()不会阻塞。
accept = serverSocketChannel.accept();
System.out.println("=================");
System.out.println("服务器等待连接...");
AsynchronousSocketChannel socketChannel = accept.get();// get()方法将阻塞。
System.out.println("服务器接受连接");
System.out.println("服务器与" + socketChannel.getRemoteAddress() + "建立连接");
ByteBuffer buffer = ByteBuffer.wrap("欢迎".getBytes());
Future write = socketChannel.write(buffer);
while(!write.isDone()) {
Thread.sleep(10);
}
System.out.println("服务器发送数据完毕.");
socketChannel.close();
}
}
}
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.Future;
/**
* @ClassName Client
* @Description 客户端
* @Author lzq
* @Date 2019/5/30 14:06
* @Version 1.0
**/
public class Client {
public static void main(String[] args) {
AsynchronousSocketChannel socketChannel = null;
try {
socketChannel = AsynchronousSocketChannel.open();
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 80);
Future connect = socketChannel.connect(inetSocketAddress);
while (!connect.isDone()) {
Thread.sleep(10);
}
System.out.println("建立连接" + socketChannel.getRemoteAddress());
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future read = socketChannel.read(buffer);
while (!read.isDone()) {
Thread.sleep(10);
}
System.out.println("接收服务器数据:" + new String(buffer.array(), 0, read.get()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @ClassName ServerTestDemo1
* @Description 服务端
* @Author lzq
* @Date 2019/5/31 15:16
* @Version 1.0
**/
public class ServerTestDemo1 {
public static void main(String[] args) {
//1、创建一个线程组,用来接收客户端连接
EventLoopGroup boosGroup = new NioEventLoopGroup();
//2、创建一个线程组,用来处理各种IO操作
EventLoopGroup workerGroup = new NioEventLoopGroup();
//3、创建服务器端启动助手,配置参数
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boosGroup,workerGroup) //4、设置两个线程组
.channel(NioServerSocketChannel.class) //5、使用它作为服务器端通道的实现
.option(ChannelOption.SO_BACKLOG,128) //6、设置线程中等待连接的个数
.childOption(ChannelOption.SO_KEEPALIVE,true) //7、保持活动的连接状态
.childHandler(new ChannelInitializer() { //8、创建一个通道初始化对象
@Override
//9、往链中添加自定义的Handler类
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("服务器已就绪...");
ChannelFuture channelFuture = null;
try {
channelFuture = bootstrap.bind(9999).sync();//10、绑定端口,非阻塞
System.out.println("服务端已启动...");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//11、关闭通道,关闭线程组
try {
if(channelFuture != null) {
channelFuture.channel().closeFuture().sync();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @ClassName NettyServerHandler
* @Description 服务端用的业务处理类
* @Author lzq
* @Date 2019/5/31 15:13
* @Version 1.0
**/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
//读取数据事件
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf)msg;
System.out.println("<客户端>"+byteBuf.toString(CharsetUtil.UTF_8));
}
@Override
//读取数据完毕事件
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("欢迎",CharsetUtil.UTF_8));
}
@Override
//发生异常事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @ClassName ClientTestDemo2
* @Description 客户端
* @Author lzq
* @Date 2019/5/31 15:16
* @Version 1.0
**/
public class ClientTestDemo2 {
public static void main(String[] args) {
//1、创建线程组
EventLoopGroup group = new NioEventLoopGroup();
//2、创建一个启动助手,完成配置
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group) //3、配置线程组
.channel(NioSocketChannel.class) //4、设置客户端的实现类
.handler(new ChannelInitializer() { //5、创建初始化对象
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//6、往链中添加Handler
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端已就绪...");
ChannelFuture channelFuture = null;
try {
//7、启动客户端,连接服务器端
channelFuture = bootstrap.connect("127.0.0.1", 9999).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//8、关闭连接
try {
if(channelFuture != null) {
channelFuture.channel().closeFuture().sync();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
group.shutdownGracefully();
}
}
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @ClassName NettyClientHandler
* @Description 客户端用的业务处理类
* @Author lzq
* @Date 2019/5/31 15:15
* @Version 1.0
**/
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Override
//通道就绪事件
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("你好",CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg)抛出异常{
ByteBuf byteBuf =(ByteBuf)msg;
的System.out.println( “<服务端>” + byteBuf.toString(CharsetUtil.UTF_8));
}
}