1. 程式人生 > >網絡編程-第二節

網絡編程-第二節

ali ica esc \n pla creates jbutton 主機 網絡

技術分享圖片

1.1 基礎題:客戶端與服務器持續通信

1.2 應用題:設計帶窗口客戶端

導入程序MyServer.java、MyClient.java、ClientThread.java。補充程序MyClient.java的代碼(在“//TODO 添加代碼”提示的位置),使得

1) 客戶端在運行之後打開如下窗口,用戶可以從文本框”Message:”中輸入信息,點擊“Send”之後,將信息發送給服務器,並將其顯示在文本區域中;

2) 客戶端接收到服務器回復的信息,將其顯示在文本區域”Information Border”中;

MyServer.java代碼如下:

package
cn.edu.sise; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import javax.swing.JOptionPane; /** * Echo服務器:根據Echo協議,接收來自客戶機消息,並立即回送。 * @author 董相誌,版權所有,2016--2018,[email protected]
*/ public class MyServer extends javax.swing.JFrame { private ServerSocket listenSocket=null; //偵聽套接字 private Socket toClientSocket=null; //與客戶機對話的套接字 public static int clientCounts=0; //客戶數量編號 /** * Creates new form EchoServer */ public MyServer() { initComponents(); }
/** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { topPanel = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); txtHostName = new javax.swing.JTextField(); jLabel2 = new javax.swing.JLabel(); txtHostPort = new javax.swing.JTextField(); btnStart = new javax.swing.JButton(); midPanel = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); txtArea = new javax.swing.JTextArea(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("My Server: 1707"); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { formWindowClosing(evt); } }); topPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Server Info Border", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("宋體", 1, 18))); // NOI18N jLabel1.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N jLabel1.setText("Host Name:"); txtHostName.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N txtHostName.setText("localhost"); jLabel2.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N jLabel2.setText("Port:"); txtHostPort.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N txtHostPort.setText("7"); btnStart.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N btnStart.setText("Start"); btnStart.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnStartActionPerformed(evt); } }); javax.swing.GroupLayout topPanelLayout = new javax.swing.GroupLayout(topPanel); topPanel.setLayout(topPanelLayout); topPanelLayout.setHorizontalGroup( topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(topPanelLayout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(txtHostName, javax.swing.GroupLayout.DEFAULT_SIZE, 131, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(txtHostPort, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(btnStart) .addContainerGap()) ); topPanelLayout.setVerticalGroup( topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(topPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(txtHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel2) .addComponent(txtHostPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(btnStart)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START); midPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Information Border", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("宋體", 1, 18))); // NOI18N midPanel.setLayout(new java.awt.BorderLayout()); txtArea.setEditable(false); txtArea.setBackground(new java.awt.Color(204, 255, 255)); txtArea.setColumns(20); txtArea.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N txtArea.setRows(5); jScrollPane1.setViewportView(txtArea); midPanel.add(jScrollPane1, java.awt.BorderLayout.CENTER); getContentPane().add(midPanel, java.awt.BorderLayout.CENTER); pack(); }// </editor-fold>//GEN-END:initComponents //啟動服務器 private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed try { btnStart.setEnabled(false); //禁用按鈕,避免重復啟動 String hostName=txtHostName.getText();//主機名 int hostPort=Integer.parseInt(txtHostPort.getText());//端口 //構建服務器的SocketAddress格式地址 SocketAddress serverAddr=new InetSocketAddress(InetAddress.getByName(hostName),hostPort); listenSocket=new ServerSocket(); //創建偵聽套接字 listenSocket.bind(serverAddr); //綁定到工作地址 txtArea.append("服務器開始等待客戶機連接...\n"); } catch (IOException ex) { } //創建一個匿名線程,用於偵聽和接受客戶機連接,並創建響應客戶機的會話線程 new Thread(new Runnable() { @Override public void run() { try { while (true) { //處理客戶機連接 toClientSocket=listenSocket.accept();//偵聽並接受客戶機連接 clientCounts++;//客戶機數量加1 txtArea.append(toClientSocket.getRemoteSocketAddress()+ " 客戶機編號: "+clientCounts+ " 會話開始...\n"); //創建客戶線程clientThread,實現一客戶一線程 Thread clientThread=new ClientThread(toClientSocket,clientCounts); clientThread.start(); //啟動任務線程 } //end while } catch (IOException ex) { JOptionPane.showMessageDialog(null, ex.getMessage(), "錯誤提示", JOptionPane.ERROR_MESSAGE); } }//end run() }).start(); }//GEN-LAST:event_btnStartActionPerformed //關閉服務器之前 private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing //關閉服務器之前釋放套接字 if (listenSocket!=null) listenSocket=null; if (toClientSocket!=null) toClientSocket=null; }//GEN-LAST:event_formWindowClosing /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(MyServer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(MyServer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(MyServer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(MyServer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> //</editor-fold> //</editor-fold> //</editor-fold> /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new MyServer().setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnStart; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JPanel midPanel; private javax.swing.JPanel topPanel; public static javax.swing.JTextArea txtArea; private javax.swing.JTextField txtHostName; private javax.swing.JTextField txtHostPort; // End of variables declaration//GEN-END:variables }

MyClient.java代碼如下:

package cn.edu.sise;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class MyClient {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // TODO 1.添加代碼:在窗口標題裏寫上自己的學號
        JFrame frame = new JFrame("Client: 1707");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(new MyPanel());
        frame.setPreferredSize(new Dimension(600, 300));
        frame.pack();
        frame.setVisible(true);
    }

}

class MyPanel extends JPanel {
    JTextField tf;
    JTextArea ta;

    BufferedReader in = null;
    BufferedWriter out = null;

    public MyPanel() {

        this.setLayout(new BorderLayout());
        JPanel p1 = new JPanel();
        JLabel lb1 = new JLabel();
        lb1.setFont(new java.awt.Font("宋體", 1, 16)); // NOI18N
        lb1.setText("Message:");
        p1.add(lb1);
        tf = new JTextField(25);
        p1.add(tf);
        JButton btn = new JButton("Send");
        btn.addActionListener(new MyListerner());
        p1.add(btn);
        p1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Communication Border",
                javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION,
                new java.awt.Font("宋體", 1, 14))); // NOI18N

        this.add(p1, BorderLayout.NORTH);

        JPanel p2 = new JPanel();
        p2.setLayout(new java.awt.BorderLayout());
        p2.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Information Border",
                javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION,
                new java.awt.Font("宋體", 1, 14))); // NOI18N

        JScrollPane sp1 = new JScrollPane();
        sp1.setPreferredSize(new java.awt.Dimension(8, 250));
        ta = new JTextArea(5, 10);
        ta.setEditable(false);
        sp1.setViewportView(ta);
        p2.add(sp1, BorderLayout.CENTER);
        this.add(p2, BorderLayout.CENTER);

        try {
            Socket s = new Socket();
            // TODO 2.添加代碼 1) 新建SocketAddress的對象,指定要連接的服務器;
            // 2)調用Socket的方法連接服務器

            SocketAddress address=new InetSocketAddress("localhost",7);

            // 連接服務器
            s.connect(address);
            

            in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            // TODO 3.添加代碼 : 上面已給出輸入流的代碼,請補充輸出流的
            out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

        } catch (IOException ex) {
            System.out.println("異常信息:" + ex.getMessage());
        }
    }

    class MyListerner implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub

            String sendStr = tf.getText(); // 從文本框中讀取用戶輸入
            tf.setText("");// 將文本框中的字符清空
            // TODO 4.添加代碼:向服務器發送字符串
            try{
                out.write(sendStr);
                out.newLine();
                out.flush();
            }catch (IOException ex) {
                System.out.println("異常信息:"+ex.getMessage());
            
            }    
            

            System.out.println("向服務器發送字符串成功!" + sendStr);

            ta.append("To server: " + sendStr + "\n");// 將字符串顯示在文本區域

            // TODO 5.添加代碼: 接收服務器回復的字符串,並顯示在文本區域
            try{
            ta.append("Recv: " + in.readLine() + ‘\n‘);
            }catch (IOException ex) {
                System.out.println("異常信息:"+ex.getMessage());
            
            }

        }
    }
}

ClientThread.java代碼如下:

package cn.edu.sise;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 *
 * @author World
 */
public class ClientThread extends Thread {
    private Socket toClientSocket=null;//會話套接字
    private BufferedReader in; //網絡輸入流
    private PrintWriter out; //網絡輸出流
    private int clientCounts=0;//在線客戶機總數
    public ClientThread(Socket toClientSocket,int clientCounts) { //構造函數
        this.toClientSocket=toClientSocket;
        this.clientCounts=clientCounts;
    }    
    @Override
    public void run(){
        try {          
            // 創建綁定到套接字toClientSocket上的網絡輸入流與輸出流
            in=new BufferedReader(new InputStreamReader(toClientSocket.getInputStream(),"UTF-8"));
            out=new PrintWriter(new OutputStreamWriter(toClientSocket.getOutputStream(),"UTF-8"),true);
            //5. 根據服務器協議,在網絡流上進行讀寫操作
            String recvStr;
            while ((recvStr=in.readLine())!=null){ //只要客戶機不關閉,則反復等待和接收客戶機消息
               Date date=new Date();
               DateFormat format=new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
               String time=format.format(date);
               MyServer.txtArea.append(toClientSocket.getRemoteSocketAddress()+ " 客戶機編號: "+clientCounts+" 消息:"+recvStr+" :"+time+"\n"); //解析並顯示收到的消息
               //按照echo協議原封不動回送消息
               out.println(toClientSocket.getLocalSocketAddress()+ " 客戶機編號: "+clientCounts+" Echo消息:"+recvStr+" : "+time);
            }//end while   
            MyServer.clientCounts--; //客戶機總數減1
            //遠程客戶機斷開連接,線程釋放資源
            if (in!=null) in.close();
            if (out!=null) out.close();
            if (toClientSocket!=null) toClientSocket.close();             
        }catch (IOException ex) {}
    } //end run
} //end class

運行結果:

技術分享圖片

網絡編程-第二節