文章目录
1(byte)字节 = 8(bit)位;1(KB)千字节 = 1024(byte)字节
网络相关概念
IP地址
IP地址的组成=网络地址+主机地址
IPV4
- 4个字节(32位)表示
- 一个字节有0 ~ ( 2 8 − 1 ) (2^8-1) (28−1)
IPV6
- 16个字节(128位)表示 是IPV4长度的四倍
IPV4分类
127.0.0.1:本机地址
- A类
- A类地址分配的主机号有24位,范围广
- 0.0.0.0 到 127.255.255.255
- B类
- B类地址分配的主机号有16位
- 128.0.0.0 到 191.255.255.255
- C类
- C类地址分配的主机号有8位
- 192.0.0.0 到 223.255.255.255
- D类
- 224.0.0.0 到 239.255.255.255
- E类
- 240.0.0.0 到 247.255.255.255
域名
www.baidu.com
好处:为了方便记忆,解决记ip的困难
概念:将ip地址映射成域名
端口号
- 概念:用于标识计算机上某个特定的网络程序
- 表示形式:以整数形式,范围0~65535 [2个字节表示端口 0 ~ 2 16 − 1 2^{16}-1 216−1]
- 一些知名端口 0~1024已经被占用,比如 ssh 22, ftp 21,smtp 25, http80
- 常见的网络程序端口号:
- tomcat:8080
- mysql:3306
- oracle:1521
- sqlserver:1433
网络通信协议
- 协议(tcp/ip)
TCP/IP (Transmission ControlProtocol/Internet Protocol)的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的1P协议和传输层的TCP协议组成的。
TCP和UDP
- TCP协议:传输控制协议
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用”三次握手”方式(e.g:睡了吗?没睡。上号!),是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- UDP协议:用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内,不适合传输大量数据
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源(因为不是面向连接的),速度快
InetAddress类
- 相关方法
- 获取本机InetAddressi对象: getLocalHost
- 根据指定主机名/域名获取ip地址对象: getByName
- 获取InetAddress对象的主机名: getHostName
- 获取InetAddress对象的地址: getHostAddress
代码
package com.xiaolu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author 林小鹿
* @version 1.0
* InetAddress 类的使用
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
// 1、获取本机的InetAddress 对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost); // DESKTOP-96F95HS/192.168.0.115
// 2、根据指定主机名 获取InetAddress 对象
InetAddress host1 = InetAddress.getByName("DESKTOP-96F95HS");
System.out.println("host1=" + host1);
// 3、根据域名返回InetAddress 对象
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println("host2=" + host2);
// 4、通过InetAddress 对象,获取对应的地址
String baiduIP = host2.getHostAddress();
System.out.println("host2 对应的ip = " + baiduIP);
//5.通过InetAddress对象,获取对应的主机名/或者的域名
String hostName = host2.getHostName();
System.out.println("host2对应的主机名/域名=" + hostName);
}
}
TCP网络通信编程
Socket
底层使用的是TCP/IP协议
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信其实就是Socket间的通信。
- Socket 允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
代码
- 注意:在结束时需要设置写入结束标记 close()
- 字节流: shutdownOutput()
- 字符流:如果用writer.newLine()结束,对方需要使用readLine()方式读取,最后再刷新(flush),如果使用字符流,需要手动刷新,否则数据不会写入到数据通道
客户端
package com.xiaolu.socket;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author 林小鹿
* @version 1.0
* 客户端
*/
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
//思路
//1、连接服务端(IP,端口)
// 连接本机的 9999 端口, 如果连接成功,返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//2.连接上后,生成Socket,通过 socket.getOutputStream()
// 得到 和 socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3、通过输出流,写入数据到数据通道
// outputStream.write("server,睡了吗?".getBytes()); // 使用字节流写入
// 使用字符流写入
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));// 转换流
bufferedWriter.write("server,睡了吗?");
// 设置结束标记
// socket.shutdownOutput(); // 字节流
bufferedWriter.newLine(); // 字符流, 注意:要求对方使用readLine()!!
bufferedWriter.flush(); // 如果使用字符流,需要手动刷新,否则数据不会写入到数据通道
// // 获取和socket关联的输入流,读取数据(字节),并显示
// InputStream inputStream = socket.getInputStream();
// byte[] buf = new byte[1024];
// int readLen = 0;
// while ((readLen = inputStream.read(buf)) != -1) {
// System.out.println(new String(buf, 0, readLen));
// }
// 获取和socket关联的输入流,读取数据(字符),并显示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 4、关闭流对象和socket
// outputStream.close();
// inputStream.close();
bufferedWriter.close();
bufferedReader.close();
socket.close();
System.out.println("客户端已退出....");
}
}
服务端
package com.xiaolu.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 林小鹿
* @version 1.0
* 服务端
*/
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
//思路
//1.在本机的9999端口监听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
//2.当没有客户端连接9999端口时,程序会阻塞,等待连接
// 如果有客户端连接,则会返回Socket对象,程序会继续
System.out.println("服务器端,在9999端口监听,等待连接");
Socket socket = serverSocket.accept();
//3、通过socket.getInputStream()读取客户端写入到数据通道的数据,显示
InputStream inputStream = socket.getInputStream();
// 4、IO读取
// // 使用字节流读取
// byte[] buf = new byte[1024];
// int readLen = 0;
// while ((readLen = inputStream.read(buf)) != -1) {
// System.out.println(new String(buf, 0, readLen));
// }
// 使用字符流来读取
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));// 转换流
String s = bufferedReader.readLine();
System.out.println(s);
// 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
// outputStream.write("没睡呢~~~".getBytes()); // 使用字节流传输回复
// 使用字符流传输回复
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("a");
// 设置结束标记
// socket.shutdownOutput(); // 使用字节流关闭
// 使用字符流关闭
bufferedWriter.newLine(); // 字符流, 注意:要求对方使用readLine()!!
bufferedWriter.flush(); // 如果使用字符流,需要手动刷新,否则数据不会写入到数据通道
// 关闭流和socket
// inputStream.close();
// outputStream.close();
bufferedReader.close();
bufferedWriter.close();
socket.close();
serverSocket.close();
}
}
传输文件案例
工具类StreamUtils代码
package com.xiaolu.socket;
import java.io.*;
/**
* @author 林小鹿
* @version 1.0
*/
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);
}
byte[] array = bos.toByteArray();
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();
}
}
客户端代码
package com.xiaolu.socket;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author 林小鹿
* @version 1.0
* 文件上传的客户端
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
// 客户端连接服务端 8888, 得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 创建读取磁盘文件的输入流
String filePath = "d:\\0.png";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// 转成字节数组
// bytes 就是filePath对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 通过socket获取到输出流,将bytes数据发送给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
socket.shutdownOutput();// 设置写入数据的结束标记
//====接收从服务端回复的消息
InputStream inputStream = socket.getInputStream();
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
// 关闭相关的流
inputStream.close();
bos.close();
bis.close();
socket.close();
}
}
服务端代码
package com.xiaolu.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 林小鹿
* @version 1.0
* 文件上传的服务端
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
// 1.服务端在本机监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口监听");
// 2.等待连接
Socket socket = serverSocket.accept();
// 3.读取客户端发送的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
String destFilePath = "src\\girl.png";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
// 向客户端回复 收到图片
// 通过socket 获取到输出流(字符)
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("收到图片");
writer.flush();
socket.shutdownOutput();//设置写入数据的结束标记
// 关闭相关的流
writer.close();
bis.close();
bos.close();
socket.close();
serverSocket.close();
}
}
netstat指令
- netstat -an可以查看当前主机网络情况,包括端口监听情况和网络连接情况
- netstat -anb可以查看更多信息,包括应用程序
- netstat -an | more可以分页显示
- 要求在dos控制台下执行
UDP网络通信编程
- 类DatagramSocket和DatagramPacket[数据包/数据报]实现了基于UDP协议网络程序。
- UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的P地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接
UDP说明
- 没有明确的服务端和客户端,演变成数据的发送端和接收端
- 接收数据和发送数据是通过DatagramSocket对像完成
- 将数据封装到DatagramPacket对象/装包
- 当接收到DatagramPacket对象,需要进行拆包,取出数据
- DatagramSocket可以指定在哪个端口接收数据
代码A端
package com.xiaolu.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* @author 林小鹿
* @version 1.0
* UDP接收端
*/
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
//1.创建一个 DatagramSocket 对象,准备在9999接收数据
DatagramSocket socket = new DatagramSocket(9999);
//2.构建一个 DatagramPacket 对象,准备接收数据,一个数据包最大 64k
byte[] buf = new byte[64 * 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);
//===回复信息给B端
//将需要发送的数据,封装到 DatagramPacket对象
data = "好的,明天见".getBytes();
// 说明:封装的 DatagramPacket对象 data 内容字节数组, data.length, 主机(IP), 端口
packet =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.115"), 9998);
// 发送数据
socket.send(packet);
//5.关闭资源
socket.close();
System.out.println("A端退出");
}
}
代码B端
package com.xiaolu.udp;
import java.io.IOException;
import java.net.*;
/**
* @author 林小鹿
* @version 1.0
* UDP发送端B ====> 也可以接收数据
*/
public class UDPSenderB {
public static void main(String[] args) throws IOException {
//1.创建 DatagramSocket 对象,准备在9998端口 接收数据
DatagramSocket socket = new DatagramSocket(9998);
//2.将需要发送的数据,封装到 DatagramPacket对象
byte[] data = "hello 明天吃火锅~".getBytes();
// 说明:封装的 DatagramPacket对象 data 内容字节数组, data.length, 主机(IP), 端口
DatagramPacket packet =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.0.115"), 9999);
// 发送数据
socket.send(packet);
//=== 接收A端回复的信息
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String s = new String(packet.getData(), 0, packet.getLength());
System.out.println(s);
// 关闭资源
socket.close();
System.out.println("B端退出");
}
}
音乐文件下载案例
客户端代码
package com.xiaolu.socket;
import java.awt.image.BufferedImageFilter;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* @author 林小鹿
* @version 1.0
* 音乐文件下载案例
* 文件下载的客户端
*/
public class Homework01Client {
public static void main(String[] args) throws Exception {
// 1.接收用户输入,指定下载文件名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入下载文件名:");
String downloadFileName = scanner.next();
//2.客户端连接服务端,准备发送
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//3.获取和Socket关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write(downloadFileName.getBytes());
socket.shutdownOutput(); // 结束标志
//4.读取服务端返回的文件(字节数据)
BufferedInputStream bis =
new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//5.得到一个输出流,准备将 bytes 写入到磁盘文件
String filePath = "d:\\" + downloadFileName + ".mp3";
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);
//6.关闭相关的流
bos.close();
bis.close();
outputStream.close();
socket.close();
System.out.println("下载完毕");
}
}
服务端代码
package com.xiaolu.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 林小鹿
* @version 1.0
* 文件下载的服务端
*/
public class Homework01Server {
public static void main(String[] args) throws Exception {
//监听 9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//2.等待客户端连接
System.out.println("服务端在9999端口监听,等待下载文件");
Socket socket = serverSocket.accept();
//3.读取 客户端发送要下载的文件名
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1) {
downLoadFileName += new String(b, 0 , len);
}
System.out.println("客户端希望下载的文件名=" + downLoadFileName);
// 服务器上返回客户端需要下载的音乐文件
String resFileName = "";
if ("高山".equals(downLoadFileName)) {
resFileName = "src\\高山.mp3";
}else {
resFileName = "src\\日系.mp3";
}
//4.创建一个输入流,读取文件
BufferedInputStream bis =
new BufferedInputStream(new FileInputStream(resFileName));
//5.使用工具类 StreamUtils,读取文件到一个字节数组里
byte[] bytes = StreamUtils.streamToByteArray(bis);
//6.得到Socket关联的输出流
BufferedOutputStream bos =
new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
socket.shutdownOutput(); // 结束标记
//关闭相关的流
bis.close();
inputStream.close();
bos.close();
socket.close();
serverSocket.close();
}
}
本文含有隐藏内容,请 开通VIP 后查看