0

持続的接続を使用した単純なGET要求をサポートする基本的なHTTP/1.1準拠のWebサーバーを作成しようとしました。61行目でSocketException:Connection Resetエラーが発生しています(if(line == null || line.equals( ""))。実行してから、Chromeブラウザーをローカルホストのポート番号に誘導してテストしています。複数の画像を含むページでテストすると、例外が発生する前に1つのリクエストしか処理されていないように見えますが、これはあらゆる種類のソケットプログラミングでの最初の試みであるため、何が問題なのかわかりません。

DataOutputStreamを削除した後に更新されたコードは次のとおりです。

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.StringTokenizer;

public class webserve
{
    public static void main(String[] args) throws Exception
    {
        String rootPath = "~/Documents/MockWebServerDocument/";
        int port = 10000;

        if(rootPath.startsWith("~" + File.separator))
        {
            rootPath = System.getProperty("user.home") + rootPath.substring(1);
        }

        String requestLine="";
        StringTokenizer tokens=null;
        String line, command;
        Date date = new Date();
        String connectionStatus="";


        //Create new server socket listening on specified port number
        ServerSocket serverSocket = new ServerSocket(port);

        while(true)
        {
            //Wait for a client to connect and make a request
            Socket connectionSocket = serverSocket.accept();
            System.out.println("Socket opened");

            //Input stream from client socket
            BufferedReader incomingFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
            //PrintWriter to send header to client socket
            PrintWriter outgoingHeader = new PrintWriter(connectionSocket.getOutputStream(),true);
            //OutputStream to send file data to client socket
            ObjectOutputStream outgoingFile = new ObjectOutputStream(connectionSocket.getOutputStream());
            //Date format for HTTP Header
            SimpleDateFormat HTTPDateFormat = new SimpleDateFormat("EEE MMM d hh:mm:ss zzz yyyy");


            //Create a HashMap to store the request header information
            HashMap<String,String> requestHeader = new HashMap<String,String>();

            while(connectionSocket.isConnected())
            {
                //requestHeader.clear();

                while((line = incomingFromClient.readLine()) != null)
                {
                    if(line.isEmpty())
                    {   
                        break;
                    }
                    //If this is the first line of the request, i.e doesnt contain a colon
                    if(!(line.contains(":")))
                    {
                        requestLine = line;
                        requestHeader.put("Request", requestLine);
                    }
                    else
                    {
                        //Otherwise, find the colon in the line and create a key/value pair for the HashMap
                        int index = line.indexOf(':')+2;
                        String header = line.substring(0,index-1);
                        line = line.substring(index).trim();

                        requestHeader.put(header, line);

                        System.out.println(header + " " + line);
                    }
                }   

                connectionStatus = (String)requestHeader.get("Connection:");
                requestLine = (String)requestHeader.get("Request");

                System.out.println("RequestLine: " + requestLine);

                if(!requestLine.equals("")||!(requestLine.equals(null)))
                {
                    tokens = new StringTokenizer(requestLine);

                    command = tokens.nextToken();
                    String filename = tokens.nextToken();
                    filename = cleanUpFilename(filename);
                    String fullFilepath = rootPath + filename;
                    System.out.println("Full FilePath: " + fullFilepath);

                    File file = new File(fullFilepath);

                    //Get the number of bytes in the file
                    int numOfBytes=(int)file.length();

                    //Open a file input stream using the full file pathname
                    FileInputStream inFile = new FileInputStream(fullFilepath);

                    //Create byte array to hold file contents
                    byte[] fileInBytes = new byte[numOfBytes];

                    inFile.read(fileInBytes,0,numOfBytes);

                    inFile.close();


                    //Write the header to the output stream 
                    outgoingHeader.print("HTTP/1.1 200 OK\r\n");
                    outgoingHeader.print("Date: " + HTTPDateFormat.format(date)+"\r\n");
                    outgoingHeader.print("Server: BC-Server\r\n");
                    outgoingHeader.print("Last-Modified: " + HTTPDateFormat.format(file.lastModified())+"\r\n");
                    outgoingHeader.print("Connection: keep-alive\r\n");
                    outgoingHeader.print("Content-Length: " + numOfBytes);
                    outgoingHeader.print("\r\n\r\n");               

                    //When the header has been printed, write the byte array containing the file
                    //to the output stream
                    outgoingFile.writeObject(fileInBytes);

                    if(!(connectionStatus.equals("keep-alive")))
                    {
                        System.out.println("Closing: " + connectionStatus);
                        outgoingHeader.close();
                        outgoingFile.close();
                        break;
                    }
                    else
                        continue;

                }       

            }

        }
    }

    public static String cleanUpFilename(String filename)
    {
        //If there is a "/" at the start of the filename, then remove it
        if(filename.charAt(0) == '/')
        {
            filename = filename.substring(1);
        }

        //If we are given an absolute URI request, strip all characters
        //before the third "/"
        if(filename.startsWith("http://"));
        {
            try
            {
                URI httpAddress = new URI(filename);

                //Get the path from the supplied absolute URI, that is remove
                //all character before the third "/"
                filename = httpAddress.getPath();

                //Again, we may have to trim this modified address if there is an
                //extra "/" at the start of the filename
                if(filename.charAt(0) == '/')
                {
                    filename = filename.substring(1);
                }
            }
            catch (URISyntaxException e)
            {                   
                e.printStackTrace();
            }
        }

        return filename;
    }

}

これが私のエラートレースです:

Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:185)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:282)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:324)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:176)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:153)
    at java.io.BufferedReader.readLine(BufferedReader.java:316)
    at java.io.BufferedReader.readLine(BufferedReader.java:379)
    at webserve.main(webserve.java:61)

