Java

来源:互联网 发布:人力资源软件 免费 编辑:程序博客网 时间:2024/06/06 06:41
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket; public class EchoServer {     private static final int ECHO_SERVER_PORT = 6789;     public static void main(String[] args) {                try(ServerSocket server = new ServerSocket(ECHO_SERVER_PORT)) {            System.out.println("服务器已经启动...");            while(true) {                Socket client = server.accept();                new Thread(new ClientHandler(client)).start();            }        } catch (IOException e) {            e.printStackTrace();        }    }     private static class ClientHandler implements Runnable {        private Socket client;         public ClientHandler(Socket client) {            this.client = client;        }         @Override        public void run() {            try(BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));                    PrintWriter pw = new PrintWriter(client.getOutputStream())) {                String msg = br.readLine();                System.out.println("收到" + client.getInetAddress() + "发送的: " + msg);                pw.println(msg);                pw.flush();            } catch(Exception ex) {                ex.printStackTrace();            } finally {                try {                    client.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    } }

注意:上面的代码使用了Java 7的TWR语法,由于很多外部资源类都间接的实现了AutoCloseable接口(单方法回调接口),因此可以利用TWR语法在try结束的时候通过回调的方式自动调用外部资源类的close()方法,避免书写冗长的finally代码块。此外,上面的代码用一个静态内部类实现线程的功能,使用多线程可以避免一个用户I/O操作所产生的中断影响其他用户对服务器的访问,简单的说就是一个用户的输入操作不会造成其他用户的阻塞。当然,上面的代码使用线程池可以获得更好的性能,因为频繁的创建和销毁线程所造成的开销也是不可忽视的。

下面是一段回显客户端测试代码:

import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner; public class EchoClient {     public static void main(String[] args) throws Exception {        Socket client = new Socket("localhost", 6789);        Scanner sc = new Scanner(System.in);        System.out.print("请输入内容: ");        String msg = sc.nextLine();        sc.close();        PrintWriter pw = new PrintWriter(client.getOutputStream());        pw.println(msg);        pw.flush();        BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));        System.out.println(br.readLine());        client.close();    }}
如果希望用NIO的多路复用套接字实现服务器,代码如下所示。NIO的操作虽然带来了更好的性能,但是有些操作是比较底层的,对于初学者来说还是有些难于理解。

import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator; public class EchoServerNIO {     private static final int ECHO_SERVER_PORT = 6789;    private static final int ECHO_SERVER_TIMEOUT = 5000;    private static final int BUFFER_SIZE = 1024;     private static ServerSocketChannel serverChannel = null;    private static Selector selector = null;    // 多路复用选择器    private static ByteBuffer buffer = null;    // 缓冲区     public static void main(String[] args) {        init();        listen();    }     private static void init() {        try {            serverChannel = ServerSocketChannel.open();            buffer = ByteBuffer.allocate(BUFFER_SIZE);            serverChannel.socket().bind(new InetSocketAddress(ECHO_SERVER_PORT));            serverChannel.configureBlocking(false);            selector = Selector.open();            serverChannel.register(selector, SelectionKey.OP_ACCEPT);        } catch (Exception e) {            throw new RuntimeException(e);        }    }     private static void listen() {        while (true) {            try {                if (selector.select(ECHO_SERVER_TIMEOUT) != 0) {                    Iterator<SelectionKey> it = selector.selectedKeys().iterator();                    while (it.hasNext()) {                        SelectionKey key = it.next();                        it.remove();                        handleKey(key);                    }                }            } catch (Exception e) {                e.printStackTrace();            }        }    }     private static void handleKey(SelectionKey key) throws IOException {        SocketChannel channel = null;         try {            if (key.isAcceptable()) {                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();                channel = serverChannel.accept();                channel.configureBlocking(false);                channel.register(selector, SelectionKey.OP_READ);            } else if (key.isReadable()) {                channel = (SocketChannel) key.channel();                buffer.clear();                if (channel.read(buffer) > 0) {                    buffer.flip();                    CharBuffer charBuffer = CharsetHelper.decode(buffer);                    String msg = charBuffer.toString();                    System.out.println("收到" + channel.getRemoteAddress() + "的消息:" + msg);                    channel.write(CharsetHelper.encode(CharBuffer.wrap(msg)));                } else {                    channel.close();                }            }        } catch (Exception e) {            e.printStackTrace();            if (channel != null) {                channel.close();            }        }    } }
import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.charset.CharacterCodingException;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;import java.nio.charset.CharsetEncoder; public final class CharsetHelper {    private static final String UTF_8 = "UTF-8";    private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder();    private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();     private CharsetHelper() {    }     public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{        return encoder.encode(in);    }     public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{        return decoder.decode(in);    }}