zoukankan      html  css  js  c++  java
  • 记录 serverSocket socket 输入,输出流,关闭顺序,阻塞,PrintWriter的一些问题.

    关于socket.getOutputStream() 的一些问题, OutputStream的flush是一个空方法,所以需要另一个实现了Flush的流来包装一下

    这里为什么使用PrintWriter,而不使用BufferedWriter

    原因是在接收方使用BufferedReader 的readLine,而BufferedWriter.write并不会自动换行,所以会导致读取阻塞,需要手动换行,代码如下:

                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bw.write("你好啊");
    //            因为在服务端使用的是readLine,所以如果不调用newLine,那么会一直阻塞
                bw.newLine();
                bw.flush();

    以下两个测试类代码,在输出数据的时候,输出空行为结束符,在读取输入流的时候都在循环内判断了readLine长度是否为0(当然规范的做法是约定长度,根据长度判断是否结束),原因如下摘抄☞:点击这里

    对于socket,不能认为把某次写入到流中的数据读取完了就算流结尾了,但是socket流还存在,还可以继续往里面写入数据然后再读取。所以用BufferedReader封装socket的输入流,调用BufferedReader的readLine方法是不会返回null的

    所以在循环内如果不判断   msg!=null&&msg.length()>0  那么程序将会一直阻塞在这里(程序是因为readLine阻塞,并不是死循环)

    关于流的关闭会影响socket的使用,而且对一次连接关闭流以后,没有办法再次打开,哪怕只关闭输入流,也会导致输出流不能使用.反之亦然.

    所以如果在一次IO操作以后,还有另一次IO,那么就先不关闭.等全部用完再关闭.

    ServerSocket 

    @RunWith(JUnit4.class)
    public class ServerSocketTest {
        @Test
        public void testServer(){
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket();
    //            serverSocket.setReuseAddress(true);
    //            System.out.println(InetAddress.getLocalHost());//获取的本机地址不一定正确
                serverSocket.bind(new InetSocketAddress(8000));
                
                while(true){
                    //一旦连接,返回的socket包含客户端信息的socket
                    Socket socket = serverSocket.accept();
                    PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
                    pw.println("host:"+socket.getInetAddress()+":"+socket.getPort()+"建立链接");
                    //这里发送空行作为结束符,当然规范做法是根据长度作为标识
                    pw.println("");
                    //因为new PrinWriter的时候指定了autoFlush的参数为true所以不用手动flush
    //                pw.flush();
                    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){
                        System.out.println(msg);
                    }
                    pw.close();
                    br.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
        
    }

    ClientSocket

    /**
     * 
     * @author lzw
     *
     */
    @RunWith(JUnit4.class)
    public class SocketClient {
        @Test
        public void testClient() throws UnknownHostException, IOException{
            //表示连接到服务器的 地址以及端口
            SocketAddress address = new InetSocketAddress("19.95.103.112",8000);
            Socket socket = new Socket();
            socket.connect(address,60000);//连接
            //读取服务端返回的数据
            getMsb(socket);
            sendMsg(socket);
            socket.close();
        }
        
        
        private void sendMsg(Socket socket){
            PrintWriter pw = null;
    //        BufferedWriter bw = null;
            try {
                
    //            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    //            bw.write("你好啊");
                //因为在服务端使用的是readLine,所以如果不调用newLine,那么会一直阻塞
    //            bw.newLine();
    //            bw.flush();
    //            OutputStream os =  socket.getOutputStream();
    //            //这个是一个空方法
    //            os.flush();
                pw = new PrintWriter(socket.getOutputStream(),true);
                pw.println("你好啊");
           //输出空行作为结束标识
           pw.println("");
    //因为new PrinWriter的时候指定了autoFlush的参数为true所以不用手动flush // pw.flush(); } catch (IOException e) { e.printStackTrace(); }finally{ //因为本次连接,到这个方法以后没有更多交互,所以可以关闭 if(pw!=null){ pw.close(); } } } private void getMsb(Socket socket){ InputStream is = null; BufferedReader br = null; try { is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); for(String msg = br.readLine();msg!=null&&msg.length()>0;msg = br.readLine()){ System.out.println(msg+"--"); } } catch (IOException e) { e.printStackTrace(); }finally{ //这里不能关闭流,否则会把socket也关闭了(因为后面还要发送数据,所以不能关闭流,不管是关闭输入输入其中之一,都会导致输入和输出都不能使用) // try { // if(br!=null) // br.close(); // } catch (IOException e) { // e.printStackTrace(); // } } } }
  • 相关阅读:
    对象内存布局 (2)
    对象内存布局 (1)
    C++虚函数及虚函数表解析
    C++ inline 函数
    第十六章 贪心算法——0/1背包问题
    动态规划——活动选择问题
    第十六章 贪心算法——活动选择问题
    第十五章 动态规划——最优二叉搜索树
    Cannot load supported formats: Cannot run program "svn"
    idea 配置多个tomcat
  • 原文地址:https://www.cnblogs.com/sweetchildomine/p/6477563.html
Copyright © 2011-2022 走看看