网络编程-第二节
Posted wei01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程-第二节相关的知识,希望对你有一定的参考价值。
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("服务器开始等待客户机连接... "); } catch (IOException ex) { } //创建一个匿名线程,用于侦听和接受客户机连接,并创建响应客户机的会话线程 new Thread(new Runnable() { @Override public void run() { try { while (true) { //处理客户机连接 toClientSocket=listenSocket.accept();//侦听并接受客户机连接 clientCounts++;//客户机数量加1 txtArea.append(toClientSocket.getRemoteSocketAddress()+ " 客户机编号: "+clientCounts+ " 会话开始... "); //创建客户线程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 + " ");// 将字符串显示在文本区域 // TODO 5.添加代码: 接收服务器回复的字符串,并显示在文本区域 try{ ta.append("Recv: " + in.readLine() + ‘ ‘); }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+" "); //解析并显示收到的消息 //按照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
运行结果:
以上是关于网络编程-第二节的主要内容,如果未能解决你的问题,请参考以下文章