bio(sockect)或java的nio或netty实现的简单服务器

bio(sockect)或java的nio或netty实现的简单服务器

基于 bio服务器

服务器

服务端开启的时ServerSocket,客户端开启的是Socket,服务端可以通过ServerSocket.accept()获得客户端的Socket,通过ServerSocket.accept().getInputStream即获得输入流。客户端可以通过new Socket(ip,port).getOutputStream获得输出流

public class Server
{
    public static void main( String[] args )
    {
        ServerSocket serverSocket=null;
        Socket client=null;
        PrintWriter pw=null;
        try {
             serverSocket=new ServerSocket(8080);
             client=serverSocket.accept();
            BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream()));
             pw=new PrintWriter(client.getOutputStream());
            String request="",response="";
            StringBuilder ab=new StringBuilder();

            while((request=in.readLine())!=null){
               System.out.println(request);
            }
            response="客户端,奥里给";
            pw.write(response);
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                client.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

public class Client {
    public static void main(String args[]){
        try {
            Socket client = new Socket("localhost",8080);
            OutputStream os=client.getOutputStream();
            os.write("服务器,奥力给".getBytes("utf-8"));//write的后面一定要有关闭流或者shutdownOutput()告知以输入完的操作,否则程序会报错
            client.shutdownOutput(); //告诉服务器已发送完毕注意这里不是os.close();---会报Socket is closed,也不是client.close()
            //当然,如果不想接受服务端传来的消息,可以使用client.close()断开输出流
            BufferedReader bf=new BufferedReader(new InputStreamReader(client.getInputStream()));
            String response="";
            while((response=bf.readLine())!=null){
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

效果如下:
在这里插入图片描述
在这里插入图片描述
这里的socket是短连接。即一次请求应答后就断开了tcp的连接,下面介绍如何使用长连接。(就是死循环socket.accept())参考链接
客户端

public class Client {
    public static void main(String args[]){
        try {
            Socket client = new Socket("localhost",8080);
            OutputStream os=client.getOutputStream();
            os.write("服务器,奥力给".getBytes("utf-8"));//write的后面一定要有关闭流或者shutdownOutput()告知以输入完的操作,否则程序会报错
            client.shutdownOutput(); //告诉服务器已发送完毕注意这里不是os.close();---会报Socket is closed,也不是client.close()
            //当然,如果不想接受服务端传来的消息,可以使用client.close()断开输出流
            BufferedReader bf=new BufferedReader(new InputStreamReader(client.getInputStream()));
            String response="";
            while((response=bf.readLine())!=null){
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器:

public class Server
{
    static int requestCount=1;
    public static void main( String[] args )
    {
        ServerSocket serverSocket=null;
        Socket client=null;
        PrintWriter pw=null;
        try {
             serverSocket=new ServerSocket(8080);
             while(true){
                 client=serverSocket.accept();
                 new Thread(new Task(client)).start();
             }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                client.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    static class Task implements Runnable{
        Socket socket=null;
        public Task(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            BufferedReader in= null;
            try {
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            PrintWriter pw=new PrintWriter(socket.getOutputStream());
            String request="",response="";
            StringBuilder ab=new StringBuilder();

            while((request=in.readLine())!=null){
                System.out.println(request);
            }
            response="客户端,奥里给 "+requestCount++ +" 次";
            pw.write(response);
            pw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

运行效果如下:
在这里插入图片描述
在这里插入图片描述
以上是BIO模型的网络,下面写一下NIO模型的服务器

backlog参数对TCP连接建立的影响
套接字编程中listen的第二个参数backlog是什么意思?多大的值合适?我不假思索地回答它表示服务器可以接受的并发请求的最大值

基于java的nio服务器

public class PlainNioServer {
    public static void main(String[] args) {
        try {
            new PlainNioServer().server(9999);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void server(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        ServerSocket ss = serverChannel.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        ss.bind(address);
        Selector selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
        for (;;){
            try {
                selector.select();
            } catch (IOException ex) {
                ex.printStackTrace();
                //handle exception
                break;
            }
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server =
                                (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_WRITE |
                                SelectionKey.OP_READ, msg.duplicate());
                        System.out.println(
                                "Accepted connection from " + client);
                    }
                    if (key.isWritable()) {
                        SocketChannel client =
                                (SocketChannel) key.channel();
                        ByteBuffer buffer =
                                (ByteBuffer) key.attachment();
                        while (buffer.hasRemaining()) {
                            if (client.write(buffer) == 0) {
                                break;
                            }
                        }
                        client.close();
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                        // ignore on close
                    }
                }
            }
        }
    }
}

基于netty的服务器

关于在线聊天服务器可参考连接
服务端

public class NettyServer {
    private int port;

    public NettyServer(int port) {
        this.port=port;
    }

    public static void main(String[] args) {
        new NettyServer(8888).start();
    }

    private void start() {
        EventLoopGroup boss=new NioEventLoopGroup();  //事件循环多线程---接收请求的
        EventLoopGroup worker=new NioEventLoopGroup(); //事件循环多线程---处理请求的

        ServerBootstrap bootstrap=new ServerBootstrap();    //netty服务器启动的一个驱动类,即初始化服务器配置的
        bootstrap.group(boss,worker).channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new ChannelInboundHandlerAdapter(){
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        ByteBuf buf = (ByteBuf) msg;
                                        System.out.println("服务端收到请求:"+ ByteBuf2String.convertByteBufToString(buf));
                                        /**
                                         *  Netty中的消息传递,都必须以字节的形式,以ChannelBuffer为载体传递。
                                         */
                                        /**
                                         * ByteBuf in;
                                         * in.writeBytes("你收到了吗".getBytes());
                                         */
                                       ctx.writeAndFlush(Unpooled.copiedBuffer(("ok".getBytes())));
                                       ctx.close();
                                    }
                                });
                    }
                });
        try {
           ChannelFuture f= bootstrap.bind(port).sync();
            f.addListener(new GenericFutureListener<ChannelFuture>() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    //System.out.println("Netty init over,result:{}"+ future.isSuccess());
                }
            });
           f.channel().closeFuture().sync();
           // System.out.println("============5252535353=========");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }
    }
}

客户端

扫描二维码关注公众号,回复: 8732147 查看本文章
public class NettyClient {
    public static void main(String[] args) {
        new NettyClient().clientStart();
    }

    private void clientStart() {
        EventLoopGroup workers = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(workers)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {

                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {

                                final ChannelFuture f = ctx.writeAndFlush(Unpooled.copiedBuffer(("HelloNetty".getBytes())));
                                System.out.println("客户端发送请求:"+"HelloNetty");
                            }

                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                try {
                                    ByteBuf buf = (ByteBuf) msg;
                                    System.out.println("客户端收到响应:"+  ByteBuf2String.convertByteBufToString(buf));
                                } finally {
                                    ReferenceCountUtil.release(msg);
                                }
                            }
                        });
                    }
                });

        try {
            //System.out.println("start to connect...");
            ChannelFuture f = b.connect("127.0.0.1", 8888).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workers.shutdownGracefully();
        }
    }
}

还有一个工具类【bytebuff转string】

public class ByteBuf2String {
    public static String convertByteBufToString(ByteBuf buf) {
        String str;
        if(buf.hasArray()) { // 处理堆缓冲区
            str = new String(buf.array(), buf.arrayOffset() + buf.readerIndex(), buf.readableBytes());
        } else { // 处理直接缓冲区以及复合缓冲区
            byte[] bytes = new byte[buf.readableBytes()];
            buf.getBytes(buf.readerIndex(), bytes);
            str = new String(bytes, 0, buf.readableBytes());
        }
        return str;
    }
}

效果如下:
在这里插入图片描述
在这里插入图片描述

发布了437 篇原创文章 · 获赞 82 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_41063141/article/details/103654575