实验八:Java网络编程

一、实验目的

  1. 掌握URLConnection与URL的关系及编程方法。
  2. 理解网络流的概念。
  3. 掌握基于TCP/IP的Socket/ServerSocket编程方法。
  4. 掌握基于UDP的DatagramSocket/DatagramPacket编程方法。

二、实验内容及步骤

1. 基于TCP/IPSocket通信

1-1 基于TCP/IPSocket通信的服务器端代码如下:

import java.io.DataInputStream;
import java.net.ServerSocket;  //服务端套接字
import java.net.Socket;   //套接字
 
public class Server1{    //服务端
    public static void main(String[] args) throws Exception {
        ServerSocket ss= new ServerSocket(7777);  //设置服务器 的监听端口
        System.out.println("Server started.");
        while(true){   //始终监听
            //监听客户端请求
            Socket cs = ss.accept();  //可能产生阻塞(等待)的原因是没有客户端请求
            DataInputStream dis = new DataInputStream(cs.getInputStream());//
            System.out.println(dis.readUTF());  //输出来自客户端传送的信息
            dis.close();
            cs.close();
        }
    }
}

运行结果:

 

相关要点如下:

  • 先运行服务器端,然后再运行客户端,客户端程序运行后,服务器端会输出来自客户端的信息
  • 服务器打开后会阻塞线程知道监听到端口中的信息并将其输出

1-2 基于TCP/IPSocket通信的客户端代码如下:

import java.io.DataOutputStream;  //数据输出字节流
import java.net.Socket;
 
public class Client1 {  //客户端
    public static void main(String[] args) throws Exception {
        // 第一个参数为服务器IP
        // 第二参数7777为服务器端口,与创建ServerSocket时使用的端口一致
        Socket s = new Socket("127.0.0.1", 7777);  //创建客户端
 
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        dos.writeUTF("Hello Server!"); // 向服务器传送信息
        //System.out.println("客户端信息已发送。");
 
        Thread.sleep(5000);  //休眠5秒
 
        dos.flush();
        dos.close(); // 超类方法
        s.close();
    }
}

相关要点如下:

  • 通过数据输出流向服务器发送消息,端口必须与服务器端口一致
  • 同一网段的不同电脑,也可以完成连接

2. 基于UDPSocket通信

2-1 服务器端程序代码如下:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
 
public class Server2 {
    @SuppressWarnings("resource")
    public static void main(String[] args) throws Exception{
 
        byte buf[]=new byte[1024];
 
        //设置数据报文包
        DatagramPacket dp=new DatagramPacket(buf,buf.length);
 
        //创建报文接收端口,在客户端程序会使用该端口号
        DatagramSocket ds=new DatagramSocket(5678);
 
        System.out.println("Server started.");
        while(true){
            ds.receive(dp);  //阻塞式的接收
            System.out.println(new String(buf,0,dp.getLength())+",Server!");
        }
    }
}

2-2 客户端程序代码如下:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
 
public class Client2 {
    public static void main(String[] args) throws Exception{       
        byte[] buf=(new String("Hello")).getBytes();   
        //定义数据报文包对象,包含了服务器地址及端口,InetSocketAddress继承抽象类SocketAddress
        DatagramPacket dp=new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678));  
        DatagramSocket ds=new DatagramSocket(9999); //创建对象         
        ds.send(dp);  //发送到指定的服务器端口
        ds.close();
    }
}

运行结果:

 

相关要点如下:

  • 创建服务端,需要使用大于1024的端口
  • 创建客户端,需要使用服务器端口

3. 简易图形用户界面聊天程序

3-1 服务器代码如下:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
public class Server3 extends JFrame{
          static JTextArea area;
          JTextField field;
          JButton button;
          static PrintStream writer;
          public Server3(){
                   this.setTitle("服务器");
                   this.setSize(400,500);
                   area = new JTextArea(25,30);
                   area.setEditable(false);
                   field = new JTextField(20);
                   button = new JButton("提交");
                   JPanel panel = new JPanel();
                   JScrollPane sp = new JScrollPane(area);
                   this.add(sp,BorderLayout.CENTER);
                   panel.add(field);
                   panel.add(button);
                   this.add(panel,BorderLayout.SOUTH);
                   this.setVisible(true);
                   this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                  
                   button.addActionListener(new ActionListener(){
 
                             @Override
                             public void actionPerformed(ActionEvent e) {
                                      String text = field.getText();
                                      writer.println(text);
                                      area.append("我:"+text+"\n");
                                      field.setText("");
                             }
                            
                   });
          }
          public static void main(String[] args) throws Exception {
                   Server3 s = new Server3();
                   ServerSocket server = new ServerSocket(8899);
                   System.out.println("开始监听...");
                   Socket socket = server.accept();
                   InetAddress address = socket.getInetAddress();
                   String name = address.getLocalHost().getHostName();
                   System.out.println(name+"已连接");
                   BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                   writer = new PrintStream(socket.getOutputStream(), true);
                   while (true) {
                             String line = null;
                             line = reader.readLine();
                             if (line != null) {         
                                                area.append("客户端:"+line+"\n");
                             }
 
                   }
          }
    }

相关要点如下:

  • 该服务器通过获取端口中的输入流读信息,并将信息通过输出流发送给客户端
  • 在发送消息的同时,服务器也会将信息写到面板上

3-3 客户端代码如下:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
public class Client3 extends JFrame{
 
          static JTextArea area;
          JTextField field;
          JButton button;
          static PrintWriter writer;
          public Client3(){
                   this.setTitle("客户端");
                   this.setSize(400,500);
                   area = new JTextArea(25,30);
                   area.setEditable(false);
                   field = new JTextField(20);
                   button = new JButton("提交");
                   JScrollPane sp = new JScrollPane(area);
                   JPanel panel = new JPanel();
                   this.add(sp,BorderLayout.CENTER);
                   panel.add(field);
                   panel.add(button);
                   this.add(panel,BorderLayout.SOUTH);
                   this.setVisible(true);
                   this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                  
                   button.addActionListener(new ActionListener(){
 
                             @Override
                             public void actionPerformed(ActionEvent e) {
                                      String text = field.getText();
                                      writer.println(text);
                                      area.append("我:"+text+"\n");
                                      field.setText("");
                             }
                            
                   });
          }
          public static void main(String[] args) throws Exception{
                   Client3 c = new Client3();
                   Socket socket = new Socket("127.0.0.1",8899);
                   OutputStream out = socket.getOutputStream();
                   BufferedReader reader1 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                   writer = new PrintWriter(out,true);
                   System.out.println("已经成功和服务器连接...");
                   while(true){
                             String line = reader1.readLine();
                             area.append("服务器:"+line+"\n");
                   }
          }
 
}

运行效果:

 

相关要点如下:

  • 获取名字信息和输出信息后,将其发送到服务器,再接收服务器返回的信息并将其显示

三、实验小结

  • 分析UDP通信和TCP通信的利弊
  • 总结多线程通信的具体实现方法