私は完全に途方に暮れているので、どんな助けでも大歓迎です。

4

4 に答える 4

0

複数の出力ストリームを同時に使用することは非常に問題があります。この場合ObjectOutputStream、オブジェクトを書き込もうとしていることが確実であり、すでにヘッダーを書き込んでフラッシュしているまで、を作成しないObjectOutputStreamでください。現在のコードでは、おそらくヘッダーの前に表示されるヘッダーを出力に書き込むためです。クライアントにバーフを引き起こします。

一般に、SocketException: Connection Reset通常は、ピアによって既に閉じられている接続に書き込んだことを意味します。この場合、ピアはクライアントであり、クライアントは Web ブラウザーであるため、ユーザーがページの読み込みを停止した、ブラウジングを停止した、ブラウザーを終了した、タブを閉じたなど、あらゆることを意味します。それはあなたの問題ではありません。ソケットを閉じて、それを忘れてください。

同じ理由で、サーバーは妥当な読み取りタイムアウト (たとえば 10 ~ 30 秒など) を設定し、起動した場合は救済する必要があります。

于 2013-02-27T00:55:03.420 に答える
0

chrome の代わりに telnet、wget、または curl を使用して接続をテストしてみてください。これにより、TCP/IP 接続の両側を制御できるようになります。

あなたのWebクライアントが側から接続を閉じていると思います.そのソケットから再度読み込もうとしています(はい、isConnected()リモートパーティが接続を閉じたときにこのエラーをスローします)。残念ながら、例外をキャッチして適切に処理する以外に、これに対抗する簡単な方法はありません。

これは、同期ソケットでよく発生する問題です。java.nio代わりに、チャネルとセレクターを使用してみてください。

于 2013-02-26T23:09:10.660 に答える
0

サーバーの最も明白な問題は、マルチスレッド化されていないことです。問題の説明を読み直した後、それが根本的な原因のようです。接続ごとに 1 つのスレッドが必要です。の後serverSocket.accept()、connectionSocket を処理する新しいスレッドを作成します。

    while(true)
    {
        //Wait for a client to connect and make a request
        Socket connectionSocket = serverSocket.accept();

        new Thread()
        {
            public void run()
            {
                //Input stream from client socket
                BufferedReader incomingFromClient = ...

                etc

            }
        }.start();
于 2013-02-27T01:38:32.823 に答える
-1

は使用できませんDataOutputStream。Java-Java 通信用です。Writerヘッダーの書き込みを試し、ファイル コンテンツの書き込みには元の OutputStream を試してください。

何が起こっているかというと、ブラウザが無効な応答を見て、接続を閉じます。サーバーはまだクライアントに書き込みを行っていますが、クライアントは接続が切断されているため RST を返します。

于 2013-02-26T23:37:49.067 に答える