サーバー、クライアントの統合

機能の見直しと統合

待ち受けるサーバーは、アクセスがあるとソケットをそのままKitayo06に渡します。

Kitayo06はそのソケットを使ってストリームを得て相手からメッセージを読み、表示をしたらソケットを閉じます。

Kitayo06に用意された返信ボタンによりClient06が起動します。Client06は返信相手のホスト名だけを受け継ぎます。返信文を入力してボタンをクリックした後に改めて返信先と接続を作って送信します。

またClient06はServer06からも起動されますが、この時はホスト名は起動してから入力されるようにします。

Server06
受信待機と送信ボタンの受付
クライアントから
のアクセス
ボタンのクリック
Kitayo06
受信と表示
ボタンの
クリック
Client06
送信のみ

使う時には、Server06からスタートします。今の所Client06は個別に起動できません。

いままでサーバーを起動したままクライアントを起動して自分のホストで動作テストをしていましたが、サーバーを2つ同時に立てられませんから(PORTが同じなので)、テストは1つのサーバーからクライアントを起動して自分に送信して行います。

サーバー部分

このサーバーも 10001 ポートで待ちます。このポート番号はここだけで指定します。

プログラム名 Server06.java

/** サーバー、クライアントの統合 */
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class Server06 extends JFrame implements ActionListener {
    ServerSocket mysvsoc;
    Socket mysoc;
    int PORT = 10001;
    JButton sndbttn;
    JButton endbttn;
    public Server06() {
        setTitle("Server06 "+Thread.currentThread().getName());
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        sndbttn = new JButton("送信");
        endbttn = new JButton("終了");
        setLayout(new BorderLayout());
        add(sndbttn, BorderLayout.CENTER);
        add(endbttn, BorderLayout.EAST);
        sndbttn.addActionListener(this);
        endbttn.addActionListener(this);
        pack();
        setVisible(true);
        try {
            mysvsoc = new ServerSocket( PORT );
            while( true ) {
                System.out.println( "受信のため待機中..." );
                Socket mysoc = mysvsoc.accept();  //受信待ち
                String remotehost = mysoc.getInetAddress().getHostName();
                System.out.println("from " + remotehost);
                // 処理をKitayo06に任せます
                new Kitayo06(mysoc);
                Kitayo06 kitayo = new Kitayo06(mysoc);
                kitayo.setLocationRelativeTo(this);
            }
        }
        catch( IOException e ) {
            System.err.println("IO Error");
        }
    }
    public void actionPerformed(ActionEvent ev) {
        if (ev.getSource() == sndbttn) {
            System.out.println("Client06 " + PORT);
            Client06 cl = new Client06( "" , PORT);
            cl.setLocationRelativeTo(this);
        }
        if (ev.getSource() == endbttn) {
            try{
                if (mysoc == null) mysoc = new Socket( "127.0.0.1", PORT );
                mysoc.close();
                mysvsoc.close();
                System.exit(0);
            }
            catch( IOException ex ){
                System.err.println("IO Error in action");
            }
        }
    }
    public static void main( String[] args ) {
         Server06 sv = new  Server06();
    }
}

起動するとこのようなウインドウが開きます。

サーバー06

このサーバーはひとつのホストに一つだけ起動できます。2つ起動するとポートの取り合いになり動作がおかしくなります。

通信相手のホストでも同じサーバーを起動して通信することを想定しています。

受信を委託されるGUIプログラム

プログラム名 Kitayo06.java

/** GUIで受信を知らせる */
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class Kitayo06 extends JFrame implements ActionListener {
    String remotehost;
    Socket mysoc;
    JButton sndbttn;
    int PORT;
    public Kitayo06(Socket soc) {
        mysoc = soc;
        setTitle("Kitayo06 "+Thread.currentThread().getName());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE); //[×]ボタン処理
        JLabel aite = new JLabel("相手機: "+mysoc.getInetAddress().getHostName());
        JLabel rcvmsg = new JLabel("受信文: ");
        sndbttn  = new JButton("返信");
        sndbttn.addActionListener(this);
        PORT       = mysoc.getLocalPort();
        remotehost = mysoc.getInetAddress().getHostName();
        setLayout(new GridLayout(3,1,0,0));
        add(aite);
        add(rcvmsg);
        add(sndbttn);
        Dimension ps = rcvmsg.getPreferredSize();
        ps.width = 224;
        rcvmsg.setPreferredSize(ps);
        try{
            InputStreamReader in 
               = new InputStreamReader(mysoc.getInputStream());
            BufferedReader inb = new BufferedReader(in);
            String line;
            line = inb.readLine();
            rcvmsg.setText("受信文: "+line);
            inb.close();
            in.close();
            mysoc.close();
        }
        catch( IOException e ) {
            System.err.println("IO Error");
        }
        pack();
        setVisible(true);
    }
    public void actionPerformed(ActionEvent ev) {
        if (ev.getSource() == sndbttn) {
            Client06 cl = new Client06( remotehost , PORT);
            cl.setLocationRelativeTo(this);
            dispose();  //自分は消える
        }
    }
}

次のようなウインドウで通信文を示し、返信ボタンを押すと送信クライアントを起動します。

Kitayo06

送信クライアント

プログラム名 Client06.java

/** GUIで送信するクライアント */
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class Client06 extends JFrame implements ActionListener {
    JTextField aite;
    JTextField sndmsg;
    JButton sndbttn;
    Socket mysoc;
    int PORT;
    public Client06(String host,int p) {
        setTitle("Client06 "+Thread.currentThread().getName());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        PORT = p;
        String bttntext = "送信";
        if (host!="") bttntext = "返信";
        aite = new JTextField(host);
        sndmsg   = new JTextField(20);
        sndbttn  = new JButton(bttntext);
        setLayout(new GridLayout(3,1,0,0));
        add(aite);
        add(sndmsg);
        add(sndbttn);
        sndbttn.addActionListener(this);
        pack();
        setVisible(true);
        if (host!="") sndmsg.requestFocusInWindow();
    }
    public void actionPerformed(ActionEvent ev) {
        if (ev.getSource() == sndbttn) {
            try{
                mysoc = new Socket( aite.getText(), PORT );
                System.out.println( aite.getText() + " " + PORT);
                OutputStreamWriter out
                  = new OutputStreamWriter(mysoc.getOutputStream());
                BufferedWriter outb = new BufferedWriter(out);
                String msg = sndmsg.getText();
                outb.write( msg );
                outb.newLine();
                outb.close();
                out.close();
                mysoc.close();
            }
            catch( UnknownHostException ex ) {
                System.err.println( "Host not found" );
            }
            catch( IOException ex ) {
                System.err.println("IO Error in action");
            }
            dispose();
        }
    }
}

Kitayo06から呼び出されると次のようになります。

返信時のClient06

返事の文を書いて返信ボタンを押せば相手と接続して送信し、自らは消えます。

返信文の記入後のClient06

一方、Server06から送信ボタンを押せば、相手のホスト名が空白のままClient06が起動します。

送信ボタンで起動されたClient06

今でどおり、相手のホスト名と通信文を入れて送信すると、自らは消えます。


Javaプログラミング
聖愛中学高等学校
http://www.seiai.ed.jp/
Dec.2008
Nov.2012