Java Socket 多线程简单入门案例

来源:互联网 发布:域名备案 百科 编辑:程序博客网 时间:2024/06/05 01:44

上一篇:Java Socket 单线程的简单入门案例

1. 目录结构

这里写图片描述

2. StartClient.java源码

    package socket.thread;    import java.net.InetAddress;    import java.net.UnknownHostException;    public class StartClient {     /**     * 需要先启动服务端StartServer,再运行客户端StartClient         * 请注意,由于线程运行的不确定性,打印输出语句的次序是不确定的。。。     *      * 但是,不论输出语句的次序如何变化,客户端总有三个线程请求到服务端,     * 并且服务器端在处理完请求后会关闭Socker和IO。     *      * @param args     * @throws UnknownHostException     */    public static void main(String[] args) throws UnknownHostException {        int threadNo = 0;        // 设置连接地址类        InetAddress addr = InetAddress.getByName("localhost");        // 从循环中生成3个客户端,每个客户端会开启一个通讯线程,每个线程首先将先向服务器端发送"Hello Server,My id is "的字符串,然后发送”byebye”,终止该线程的通讯。        for (threadNo = 0; threadNo < 3; threadNo++) {            new SocketClient(addr);        }    }    }

3. SocketClient.java源码

     package socket.thread;    import java.io.BufferedReader;    import java.io.BufferedWriter;    import java.io.IOException;    import java.io.InputStreamReader;    import java.io.OutputStreamWriter;    import java.io.PrintWriter;    import java.net.InetAddress;    import java.net.Socket;    public class SocketClient extends Thread {    // 客户端的socket    private Socket socket;    // 线程统计数,用来给线程编号    private static int cnt = 0;    // 客户端id    private int clientId = cnt++;    // io对象    private BufferedReader in;    private PrintWriter out;    // 构造函数,在创建该实体时执行    public SocketClient(InetAddress inetAddress) {        try {            // 通过inetAddress和端口号初始化Socket对象            socket = new Socket(inetAddress, 3333);            // 实例化IO对象            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);            // 开启线程            start();        } catch (IOException e) {            e.printStackTrace();            try {                // 出现异常,关闭socket                socket.close();            } catch (IOException e2) {                e2.printStackTrace();            }        }    }    // 线程主体方法    public void run() {        try {            // 向Socket信道上传输本客户端的ID号            out.println("Hello Server,My id is " + clientId);            // 收到服务端发来的信息,打印出来            String str = in.readLine();            System.out.println(str);            // 向服务器端发送“byebye”结束本次通信            out.println("byebye");        } catch (IOException e) {            e.printStackTrace();            throw new RuntimeException(e);        } finally {            try {                // 出现异常,关闭socket                socket.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

4. StartServer.java源码

    package socket.thread;    import java.io.IOException;    import java.net.ServerSocket;    import java.net.Socket;        /**         * 服务器端运行类         */        public class StartServer {    // 服务器监听口号    static final int portNo = 3333;    /**     * @param args     * @throws IOException     */    public static void main(String[] args) throws IOException {        // 根据端口号,创建一个ServerSocket类型的服务器端的Socket,用来同客户端通讯。        ServerSocket serverSocket = new ServerSocket(portNo);        System.out.println("The Server is start: " + serverSocket);        try {            for (;;) {                // 阻塞,直到有客户端连接                Socket socket = serverSocket.accept();                // 通过构造函数,启动线程                new SocketServer(socket);            }        } finally {            // 关闭socket            serverSocket.close();        }    }}

5. SocketServer.java源码

     package socket.thread;    import java.io.BufferedReader;    import java.io.BufferedWriter;    import java.io.IOException;    import java.io.InputStreamReader;    import java.io.OutputStreamWriter;    import java.io.PrintWriter;    import java.net.Socket;    /**     * 使用套接字连接多个客户机      * 如果我们在通过程序里引入多线程的机制,可让一个服务器端同时监听并接收多个客户端的请求,并同步地为它们提供通讯服务。     * 基于多线程的通讯方式,将大大地提高服务器端的利用效率,并能使服务器端能具备完善的服务功能。     *     * 这个类通过继承Thread类来实现线程的功能,也就是说,在其中的run方法里,定义了该线程启动后要执行的业务动作。     */    public class SocketServer extends Thread {    // 客户端的socket    private Socket clientSocket;    // IO句柄    private BufferedReader in;    private PrintWriter out;    // 默认的构造函数    public SocketServer() {    }    // 带参数构造函数,初始化了本类里的Socket对象,同时实例化了两类IO对象。    public SocketServer(Socket socket) throws IOException {        clientSocket = socket;        // 初始化in和out句柄        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));        out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())), true);        // 通过start方法,启动定义在run方法内的本线程的业务逻辑。        start();    }    // 线程执行的主体内容    public void run() {        try {            // 用循环来监听通讯内容。for(;;) 等同于while(true),死循环            for (;;) {                // 读取从Socket信道上传输过来的客户端发送的通讯信息。                String str = in.readLine();                // 如果得到的信息为“byebye”,则表明本次通讯结束,退出for循环。                if (str.equals("byebye")) {                    break;                }                // 将字符串发送给客户端                System.out.println("In Server reveived the info: " + str);                out.println(str);            }            System.out.println("closing the server socket!");        } catch (IOException e) {            e.printStackTrace();            throw new RuntimeException(e);        } finally {            System.out.println("close the Server socket and the io.");            // 关闭客户端的Socket句柄。            try {                clientSocket.close();            } catch (IOException e) {                e.printStackTrace();                throw new RuntimeException(e);            }        }    }    }

下一篇:Java Socket 基于UDP协议的多线程连接

原创粉丝点击