Java,InputStream,Socket阻塞.(关于HTTP请求的IO问题自我总结)

简介: Java,InputStream,Socket阻塞.(关于HTTP请求的IO问题自我总结)

前言:


由于项目的需求,需要实现以下流程:


1. Client发送HTTP请求到Server.


2. Server接收HTTP请求并显示出请求的内容(包含请求的头及Content的内容)


服务端实现:


Server部分代码如下:


import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
/**
 *  
 * @author Anson
 */
public class Server{
    private String ServerIP;
    private int ServerPort;
    private boolean shutdown = false;
    /**
       * Init Server
       */
    public void init(){
        ServerIP = "192.168.0.1";
        ServerPort = 8082;
    }
    /**
     *  
     */
    public void await(){
        ServerSocket serverSocket = null;
        try {
            serverSocket =  new ServerSocket(ServerPort, 1, InetAddress.getByName(ServerIP));
        }catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        // Loop waiting for a request
        while(!shutdown){
            Socket          socket  = null;
            InputStream     input   = null;
            OutputStream    output  = null;
            try {
                socket  = serverSocket.accept();
                input   = socket.getInputStream();
                output  = socket.getOutputStream();
                this.parse(input);
                 // Close the socket
                socket.close();
            }catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
    }
    public void parse(InputStream input) {
        // Read a set of characters from the socket
        StringBuffer request = new StringBuffer(2048);
        int i;
        byte[] buffer = new byte[2048];
        try {
            i = input.read(buffer);
        }catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }
        for (int j=0; j<i; j++) {
            request.append((char) buffer[j]);
        }
        System.out.println(request.toString());
    }
}

再编写StartServer.java


....
public class StartServer{
    public static void main(String[] args){
        Server server = new Server();
        server.init();
        server.await();
        .....
    }
}

跟着,客户端的代码做法有很多,


可以用最简单的Socket,


也可以用HttpClient,


或其它客户端如:OC


具体做法,网上有很多,在此不细述.


我用的是OC,


当然,可能有些做法,并不会出现这样的问题,


毕竟,我,并非一个高手.


我只描述我遇到的状况,


成功实现的可以忽略.


问题描述:


当客户端发送的数据量小于一定长度(如2048byte)的时候,


Server运行正常,即可以正常打印出请求的内容.


如:GET index HTTP/1.1


   ........


请求的头加上一些Content.


但当数据量大于2048的时候,奇怪的问题出现了.


有时会发现数据读不全.


例如,在请求的头下面,Content的内容是一串XML的String:


<?xml version="1.0" encoding="UTF-8" ?><label1>label1></label1>......


当请求的头加上XML的String的总长度超过2048,那么,可能出现在情况就是超过的部分丢失.


解决办法:


可能已经有人发觉,在上面的Server里面的parse(InputStream input)这里的处理有问题.


因为很大程度上这个2048在StringBuffer的定义时就出现了.


所以,第一个失败的尝试便是修改2048.


第一次变成10*2048


跟着是100*2048....


最后是1000*2048....


但结果可以发现:数据量的限制并不会随着这个数值的成倍增长而以相同倍数增长.有时可能是为了增加一倍,


而这个数值必需增加20倍.....


最后发现这个办法不可能,


于是,改变了读取的办法.


用了其它的如StreamBufferReader还有很多其它的来尝试读取,


结果却令人失望,


甚至于这时候出现了阻塞.


即,在读取的过停中,卡住了,


直到等到客户端的请求超时,才跳出来.


所以这些方法也失败了.


具体的情况也记不大清楚了.


之后的另一个方法:


String request = "";
           //如果不先读一次,那么下面的input.available()有可能是0值.
           char firstbyte = (char) input.read();
            request += firstbyte;
            int ava = 0;
            while ((ava = input.available()) > 0) {
                try {
                    // 在此睡眠0.1秒,很重要
                    Thread.sleep(100);
                } catch (Exception t) {
                    t.printStackTrace();
                }
                byte[] bufferedbyte = new byte[ava];
                input.read(bufferedbyte, 0, ava);
                request += new String(bufferedbyte, "UTF-8");
            }


这是一个成功解决的方法,


之所以要睡眠0.1秒,等待高手帮忙解答,


这也许跟网络有关系,


当然,数据量越大,睡眠的时应该有小小的加长.(缓冲时间).


虽然以上的做法成功实现了,但对于服务器来说,效率是个问题,所以只能寻找更优的办法.



第三次更改:



int readInt = 0;
      int availableCount = 0;
      char requestHead = (char)(input.read());
      request += requestHead;
