实验八:Java网络编程
一、实验目的
- 掌握URLConnection与URL的关系及编程方法。
- 理解网络流的概念。
- 掌握基于TCP/IP的Socket/ServerSocket编程方法。
- 掌握基于UDP的DatagramSocket/DatagramPacket编程方法。
二、实验内容及步骤
1. 基于TCP/IP的Socket通信
1-1 基于TCP/IP的Socket通信的服务器端代码如下:
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/IP的Socket通信的客户端代码如下:
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. 基于UDP的Socket通信
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通信的利弊
- 总结多线程通信的具体实现方法