Java学习-11-韩顺平老师
Java-网络编程入门
目录:
01-网络相关概念
02-InetAddress类
03-套接字Socket
04-网络上传和下载文件
05-UDP网络编程
网络编程相关概念
网络通信:
1.概念:两台设备之间通过网络实现数据传输。
2.网络通信:将数据通过网络从一台设备传输到另一台设备。
3.java.net包下提供了一系列的类或者接口,供程序员使用,完成网络通信。
网络:
1.概念:两台或者多台设备通过一个定物理设备连接起来构成的网络。
2.根据覆盖范围不同,对网络的进行分类:
局域网:覆盖范围小。
城域网:覆盖范围较大,可以覆盖一个城市。
广域网:覆盖范围大,可以覆盖全国,甚至全球。
ip地址:
1.概念:用于唯一标识一网络中的每台计算机。
2.查看ip地址:ipconfig
3.ip地址表示形式:十进制 xxx.xxx.xxx.xxx
4.每个十进制范围0-255
5.ip地址组成 = 网络地址 + 主机地址。
6.ipv6是互联网工程任务组设计的用于替代ipv4的下一代ip协议。
7.ip地址分为五类:A,B,C,D,类,第一个十进制位每一级向左位移一位。
域名和端口号:
1.域名是ip地址的映射。
2.端口号用于标识计算机上某一个特定的网络程序。
网络协议:
TCP协议:
1.使用TCP协议前,需先 建立TCP连接,形成传输数据的通道。
2.传输前,采用“三次握手”方法,可以可靠传输。
3.TCP协议进行痛的两个应用进程:客户端、服务端。
4.在连接中可进行大数量的传输。
5.传输完成,需释放已建立的连接。
UDP协议:
1.将数据、源、目的封装成数据包,不需要建立连接。
2.每个数据报的大小限制在64k内。
3.因无需连接,故是不可靠的。
4.发送数据结束时无需释放资源(因为不是面向连接的),速度快。
InetAddress类
相关方法:
1.getLocalHost:获取主机InetAddress对象。
2.getByName:根据指定主机名/域名获取ip地址对象。
3.getHostName:获取InetAddress对象的主机名。
4.getHostAddress:获取InetAddress对象的地址。
public class InetAddress_ {
public static void main(String[] args) throws UnknownHostException {
// 获取本地主机的ip地址对象
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(inetAddress); // DESKTOP-IFINBBF/127.0.0.1
InetAddress byName = InetAddress.getByName("DESKTOP-IFINBBF");
System.out.println(byName); // DESKTOP-IFINBBF/127.0.0.1
// 通过域名或者主机名来获取ip地址对象
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1); // www.baidu.com/36.152.44.95
// getHostName
System.out.println(byName1.getHostName()); // www.baidu.com
// getAddress
System.out.println(byName1.getHostAddress()); // 36.152.44.95
}
}
套接字Socket
基本介绍:
1.套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
2.网络通信两端都要有Socket,两台机器之间通信的端点。
3.网络通信其实就是Socket之间的通信。
4.Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
5.一般主动发起网络通信的是客户端,等待通信请求的位服务端。
TCP网络通信编程:
1.基于客户端-服务端网络通信。
2.底层使用的是TCP/IP协议。
基于Socket的TCP网络通信编程:
具体实例:
1.编写一个服务端,和一个客户端。
2.服务器在9999端口监听。
3.客户端连接到服务器段,发送"hello,serve",并接受服务器发的
“hello,client”,在退出
4.服务器端接受到客户端发送的信息,输出,并发送“hello,client”
使用字节流实现
服务端:
public class SocketServe_ {
public static void main(String[] args) throws IOException {
// 创建一个ServeSocket对象
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端正在监听9999端口...");
// 监听 9999 端口 并且返回一个socket对象
Socket socket = serverSocket.accept();
// 通过socket.getInputStream获得一个InputStream对象,接受客户端信息
InputStream inputStream = socket.getInputStream();
int len = 0;
byte[] buf = new byte[1024];
while ((len = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,len));
}
// 通过socket.getOutputStream 获得一个OutputStream 向客户端发送信息
String str = "hello,client";
OutputStream outputStream = socket.getOutputStream();
outputStream.write(str.getBytes());
// 标识已经发送完成,让服务器不要再等待,可以执行下面的代码了
socket.shutdownOutput();
System.out.println("服务端退出了");
// 关闭socket和流,释放资源
inputStream.close();
outputStream.close();
socket.close();
}
}
客户端:
public class SocketClient_ {
public static void main(String[] args) throws IOException {
// 创建一个Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 通过socket.getOutputStream 获得一个OutputStream 向服务端发送信息
OutputStream outputStream = socket.getOutputStream();
String str = "hello,server";
outputStream.write(str.getBytes());
// 标识已经发送完成,让服务器不要再等待,可以执行下面的代码了
socket.shutdownOutput();
// 通过socket.getInputStream获得一个InputStream对象,接受服务端信息
InputStream inputStream = socket.getInputStream();
int len = 0;
byte[] buf = new byte[1024];
while ((len = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,len));
}
socket.shutdownInput();
System.out.println("客户端退出了");
// 关闭socket和流,释放资源
outputStream.close();
inputStream.close();
socket.close();
}
}
使用字符流实现:
服务端:
public class SocketServe01 {
public static void main(String[] args) throws IOException {
// 创建一个ServeSocket对象
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端正在监听9999端口...");
// 监听 9999 端口 并且返回一个socket对象
Socket socket = serverSocket.accept();
// 通过socket.getInputStream获得一个InputStream对象,
// 再通过InputStreamReader 转换成字符流,接受服务端信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 只能使用一次readLine,否则下面代码不再执行
System.out.println(br.readLine());
// 通过socket.getOutputStream 获得一个OutputStream
// 再将字节流通过OutputStreamWriter装换成字符流,再向服务端发送信息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String str = "hello,client";
bw.write(str);
// 使用bw.newLine 表示写入完成,就不需要socket.shutdownOutput()了
// 但是接受方,必须使用 readLine 接收
bw.newLine();
//使用Writer子类 一定要flush以下,不然没有真正的写入socket中
bw.flush();
System.out.println("服务端退出了");
// 关闭socket和流,释放资源
br.close();
bw.close();
socket.close();
}
}
客户端:
public class SocketClient01 {
public static void main(String[] args) throws IOException {
// 创建一个Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 通过socket.getOutputStream 获得一个OutputStream
// 再将字节流通过OutputStreamWriter装换成字符流,再向服务端发送信息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String str = "hello,server";
bw.write(str);
// 使用bw.newLine 表示写入完成,就不需要socket.shutdownOutput()了
// 但是接受方,必须使用 readLine 接收
bw.newLine();
// 使用Reader子类写入必须flush一下,不然没有真正写入
bw.flush();
// 标识已经发送完成,让服务器不要再等待,可以执行下面的代码了
// socket.shutdownOutput();
// 通过socket.getInputStream获得一个InputStream对象,
// 再通过InputStreamReader 转换成字符流,接受服务端信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(br.readLine());
System.out.println("客户端退出了");
// 关闭socket和流,释放资源
bw.close();
br.close();
socket.close();
}
}
网络上传和下载文件
1.上传文件:
1.编写一个服务端和客户端
2.服务器端再9999接口监听
3.客户端接受服务端,发送的一张图片 e:\\a.png
4.服务端接受图片,保存到src目录下,并发送服务端收到了图片,在退出
5.客户端接受服务端信息,并打印出来,在退出
6.使用到StreamUtils.java这个自己封装的工具类
自定义工具类 StreamUtils.java : 实现文件读取 字节数组 和 字符串之间的转换
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
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 转成字节数组
bos.close();
return array; // 返回字节数组
}
/**
* 功能:将InputStream转换成String
* @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();
}
}
服务端:
public class UploadServe {
public static void main(String[] args) throws Exception {
// 建立服务器
ServerSocket serverSocket = new ServerSocket(9999);
// 监听9999端口
System.out.println("服务端正在监听 9999 端口,等待接受数据");
Socket socket = serverSocket.accept();
// 通过 socket.getInputStream() 获得一个InputStream流来读取网络传输数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 标识已经读写完成
socket.shutdownInput();
// 将读取成功的数据写入内存 src\\a.jpg
BufferedOutputStream bos1 = new BufferedOutputStream(new FileOutputStream("src\\a.jpg"));
bos1.write(bytes);
// 刷新以下
bos1.flush();
bos1.close();
// 返回一个 “文件读取成功”
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write("文件读取成功".getBytes());
// 标识已经写入完成
socket.shutdownOutput();
// 关闭相关资源
bis.close();
bos.close();
socket.close();
serverSocket.close();
}
}
客户端:
public class UploadClient {
public static void main(String[] args) throws Exception {
// 常见一个socket
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//将 e:\\a.jpg 读出,并放在byte数组中,使用StreamUtils工具
byte[] buf; // 存储图片数组
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\a.jpg"));
buf = StreamUtils.streamToByteArray(bis);
// 通过socket获得一个OutPutStream 来发送数据
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
// 将字符数组写入到网络中
bos.write(buf);
// 添加写入完成表示符
socket.shutdownOutput();
// 接受服务端传来的数据
BufferedInputStream bis1 = new BufferedInputStream(socket.getInputStream());
String str = StreamUtils.streamToString(bis1);
System.out.println(str);
System.out.println("客户端退出");
// 关闭相关流,释放资源
bis.close();
bos.close();
bis1.close();
socket.close();
}
}
2.下载文件
1.编写一个服务端和客户端
2.服务器端再9999接口监听
3.服务端发送需要下载图片的名称 "伤感头像.jpg"
4.服务端接受图片名称,从e盘目录下返回图片给客户端,如果没有"伤感头像.jpg",就返回"默认头像.jpg"
5.客户端接受到数据后保存到本地 d:\\xxx.jpg
6.使用到StreamUtils.java这个自己封装的工具类
StreamUtils.java: 仍然使用上面自己定义的工具类
服务端:
public class DownLoadServer {
public static void main(String[] args) throws Exception {
// 创建监听器
ServerSocket serverSocket = new ServerSocket(9999);
// 监听9999端口
System.out.println("服务端正在监听9999端口,等待接受文件名称");
Socket socket = serverSocket.accept();
// 创建接受文件名称
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downFileName = "";
while ((len = inputStream.read(b)) != -1){
downFileName += new String(b,0,len);
}
String resFileName = "";
if("伤感图片.jpg".equals(downFileName)){
resFileName = "e:\\伤感图片.jpg";
}else{
resFileName = "e:\\默认图片.jpg";
}
System.out.println(resFileName);
// 通过文件名从src目录中读取文件,转换成byte[]数组
BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream(resFileName));
byte[] bytes = StreamUtils.streamToByteArray(bis1);
// 将数据通过 socket.getOutputStream 发送给客户端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
// 标识已经写入完成
socket.shutdownOutput();
// 关闭相关资源
inputStream.close();
bis1.close();
bos.close();
socket.close();
serverSocket.close();
}
}
客户端:
public class DownloadClient {
public static void main(String[] args) throws Exception {
// 我这里是对本机操作,所以使用的getLocalHost获取ip地址,
// 如果其他服务器就是用 InetAddress.getByName() + ip 地址来获取
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// 发送图片名称
String downLoadName = "伤感图片.jpg";
OutputStream outputStream = socket.getOutputStream();
outputStream.write(downLoadName.getBytes());
socket.shutdownOutput(); // 标识已经写入完成
// 当服务器返回数据,就收服务器返回的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis); // 获取文件数据的字节数组形式
// 将数据写入到e盘下
BufferedOutputStream bos1 = new BufferedOutputStream(new FileOutputStream("d:\\" + downLoadName));
bos1.write(bytes); // 写入e盘
// 关闭相关资源
bis.close();
outputStream.close();
bos1.close();
socket.close();
}
}
UDP网络编程
应用案列:
1.编写一个接受接收端A,和一个发送端B.
2.接收端A在9999端口等待接受数据(receive)
3.发送端A向接受B发送数据"hello,明天吃火锅"
4.接受端B接受到 A发送的信息,回复"好的,明天见",再退出
5.接收到接受到数据后再退出
发送方:
public class Send {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(8888);
// 创建一个 DatagramPacket 并且指定发送的ip地址和端口号、
byte[] data = "hello,明天吃火锅".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data,data.length, InetAddress.getLocalHost(),9999);
datagramSocket.send(datagramPacket);
// 接收接收方数据
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes,bytes.length);
datagramSocket.receive(packet);
// 拆包
byte[] data1 = packet.getData();
int length = packet.getLength();
String s = new String(data1, 0, length);
System.out.println(s);
}
}
接收方:
public class Receive {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(9999);
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,1024);
// 接受数据,并放在 datagramPacket
System.out.println("接受方正在端口9999,等待接受数据");
datagramSocket.receive(datagramPacket);
// 拆包
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String s = new String(data, 0, length);
System.out.println(s);
// 发送数据给发送方
byte[] data1 = "好的,明天见".getBytes();
DatagramPacket packet = new DatagramPacket(data1,data1.length, InetAddress.getLocalHost(),8888);
datagramSocket.send(packet);
}
}