<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          每日一例 | 昨天手寫(xiě)服務(wù)器問(wèn)題搞定了……后面繼續(xù)搞事情……

          共 16900字,需瀏覽 34分鐘

           ·

          2021-06-02 02:36

          問(wèn)題搞定了

          昨天的問(wèn)題,已經(jīng)找到原因了,是因?yàn)檎?qǐng)求參數(shù)里有空字符串的情況,就是這些空字符串,導(dǎo)致inputStream被阻塞,所以最終無(wú)法響應(yīng)給瀏覽器端。

          昨天的doService方法是這樣寫(xiě)的:

          public void doService(SyskeRequest request, SyskeResponse response) throws Exception {
                  try {
                      byte[] bytes = new byte[1024];
                      int read;
                      ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                      while ((read = request.getInputStream().read(bytes)) != -1) {
                          byteArrayOutputStream.write(bytes);
                      }
                      byte[] toByteArray = byteArrayOutputStream.toByteArray();
                      String requestStr = new String(toByteArray);
                      System.out.println(String.format("請(qǐng)求參數(shù):%s", requestStr));
                      String[] split = requestStr.split("\r\n");
                      System.out.println("end");
                      response.write("hello syskeCat");
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

          簡(jiǎn)單調(diào)整下,就可以了

          public static void doService(SyskeRequest request, SyskeResponse response) {
                  try {
                      String readLine;
                      ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()));
                      while ((readLine = bufferedReader.readLine()) != null) {
                          if(readLine.length() == 0){
                              break;
                          }
                          byteArrayOutputStream.write(bytes);
                      }
                      byte[] toByteArray = byteArrayOutputStream.toByteArray();
                      String requestStr = new String(toByteArray);
                      System.out.println(String.format("請(qǐng)求參數(shù):%s", requestStr));
                      String[] split = requestStr.split("\r\n");
                      System.out.println("end");
                      response.write("hello syskeCat");
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }

          我把不一樣的地方單獨(dú)提出來(lái):

          這是原來(lái)的寫(xiě)法:

          while ((read = request.getInputStream().read(bytes)) != -1) {
                          byteArrayOutputStream.write(bytes);
                      }

          修改之后:

           BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()));
                      while ((readLine = bufferedReader.readLine()) != null) {
                          if(readLine.length() == 0){
                              break;
                          }
                      }

          其實(shí),寫(xiě)這段代碼就是為了拿到請(qǐng)求頭和請(qǐng)求參數(shù):

          {Cookie= NMTID=00O3GJZgJXpkp8vI0cpmNRliUnGvYkAAAF4sPsi2w, Accept= text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9, Connection= keep-alive, User-Agent= Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36, Sec-Fetch-Site= cross-site, Sec-Fetch-Dest= document, Host= localhost:8080, Accept-Encoding= gzip, deflate, br, Sec-Fetch-Mode= navigate, sec-ch-ua= " Not A;Brand";v="99""Chromium";v="90""Google Chrome";v="90", sec-ch-ua-mobile= ?0, Cache-Control= max-age=0, Upgrade-Insecure-Requests= 1, Sec-Fetch-User= ?1, Accept-Language= zh-CN,zh;q=0.9}

          直接刪除掉while循環(huán)也行,但是也就拿不到完整的請(qǐng)求信息了。而且經(jīng)過(guò)我的實(shí)驗(yàn),如果把空字符判斷那塊拿掉,就又會(huì)出現(xiàn)昨天的情況了。

          項(xiàng)目已建好

          昨天立的flag,今天已經(jīng)把倉(cāng)庫(kù)建好了,寫(xiě)了一些簡(jiǎn)單的代碼,以后就是慢慢添磚添瓦了。我們先來(lái)看看,現(xiàn)在是什么進(jìn)展。

          項(xiàng)目結(jié)構(gòu)

          創(chuàng)建了一個(gè)maven項(xiàng)目,目前只實(shí)現(xiàn)了簡(jiǎn)單的RequestResponse,可以實(shí)現(xiàn)簡(jiǎn)單的請(qǐng)求,但是還不能根據(jù)不同的請(qǐng)求返回對(duì)應(yīng)的結(jié)果,這是下一步的工作。

          關(guān)于這個(gè)項(xiàng)目,初步的計(jì)劃是,后面會(huì)逐步實(shí)現(xiàn)Springboot的一些簡(jiǎn)單功能,最后希望能通過(guò)這個(gè)項(xiàng)目,能夠更深入地了解springboot,了解web服務(wù)器。目前是基于傳統(tǒng)的socket實(shí)現(xiàn)的,后面想以NIO的方式再寫(xiě)一遍,大概率會(huì)用Netty

          服務(wù)器入口

          這里啟用了一個(gè)線(xiàn)程池來(lái)處理客戶(hù)端的請(qǐng)求

          public class SyskeBootServerApplication {
              private static final Logger logger = LoggerFactory.getLogger(SyskeBootServerApplication.class);
              private static final int SERVER_PORT = 8080;
              private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(51010, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

              public static void main(String[] args) {
                  start();
              }

              /**
               * 啟動(dòng)服務(wù)器
               * @throws Exception
               */

              public static void start() {
                  try (ServerSocket serverSocket = new ServerSocket(SERVER_PORT) ) {
                      Socket accept = null;
                      logger.info("SyskeCatServer is starting……, port: {}", SERVER_PORT);
                      while ((accept = serverSocket.accept()) != null){
                          threadPoolExecutor.execute(new SyskeRequestHandler(accept));
                      }
                  } catch (Exception e) {
                      logger.error("服務(wù)器后端異常");
                  }
              }
          }

          請(qǐng)求處理線(xiàn)程

          這里的核心在run方法,也就是在這里處理客戶(hù)端的請(qǐng)求,后期要著重實(shí)現(xiàn)doDispatcher()方法,實(shí)現(xiàn)請(qǐng)求的分發(fā)和響應(yīng)。在SyskeRequestHandler被實(shí)例化的時(shí)候,會(huì)根據(jù)客戶(hù)端socket構(gòu)建requstresponse

          public class SyskeRequestHandler implements Runnable {
              private final Logger logger = LoggerFactory.getLogger(SyskeRequestHandler.class);
              private Socket socket;
              private SyskeRequest syskeRequest;
              private SyskeResponse syskeResponse;

              public SyskeRequestHandler(Socket socket) throws IOException{
                  this.socket = socket;
                  init();
              }

              private void init() throws IOException{
                  this.syskeRequest = new SyskeRequest(socket.getInputStream());
                  this.syskeResponse = new SyskeResponse(socket.getOutputStream());
              }

              @Override
              public void run() {
                  try {
                     doDispatcher();
                  } catch (Exception e) {
                      logger.error("系統(tǒng)錯(cuò)誤:", e);
                  }
              }

              /**
               * 請(qǐng)求分發(fā)處理
               * @throws Exception
               */

              public void doDispatcher() throws Exception{
                  logger.info("請(qǐng)求頭信息:{}", syskeRequest.getHeader());
                  logger.info("請(qǐng)求信息:{}", syskeRequest.getRequestAttributeMap());
                  syskeResponse.write(String.format("hello syskeCat, dateTime:%d", System.currentTimeMillis()));
                  socket.close();
              }
          }

          請(qǐng)求封裝

          除了獲取inputStream,還有獲取請(qǐng)求參數(shù)和請(qǐng)求頭的封裝。后面還要繼續(xù)完善請(qǐng)求頭這一塊,實(shí)現(xiàn)獲取請(qǐng)求地址和具體參數(shù)的需求。

          public class SyskeRequest implements Request {
              /**
               * 輸入流
               */

              private InputStream inputStream;
              /**
               * 請(qǐng)求參數(shù)
               */

              private Map<String, String> requestAttributeMap;

              private String header;

              public SyskeRequest(InputStream inputStream) throws IOException{
                  this.inputStream = inputStream;
                  initRequest();
              }

              @Override
              public InputStream getInputStream() {
                  return inputStream;
              }

              @Override
              public Map<String, String> getRequestAttributeMap() throws IOException{
                  if (requestAttributeMap != null) {
                      return requestAttributeMap;
                  }
                  initRequest();
                  return requestAttributeMap;
              }

              /**
               * 初始化請(qǐng)求
               *
               * @throws IOException
               */

              private void initRequest() throws IOException {
                  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                  header = bufferedReader.readLine();
                  Map<String, String> attributeMap = Maps.newHashMap();
                  String readLine = null;
                  while ((readLine = bufferedReader.readLine()) != null) {
                      if(readLine.length()==0) {
                          break;
                      }
                      if (readLine.contains(":")) {
                          String[] split = readLine.split(":"2);
                          attributeMap.put(split[0], split[1]);
                      }
                  }
                  requestAttributeMap = attributeMap;
              }

              public String getHeader() {
                  return header;
              }
          }

          響應(yīng)封裝

          現(xiàn)在的響應(yīng)信息太單一了,不論前端發(fā)送啥請(qǐng)求,后端始終響應(yīng)的是html,這塊也有再優(yōu)化。下一步就是要實(shí)現(xiàn)根據(jù)請(qǐng)求頭,響應(yīng)對(duì)應(yīng)的數(shù)據(jù)信息。

          public class SyskeResponse implements Response {
              private OutputStream outputStream;

              public SyskeResponse(OutputStream outputStream) {
                  this.outputStream = outputStream;
              }

              @Override
              public OutputStream getOutputStream() {
                  return outputStream;
              }

              //將文本轉(zhuǎn)換為字節(jié)流
              public void write(String content) throws IOException {
                  StringBuffer httpResponse = new StringBuffer();
                  // 按照HTTP響應(yīng)報(bào)文的格式寫(xiě)入
                  httpResponse.append("HTTP/1.1 200 OK\n").append("Content-Type:text/html\n").append("\r\n")
                      .append("<html><head><link rel=\"icon\" href=\"data:;base64,=\"></head><body>").append(content)
                      .append("</body></html>");
                  // 將文本轉(zhuǎn)為字節(jié)流
                  outputStream.write(httpResponse.toString().getBytes());
                  outputStream.flush();
                  outputStream.close();
              }
          }

          總結(jié)

          flag立好了,項(xiàng)目也建起來(lái),后面就是實(shí)現(xiàn)自己的想法了。說(shuō)實(shí)話(huà),我現(xiàn)在還是挺期待的,感覺(jué)這是個(gè)很有意思的事情。可能看文章的小伙伴不一定能get到任何點(diǎn),但對(duì)我來(lái)說(shuō)真的是顛覆性的,昨天我也說(shuō)了,今天依然有這樣的感覺(jué)。以前,頂多是寫(xiě)寫(xiě)前端頁(yè)面,寫(xiě)寫(xiě)后端接口,但是這個(gè)請(qǐng)求如何從前端到后端的,就是特別謎,也從來(lái)沒(méi)想明白,但是昨天一下就醍醐灌頂了,感覺(jué)這一道大門(mén)終于被打通了,這感覺(jué)有一種發(fā)自心底的愉悅和興奮,我甚至有種想馬上把其他功能需求都實(shí)現(xiàn)的沖動(dòng)。

          下面是項(xiàng)目的開(kāi)源倉(cāng)庫(kù),有興趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推薦你自己動(dòng)個(gè)手,自己寫(xiě)一下,真的感覺(jué)不錯(cuò):

          https://github.com/Syske/syske-boot
          - END -


          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色一级一级直播间 | 操嫩逼| 九九热视频精品在线 | 黄片伊人 | 成人精品999 |