系列文章目录
Java基础篇之jdk、jre环境变量的配置
第一章 – Java基本语法
第六章 – Java集合
第七章 – Java网络编程(一)
第七章 – Java网络编程(二)
第七章 – Java网络编程(三)
前言
本章节介绍两个网络编程的经典案例,涉及字节流编程、字符流编程,以及网络文件下载操作
一、TCP协议使用字符流完成数据传输
要求:
- 使用字符流的方式,编写一客户端程序和服务端程序
- 客户端发送”name”,服务器端接收到后,返回”我是nova”,nova是你自己的名字
- 客户端发送”hobby”,服务器端接收到后,返回”编写java程序”
- 不是这两个问题,回复”你说啥呢”
实现思路:
服务端:
- 首先服务端需要在IP:端口进行监听,即创建一个服务端
- 服务端等待客户端连接,如果没有客户端连接,将卡在这儿不往下执行
- 有客户端连接,则拿到这个socket,获取到关联socket的字符输入流,获取客户端从数据通道发送的数据
- 拿到数据后,判断客户端说了啥(可用switch,也可用if-else结构,判断,目前只支持一次通讯,如果可以多次通讯即扩展为聊天功能),按要求返回对应的字符串
- 获取socket相关联的字符输出流,将字符串写入数据通道
- 设置写入结束标记(很重要,如果不设置客户端不知道是不是写完了,将会卡顿)
- 发送完数据后,将相关流资源关闭
客户端:
- 创建一个客户端,通过IP:端口连接上服务端
- 获取socket相关联的字符输出流,将数据写入数据通道
- 设置写入结束标记
- 获取socket相关的字符输入流,获取服务端返回的数据
- 将数据打印出来
- 关闭相关资源
代码实现:
- 服务端:
package com.cuinn.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
* 使用字符流
*/
@SuppressWarnings({"all"})
public class Homework01Server {
public static void main(String[] args) throws IOException {
// 1.创建服务端socket
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接...");
// 2.等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("socket=" + socket.getClass());
// 3.获取客户端在数据通道写入的数据
InputStream inputStream = socket.getInputStream();
// 4.IO读取
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 5.向数据通道写入数据
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
// 6.判断从数据通道获取的数据是什么
switch (s){
case "name":
bufferedWriter.write("我是nova");
break;
case "hobby": bufferedWriter.write("编写java程序");
break;
default: bufferedWriter.write("你说啥呢");
}
bufferedWriter.newLine();
bufferedWriter.flush();
// 6.关闭外层流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
}
}
- 客户端:
package com.cuinn.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端
* 使用字符流
*/
@SuppressWarnings({"all"})
public class Homework01Client {
public static void main(String[] args) throws IOException {
// 1.创建客户端socket
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端 socket返回=" + socket.getClass());
// 2.获取输出流
OutputStream outputStream = socket.getOutputStream();
// 3.向数据通道写数据
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
// 4.从键盘读取用户的问题
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的问题");
String question = scanner.next();
bufferedWriter.write(question);
bufferedWriter.newLine();// 插入一个换行符,表示写入内容结束,要求对方使用readLine()
bufferedWriter.flush();// 如果使用字符流需要手动刷新,否则数据不会写入数据通道
// 5.获取输入流
InputStream inputStream = socket.getInputStream();
// 6.读取服务端写入数据通道的数据
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 7.关闭外层流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
System.out.println("客户端退出...");
}
}
二、UDP协议实现单次通讯
要求:
- 编写一个接收端A,和一个发送端B,使用UDP协议完成
- 接收端在8888端口等待接收数据(receive)
- 发送端向接收端发送数据”四大名著是哪些”
- 接收端接收到发送端发送的问题后,返回”四大名著是《红楼梦》…”,否则返回what?
- 接收端和发送端程序退出
实现思路:
接收端:
- 创建一个DatagramSocket对象,固定一个端口,准备在这个端口接收数据
- 构建一个DatagramPacket对象,准备接收数据
- 调用接收方法, 将通过网络传的DatagramPacket对象填充到packet对象
- 可以把packet进行拆包,取出数据,并显示。
- 判断发送端发送的是什么,按要求回复
- 创建DatagramPacket对象,装包,发送给对方
- 关闭相关资源
发送端:
- 创建一个DatagramSocket对象,固定一个端口,准备在这个端口接收数据
- 从键盘读取数据,将需要发送的数据,封装到DatagramPacket对象
- 装包,发送数据(data内容字节数组,data.length, 主机(IP),端口)
- 接收发送端发送的数据报
- 数据填充到packaet
- 拆包
- 关闭相关资源
代码实现:
- 接收端A:
package com.cuinn.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* @author ckwu
* @version 1.0
* @project JavaProject
* @description 接收端A
* @date 2022-10-06 12:58:54
*/
@SuppressWarnings({"all"})
public class Homework02ReceiveA {
public static void main(String[] args) throws IOException {
// 1.创建一个DatagramSocket对象,准备在9999接收数据
DatagramSocket socket = new DatagramSocket(8888);
// 2.构建一个DatagramPacket对象,准备接收数据
// UDP协议数据包最大64k
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// 3.调用接收方法, 将通过网络传的DatagramPacket对象填充到packet对象
// 提示:当有数据包发送到本机的9999端口时,就会接收到数据,如果没有数据报发送到本机的9999端口,就会阻塞等待。
System.out.println("接收端A 等待接收数据..。");
socket.receive(packet);
// 4.可以把packet进行拆包,取出数据,并显示。
int length = packet.getLength();// 世界接收的数据字节长度
byte[] data = packet.getData();// 接收到的数据
String s = new String(data, 0, length);
System.out.println(s);
String answer = "";
if ("四大名著是哪些".equals(s)){
answer = "四大名著是《红楼梦》《西游记》《三国演义》《水浒传》";
}else {
answer = "what?";
}
// 5.向接收端B回复“好的,明天见”
data = answer.getBytes();
packet = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.107"), 9998);
// 6.发送数据包
socket.send(packet);
// 5.关闭资源
socket.close();
System.out.println("A端退出...");
}
}
- 发送端B:
package com.cuinn.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* @author ckwu
* @version 1.0
* @project JavaProject
* @description 发送端B
* @date 2022-10-06 13:01:00
*/
@SuppressWarnings({"all"})
public class Homework02SenderB {
public static void main(String[] args) throws IOException {
// 1.创建DatagramSocket对象,准备在9998端口接收数据
DatagramSocket socket = new DatagramSocket(9998);
// 2.将需要发送的数据,封装到DatagramPacket对象
// 从键盘读取数据
System.out.println("请输入你的问题:");
Scanner scanner = new Scanner(System.in);
String question = scanner.next();
byte[] data = question.getBytes();
// 说明:封装的DatagramPacket对象 data内容字节数组,data.length, 主机(IP),端口
DatagramPacket packet =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.107"), 8888);
socket.send(packet);
// 3.接收发送端A发送的数据报
data = new byte[1024];
packet = new DatagramPacket(data, data.length);
// 4.数据填充到packaet
socket.receive(packet);
// 5.拆包
data = packet.getData();
int length = packet.getLength();
String s = new String(data, 0, length);
System.out.println(s);
//3.关闭资源
socket.close();
System.out.println("");
System.out.println("B端退出...");
}
}
三、网络文件下载
要求:
- 编写客户端程序和服务端程序
- 客户端可以输入一个音乐文件名,比如高山流水,服务端收到音乐名后,可以给客户端返回个音乐文件,如果服务器没有这个文件,返回一个默认的音乐即可。
- 客户端收到文件后,保存到本地d:\
图解:
代码实现:
- 服务端:
package com.cuinn.homework;
import com.cuinn.upload.StreamUtils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author ckwu
* @version 1.0
* @project JavaProject
* @description 服务端
* @date 2022-10-06 22:15:42
*/
public class Homework03Server {
public static void main(String[] args) throws Exception {
// 1.创建服务端,在9999端口监听
ServerSocket serverSocket = new ServerSocket(9999);
// 2.等待连接
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
// 3.读取客户端写入数据通道的数据
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
String downloadFileName = "";
while((len = inputStream.read(buf)) != -1){
downloadFileName += new String(buf, 0, len);
}
System.out.println("客户端希望下载的文件名:" + downloadFileName);
// 如果客户下载的是空心,返回空心.mp3,否则一律返回声声唱.mp3
String resFileName = "";
if("空心".equals(downloadFileName)){
resFileName = "src\\空心.mp3";
}else {
resFileName = "src\\声声唱.mp3";
}
// 4.创建一个输入流读取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resFileName));
// 5.使用工具类读取到一个字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 6.得到socket关联的输出流
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// 7.写入到数据通道,返回给客户端
bos.write(bytes);
socket.shutdownOutput();// 设置结束标记
// 8.关闭相关资源
bis.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出...");
}
}
- 客户端:
package com.cuinn.homework;
import com.cuinn.upload.StreamUtils;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* @author ckwu
* @version 1.0
* @project JavaProject
* @description 客户端
* @date 2022-10-06 22:16:04
*/
public class Homework03Client {
public static void main(String[] args) throws Exception {
// 1.接收用户指定下载的文件名
System.out.println("请输入要下载的文件名;");
Scanner scanner = new Scanner(System.in);
String fileName = scanner.next();
// 2.连接服务端,准备发送文件名
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 3.获取要写入文件名的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write(fileName.getBytes());
// 设置写入结束标记
socket.shutdownOutput();
// 4.读取服务端返回的字节数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 5.得到一个输出流,准备将bytes写入到磁盘
String destFileName = "d:\\" + fileName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFileName));
bos.write(bytes);
// 6.关闭相关资源
bos.close();
bis.close();
outputStream.close();
socket.close();
System.out.println("客户端下载完毕,正确退出...");
}
}
工具类:
package com.cuinn.upload;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 流处理工具类
*/
public class StreamUtils {
/**
* 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
* @param is
* @return
* @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];// 字节数组
int len;
while((len = is.read(b)) != -1){// 循环读取
bos.write(b, 0, len);// 然后将bos转换成字节数组
}
byte[] array = bos.toByteArray();
bos.close();
return array;
}
/**
* 功能,将输入流获取的内容转换成字符串
* @param is
* @return
* @throws Exception
*/
public static String streamToString(InputStream is) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while((line=reader.readLine()) != null){
builder.append(line+"\r\n");
}
return builder.toString();
}
}
总结
网络章节的相关知识及案例分了几篇文章来讲解,这样或许更详细点,不至于显得一篇下来,文章内容臃肿,接下来会写一些实战类类似于聊天的功能,希望支持,和大家一起进步。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71705.html