socket 帮忙改错 客户端关闭的时候不要让程序崩

我之前没说清楚 怪我...
图片说明
图片说明
图片说明

我想让客户端给服务器发送CLOSE,然后服务器关闭和这个客户端的连接。 但是只要一输入CLOSE 客户端那边都运行不了 更不要说发送给服务器 感觉是一个很简单的问题 但是一直调不通

只要有一个客户端退出 剩下的程序整个崩 有没有办法加几条语句让剩下的客户端和服务器正常运行

服务器



@RestController
@RequestMapping("/Socket")
@Api("服务器")
@Service
public class SocketService {
    @Autowired
    SetDao setDao;

//    SendData send=new SendData();
    static Scanner input = new Scanner(System.in);
    static List<Socket> list = new ArrayList();
    static Integer count =0;
    public static final Integer PORT=8888;

    @RequestMapping(value = "/photo", method = RequestMethod.POST)
    public String photocontrol(@RequestBody Integer e) throws IOException{
        SendData send=new SendData();
        if(e%2==0)
            send.msg="OPENPHOTO";
        else if(e%2==1)
            send.msg="CLOSEPHOTO";
        return "SUCCESS_PHOTO";
    }

    @RequestMapping(value = "/create", method = RequestMethod.GET)
    public  void createServerSocket(){
//    {
        try {
            //创建服务器
            ServerSocket server = new ServerSocket(PORT);
            System.out.println("***服务器即将启动***");
            while (true) {
                Socket s = server.accept();
                list.add(s);
                System.out.println("当前客户端的数量为:" + (count + 1));
                //发信息(有多个客户端)
                if (count == 0) {
                    new SendData().start();
                }
                //收信息
                new GetData(new DataInputStream(list.get(count).getInputStream())).start();
                count++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
//    }
    }

    //给客户端发送信息
    public static class SendData extends Thread {
        private DataOutputStream dOutput;
        public static String msg;
        @Override
        public void run() {
            while (true) {
                try {
//                  String msg =input.next();
                    if (msg!=null) {
                        for (Socket socket : list) {
                            dOutput = new DataOutputStream(socket.getOutputStream());
                            dOutput.writeUTF(msg);
                        }
                        msg=null;
                    }
                } catch (IOException e) {
//                    break;
                    e.printStackTrace();
                }
            }
        }
    }

    //读取客户端发来的信息
    public static class GetData extends Thread {
        private DataInputStream dInput;
        public GetData(DataInputStream _dInput) {
            dInput=_dInput;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    String msg = dInput.readUTF();
                    if (msg != null) {
                        System.out.println("客户端:"+ msg);
//                       if(msg.equals("CLOSE")) {
//                            dInput.close();
//                            list.remove(count);
//                            count--;
//                            System.out.println("当前客户端的数量为:"+count);
//                        }
//                        if(socket.getKeepAlive()==false){
//                            ((Reader)in).close();
//                            temp="客户端"+socket.getPort()+"退出";
//                            ss.appendMessage(temp);
//                            socket.close();
//                            this.stop();

                    }
                } catch (IOException e) {
                    try {
                        dInput.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                }
            }
        }
    }

}

客户端



@RestController
@RequestMapping("/TestSocket")
@Api("客户端")
@Service
public class TestSocketService {
    static Scanner input = new Scanner(System.in);
    public static final Integer PORT=8888;

    @RequestMapping(value = "/create", method = RequestMethod.GET)
    public void createSocket() throws IOException {
        Socket socket = new Socket("localhost",PORT);
        System.out.println("已连接服务器");

        new GetData(new DataInputStream(socket.getInputStream())).start();
        new SendData(new DataOutputStream(socket.getOutputStream())).start();
    }

    //读取服务器发来的信息
    public static class GetData extends Thread {
        private DataInputStream dInput;
        public GetData(DataInputStream _dInput) {
            dInput = _dInput;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    String msg = dInput.readUTF();
                    if (msg != null) {
                        System.out.println("服务器:" + msg);

                    }
                } catch (IOException e) {
                    try {
                        dInput.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                }
            }
        }
    }

    //给服务器发送信息
    public static class SendData extends Thread {
        private DataOutputStream dOutput;
        public SendData(DataOutputStream _dOutput) {
            dOutput = _dOutput;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    System.out.println("给服务器发消息:");
                    String msg =input.next();
                    if (msg != null) {
                        dOutput.writeUTF(msg);
                    }
                } catch (IOException e) {
                    break;
//                    e.printStackTrace();
                }
            }
        }
    }
}

5个回答

上面给你回答了一次,没想到还是没解决你的问题哈,看你补充的提问,我又自己测试了下,找到了问题的原因。希望你能采纳。

首先说下你这个错误的原因:多个线程同时操作一个Scanner(看下面代码,你定义的是静态的),而这个Scanner又是个非线程安全的类。这就导致了多线程抢占同一资源,最终引起了不可预测的异常。
static Scanner input = new Scanner(System.in);

一个Scanner只能对应一个客户端,所以如果你要测试多个客户端的话,你需要启动多个进程去测试,而不是在一个进程里启动多个线程。
另外,在eclipse里的话,如果你启动多次main方法,他是有多个输入窗口的,每个scanner对应一个窗口。

重新运行一次,再读取一下指令

 for (Socket socket : list) {
 ty{
                            dOutput = new DataOutputStream(socket.getOutputStream());
                            dOutput.writeUTF(msg);
                                                        }catch(Throwable ex){
                                                        }
                        }
danielinbiti
danielinbiti 回复Mtone_007: 异常就remove掉,count--
接近 2 年之前 回复
Mtone_007
Mtone_007 能帮忙试一下这几条语句吗?
接近 2 年之前 回复
Mtone_007
Mtone_007 我想的是能不能收到客户端发过来的CLOSE 之后 让count--,然后让这个客户端退出list 试了一下 没有实现
接近 2 年之前 回复

具体不知道你在哪里崩了哈,解决问题的思路就是在你崩掉的地方加入逻辑判断来避免异常的抛出或者try/catch来捕获异常
在你遍历客户端list的时候可以加入下面的判断:
1.socket.isClosed();//判断客户端是否已经关闭。
2.socket.isOutputShutdown();//判断客户端的输出流是否已经关闭。
当然,socket对象还提供了很多判断方法,通过这些判断你就可以知道客户端是否正常,如果不正常,你就count--,如果正常,那就继续下面的业务处理。

另外,客户端与服务端如何知道对方是否正常运行的一个办法就是:心跳通讯,就是说客户端与服务端每隔几秒互相发送信息来确认对方是否正常,如果对方进行回复,判断为正常;如果不回复,那么就判断对方掉线。

catch(IOException ...

你把IOException全部改成Exception试试

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!