socket编程时的发送与接收数据时的问题解析

作者:Mzoro 时间:2022-12-31 03:57:28 

socket 编程时的发送与接收数据时的问题

在编写一个测试方法时,需要用启动一个程序监听一个端口,测试发送的数据是事正常,但是总是出现两个问题,一是 Socked 总是在 OutputSteam.write () 方法之前被关闭,但是没有使用代码调用 Socket 的 Close 方法,另一个是在接收数据时,总是卡在 InputSteam.read () 方法处 (一般发生在前一个 Socket 在写数据时异常中断后再次有新 Socket 连接时),得不到数据,直到发送端关闭 Socket, 下面是代码

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();
               }
           }
       }
   }
}

分析原因

  • 在第 76 行代码调用的方法中 调用的 InputStream.close () 方法,导致了 Socket 也跟着关闭了,不清楚是什么原因引起的,但是去掉 InputStream.close () 确实 OutputStream 可以向请求端改善数据了

  • 在 OutputStream 的问题解决之后,InputStream 的问题也跟着没有了,因为我在测试时使用的是浏览器 http 发起的这个 Socket,所以我猜测是在第一次 Socket 异常中断后浏览器再次触发了重试;;

问题更新

两天后发现新问题: InputStream 在包装成 BufferedReader 整行读取时到 http 请求的最后一行还会继续向下一行读,但是发送端这时已经不发送数据了,造成服务端一直卡在这里等待

问题原因

BufferedReader.readLine () 方法在读取文件只,因为文件最后会是一个 - 1 ,所以可以知道在哪里结束,但网络请求最后没有这个 - 1 所以在读了最后一行后不知道请求数据已经没有更多了,造成一直阻塞

解决思路

http 请求(只讨论 get 与 post 两种方法),get 请求只有请求头,在读取到第一个空行时就可以结束,post 请求有请求体,可以根据请求头中 ContentLength 判断是否读取完

来源:https://my.oschina.net/Mzoro/blog/3144732

标签:socket,发送接受,接收数据
0
投稿

猜你喜欢

  • Java实现发红包功能

    2023-12-09 10:33:03
  • Android TextView控件文字添加下划线的实现方法

    2022-03-11 06:01:43
  • java中@SuppressWarnings注解用法详解

    2023-09-20 23:11:40
  • Servlet3.0实现文件上传的方法

    2023-08-15 00:52:44
  • 解析SpringSecurity自定义登录验证成功与失败的结果处理问题

    2021-09-01 16:42:59
  • 详解Java设计模式之备忘录模式的使用

    2023-09-10 09:38:32
  • android底部弹出iOS7风格对话选项框(QQ对话框)--第三方开源之IOS_Dialog_Library

    2023-02-18 17:42:44
  • intellij idea14打包apk文件和查看sha1值

    2022-05-25 13:18:37
  • SpringBoot切面拦截@PathVariable参数及抛出异常的全局处理方式

    2023-05-27 13:59:52
  • Android 7.0系统webview 显示https页面空白处理方法

    2021-10-22 09:36:49
  • Android Dialog对话框实例代码讲解

    2021-12-18 06:34:50
  • C# 静态构造函数使用总结

    2022-04-28 16:27:35
  • 详解Java ScheduledThreadPoolExecutor的踩坑与解决方法

    2022-11-25 17:34:17
  • 以一个着色游戏展开讲解Android中区域图像填色的方法

    2023-02-04 10:02:51
  • C# WinForm制作登录界面的实现步骤

    2022-09-06 18:32:54
  • C# 多窗口委托通信的实现

    2023-01-22 02:21:31
  • wpf将表中数据显示到datagrid示例

    2023-06-13 04:14:06
  • Springboot集成graylog及配置过程解析

    2023-06-18 17:15:02
  • C#字符串加密解密方法实例

    2022-01-11 23:30:14
  • java 中二分法查找的应用实例

    2021-10-18 08:43:33
  • asp之家 软件编程 m.aspxhome.com