TCP/IP Server程式

來源:cww

 

主要是java.net.ServerSocket java.net.Socket 物件的應用,前者負責建立一個Listen Port

接收想取得連線的Client,而一旦Client連進來了,便產生一個Socket物件,負責和Client做往後

的所有Talking

常用的ServerSocket Constructor主要有

ServerSocket(int PortNo)  ServerSocket(int PortNo, int MaxQueue)

PortNo指的是Listen Port,而MaxQueue是最多的同時連線

 

建立起ServerSocket物件後,便得執行其accept()的方法,執行accept()後,ThreadHold住,直到

Client連進來,進而傳回一個Socket物件。我們可以想像Client/ServerTalking就是Client/Server

Socket物件的資料傳送(Client/Server各有一個Socket物件),而Socket物件如何把Data傳到另一個

Socket物件上呢,那需先用 socket物件的 getOutputStream()以取得OutputStream物件,之後便可以

運用File 的一系列物件與方法把Data傳出去,相同的,另一端要以 getInputStream() 取得一InputStream

物件,再用File 的一系列物件與方法把Data讀出來。

Client/ServerTalking的這個Socket與原先ListenServerSocket兩者並沒有什麼關係了,Socket

以另外的PortNoTalking,而PortNo會是多少呢,這是由系統給定的,所以每次不見得相同,我們可以用

getPort()取得TalkingPortNo

 

以下程式是 一個JavaApplication,會產生一個 Frame,所有與Client的訊息傳送,都會顯示在TextField

之中。在這裡有兩個考量,為何以下程式片斷中,要用New 一個myThread來與Client Talking,而不是用

目前Thread來做就好?別忘了,目前的Threads1=serv.accept()這一行會Hold住以等待Client的連線要

求,所以只好Create另一個Thread來與Client Talking。另外,為什麼Listen的程式也要用一個獨立的Thread

來做,難道把以下的程式放到frame1中不行嗎?其實也可以這樣做,不過,本程式希望Client的訊息只要

傳過來,便立即在FrameTextField 中顯示,如果下面的這段程式寫在frame1中,那代表會用main thread

執行s1=serv.accept(),而main Thread便Hold住了,而其他的Thread雖改變了TextField中的值,但是本程

式負責顯示TextFieldmain ThreadHold住,所以不會顯示,而會等到Listen的動作不再時,才有機會來

顯示TestField中的內容。

 

      while (true) {

           //等候Client的連線 

           s1=serv.accept();

           //有人連進來了,開啟另一個Thread,並以Socket s1 Talking

           myThread mt=new myThread(s1, frame, serv);

           frame.socketal.add(mt); //記錄有一個ThreadClient在做Talking

       }

 

------------------- Listen.java --------------------------------------------------------------

package mysock;

import java.net.*;

import java.io.*;

 

public class Listen extends Thread {

  private Frame1 frame;

  private ServerSocket serv;

  public Listen(Frame1 frame) {

    super("MyListen");

    this.frame = frame;

    start();

  }

  public void run() {

 

   try {

       //PortNo 5051上做Listen,且最多同時4Client進來

       serv=new ServerSocket(5051,4);

    }catch (Exception se){

      System.out.println("Init ServerSocker Error!!");

    }

    Socket s1=null;

    try {

       while (true) {

           //等候Client的連線 

           s1=serv.accept();

           //有人連進來了,開啟另一個Thread,並以Socket s1 Talking

           myThread mt=new myThread(s1, frame, serv);

           frame.socketal.add(mt); //記錄有一個ThreadClient在做Talking

       }

   }catch (Exception ee){

      //如果myThreadserv.close(),會使serv.accept()產生Exception

      System.out.println("Server Socket Closed by Exception" +

            ee.getMessage() );

      frame.jTextArea1.setText(frame.jTextArea1.getText()+

            "Server Socket Closed by Exception" +

             ee.getMessage() );

   }

 

  }

}

------------------- myThread.java --------------------------------------------------------------

package mysock;

 

import java.net.*;

import java.io.*;

import javax.swing.*;

 

public class myThread extends Thread {

  private Socket socket = null;

  private Frame1 frame;

  private ServerSocket serv;

  public myThread(Socket socket, Frame1 frame, ServerSocket serv) {

    super("MyThread");

    this.socket = socket;

    this.frame = frame;

    this.serv = serv;

    start();

  }

