質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Java

    13500questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

javaソケットプログラミング

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 1,015

kentsu141

score 49

以下のコードでproxyサーバの基礎としてTCP通信の実装とそのクライアントを作成しようとしているのですが
tcp通信を行うサーバ側のコードの58行目でnullpointerのエラーが
クライアント側に関しては実行してもコンソールに何も表示されません

また完成形の動作として
ローカルhttpプロキシサーバとして動作させ、URLを受け取ったあと対象のwebサーバにhttpリクエストを送信、httpレスポンスを受け取り
クライアントに送り返すというものを想定して作成します

そのためサーバ側では文字列(URL)を受け取るまで接続可能な状態にしておきたいです。

上記の機能を実装するにはどのような点を改善すればいいのでしょうか?


package main;

import java.net.*;
import java.io.*;

/**
 * @author kentsu-141
 * httpProxyServer本体のクラスファイル
 * */

public class HttpProxyServer{
    
    
    private HttpProxyServerThread proxyThread;
    
    HttpProxyServer(){
        proxyThread = new HttpProxyServerThread();
        proxyThread.start();
    }
    
    public static void main(String[] args){
        
        HttpProxyServer httpProxy = new HttpProxyServer();
    }

}

/**
 * httpプロキシサーバのスレッドに関するクラス
 * */

class HttpProxyServerThread extends Thread{
    
    //接続待ちするポート番号,接続待ちに使用するソケット,プロキシサーバ本体のソケット
    private final int port = 8080;
    private Socket accessSocket;
    private ServerSocket ProxyServerSocket;
    
    private boolean flag = true;
    
    @Override
    public void run(){
        
        try{
            
            ProxyServerSocket = new ServerSocket(port);
            System.out.println("accept port:"+port);
            System.out.println("---proxy server start---");
            
            accessSocket = ProxyServerSocket.accept();
            
            BufferedReader in = new BufferedReader(new InputStreamReader(accessSocket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(accessSocket.getOutputStream()));
            
            String url;
            String webState = "";
            //送られてきた内容を取得、返し
            while(!(url = in.readLine()).equals("") || (url = in.readLine()).equals(null)){
                
                System.out.println("receive:"+url);
                
                //送られてきたwebサイト情報をクライアントに返す
                out.write(webState);
                out.flush();
                
            }
            
        }catch(Exception err){
            err.printStackTrace();
        }finally{
            try{
                //使用したソケットをクローズする
                accessSocket.close();
                ProxyServerSocket.close();
            }catch(Exception err){
                err.printStackTrace();
            }
        }
    }
    
}

/**
 * httpConnectionに関するクラス
 * */

class httpConnection{
    
    
    
}

package main;

import java.net.*;
import java.io.*;

public class MainClient {
    
    private static final int usePort = 8080;
    private static final String useHost = "localhost";
    private Socket clientSocket;
    
    public static void main(String... args){
        if(args.length < 1){
            System.exit(-1);
        }
        
        try(Socket socket = new Socket(useHost,usePort)){
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            
            
            BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("sendURL:");
            String send = input.readLine();
            
            out.write(send);
            out.flush();
            
            String result;
            
            result = in.readLine();
            
            System.out.println("result:"+result);
            
            
        }catch(Exception err){
            
        }
        
        
    }
    
