Java 网络编程时序问题

本文探讨了Java网络编程时遇到的问题,强调了URLConnection操作的严格时序。详细步骤包括创建URL,获取URLConnection,开启输出功能,打开连接,写入数据,关闭流等。特别指出,必须先关闭输出流再获取输入流,否则数据无法传输到服务器。源码分析揭示了URLConnection通过反射获取具体实现,以及OutputStream和InputStream的工作原理。
摘要由CSDN通过智能技术生成

起因

这两天在做有关网络的编程练习,发现网路已经联通,但是服务器端接收不到数据,排查了好久,功能一个个测试了之后,服务端的代码没有问题了.焦点落在客户端.最后通过查看源代码,发现原来是要按照严格的时序来进行操作.如下:
1. 创建URL实例;
2. 获取URLConnection 实例,如果单纯的只是从服务器读数据,直接从URL实例读就可以了;
3. setDoOutput 设置输出功能,这样就相当于POST 方式;
4. 打开链接服务器的一个连接,这一步其实可以省略;
5. getOutputStream()获取输出流,此方法会隐式打开与服务端的连接;
6. write()将数据写到输出流;
7. close()关闭输出流;
8. getOutputStream()获取输入流;
9. read()从输入流读取服务端返回数据;
10. close()关闭输入流.

这其中,第8步 必须 在第7步 之后,否则数据是无法传输到服务端的.因为在使用getOutputStream() 的同时,会将getOutputStream() 获取的输出流关闭,这就造成实际上并没有把数据写出去,因此服务器端自然无法接收到数据.

好了,TL;DR,如果这是为了知道原因,到这一步也就完了,下面的就没必要看了.

下面是源码分析:

URLConnection#openConnection()

位置:java/net/URL.java

public URLConnection openConnection() throws java.io.IOException {
    return handler.openConnection(this);
}

//其中 handler 为
URLStreamHandler handler = handlers.get(protocol);
//Handlers 为HashTable的实例
static Hashtable<String,URLStreamHandler> handlers = new Hashtable<>();
//那么, 既然是HashTable , 有get 就会有put ,我们看看put 在哪?通过寻找发现,handlers.put() 仅仅有一处:在static URLStreamHandler getURLStreamHandler(String protocol)中

static URLStreamHandler getURLStreamHandler(String protocol) {

        URLStreamHandler handler = handlers.get(protocol);
        if (handler == null) {

            boolean checkedWithFactory = false;

            // Use the factory (if any)
            if (factory != null) {
                handler = factory.createURLStreamHandler(protocol);
                checkedWithFactory = true;
            }

            // Try java protocol handler
            if (handler == null) {
                String packagePrefixList = null;

                packagePrefixList
                    = java.security.AccessController.doPrivileged(
                    new sun.security.action.GetPropertyAction(
                        protocolPathProp,""));
                if (packagePrefixList != "") {
                    packagePrefixList += "|";
                }

                // REMIND: decide whether to allow the "null" class prefix
                // or not.
                packagePrefixList += "sun.net.www.protocol";

                StringTokenizer packagePrefixIter =
                    new StringTokenizer(packagePrefixList, "|");

                while (handler == null &&
                       packagePrefixIter.hasMoreTokens()) {

                    String packagePrefix =
                      packagePrefixIter.nextToken().trim();
                      //通过反射获取实际的 URLConnection 的子类
                        String clsName = packagePrefix + "." + protocol +
                          ".Handler";
                        Class<?> cls = null;
                        try {
                            cls = Class.forName(clsName);
                        } catch (ClassNo
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值