2013/11/22

[JAVA] Socket網路server/client文字傳輸程式

想要練習對程式語言的各種應用熟悉程度,像是檔案I/O、執行緒、網路Socket還有程式介面,最快速的方式就是寫一個類似MSN的文字傳輸程式。既可以綜合練習到以上的部分,還可以藉由撰寫的過程中,更加了解程式語言。

JAVA也不例外,物件程式導向的程式語言,筆者對此一直還懵懵懂懂,但透過撰寫這個程式,對於類別架構、Socket還有AWT(Abstract Window Toolkit)物件的應用,更有不同的心得。




首先,撰寫Socket程式,由於是利用TCP傳輸的server/client架構來撰寫,應用在AWT視窗程式上,就必須要透過多執行緒來執行。總不能在server等待連線的時候,把所有的資源佔住,讓其他視窗的物件無法執行吧。

因此程式架構的設計上,利用兩個執行緒來跑socket的兩個port,一個用來send文字,另外一個用來receive文字,達到雙向傳輸的功能。且利用執行緒就可以同時還讓視窗的其他物件可以有事件監聽,譬如button可以設計一個exit鍵,按下之後把視窗給關閉,架構圖如下:


JAVA是一個物件導向的語言,所以常常會看到new {Object()}這類的語法,可以想像成整個JAVA就是一個書桌,而這些物件就是你擺在書桌上面的鉛筆、橡皮擦還有書籍,可以為這些物件設計功能事件,譬如:橡皮擦會在書本髒掉時做擦拭清潔。整個合起來就是一個AWT的視窗程式了。

範例中使用了Frame、Button、Lable、TextArea、TextField和自己創造的類別CServer的物件,利用new的語法創造並且使用constructor的方式指定物件的預設架構。
 static Frame frm=new Frame("JAVA Socket Server AWT Program");
 static Button btn1=new Button("Start");
 static Button btn2=new Button("Exit");
 static Label lab1=new Label("Host IP Address");
 static Label title=new Label("JSocket");
 static TextArea txa1=new TextArea("",6,10,TextArea.SCROLLBARS_VERTICAL_ONLY);
 static TextArea txa2=new TextArea("",6,10,TextArea.SCROLLBARS_NONE);
 static TextField txf1=new TextField("127.0.0.1");
 static CServer_send ss=new CServer_send();
 static CServer_Recv sr=new CServer_Recv();

接著利用setBound以及add method,把一連串的物件Layout建立好。然後設計button的事件,當btn1按下之後,產生兩個thread分別跑socket的兩個port,用來傳輸及接收文字;btn2則是用來作為程式離開的事件使用。事件actionPerformed則實作ActionListener介面,當按下的button為btn1時,則跑繼承了thread的CServer類別的執行緒;如果是btn2則是關閉整個frm視窗。
         btn1.addActionListener(new ActLis());
         btn2.addActionListener(new ActLis());

   static class ActLis implements ActionListener
   {
      public void actionPerformed(ActionEvent e)
      {
         Button btn=(Button) e.getSource();
         if(btn==btn1)
         {
            txa1.setText("Waiting for connecting("+txf1.getText()+")...\n");
            System.out.println("Waiting for connecting...");
            txf1.setEditable(false);
            ss.start();
            sr.start();
         }
         else if(btn==btn2)
            System.exit(0);
         else
            System.out.println("No Button Click!");
      }
   }

執行緒的執行上,JAVA的設計是,建立繼承了Thread的類別,在run()的method中放入要利用多執行緒執行的程式碼,在其他類別中就可以利用呼叫start()這個method來啟動執行緒。像是底下,利用繼承了Thread的CServer_send類別產生ss的物件,在主類別test_server中就可以利用ss.start()來呼叫CServer_send中的run()來執行。
class CServer_send extends Thread
{
   static int flag_send=0;
   public void run()
   {
      try
      {
         test_server.txa2.addKeyListener(new KeyLis());
        
         ServerSocket svs = new ServerSocket(2525);

         Socket s=svs.accept();
         test_server.txa1.append("Clinet connecting for sending successfully!!\n");
         System.out.println("Clinet connecting for sending successfully!!");
        
         System.out.println("Data transfering...");
         OutputStream out=s.getOutputStream();
         String str;
         while(true)
         {
            if(flag_send==1)
            {
               str=test_server.txa2.getText();
               out.write(str.getBytes());
               flag_send=0;
               System.out.print("Send:"+str);
            }
            sleep((int)(100*Math.random())); 
         }
         //in.close();
         //out.close();
         //s.close();
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
   static class KeyLis extends KeyAdapter
   {
      public void keyPressed(KeyEvent e)
      {
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            flag_send=1;
         }
      }
      public void keyReleased(KeyEvent e)
      {  
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            test_server.txa1.append("Server: "+test_server.txa2.getText());
            test_server.txa2.setText("\r");
         } 
          
      }  
   }
}

