sslsocket的服务器端存在eofexception,而确实存在数据

时间:2015-12-12 11:52:07

标签: sockets ssl eofexception

我有这个虚拟程序:

package com.company;

import javax.net.ssl.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.security.*;
import java.security.cert.CertificateException;

class MyClass implements Serializable
{
    private int i,j;

    public MyClass(int i, int j)
    {
        this.i = i;
        this.j = j;
    }

    public int getJ()
    {
        return j;
    }

    public void setJ(int j)
    {
        this.j = j;
    }

    public int getI()
    {
        return i;
    }

    public void setI(int i)
    {
        this.i = i;
    }
}
class SSLContextHelper
{
    static SSLContext createSSLContext(String path) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, KeyManagementException, CertificateException
    {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(path),"DSL2137976".toCharArray());

        // Create key manager
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(keyStore, "DSL2137976".toCharArray());
        KeyManager[] km = keyManagerFactory.getKeyManagers();

        // Create trust manager
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
        trustManagerFactory.init(keyStore);
        TrustManager[] tm = trustManagerFactory.getTrustManagers();

        // Initialize SSLContext
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(km,  tm, new SecureRandom());

        return sslContext;
    }
}
class ServerThread extends Thread
{
    ServerSocket server;
    Socket client;
    ObjectOutputStream out;
    ObjectInputStream in;
    boolean issecure;
    SSLContext sslContext;
    public ServerThread(int port, boolean issecure) throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException
    {
        this.issecure=issecure;
        client=null;
        if(issecure)
        {
            sslContext = SSLContextHelper.createSSLContext("/usr/lib/jvm/java-8-openjdk/jre/lib/security/ssltest");
            SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
            server = sslServerSocketFactory.createServerSocket(port);
            server.setSoTimeout(200);
        }
        else
            server=new ServerSocket(port);
    }

    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                if(client==null)
                {
                    if (issecure)
                    {
                        SSLSocket clientssl = (SSLSocket) server.accept();
                        clientssl.setEnabledCipherSuites(clientssl.getSupportedCipherSuites());
                        clientssl.startHandshake();
                        client = clientssl;
                    }
                    else
                        client = server.accept();

                    in = new ObjectInputStream(client.getInputStream());
                    out = new ObjectOutputStream(client.getOutputStream());
                    client.setSoTimeout(200);
                }
                String[] req = in.readUTF().split("\n");
                out.writeUTF("hello I'm the server");
                out.flush();
                req = in.readUTF().split("\n");
                out.writeUTF("I mean I'll serve you");
                out.flush();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
}
public class Main
{
    public static void main(String... args) throws IOException, ClassNotFoundException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException
    {
        ServerThread serverThread=new ServerThread(14200, true);
        serverThread.setDaemon(true);
        serverThread.start();
        ServerThread mail=new ServerThread(14201, false);
        mail.setDaemon(true);
        mail.start();
        try
        {
            Thread.sleep(5000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        SSLSocket client=(SSLSocket)SSLContextHelper.createSSLContext("/usr/lib/jvm/java-8-openjdk/jre/lib/security/ssltest").getSocketFactory().createSocket();
        client.connect(new InetSocketAddress("localhost",14200),5000);
        Socket mailclient = new Socket();
        mailclient.connect(new InetSocketAddress("localhost", 14201), 5000);
        client.startHandshake();
        client.setSoTimeout(5000);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        ObjectInputStream in = new ObjectInputStream(client.getInputStream());

        out.writeUTF("hello\nhow are you");
        out.flush();
        System.out.println(in.readUTF());
        out.writeUTF("what\nI didn't understand");
        out.flush();
        System.out.println(in.readUTF());
        int i=0;
        while (i<=1)
        {
            try
            {
                try
                {
                    Thread.sleep(10000);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }

                out.writeUTF("hello\nhow are you");
                out.flush();
                System.out.println(in.readUTF());
                out.writeUTF("what\nI didn't understand");
                out.flush();
                System.out.println(in.readUTF());
                i++;
            }
            catch (SocketTimeoutException ignored)
            {

            }
        }
    }
}

它只是我所拥有的真实程序的模拟,客户端的Thread.sleep模拟用户在点击按钮之前与系统进行一些交互(第一次睡眠是模拟用户将登录信息,第二个睡眠是用户打开选项卡,点击链接,回答对话框等)。

不幸的是,在server.accept成功之后(即客户端连接时),我在服务器端获得了EOFException。

我知道当没有数据可以获得此异常时,即使在客户端这两行(while循环之前的第一行)之后也会发生这种情况:

out.writeUTF("hello\nhow are you");
out.flush();

在这两行之后,客户端等待5秒(我放置的超时),在此5秒内服务器保持其EOFException,当超时完成时,客户端获得SocketTimeoutException并退出程序。

原始程序在服务器端获得相同的EOFException,它在我移动到SSLSockets时开始。

那么这里的问题是什么?

修改

我发现当我删除超时(读取超时而不是接受超时)时,它可以完美地工作。

使用超时,将其设置为不同的值会给我带来奇怪的NullPointerExceptions(in为空!!!!!!!!!!)。

我需要超时,因为在我的真实程序中,服务器不会永远等待客户端,它还有其他客户端也可以服务。

为什么超时导致这个?

0 个答案:

没有答案