//取得请求的类型是PUT或GET
      if(requestHead == 'P') {//主要是PUT的方法里面会带有XML.
        while((readInt=input.read()) != -1) {
        request += (char)readInt;
        if(request.indexOf("</endXML>") != -1){
          break;
        }
        }
        System.out.println("this is put\n" +request);
      } else if(requestHead=='G') {//GET的方法内容比较少,用以下的方法可以正常实现
        while((availableCount=input.available()) > 0){
        byte[] requestbuffer = new byte[availableCount];
        input.read(requestbuffer);
        request += new String(requestbuffer, "UTF-8");
        }


*代码并不完整.


这种做法,我在读取XML的String里加上了一个结束的判断即对"</endXML>"的判断(当然,这是在知道Content内容的基础上这种做法才可行).


虽然暂时解决了问题,但仍然不能完美解决存在的问题.


第四次更改:


这也是最后一次更改,办法是:


在PUT的请求里面,先取得一个Content-Length:的请求头的值length.


这里的大小就是Content的长度.


在这个基础上,


先判断是否开始读取Content:


if(requestString.indexOf("\r\n\r\n") != -1)
.....



之后再循环读取:


for(int i=0; i < length; i++){
        requestString += (char)input.read();
    }


当读完length后,跳出循环,


并跳出读取input的读取.


.......


问题在此告一段落.



若有哪位朋友懂得其中原理,恳请告知,


知其然而不知其所以然,心里不免有个结.


结言:


以上做法,仅供参考.


若有错误,请不啬指出.



欢迎转载


转载进请注明转自:http://ansonlai.iteye.com


相关文章
|
4月前
|
存储 人工智能 Java
java之通过Http下载文件
本文介绍了使用Java实现通过文件链接下载文件到本地的方法,主要涉及URL、HttpURLConnection及输入输出流的操作。
273 0
|
6月前
|
JSON 安全 网络协议
HTTP/HTTPS协议(请求响应模型、状态码)
本文简要介绍了HTTP与HTTPS协议的基础知识。HTTP是一种无状态的超文本传输协议,基于TCP/IP,常用80端口,通过请求-响应模型实现客户端与服务器间的通信;HTTPS为HTTP的安全版本,基于SSL/TLS加密技术,使用443端口,确保数据传输的安全性。文中还详细描述了HTTP请求方法(如GET、POST)、请求与响应头字段、状态码分类及意义,并对比了两者在请求-响应模型中的安全性差异。
579 20
|
12月前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
565 3
|
Java Maven Windows
使用Java创建集成JACOB的HTTP服务
本文介绍了如何在Java中创建一个集成JACOB的HTTP服务,使Java应用能够调用Windows的COM组件。文章详细讲解了环境配置、动态加载JACOB DLL、创建HTTP服务器、实现IP白名单及处理HTTP请求的具体步骤,帮助读者实现Java应用与Windows系统的交互。作者拥有23年编程经验,文章来源于稀土掘金。著作权归作者所有,商业转载需授权。
299 2
使用Java创建集成JACOB的HTTP服务
|
11月前
|
JSON Java 数据格式
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
234 25
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
|
10月前
|
Java 物联网 定位技术
Java socket获取gps定位
通过Java Socket编程获取GPS定位信息可以实现实时的地理位置跟踪。本文介绍了如何搭建Socket服务器、解析GPS数据以及实现客户端发送GPS数据的流程。希望这篇文章能为开发者提供清晰的指导,帮助构建高效的GPS定位系统。
268 7
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
173 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
12月前
|
安全 API 网络安全
使用OkHttp进行HTTPS请求的Kotlin实现
使用OkHttp进行HTTPS请求的Kotlin实现
|
网络协议 安全 Java
Java Socket原理
Java Socket原理是指在Java中通过Socket实现的网络通信的基础理论与机制。Socket是网络中不同设备间通信的一种标准方式,它允许应用程序之间通过TCP/IP等协议进行数据交换。在Java中,利用Socket编程可以方便地创建客户端与服务器端应用,实现跨网络的数据传输功能,是互联网软件开发中的重要技术之一。它支持多种通信模式,如可靠的流式套接字(TCP)和数据报式套接字(UDP)。
218 10
|
JSON Java fastjson
Java Http 接口对接太繁琐?试试 UniHttp 框架吧
UniHttp 是一个声明式的 HTTP 接口对接框架,旨在简化第三方 HTTP 接口的调用过程。通过注解配置,开发者可以像调用本地方法一样发起 HTTP 请求,无需关注请求的构建和响应处理细节。框架支持多种请求方式和参数类型,提供灵活的生命周期钩子以满足复杂的对接需求,适用于企业级项目的快速开发和维护。GitHub 地址:[UniAPI](https://github.com/burukeYou/UniAPI)。