public class test_server
{
   public static void main (String[] args)
   {
      static CServer_send ss=new CServer_send();
      ss.start();
   }
}

透過以上就可以很簡單地把JAVA AWT Socket的網路文字傳輸程式給實做出來了。底下為參考程式碼:
test_server.java
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

class CServer_send extends Thread
{
   static int flag_send=0;
   public void run()
   {
      try
      {
         test_server.txa2.addKeyListener(new KeyLis());
        
         ServerSocket svs = new ServerSocket(2525);

         Socket s=svs.accept();
         test_server.txa1.append("Clinet connecting for sending successfully!!\n");
         System.out.println("Clinet connecting for sending successfully!!");
        
         System.out.println("Data transfering...");
         OutputStream out=s.getOutputStream();
         String str;
         while(true)
         {
            if(flag_send==1)
            {
               str=test_server.txa2.getText();
               out.write(str.getBytes());
               flag_send=0;
               System.out.print("Send:"+str);
            }
            sleep((int)(100*Math.random())); 
         }
         //in.close();
         //out.close();
         //s.close();
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
   static class KeyLis extends KeyAdapter
   {
      public void keyPressed(KeyEvent e)
      {
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            flag_send=1;
         }
      }
      public void keyReleased(KeyEvent e)
      {  
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            test_server.txa1.append("Server: "+test_server.txa2.getText());
            test_server.txa2.setText("\r");
         } 
          
      }  
   }
}
class CServer_Recv extends Thread
{
   public void run()
   {
      byte buff[] = new byte[1024];
      try
      {
         ServerSocket svs = new ServerSocket(2526);
        
         Socket s=svs.accept();
         test_server.txa1.append("Clinet connecting for receiving successfully!!\n");
         System.out.println("Clinet connecting for receiving successfully!!");
        
         InputStream in=s.getInputStream();
         int n;
         while(true)
         {
            n=in.read(buff);
            test_server.txa1.append("Client: "+new String(buff,0,n));
            System.out.print("Received from client: ");
            System.out.print(new String(buff,0,n));
            sleep((int)(100*Math.random())); 
         }
         //in.close();
         //s.close();
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
}

public class test_server
{
   static Frame frm=new Frame("JAVA Socket Server AWT Program");
   static Button btn1=new Button("Start");
   static Button btn2=new Button("Exit");
   static Label lab1=new Label("Host IP Address");
   static Label title=new Label("JSocket");
   static TextArea txa1=new TextArea("",6,10,TextArea.SCROLLBARS_VERTICAL_ONLY);
   static TextArea txa2=new TextArea("",6,10,TextArea.SCROLLBARS_NONE);
   static TextField txf1=new TextField("127.0.0.1");
   static CServer_send ss=new CServer_send();
   static CServer_Recv sr=new CServer_Recv();
  
   public static void main (String[] args)
   {
     try
      {
         InetAddress adr=InetAddress.getLocalHost();
         txf1.setText(adr.getHostAddress());
         btn1.addActionListener(new ActLis());
         btn2.addActionListener(new ActLis());
         frm.addWindowListener(new WinLis());
        
         frm.setLayout(null);
         title.setBounds(20,40,75,40);
         btn1.setBounds(280,40,100,20);
         btn2.setBounds(280,65,100,20);
         frm.setBounds(100,100,400,300);
         frm.setBackground(new Color(151,255,255));
         lab1.setBounds(100,40,160,20);
         txa1.setBounds(20,95,360,140);
         txa2.setBounds(20,240,360,40);
         txf1.setBounds(100,65,160,20);
         txa1.setEditable(false);
         title.setFont(new Font("Serief",Font.BOLD+Font.ITALIC,18));
         title.setForeground(Color.BLUE);
         frm.add(title);
         frm.add(btn1);frm.add(btn2);
         frm.add(lab1);
         frm.add(txa1);frm.add(txa2);
         frm.add(txf1);
         frm.setVisible(true);
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
  
   static class ActLis implements ActionListener
   {
      public void actionPerformed(ActionEvent e)
      {
         Button btn=(Button) e.getSource();
         if(btn==btn1)
         {
            txa1.setText("Waiting for connecting("+txf1.getText()+")...\n");
            System.out.println("Waiting for connecting...");
            txf1.setEditable(false);
            ss.start();
            sr.start();
         }
         else if(btn==btn2)
            System.exit(0);
         else
            System.out.println("No Button Click!");
      }
   }
   static class WinLis extends WindowAdapter
   {
      public void windowClosing(WindowEvent e)
      {
         frm.dispose();
         System.exit(0);
      }
   }
}

test_client.java
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

class CClient_send extends Thread
{
   static int flag_send=0;
   public void run()
   {
      try
      {
         test_client.txa2.addKeyListener(new KeyLis());
                 
         Socket s=new Socket(test_client.txf1.getText(),2526);
         test_client.txa1.append("Connected with server for sending successfully!!\n");
         System.out.println("Connected with server for sending successfully!!");
        
         System.out.println("Data transfering...");
         OutputStream out=s.getOutputStream();
         String str;
         while(true)
         {
            if(flag_send==1)
            {
               str=test_client.txa2.getText();
               out.write(str.getBytes());
               flag_send=0;
               System.out.print("Send:"+str);
            }
            sleep((int)(100*Math.random())); 
         }
         //in.close();
         //out.close();
         //s.close();
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
   static class KeyLis extends KeyAdapter
   {
      public void keyPressed(KeyEvent e)
      {
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            flag_send=1;
         }
      }
      public void keyReleased(KeyEvent e)
      {  
         if(e.getKeyCode()==KeyEvent.VK_ENTER)
         { 
            test_client.txa1.append("Client: "+test_client.txa2.getText());
            test_client.txa2.setText("\r");
         } 
          
      }  
   }
}
class CClient_Recv extends Thread
{
   public void run()
   {
      byte buff[] = new byte[1024];
      try
      {
         Socket s=new Socket(test_client.txf1.getText(),2525);
         test_client.txa1.append("Connected with server for receiving successfully!!\n");
         System.out.println("Connected with server for receiving successfully!!");
        
         InputStream in=s.getInputStream();
         int n;
         while(true)
         {
            n=in.read(buff);
            test_client.txa1.append("Server: "+new String(buff,0,n));
            System.out.print("Received from server: ");
            System.out.print(new String(buff,0,n));
            sleep((int)(100*Math.random())); 
         }
         //in.close();
         //s.close();
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
}


public class test_client
{
   static Frame frm=new Frame("JAVA Socket Client AWT Program");
   static Button btn1=new Button("Connect");
   static Button btn2=new Button("Exit");
   static Label lab1=new Label("Server IP Address");
   static Label title=new Label("JSocket");
   static TextArea txa1=new TextArea("",6,10,TextArea.SCROLLBARS_VERTICAL_ONLY);
   static TextArea txa2=new TextArea("",6,10,TextArea.SCROLLBARS_NONE);
   static TextField txf1=new TextField("127.0.0.1");
   static CClient_Recv cr=new CClient_Recv();
   static CClient_send cs=new CClient_send();
  
   public static void main (String[] args)
   {
     try
      {
         btn1.addActionListener(new ActLis());
         btn2.addActionListener(new ActLis());
         frm.addWindowListener(new WinLis());
         frm.setLayout(null);
         title.setBounds(20,40,75,40);
         btn1.setBounds(280,40,100,20);
         btn2.setBounds(280,65,100,20);
         frm.setBounds(450,150,400,300);
         frm.setBackground(new Color(151,255,255));
         lab1.setBounds(100,40,160,20);
         txa1.setBounds(20,95,360,140);
         txa2.setBounds(20,240,360,40);
         txf1.setBounds(100,65,160,20);
         txa1.setEditable(false);
         title.setFont(new Font("Serief",Font.BOLD+Font.ITALIC,18));
         title.setForeground(Color.BLUE);
         frm.add(title);
         frm.add(btn1);frm.add(btn2);
         frm.add(lab1);
         frm.add(txa1);frm.add(txa2);
         frm.add(txf1);
         frm.setVisible(true);
        
      }
      catch(Exception e)
      {
         System.out.println("Error:"+e);
      }
   }
  
   static class ActLis implements ActionListener
   {
      public void actionPerformed(ActionEvent e)
      {
         Button btn=(Button) e.getSource();
         if(btn==btn1)
         {
            test_client.txa1.setText("Waiting for connecting with server("+txf1.getText()+")...\n");
            System.out.println("Waiting for connecting with server...");
            txf1.setEditable(false);
            cs.start();
            cr.start();
         }
         else if(btn==btn2)
            System.exit(0);
         else
            System.out.println("No Button Click!");
      }
   }
   static class WinLis extends WindowAdapter
   {
      public void windowClosing(WindowEvent e)
      {
         frm.dispose();
         System.exit(0);
      }
   }
}

Server執行結果


Client執行結果

透過Socket、類別繼承和AWT的練習,可以讓JAVA更快速的上手。

沒有留言:

張貼留言