   public void run() {

        JTextArea jText=frame.jTextArea1;

           try {

            //取得Socket OutputStream/InputStream以便傳Data

               PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

               BufferedReader in = new BufferedReader(

                                               new InputStreamReader(

                                               socket.getInputStream()));

 

               jText.setText(jText.getText() + "\n收到RequestLocalPort=" +

                      String.valueOf(socket.getPort()));

            System.out.println(jText.getText());

            String strData;

               while (true) {

                //讀取Client送來的Data

                      strData = in.readLine();

                jText.setText(jText.getText() + "\n收到Client訊息:"+strData+

                  ",LocalPort=" +  String.valueOf(socket.getPort()));

                System.out.println(jText.getText());

                     if (strData.equals("Close"))  //收到Close代表Client要停止了

                         break;

                else if (strData.equals("Quit")) //收到Quit,代表Listen也要停了

                    break;

                else

                   out.println("收到您的訊息:"+strData);

               }

               out.close();

               in.close();

               socket.close();

 

        if (frame.socketal.remove(this) )  //去除Array List中的Data

             System.out.println("Remove Socket OK");

        System.out.println("Remains in SocketCollection:" +

                       frame.socketal.size());

        if (strData.equals("Quit")) {

           serv.close(); //如此強迫Listen停掉

        }

           } catch (IOException e) {

               e.printStackTrace();

           }

    }

}

------------------------------frame1.java -------------------------------------------

package mysock;

 

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import java.util.*;

 

 

public class Frame1 extends JFrame {

 

  ServerSocket ser=null;

  ArrayList socketal=new ArrayList(); //用以記錄連線中的Socket

 

  JPanel contentPane;

  JButton jButton5 = new JButton();

  JScrollPane jScrollPane1 = new JScrollPane();

  JTextArea jTextArea1 = new JTextArea();

 

  /**Construct the frame*/

  public Frame1() {

    enableEvents(AWTEvent.WINDOW_EVENT_MASK);

    try {

      jbInit();

    }

    catch(Exception e) {

      e.printStackTrace();

    }

  }

  /**Component initialization*/

  private void jbInit() throws Exception  {

    //setIconImage(Toolkit.getDefaultToolkit().createImage(Frame1.class.getResource("[Your Icon]")));

    contentPane = (JPanel) this.getContentPane();

    contentPane.setLayout(null);

    this.setSize(new Dimension(400, 300));

    this.setTitle("Frame Title");

 

    jButton5.setText("Server2");

    jButton5.setBounds(new Rectangle(126, 227, 117, 20));

    jButton5.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {

        jButton5_actionPerformed(e);

      }

    });

    jScrollPane1.setBounds(new Rectangle(45, 10, 283, 202));

    jTextArea1.setText("jTextArea1");

    contentPane.add(jScrollPane1, null);

    contentPane.add(jButton5, null);

    jScrollPane1.getViewport().add(jTextArea1, null);

 

  }

  /**Overridden so we can exit when window is closed*/

  protected void processWindowEvent(WindowEvent e) {

 

    if (e.getID() == WindowEvent.WINDOW_CLOSING) {

      Iterator itr = socketal.iterator();

      //如果有Socket程式未結束前,main Thread不能結束

      while (itr.hasNext()) {

          myThread mt = (myThread) itr.next();

          if (mt.isAlive()) {

              System.out.println("Still Alive");

              return;

          }

      }

      super.processWindowEvent(e);

      System.exit(0);

    }

  }

  void jButton5_actionPerformed(ActionEvent e) {

    Listen ls=new Listen(this); //產生一個ListenThread

  }

}

----------------------------------------Application1.java -----------------------------------

package mysock;

 

import javax.swing.UIManager;

import java.awt.*;

 

public class Application1 {

  boolean packFrame = false;

 

  /**Construct the application*/

  public Application1() {

    Frame1 frame = new Frame1();

    //Validate frames that have preset sizes

    //Pack frames that have useful preferred size info, e.g. from their layout

    if (packFrame) {

      frame.pack();

    }

    else {

      frame.validate();

    }

    //Center the window

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    Dimension frameSize = frame.getSize();

    if (frameSize.height > screenSize.height) {

      frameSize.height = screenSize.height;

    }

    if (frameSize.width > screenSize.width) {

      frameSize.width = screenSize.width;

    }

    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);

    frame.setVisible(true);

  }

  /**Main method*/

  public static void main(String[] args) {

    try {

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

    }

    catch(Exception e) {

      e.printStackTrace();

    }

    new Application1();

  }

}