Java多线程与网络编程综合使用

来源:互联网 发布:手机淘宝怎么退款 编辑:程序博客网 时间:2024/05/22 12:14

最近重新看多线程与网络编程这一块的知识,好久没碰这一块了,都忘得差不多了,这里将这两个模块的知识串接一下。同时处理多线程与网络编程最为经典的例子莫过于聊天室,那我就聊天室案例作为一个回顾。
首先,我们来看以下代码:

package MultiTCP;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * 必须先启动再连接 * 1、创建服务器 指定端口 ServerSocket(int port) * 2、接收客户端的连接  阻塞式 * 3、发送数据+接收数据 *  * 接收多个客户端 */@SuppressWarnings("all")public class MultiServer {    public static void main(String[] args) throws IOException {        //1、创建服务器 指定端口        ServerSocket server = new ServerSocket(8888);        while(true)//死循环 一个accept 一个客户端        {            //2、接收客户端的连接            Socket socket = server.accept();            System.out.println("一个客户端建立连接");            //2、发送数据            String msg = "欢迎使用";            //3、输出流            /*BufferedWriter bw = new BufferedWriter(                    new OutputStreamWriter(                            socket.getOutputStream()));            bw.write(msg);            bw.newLine();//一定要加行结束符,不然读不到数据            bw.flush();*/            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());            dos.writeUTF(msg);            dos.flush();        }    }}
package MultiTCP;import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;/** * 1、创建客户端 必须指定服务器+端口  此时就在连接 * Socket(String host,int port) * 2、接收数据+发送数据 */@SuppressWarnings("all")public class Client {    public static void main(String[] args) throws UnknownHostException, IOException {        //1、创建客户端 必须指定服务器+端口  此时就在连接        Socket client = new Socket("localhost",8888);        //2、接收数据        /*BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));        String echo = br.readLine();//阻塞式方法        System.out.println(echo);*/        DataInputStream dis = new DataInputStream(client.getInputStream());        String echo = dis.readUTF();        System.out.println(echo);    }}

以上代码存在的问题
服务器为一个客户端发送数据完毕才能连接下一个客户端。
因此,为了解决上述的问题,我们需要为服务器端创建多线程操作。

首先我们需要为聊天室添加发送数据和接收数据。

package CSNet;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * 创建服务器 */@SuppressWarnings("all")public class Server {    public static void main(String[] args) throws IOException {        ServerSocket server = new ServerSocket(9999);        Socket client = server.accept();        //写出数据        //输入流        DataInputStream dis = new DataInputStream(client.getInputStream());        String msg = dis.readUTF();        System.out.println("服务器收到"+msg);        //输出流        DataOutputStream dos = new DataOutputStream(client.getOutputStream());        dos.writeUTF("服务器发送给客户端"+msg);        dos.flush();                    }}
package CSNet;import java.io.BufferedReader;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;import java.net.UnknownHostException;/** * 创建客户端:发送数据+接收数据 * 写出数据:输出流 * 读取数据:输入流 * 输入流与输出流在同一个线程内,因此我们应该让 输入流与输出流彼此独立 */@SuppressWarnings("all")public class Client {    public static void main(String[] args) throws UnknownHostException, IOException {        Socket client = new Socket("localhost",9999);        //控制台的输入流        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));        DataOutputStream dos = new DataOutputStream(client.getOutputStream());        DataInputStream dis = new DataInputStream(client.getInputStream());        while(true)        {            String info = console.readLine();            //输出流            dos.writeUTF(info);            dos.flush();            //输入流            String msg = dis.readUTF();            System.out.println(msg);        }    }}

以上的代码存在输入流与输出流在同一个线程内问题,因此我们应该让输入流与输出流彼此独立。


接下来我们是需要实现多线程,让输入流与输出流分离。对客户端实现多线程。

客户端发送数据

package ThreadNet;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;/** * 发送数据线程:用于发送数据 */public class Send implements Runnable{    //控制台的输入流    private BufferedReader console;    //管道的数据输出流    private DataOutputStream dos;    //控制线程标识    private boolean isRunning = true;    //初始化    public Send() {        console = new BufferedReader(new InputStreamReader(System.in));     }    public Send(Socket client)    {        this();        try {            dos = new DataOutputStream(client.getOutputStream());        } catch (IOException e) {        }    }    //1、从控制台接收数据    private String getMsgFromConsole()    {        try {            return console.readLine();        } catch (IOException e) {        }        return "";    }    /**     * 1、从控制台接收数据     * 2、发送数据     */    public void send()    {        String msg = getMsgFromConsole();        try {            if(null!=msg&& !msg.equals(""))            {                dos.writeUTF(msg);                dos.flush();//强制刷新            }        } catch (IOException e) {             isRunning = false;//发送失败,提示关闭线程             CloseUtil.closeAll(dos,console);//如果不能发送成功,直接关闭流。        }    }    @Override    public void run() {        //线程体        while(isRunning)        {            send();        }    }}

客户端接收数据

package ThreadNet;import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;/** * 接收线程:用于接收数据 */public class Receive implements Runnable{    //管道的数据输入流    private DataInputStream dis ;    //线程标识    private boolean isRunning = true;    public Receive()    {       }       public Receive(Socket client) {        try {            dis = new DataInputStream(client.getInputStream());        } catch (IOException e) {            isRunning = false;            CloseUtil.closeAll(dis);        }    }    //接收数据的方法    public String receive()    {        String msg = "";        try {            msg = dis.readUTF();        } catch (IOException e) {            isRunning = false;            CloseUtil.closeAll(dis);        }        return msg;    }    @Override    public void run() {        //线程体        while(isRunning){            System.out.println(receive());        }       }}

客户端

package ThreadNet;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;/** * 创建客户端:发送数据+接收数据 * 写出数据:输出流 * 读取数据:输入流 * 输入流与输出流在同一个线程内 应该独立出来 */public class Client {    public static void main(String[] args) throws UnknownHostException, IOException {        Socket client = new Socket("localhost",9999);        new Thread(new Send(client)).start();//一条路径        new Thread(new Receive(client)).start();//一条路径      }}

服务器

package ThreadNet;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;/** * 创建服务器 */public class Server {    public static void main(String[] args) throws IOException {        ServerSocket server = new ServerSocket(9999);        while(true){            Socket client = server.accept();            //写出数据            //输入流            DataInputStream dis = new DataInputStream(client.getInputStream());            //输出流            DataOutputStream dos = new DataOutputStream(client.getOutputStream());            while(true)            {                       String msg = dis.readUTF();                //System.out.println(msg);                      dos.writeUTF("服务器收到数据并返回"+msg);                dos.flush();            }        }    }}

关闭流

package ThreadNet;import java.io.Closeable;import java.io.IOException;/** * 关闭流的方法 */public class CloseUtil {    public static void closeAll(Closeable ... io)    {        for(Closeable temp:io)        {            if(null==temp)            {                try {                    temp.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

这个方仍然存在问题,服务器端只能够一个一个的接收,必须要等到上一条执行完,才能进入下一条,存在所谓的先后顺序,并不具备多线程的功能。因此我们也需要对服务器进行多线程。


服务器

package MultiServer;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;/** * 创建服务器 */public class Server {    private List<MyChannel> all = new ArrayList<>();    public static void main(String[] args) throws IOException  {            new Server().start();    }    public void start() throws IOException    {           ServerSocket server = new ServerSocket(9999);           while(true)        {            Socket client = server.accept();            MyChannel channel = new MyChannel(client);            all.add(channel);//统一管理            new Thread(channel).start();//一条道路        }    }    /**     * 内部类     * 一个客户端 一条道路     * 1、输入流     * 2、输出流     * 3、接收数据     * 4、发送数据     * @author Administrator     *     */    class MyChannel implements Runnable    {        private DataInputStream dis;        private DataOutputStream dos;        private boolean isRunning = true;        private String name;        public MyChannel() {            }        //初始化        public MyChannel(Socket client)        {            try {                dis = new DataInputStream(client.getInputStream());                dos = new DataOutputStream(client.getOutputStream());                this.name = dis.readUTF();                //System.out.println(this.name);                this.send("欢迎进入聊天室");                sendOthers(this.name+"进入了聊天室",true);                        } catch (IOException e) {                CloseUtil.closeAll(dos,dis);                isRunning = false;            }        }        //接收数据        private String receive()        {            String msg = "";            try {                msg = dis.readUTF();            } catch (IOException e) {                CloseUtil.closeAll(dis);                isRunning = false;                all.remove(this);//移除自身            }            return msg;        }        //发送数据        private void send(String msg)        {            if(null==msg||msg.equals(""))            {                return;            }            try {                dos.writeUTF(msg);                dos.flush();            } catch (IOException e) {                CloseUtil.closeAll(dos);                isRunning = false;                all.remove(this);//移除自身             }        }        //发送给其他客户端        private void sendOthers(String msg,boolean sys)        {            //是否为私聊  约定            if(msg.startsWith("@")&& msg.indexOf(":")>-1)            {                //获取name                String name = msg.substring(1,msg.indexOf(":"));                String contant = msg.substring(msg.indexOf(":")+1);                for(MyChannel other:all)                {                    if(other.name.equals(name))                    {                        other.send(this.name+"对你悄悄的说:"+contant);                    }                }            }            else {                for(MyChannel other:all)                {                    if(other ==this)                    {                        continue;                    }                    if(sys==true)//系统信息                    {                        other.send("系统信息:"+msg);                    }                    else {                        //发送其它客户端                        other.send(this.name+"对所有人说"+msg);                    }                }            }            /*            //遍历容器            for(MyChannel others:all)            {                if(others == this)                {                    continue;                }                //发送给其他客户端                others.send(msg);            }*/        }        @Override        public void run() {            while(isRunning)            {                sendOthers(receive(),false);            }        }    }}

发送信息(供客服端使用)

package MultiServer;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;/** * 发送数据线程:用于发送数据 */public class Send implements Runnable{    //控制台输入流    private BufferedReader console;    //管道输出流    private DataOutputStream dos;    //控制线程标识    private boolean isRunning = true;    //名称    private String name;    //初始化    public Send() {        console = new BufferedReader(new InputStreamReader(System.in));     }    public Send(Socket client,String name)    {        this();        try {            dos = new DataOutputStream(client.getOutputStream());            this.name = name;            send(this.name);        } catch (IOException e) {            //e.printStackTrace();        }    }    //1、从控制台接收数据    private String getMsgFromConsole()    {        try {            return console.readLine();        } catch (IOException e) {            e.printStackTrace();        }        return "";    }    /**     * 1、从控制台接收数据     * 2、发送数据     */    public void send(String msg)    {        try {            if(null!=msg&& !msg.equals(""))            {                dos.writeUTF(msg);                dos.flush();//强制刷新            }        } catch (IOException e) {            //e.printStackTrace();             isRunning = false;             CloseUtil.closeAll(dos,console);        }    }    @Override    public void run() {        while(isRunning)        {            send( getMsgFromConsole());        }    }}

接收信息(供客服端使用)

package MultiServer;import java.io.DataInputStream;import java.io.IOException;import java.net.Socket;/** * 接收线程:用于接收数据 */public class Receive implements Runnable{    //管道的数据输入流    private DataInputStream dis ;    //线程标识    private boolean isRunning = true;    public Receive()    {       }       public Receive(Socket client) {        try {            dis = new DataInputStream(client.getInputStream());        } catch (IOException e) {            isRunning = false;            CloseUtil.closeAll(dis);        }    }    //接收数据的方法    public String receive()    {        String msg = "";        try {            msg = dis.readUTF();        } catch (IOException e) {            isRunning = false;            CloseUtil.closeAll(dis);        }        return msg;    }    @Override    public void run() {        //线程体        while(isRunning){            System.out.println(receive());        }       }}

客户端

package MultiServer;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;/** * 创建客户端:发送数据+接收数据 * 写出数据:输出流 * 读取数据:输入流 * 输入流与输出流在同一个线程内 应该独立出来 * 加入名称 */public class Client {    public static void main(String[] args) throws IOException    {        System.out.println("请输入用户名:");        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        String name = br.readLine();        if(name.equals(""))        {            return;        }        Socket client = new Socket("localhost",9999);        new Thread(new Send(client,name)).start();//一条路径        new Thread(new Receive(client)).start();//一条路径    }}

关闭流

package MultiServer;import java.io.Closeable;import java.io.IOException;/** * 关闭流的方法 */public class CloseUtil {    public static void closeAll(Closeable ... io)    {        for(Closeable temp:io)        {            if(null==temp)            {                try {                    temp.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

运行结果:
Client1

Client2

1 0
原创粉丝点击