socket編程時的發送與接收數據時的問題

socket編程時的發送與接收數據時的問題

在編寫一個測試方法時,須要用啓動一個程序監聽一個端口,測試發送的數據是事正常,可是老是出現兩個問題,一是Socked老是在OutputSteam.write()方法以前被關閉,可是沒有使用代碼調用Socket的Close方法,另外一個是在接收數據時,老是卡在InputSteam.read()方法處(通常發生在前一個Socket在寫數據時異常中斷後再次有新Socket鏈接時),得不到數據,直到發送端關閉Socket,下面是代碼html

package com.zoro.example.subscribe.queue;

import com.zoro.util.SendUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

/**
* @author zoro
* @version 1.0
*/
public class TestSubscribeQueue {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestSubscribeQueue.class);

    public static void main(String[] args) throws IOException {
        new Thread(new EventListener()).start();
    }


    private static String test(InputStream is) {
        BufferedReader br = null;
        InputStreamReader isr = null;
        StringBuilder sb = new StringBuilder();

        isr = new InputStreamReader(is);
        br = new BufferedReader(isr);
        String line = null;
        while (true) {
            try {
                line = br.readLine();
                if (line == null || line.length() == 0) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            sb.append(line);
            sb.append("\n");
            line = null;
            LOGGER.debug("當前讀取的數據:{}", sb.toString());
        }

        return sb.toString();
    }

    static class EventListener implements Runnable {

        private final ServerSocket ss;

        public EventListener() throws IOException {
            ss = new ServerSocket(8087);

        }


        @Override
        public void run() {
            while (true) {
                /*
                這裏獲得的InputStream 不能在OutputStream返回數據以前關閉,由於InputStream關閉以後會致使Socket關閉,你說奇怪不奇怪,這樣一來就不能正常返回數據了,報錯說Socket已經關閉
                 */
                try (Socket s = ss.accept();
                     InputStream is = s.getInputStream();
                     OutputStream os = s.getOutputStream()) {
                    LOGGER.debug("等待請求...");

                    LOGGER.debug("新請求進入");
                    if (s.isClosed() || !s.isConnected() || s.isInputShutdown()) {
                        continue;
                    }
//                    String result = SendUtil.resolveInputStream(is);
                    String result = test(is);
                    LOGGER.debug("收到請求:{}", result);
                    StringBuilder response = new StringBuilder();
                    response.append("HTTP/1.1 200 OK\r\n");
                    response.append("Content-Type:text/html\r\n");
                    response.append("\r\n");
                    response.append("123252321");
                    LOGGER.debug("即將返回數據:{}", response.toString());
                    if (!s.isClosed()) {
                        LOGGER.debug("正在返回數據");
                        os.write(response.toString().getBytes());
                        os.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

分析緣由

  1. 在第76行代碼調用的方法中 調用的 InputStream.close()方法,致使了Socket也跟着關閉了,不清楚是什麼緣由引發的,可是去掉InputStream.close()確實OutputStream能夠向請求端改善數據了
  2. 在OutputStream的問題解決以後,InputStream的問題也跟着沒有了,由於我在測試時使用的是瀏覽器http發起的這個Socket,因此我猜想是在第一次Socket異常中斷後瀏覽器再次觸發了重試;;

問題更新

兩天後發現新問題: InputStream在包裝成BufferedReader整行讀取時到http請求的最後一行還會繼續向下一行讀,可是發送端這時已經不發送數據了,形成服務端一直卡在這裏等待java

問題緣由

BufferedReader.readLine()方法在讀取文件只,由於文件最後會是一個-1 ,因此能夠知道在哪裏結束,但網絡請求最後沒有這個-1 因此在讀了最後一行後不知道請求數據已經沒有更多了,形成一直阻塞編程

解決思路

http 請求(只討論get 與post 兩種方法),get 請求只有請求頭,在讀取到第一個空行時就能夠結束,post請求有請求體,能夠根據請求頭中ContentLength 判斷是否讀取完瀏覽器

相關文章
相關標籤/搜索