java socket通信I/O阻塞>多线程实现非阻塞通信

简单的java socket通信,多个客户端同时连接,功能可在此基础上进行扩展。效果如图:

客户机发送,服务端接收!

server:


package com.lb.LB_Socket;

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 myServer {
    private ServerSocket server;
    private Socket socket;
    private BufferedReader brin;
    private PrintWriter pw;
    private BufferedReader in ;
    private Boolean bool=true;

    public static void main(String args[]){
        myServer ms = new myServer();
        try {
            ms.onServer();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void onServer() throws IOException{
        try{
            try{
                server = new ServerSocket(4440);
                System.out.println("服务器已启动!");
            }catch(Exception e){
                System.out.println("服务器未启动:"+e);
            }
            while(true){
                try{
                    socket = server.accept();
                    System.out.println("客户端接入--");
                    bool=true;
                }catch(Exception e){
                    System.out.println("出错了 :"+e);
                }
                while(bool){
                    brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    pw= new PrintWriter(socket.getOutputStream());
                    in= new BufferedReader(new InputStreamReader(System.in));


                        String content = brin.readLine();
                        System.out.println("客户端:"+content);

                        if(content.equals("exit")){
                            pw.println("欢迎下次再来!");
                            pw.flush();

                            System.out.println("客户端退出!");
                            bool=false;
                        }


                    /*
                    String replay = in.readLine();
                    pw.println(replay);
                    pw.flush();
                    */

                }


            }   
        }catch(Exception e){
            System.out.println("Error:"+e);
        }finally{
            if(pw!=null){
                pw.close();
            }
            if(brin!=null){
                brin.close();
            }
            if(in!=null){
                in.close();
            }
            if(socket!=null){
                socket.close();
            }
            if(server!=null){
                server.close();
            }
        }
    }

}

服务器端(ServerSocket):使用while()死循环一直等待客户端的连接,在使用while(bool)循环接收客户端发送来的数据,如果客户端退出则等待下一个客户机的连接,

客户端:



package com.lb.LB_Socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;

public class myClient implements Runnable{
    private Socket socket;
    private BufferedReader brin;
    private PrintWriter pw;
    private BufferedReader in ;
    private Boolean bool = true;
    public static void main(String args[]) throws IOException{
        new Thread(new myClient()).start();

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try{
            socket = new Socket("192.168.30.36",4440);
            System.out.println("客户端启动成功!");
            try{
                while(bool){
                    in = new BufferedReader(new InputStreamReader(System.in));
                    pw = new PrintWriter(socket.getOutputStream());
                    brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));


                        String readline;
                        readline = in.readLine();
                        //System.out.println(readline);

                        pw.println(readline);
                        pw.flush();

                        if(readline.equals("exit")){
                            in.close();
                            pw.close();
                            brin.close();
                            socket.close();

                            bool = false;
                        }



                        //System.out.println("服务器:"+brin.readLine());  //服务器回复

                }

            }catch(SocketException e){
                if(socket==null){
                    System.out.println("断开连接!");
                }
            }catch(Exception e){
                e.printStackTrace();
                System.out.println("未开启服务器");
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

客户端(Socket):发送数据,使用while()循环当客户机在线时连续发送消息,发送exit时,销毁对象,退出连接。

想实现无阻塞通信,双端随时发送消息,但基本的socket通信就是你发一句我发一句,我发了你不发,我这边就处于等待接收状态,也就是阻塞。
  1. 就是利用线程,接收和发送是两个线程,互不干扰,随发随收;待实践。
  2. 非阻塞的通信机制。服务器程序接收客户连接、客户程序建立与服务器的连接,以及服务器程序和客户程序收发数据的操作都可以按非阻塞的方式进行。服务器程序只需要创建一个线程,就能完成同时与多个客户通信的任务。非阻塞的通信机制主要由java.nio包(新I/O包)中的类实现,主要的类包括ServerSocketChannel、SocketChannel、Selector、SelectionKey和ByteBuffer等。
初步实现利用线程解决非阻塞通信

看下效果:这里写图片描述

基本的想法就是把发送消息和接收打印消息作为单独的线程启动。直接贴代码了

sendMsg:


package com.lb.LB_Socket;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class sendMsg implements Runnable {
    private DataOutputStream dos = null;
    //private DataInputStream dis = null;
    private Socket socket = null;
    private BufferedReader br =null ;
    private String name;
    private String content;
    boolean bool = true;

    public sendMsg(Socket socket,String name){
        //super();

        this.socket = socket;
        this.name = name;
    }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(bool){
                try {
                    dos = new DataOutputStream(socket.getOutputStream());
                    br = new BufferedReader(new InputStreamReader(System.in));

                    content = br.readLine();
                    dos.writeUTF(name+"说:"+content);
                    if(content.equals("exit")){
                        dos.close();
                        br.close();
                        socket.close();
                        bool = false;
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    bool=false;
                }

            }
        }
}

printMsg:


package com.lb.LB_Socket;

import java.io.DataInputStream;

import java.io.IOException;

import java.net.Socket;


public class printMsg implements Runnable {
    //private DataOutputStream dos = null;
    private DataInputStream dis = null;
    private Socket socket = null;
    private String content;
    boolean bool = true;

    //private String name;

    public printMsg(Socket socket){
        //super();

        this.socket = socket;
        //this.name = name;
    }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(bool){
                try {
                    dis = new DataInputStream(socket.getInputStream());
                    content = dis.readUTF();
                    System.out.println(content);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    bool=false;
                    e.printStackTrace();
                    //System.exit(1);
                }catch(Exception e){
                    bool = false;
                    e.printStackTrace();
                }
            }
        }       
}

server:


package com.lb.LB_Socket;

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 myServer implements Runnable{
    private boolean bool=true;

    Socket socket = null;
    ServerSocket server= null;

    public static void main(String args[]){
        new Thread(new myServer()).start();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try{
            try{
                server = new ServerSocket(4440);
                System.out.println("服务器已启动!");
            }catch(Exception e){
                System.out.println("服务器未启动:"+e);
            }
            while(true){
                try{
                    socket = server.accept();
                    System.out.println("客户端接入--");
                    bool=true;
                }catch(Exception e){
                    System.out.println("出错了 :"+e);
                }
                sendMsg send = new sendMsg(socket,"服务器");
                printMsg print  = new printMsg(socket);
                Thread s= new Thread(send);
                Thread p = new Thread(print);

                if(send.bool == false || print.bool==false){
                    s.interrupt();
                    p.interrupt();
                }else{
                    s.start();
                    p.start();
                }

            }   
        }catch(Exception e){
            System.out.println("Error:"+e);
        }finally{
            try{
                if(socket!=null){
                    socket.close();
                }
                if(server!=null){
                    server.close();
                }
            }catch(Exception e){
                e.printStackTrace();
            }

        }

    }
}

client:


package com.lb.LB_Socket;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class myClient{

    public static void main(String args[]){
        try {
            Socket socket = new Socket("192.168.30.36",4440);
            System.out.println("客户端启动成功!");

            sendMsg send = new sendMsg(socket,"客户");
            printMsg print  = new printMsg(socket);
            Thread s= new Thread(send);
            Thread p = new Thread(print);

            if(send.bool == false || print.bool==false){
                p.interrupt();
                s.interrupt();
            }else{
                s.start();
                p.start();
            }
            //System.out.println(socket.isConnected());
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }
}

问题是线程的控制,当成功连接以后,互发消息,当某一方断掉后,线程就会打印错误。
1. 断掉客户端,服务端起的发送、接收流线程无法判定关闭,导致下次客户端连接后,会出现短暂的接收不到消息及错误信息打印。之后恢复正常。
2. 断掉服务器,客户端的发送、接收流线程无法判定关闭退出,打印连接错误信息。

如何控制socket的连接,监听socket连接的状态以供事件处理、关闭流。

还需多多学习,东西真的太多了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heroboyluck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值