Java网络编程
一、Java网络编程
网络编程是指编写运行在多个设备(计算机)的程序,设备通过网络连接起来。java.net 包中 J2SE 的 API 包含有类和接口,提供了低层次的通信细节。可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
协议:计算机网络中,连接和通信的规则被称为网络通信协议
1.UDP协议
-
用户数据报协议(User Datagram Protocol)
-
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据
-
由于使用UDP协议消耗资源少,通信效率高,所以通常都会用于音频、视频和普通数据的传输
-
例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
2.TCP协议
-
传输控制协议(Transmission Control Protocol)
-
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据出啊u念书。在TCP连接中必须明确客户端与服务器端,由于客户端向服务器端发出连接请求,每次连接的创建都需要经过“三次握手”
3.三次握手
-
TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
-
第一次握手:客户端向服务器端发出连接请求,等待服务器确认
-
第二次握手:服务器端向客户端回送一个响应,通知客户端收到了连接请求
-
第三次握手:客户端再次向服务器端发送确认信息,确认连接

完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用非常广泛。例如上传文件、下载文件、浏览网页
二、Java中InetAddress的使用
Java具有较好的网络编程模型/库,其中非常重要的一个API便是InetAddress。在在java.net网络编程中中有许多类都使用到了InetAddress,包括ServerSocket,Socket,DatagramSocket等等。
Java提供InetAddress类(有Inet4Address和Inet6Address两种实现),可以对域名-IP进行正向、逆向解析。InetAddress解析的时候一般是调用系统自带的DNS程序,比如:Linux下默认使用哪个DNS去解析以及其规则是由/etc/resolv.conf该文件制定
IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础。InetAddress是Java对IP地址的封装。
java.net.IntAddress类是Java对IP地址的高层表示。大多数其它网络类都要用到这个类,包括Socket、ServerSocket、URL、DatagramSocket、DatagramPacket等。InetAddress的实例对象包含了IP地址,同时还可能包含主机名(如果使用主机名来获取InetAddress的实例,或者使用数字来构造,并且启用了反向主机名解析的功能)。InetAddress类提供了将主机名解析为IP地址(或反之)的方法。
InetAddress对域名进行解析是使用本地机器配置(如域名系统DNS和网络信息服务(Network Information Service,NIS))来实现。本地需要向DNS服务器发送查询的请求,然后服务器根据一系列的操作,返回对应的IP地址,为了提高效率,通常本地会缓存一些主机名与IP地址的映射,这样访问相同的地址,就不需要重复发送DNS请求了。如下:
public class Test01 { public static void main(String[] args) throws UnknownHostException { //InetAddress ia = new InetAddress();不能直接创建对象,因为InetAddress()被default修饰了。 /*InetAddress ia = InetAddress.getByName("192.168.200.114"); System.out.println(ia); InetAddress ia2 = InetAddress.getByName("localhost");//localhost指代的是本机的ip地址 System.out.println(ia2); InetAddress ia3 = InetAddress.getByName("127.0.0.1");//127.0.0.1指代的是本机的ip地址 System.out.println(ia3); InetAddress ia4 = InetAddress.getByName("DESKTOP-A5TIRM1");//封装计算机名 System.out.println(ia4); InetAddress ia5 = InetAddress.getByName("www.augus.com");//封装域名 System.out.println(ia5);*/ // InetSocketAddress ---》封装了IP,端口号 InetSocketAddress inetSocketAddress = new InetSocketAddress("192.168.200.114", 9999); System.out.println(inetSocketAddress); ///192.168.200.114:9999 System.out.println(inetSocketAddress.getHostName()); //输出计算机的名称 DESKTOP-A5TIRM1 System.out.println(inetSocketAddress.getPort());//输出端口 InetAddress ia1 = inetSocketAddress.getAddress(); System.out.println(ia1.getHostName());//输出计算机的名称 DESKTOP-A5TIRM1 System.out.println(ia1.getHostAddress());//192.168.200.114 } }
三、基于TCP的网络编程
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。
-
使用基于TCP协议的Socket网络编程实现,使用Socket对象来代表两端的通信端口
-
TCP协议基于请求-响应模式,第一次主动发起的程序被称为客户端(Client)程序
-
第一次通讯中等待连接的程序被称为服务器端(Sercer)程序

利用IO流实现数据的传输

原理说明及详细步骤
- 在服务端指定一个端口号来创建ServerSocket,并使用accept方法进行侦听,这将阻塞服务器线程,等待用户请求。
- 在客户端指定服务的主机IP和端口号来创建socket,并连接服务端ServerSocket,此时服务端accept方法被唤醒,同时返回一个和客户端通信的socket。
- 在客户端和服务端分别使用socket来获取网络通信输入/输出流,并按照一定的通信协议对socket进行读/写操作。
- 通信完成后,在客户端和服务端中分别关闭socket。
3.1.单向通信
功能:客户端发送一句话到服务器:
- 服务端代码:
public class TestServer { public static void main(String[] args) throws IOException { //1.创建套接字:指定端口号 ServerSocket serverSocket = new ServerSocket(9999); //2.等待客户端发来的信息 //accept()返回值为一个Socket,这个Socket其实就是客户端的Socket //接到这个Socket以后,客户端和服务器才真正产生了连接,才真正可以通信了 Socket accept = serverSocket.accept();//阻塞方法:等待接收客户端的数据,什么时候接收到数据,什么时候程序继续向下执行。 //操作流 InputStream inputStream = accept.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream);// 数据输入流 //4.读取客户端发来的数据: String s = dataInputStream.readUTF(); //5.输出客户端信息 System.out.println("客户端发送消息:"+s); //6.关闭流操作 dataInputStream.close(); inputStream.close(); accept.close(); serverSocket.close(); } }
- 客户端代码
public class TestClient { public static void main(String[] args) throws IOException { //1.创建套接字:指定服务器的ip和端口号: Socket socket = new Socket("192.168.200.114",9999); //2.利用输出流。发送数据 // 利用这个OutputStream就可以向外发送数据了,但是没有直接发送String的方法 // 所以在OutputStream外面套了一个处理流:DataOutputStream OutputStream outputStream = socket.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream);//数据输出流 dataOutputStream.writeUTF("你好"); //3.关闭流和网络资源 dataOutputStream.close(); outputStream.close(); socket.close(); } }
注意,测试的时候,先启动服务端,在启动客户端,执行后如下:

3.2.双向通信
修改为通信双方均可进行消息的处理
服务端:
public class TestServer { public static void main(String[] args) throws IOException { //1.创建套接字:指定端口号 ServerSocket serverSocket = new ServerSocket(9999); //2.等待客户端发来的信息 //accept()返回值为一个Socket,这个Socket其实就是客户端的Socket //接到这个Socket以后,客户端和服务器才真正产生了连接,才真正可以通信了 Socket accept = serverSocket.accept();//阻塞方法:等待接收客户端的数据,什么时候接收到数据,什么时候程序继续向下执行。 //操作流 InputStream inputStream = accept.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream);// 数据输入流 //4.读取客户端发来的数据: String s = dataInputStream.readUTF(); //5.输出客户端信息 System.out.println("接受到客户端发送消息:"+s); //6.向客户端发送消息 OutputStream outputStream = accept.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream); dataOutputStream.writeUTF("你好,很高兴认识你,我是TestServer"); //6.关闭流操作 dataOutputStream.close(); outputStream.close(); dataInputStream.close(); inputStream.close(); accept.close(); serverSocket.close(); } }
客户端
public class TestClient { public static void main(String[] args) throws IOException { //1.创建套接字:指定服务器的ip和端口号: Socket socket = new Socket("192.168.200.114",9999); //2.利用输出流。发送数据 // 利用这个OutputStream就可以向外发送数据了,但是没有直接发送String的方法 // 所以在OutputStream外面套了一个处理流:DataOutputStream OutputStream outputStream = socket.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream);//数据输出流 dataOutputStream.writeUTF("你好"); //3.接收从服务端 发送的消息 InputStream inputStream = socket.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream); System.out.println("接收到服务端发送的数据:"+dataInputStream.readUTF()); //4.关闭流和网络资源 dataOutputStream.close(); outputStream.close(); socket.close(); } }
执行后结果如下:


3.3.对象流传送
- User实体类封装对象,传递用户名和密码
public class User implements Serializable { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
- 服务端:
public class TestServer { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.创建套接字:指定端口号 ServerSocket serverSocket = new ServerSocket(9999); //2.等待客户端发来的信息 //accept()返回值为一个Socket,这个Socket其实就是客户端的Socket //接到这个Socket以后,客户端和服务器才真正产生了连接,才真正可以通信了 Socket accept = serverSocket.accept();//阻塞方法:等待接收客户端的数据,什么时候接收到数据,什么时候程序继续向下执行。 //操作流 InputStream inputStream = accept.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);// 数据输入流 //4.读取客户端发来的数据: User user = (User) objectInputStream.readObject(); //验证 boolean flae = false; if(user.getUsername().equals("admin")&& user.getPassword().equals("123321")){ flae = true; } //5.输出客户端信息 System.out.println("接受到客户端发送消息:"+user.toString()); //6.向客户端发送消息 OutputStream outputStream = accept.getOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream); //向客户端发送数据 dataOutputStream.writeBoolean(flae); //6.关闭流操作 dataOutputStream.close(); outputStream.close(); objectInputStream.close(); inputStream.close(); accept.close(); serverSocket.close(); } }
- 客户端
public class TestClient { public static void main(String[] args) throws IOException { //1.创建套接字:指定服务器的ip和端口号: Socket socket = new Socket("192.168.200.114",9999); //2.从键盘录入用户名和密码 Scanner scanner = new Scanner(System.in); System.out.print("请输入用户名:"); String name = scanner.next(); System.out.print("请输入密码:"); String pwd = scanner.next(); //封装User对象传递 User user = new User(name,pwd); //2.利用输出流。发送数据 // 利用这个OutputStream就可以向外发送数据了,但是没有直接发送String的方法 // 所以在OutputStream外面套了一个处理流:DataOutputStream OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);//数据输出流 //发送对象 objectOutputStream.writeObject(user); //3.接收从服务端 发送的消息 InputStream inputStream = socket.getInputStream(); DataInputStream dataInputStream = new DataInputStream(inputStream); //接受发送过来的boolean类型的数据 boolean b = dataInputStream.readBoolean(); if (b){ System.out.println("恭喜,登陆成功"); }else { System.out.println("用户名或者密码错误"); } //4.关闭流和网络资源 dataInputStream.close(); inputStream.close(); objectOutputStream.close(); outputStream.close(); socket.close(); } }
执行后结果如下:


3.4.加入完成处理异常方式
加入异常处理,保证代码的健壮性
- 服务端
public class TestServer { public static void main(String[] args){ // ServerSocket serverSocket=null; Socket accept=null; InputStream inputStream=null; ObjectInputStream objectInputStream=null; OutputStream outputStream=null; DataOutputStream dataOutputStream=null; try { //1.创建套接字:指定端口号 serverSocket = new ServerSocket(9999); //2.等待客户端发来的信息 //accept()返回值为一个Socket,这个Socket其实就是客户端的Socket //接到这个Socket以后,客户端和服务器才真正产生了连接,才真正可以通信了 accept = serverSocket.accept();//阻塞方法:等待接收客户端的数据,什么时候接收到数据,什么时候程序继续向下执行。 //操作流 inputStream = accept.getInputStream(); objectInputStream = new ObjectInputStream(inputStream);// 数据输入流 //4.读取客户端发来的数据: User user = (User) objectInputStream.readObject(); //验证 boolean flae = false; if(user.getUsername().equals("admin")&& user.getPassword().equals("123321")){ flae = true; } //5.输出客户端信息 System.out.println("接受到客户端发送消息:"+user.toString()); //6.向客户端发送消息 outputStream = accept.getOutputStream(); dataOutputStream = new DataOutputStream(outputStream); //向客户端发送数据 dataOutputStream.writeBoolean(flae); }catch (IOException | ClassNotFoundException e){ e.printStackTrace(); }finally { //6.关闭流操作 try { //不为null在关闭 if(dataOutputStream != null){ dataOutputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(outputStream != null){ outputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(objectInputStream != null){ objectInputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(inputStream != null){ inputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(accept != null){ accept.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(serverSocket != null){ serverSocket.close(); } } catch (IOException ioException) { ioException.printStackTrace(); } } } }
- 客户端
public class TestClient { public static void main(String[] args) { //创建 Socket socket= null; OutputStream outputStream= null; ObjectOutputStream objectOutputStream= null; InputStream inputStream= null; DataInputStream dataInputStream= null; try { //1.创建套接字:指定服务器的ip和端口号: socket = new Socket("192.168.200.114",9999); //2.从键盘录入用户名和密码 Scanner scanner = new Scanner(System.in); System.out.print("请输入用户名:"); String name = scanner.next(); System.out.print("请输入密码:"); String pwd = scanner.next(); //封装User对象传递 User user = new User(name,pwd); //2.利用输出流。发送数据 // 利用这个OutputStream就可以向外发送数据了,但是没有直接发送String的方法 // 所以在OutputStream外面套了一个处理流:DataOutputStream outputStream = socket.getOutputStream(); objectOutputStream = new ObjectOutputStream(outputStream);//数据输出流 //发送对象 objectOutputStream.writeObject(user); //3.接收从服务端 发送的消息 inputStream = socket.getInputStream(); dataInputStream = new DataInputStream(inputStream); //接受发送过来的boolean类型的数据 boolean b = dataInputStream.readBoolean(); if (b){ System.out.println("恭喜,登陆成功"); }else { System.out.println("用户名或者密码错误"); } }catch (IOException ioException){ ioException.printStackTrace(); }finally { //关闭流 try { if(dataInputStream != null){ dataInputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(inputStream != null){ inputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(objectOutputStream != null){ objectOutputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(outputStream != null){ outputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(socket != null){ socket.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } } } }
3.5.多线程接受用户请求
服务器针对一个请求服务,之后服务器就关闭了(程序自然结束了)现在需要解决:服务器必须一直在监听 ,一直开着,等待客户端的请求,这里对于服务端进行多线程改造
- 多线程类:ServerThread
public class ServerThread extends Thread{ ServerSocket serverSocket=null; Socket accept=null; InputStream inputStream=null; ObjectInputStream objectInputStream=null; OutputStream outputStream=null; DataOutputStream dataOutputStream=null; public ServerThread(Socket accept) { this.accept = accept; } @Override public void run() { try{ //操作流 inputStream = accept.getInputStream(); objectInputStream = new ObjectInputStream(inputStream);// 数据输入流 //4.读取客户端发来的数据: User user = (User) objectInputStream.readObject(); //验证 boolean flae = false; if(user.getUsername().equals("admin")&& user.getPassword().equals("123321")){ flae = true; } //5.输出客户端信息 System.out.println("接受到客户端发送消息:"+user.toString()); //6.向客户端发送消息 outputStream = accept.getOutputStream(); dataOutputStream = new DataOutputStream(outputStream); //向客户端发送数据 dataOutputStream.writeBoolean(flae); }catch (IOException | ClassNotFoundException e){ e.printStackTrace(); }finally { //6.关闭流操作 try { //不为null在关闭 if(dataOutputStream != null){ dataOutputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(outputStream != null){ outputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(objectInputStream != null){ objectInputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(inputStream != null){ inputStream.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { //不为null在关闭 if(accept != null){ accept.close(); } }catch (IOException ioException){ ioException.printStackTrace(); } try { if(serverSocket != null){ serverSocket.close(); } } catch (IOException ioException) { ioException.printStackTrace(); } } } }
服务端
public class TestServer { public static void main(String[] args){ System.out.println("=================服务端已启动==============="); //1.创建套接字:指定服务器的端口号 ServerSocket serverSocket = null; Socket accept = null; //用于记数,确定客户端的连接次数 int count = 0; try { //创建套接字对象:指定端口号 serverSocket = new ServerSocket(9999); while (true){ //加入死循环,让服务器一直处于监听状态 //阻塞方法:等待接收客户端的数据,什么时候接收到数据,什么时候程序继续向下执行。 accept = serverSocket.accept(); count++; //输入请求的客户端的信息: System.out.println("当前是第"+count+"个用户访问我们的服务器,对应的用户是:"+accept.getInetAddress()); //每次过来的客户端的请求靠线程处理: new ServerThread(accept).start();//创建启动线程 } } catch (IOException ioException) { ioException.printStackTrace(); } } }
执行后结果如下:

四、基于UDP的网络编程
TCP(客户端和服务器端地位不平等):
- 客户端:Socket 程序感受到的 使用流 :输出流
- 服务器端: ServerSocket --->Socket 程序感受到的 使用流 :输入流
UDP(发送方和接收方的地址是平等的):
- DatagramSocket:用于发送或接收数据包的套接字
- DatagramPacket:数据包
- UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象
- 基于UDP协议的通信双方而言,没有客户端和服务器概念
UDP案例: 完成网站的咨询聊天
4.1.单向通信
- 发送方
public class TestSend {//发送方 public static void main(String[] args) throws Exception { System.out.println("发送方 学生上线:"); //1.准备套接字:指定发送方的端口号 DatagramSocket ds = new DatagramSocket(8888); //2.准备数据包 String str1 = "你好呀"; //转换为byte类型 byte[] bytes = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999); //发送 ds.send(dp); //关闭资源 ds.close(); } }
- 接受方
public class TestReceive { public static void main(String[] args) throws IOException { System.out.println("接收方 老师即将上线:"); //1.创建套接字:指定接受方的端口 DatagramSocket ds = new DatagramSocket(9999); //2.创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3.接收对方的数据包,然后放入我们的dp数据包中填充 ds.receive(dp);//接收完以后 dp里面就填充好内容了 //取出数据 byte[] data = dp.getData(); //注意这里不要导错包 String s = new String(data, 0, dp.getLength()); System.out.println("学生说:"+s); //关闭 ds.close(); } }
4.2.双向通信
- 发送方
public class TestSend {//发送方 public static void main(String[] args) throws Exception { System.out.println("发送方 学生上线:"); //1.准备套接字:指定发送方的端口号 DatagramSocket ds = new DatagramSocket(8888); //2.准备数据包 Scanner scanner = new Scanner(System.in); System.out.print("学生输入信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999); //发送 ds.send(dp); //接受老师发送的数据 //创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes2 = new byte[1024]; DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length); ds.receive(dp2);//接收完以后 dp里面就填充好内容了、 //取出数据 //注意这里不要导错包 String s = new String(dp2.getData(), 0, dp.getLength()); System.out.println("老师回复说:"+s); //关闭资源 ds.close(); } }
- 接受方
public class TestReceive { public static void main(String[] args) throws IOException { System.out.println("接收方 老师即将上线:"); //1.创建套接字:指定接受方的端口 DatagramSocket ds = new DatagramSocket(9999); //2.创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3.接收对方的数据包,然后放入我们的dp数据包中填充 ds.receive(dp);//接收完以后 dp里面就填充好内容了 //取出数据 byte[] data = dp.getData(); //注意这里不要导错包 String s = new String(data, 0, dp.getLength()); System.out.println("学生说:"+s); //向学生发送数据 Scanner scanner = new Scanner(System.in); System.out.print("给学生回复信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes2 = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length, InetAddress.getByName("localhost"),8888); //发送 ds.send(dp2); //关闭 ds.close(); } }
4.3.异常处理
- 发送方
public class TestSend {//发送方 public static void main(String[] args) { System.out.println("发送方 学生上线:"); DatagramSocket ds = null; try { //1.准备套接字:指定发送方的端口号 ds = new DatagramSocket(8888); //2.准备数据包 Scanner scanner = new Scanner(System.in); System.out.print("学生输入信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999); //发送 ds.send(dp); //接受老师发送的数据 //创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes2 = new byte[1024]; DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length); ds.receive(dp2);//接收完以后 dp里面就填充好内容了、 //取出数据 //注意这里不要导错包 String s = new String(dp2.getData(), 0, dp.getLength()); System.out.println("老师回复说:"+s); }catch (IOException ioException){ ioException.printStackTrace(); }finally { //关闭资源 if(ds != null){ ds.close(); } } } }
- 接受方
public class TestReceive { public static void main(String[] args) throws IOException { System.out.println("接收方 老师即将上线:"); DatagramSocket ds = null; try { //1.创建套接字:指定接受方的端口 ds = new DatagramSocket(9999); //2.创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3.接收对方的数据包,然后放入我们的dp数据包中填充 ds.receive(dp);//接收完以后 dp里面就填充好内容了 //取出数据 byte[] data = dp.getData(); //注意这里不要导错包 String s = new String(data, 0, dp.getLength()); System.out.println("学生说:"+s); //向学生发送数据 Scanner scanner = new Scanner(System.in); System.out.print("给学生回复信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes2 = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length, InetAddress.getByName("localhost"),8888); //发送 ds.send(dp2); }finally { if(ds != null){ //关闭 ds.close(); } } } }
4.4.正常通信
- 发送方
public class TestSend {//发送方 public static void main(String[] args) { System.out.println("发送方 学生上线:"); DatagramSocket ds = null; try { //1.准备套接字:指定发送方的端口号 ds = new DatagramSocket(8888); while (true){ //2.准备数据包 Scanner scanner = new Scanner(System.in); System.out.print("学生输入信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"),9999); //发送 ds.send(dp); //接受老师发送的数据 //创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes2 = new byte[1024]; DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length); ds.receive(dp2);//接收完以后 dp里面就填充好内容了、 //取出数据 //注意这里不要导错包 String s = new String(dp2.getData(), 0, dp.getLength()); System.out.println("老师回复说:"+s); } }catch (IOException ioException){ ioException.printStackTrace(); }finally { //关闭资源 if(ds != null){ ds.close(); } } } }
- 接受方
public class TestReceive { public static void main(String[] args) throws IOException { System.out.println("接收方 老师即将上线:"); DatagramSocket ds = null; try { //1.创建套接字:指定接受方的端口 ds = new DatagramSocket(9999); while (true){ //2.创建空的数据包,打算用来接收 对方传过来的数据包: byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3.接收对方的数据包,然后放入我们的dp数据包中填充 ds.receive(dp);//接收完以后 dp里面就填充好内容了 //取出数据 byte[] data = dp.getData(); //注意这里不要导错包 String s = new String(data, 0, dp.getLength()); System.out.println("学生说:"+s); //向学生发送数据 Scanner scanner = new Scanner(System.in); System.out.print("给学生回复信息:"); String str1 = scanner.next(); //转换为byte类型 byte[] bytes2 = str1.getBytes(); /* 需要四个参数: 1.指的是传送数据转为字节数组 2.字节数组的长度 3.封装接收方的ip 4.指定接收方的端口号 */ DatagramPacket dp2 = new DatagramPacket(bytes2, bytes2.length, InetAddress.getByName("localhost"),8888); //发送 ds.send(dp2); } }finally { if(ds != null){ //关闭 ds.close(); } } } }

浙公网安备 33010602011771号