    public void connectProxyServer(){
        
        
        
    }

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

元のコードの間違いが理解できれば、この問題は解決するでしょう。
while()の中身ですが、
!(url = in.readLine()).equals("")
このコードは入力ストリームから一行読出して、それが空行でないことを確認しています。しかし、もしこの時に終わりまで読み込んでいたらnullが返ってきてしまい、nullに対してequals()を呼び出すのでエラーになります。
なおかつ、「||」でつなげられているため、次のこの部分が必ず呼ばれてしまいます。
(url = in.readLine()).equals(null)
ここではまたもや一行読出しており、合計2行読み込まれています。そして、その値が「nullである」ことを確認してます。ここは二重に間違っています。
nullの場合はequals()の呼び出しが必ずエラーになります。つまり、nullかどうかにequals()を使うのはナンセンスです。
nullでなければ結果はfalseで、「nullで有る限りループを続ける」の意味になっています。

空行("")が送られてこないことが確実なら、このwhileの部分はこれだけで十分です。
while((url = in.readLine()) != null){
この書き方はファイル読み込みなどでも頻繁に使うコード断片です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

whileの条件式で必ず2行ずつ読み込んでますが、これでは奇数行だった場合に後の方がnullポインタになります。まずurlに読み込ませて、これを評価するように修正すべきでは。
            url = in.readLine();
            while(url != null && !url.equals("")){
                
                System.out.println("receive:"+url);
                
                //送られてきたwebサイト情報をクライアントに返す
                out.write(webState);
                out.flush();
                
                url = in.readLine();
            }
この手の場合は、まずnullからチェックするのがセオリーです。
あと、空行は送られてこないと言う仕様で間違いないですか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/02/22 15:57

    はい空白は送られてこないことを前提に作っています

    キャンセル

+1

ご質問のポイントとは少しずれますが、いくつか気になったことを書きます。


catchの場合にもエラーの情報をクライアントに返すようにしておくと良いと思います。
現時点では完全なHTTP通信まで作らないとしても、簡易的なレスポンス情報として例えば、最初の1行は整数を返して、正の整数ならレスポンスのバイト数、負の整数ならエラーメッセージのバイト数を設定しておくようにします。2行目以降はそのバイト数を読み込むようにします。


あと、スレッドの処理を追加するなら、リスナーをメインスレッド、ワーカーをサブスレッドにして、リスナーは受け取ったらすぐにワーカーに受信ソケットを渡して次の待機に入るようにするほうがよりサーバーらしい動作になります。
大量のアクセスを受ける想定でなければ、サブスレッドは無くても良いんじゃないかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Javaでcsvファイルを編集して出力したい

    タイトル通りですが、コーディングしたのですが、なかなか思い通りに行きません。 問題はこちらです。 下記部分をInput.csvとしてファイルを作成し、 英語の得点を全て+10した

  • 受付中

    JUnitテストについて質問です

    今、以下のクラスについてのJUnitテストを書こうとしているのですが、どういう風にテストメソッドを設定すればよいか分かりません。 import java.io.BufferedR

  • 解決済

    java でしりとり

    java でひとりで遊べるしりとりを作りたいと思っているのですが コンピューターが自動的に返事してくれるようなものを作りたいと考えているのですが なにか参考になるようなサイトがあれ

  • 解決済

    listの参照があいまいです

    この前質問させていただいたときに回答して下さった方のソースをコンパイルしてみたんですが(いらないimportまで書いてると思いますが気にしないでください)listの参照があいまいで

  • 受付中

    private static final フィールドの値を変更してテストしたい

    例えば、実行時にstatic finalフィールドの値が決まるようなWordクラスがあったとします。 WordTestでは2つのインスタンスを生成しますが、w2の生成時には既に初

  • 解決済

    メソッドを使ったプログラムを作りたいです

    前提・実現したいこと Javaのメソッドを使う問題を解いています。 問題は以下の通りです。 ↓ 好物を元に動物の名前と特徴を出力するプログラム  ・作成するクラス 

  • 受付中

    ファイルのコピー

    Java開発初心者です。 ファイルのコピーを行うコードを書いています。 FileInputStreamとFileOutputStreamを使って、 コピーしたいファイ

  • 解決済

    会員情報システム(Java)での作り方

    javaで会員情報システムのようなものを作りたいです。 下記の実行結果(コマンドプロンプトで実行)になるような、登録プログラムを作成したいのですが、作成方法が分かりませんので、教

同じタグがついた質問を見る

  • Java

    13500questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。