24.01 网络编程
A:网络模型
网络模型一般是指
OSI(Open System Interconnection开放系统互连)七层参考模型
TCP/IP四层参考模型
主机至网络层(物理层,数据链路层),网际层,传输层,应用层(
应用层,表示层,会话层)
网络模型7层概述:
1.物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口
类型、各种传输介质的传输速率等。主要作用是传输比特
流
2.数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)
的封装与解封装。常把这一层的数据叫做帧。
3.网络层:主要将从下层接收到的数据进行IP地址的封装与解封装。
在这一层工作的设备是路由器,这一层的数据叫数据包。
4.传输层:定义了一些传输数据的协议和端口号。主要是将从下层接
收的数据进行分段和传输,到达目的地址后再进行重组。
这一层数据叫段。
5.会话层:通过传输层建立数据传输的通路。
主要在系统之间发起会话或者接受会话请求。
6.表示层:主要是进行对接的数据进行解释、加密与解密、压缩与解
压缩等。
7.应用层:主要是一些终端的应用。
24.02 网络编程三要素
A:IP地址:InetAddress:网络中设备的标识,不易记忆,可用主机名
B:端口号:用于标识进程的逻辑地址,不同进程的标识
C:传输协议:常见TCP、UDP
24.03 InetAddress类的概述和使用
A:InetAddress类的概述
为了方便我们对IP地址的获取和操作,此类表示互联网协议(IP)地址。
B:InetAddress类的常见功能
public static InetAddress getByName(String host)
public String getHostAddress() //获取IP
public String getHostName() //获取主机名
getLocalHost()
public static void main(String[] args) throws UnknownHostException {
InetAddress address = InetAddress.getByName("LAPTOP-GM5215VR"); //传入主机名或ip都可以
String hostName = address.getHostName();
String ip = address.getHostAddress();
System.out.println(hostName);
System.out.println(ip);
//获取主机名和ip
InetAddress localHost = address.getLocalHost();
System.out.println(localHost);
//获取所有的ip
InetAddress[] allByName = InetAddress.getAllByName("LAPTOP-GM5215VR");
for (InetAddress inetAddress : allByName) {
String hostAddress = inetAddress.getHostAddress();
System.out.println(hostAddress);
}
}
24.04 Socket通信原理图解
A:Socket套接字概述:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的
标识符套接字。
B:Socket原理机制:
通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
UDP通讯原理图
/*
DatagramPacket此类表示数据报包。
数据报包用来实现无连接包投递服务。
每条报文仅根据该包中包含的信息从一台机器路由到另一台机器
从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的
顺序到达。
不对包投递做出保证。
*/
import java.io.IOException;
import java.net.*;
public class UDPClient {
public static void main(String[] args) throws IOException {
//1.创建客户端的Socket
DatagramSocket ds = new DatagramSocket();
//2.发送数据
//把数据放到数据报包里面,进行发送
/*
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为length的包发送到指定主机上的指定端
口
*/
String msg = "你好UDP,我来了";
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.80.1"), 8888); //端口自己指定,最多不超过65535
ds.send(packet);
//3.释放资源
ds.close();
}
}
/*
DatagramSocket(int port)
创建数据包套接字并将其绑定到本地主机上的指定端口
创建服务端的Socket并暴露端口号
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPServer {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(8888);
System.out.println("服务器已经开启,等待连接......");
//接收数据 receive() 阻塞式方法,如果没有接收到数据报包,就一直
//处于阻塞等待的状态。
/*
从此套接字接收数据报包。当此方法返回时,DatagramPacket的缓冲
区填充了接收的数据。
数据报包也包含发送方的IP地址和发送方机器上的端口号。
此方法在接收到数据包前一直阻塞。
数据报包对象的length字段包含所接收信息的长度。
如果信息比包的长度长,该信息将被截短
*/
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
ds.receive(datagramPacket);
//取出数据报包
byte[] data = datagramPacket.getData();
//获取数据报包中的数据的实际长度
int length = datagramPacket.getLength();
//获取到客户端的ip
String ip = datagramPacket.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip + "发来消息" + s);
}
}
public class UDPClient {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入要发送的消息");
String msg = reader.readLine();
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.80.1"), 6666);
ds.send(packet);
if ("886".equals(msg)){
break;
}
}
ds.close();
}
}
public class UDPServer {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(6666);
System.out.println("服务器已经开启,等待连接.....");
while (true){
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(dp);
//取出数据
byte[] data = dp.getData();
int length = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip+" 发来消息: "+s);
if ("886".equals(s)){
break;
}
}
datagramSocket.close();
}
}
public class Demo01Thread {
public static void main(String[] args) throws SocketException {
DatagramSocket server = new DatagramSocket(6666);
DatagramSocket client = new DatagramSocket();
new UDPServerThread(server).start();
new UDPClientThread(client).start();
}
}
public class UDPClientThread extends Thread{
DatagramSocket ds = null;
public UDPClientThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入要发送的消息");
String msg = reader.readLine();
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.80.1"), 6666);
ds.send(packet);
if ("886".equals(msg)){
break;
}
}
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class UDPServerThread extends Thread{
DatagramSocket datagramSocket = null;
public UDPServerThread(DatagramSocket datagramSocket) {
this.datagramSocket = datagramSocket;
}
@Override
public void run() {
System.out.println("服务器已经开启,等待连接.....");
try {
while (true){
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(dp);
//取出数据
byte[] data = dp.getData();
int length = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip+" 发来消息: "+s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class A {
public static void main(String[] args) throws IOException {
//先开启子线程
new Thread(){
@Override
public void run() {
try {
DatagramSocket datagramSocket = new DatagramSocket(6666); //不同主机端口号可以不一样
System.out.println("A服务器已经开启,等待连接.....");
while (true){
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(dp);
//取出数据
byte[] data = dp.getData();
int length = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip+" B发来消息: "+s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
//主线程来发送消息
sendMsg();
}
private static void sendMsg() throws IOException {
DatagramSocket ds = new DatagramSocket();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入要发送B的消息");
String msg = reader.readLine();
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.80.1"), 8888);
ds.send(packet);
if ("886".equals(msg)){
break;
}
}
ds.close();
}
}
public class B {
public static void main(String[] args) throws IOException {
//先开启子线程
new Thread(){
@Override
public void run() {
try {
DatagramSocket datagramSocket = new DatagramSocket(8888);
System.out.println("B服务器已经开启,等待连接.....");
while (true){
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(dp);
//取出数据
byte[] data = dp.getData();
int length = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String s = new String(data, 0, length);
System.out.println(ip+" A发来消息: "+s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
//主线程来发送消息
sendMsg();
}
private static void sendMsg() throws IOException {
DatagramSocket ds = new DatagramSocket();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println("请输入要发送A的消息");
String msg = reader.readLine();
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.80.1"), 6666);
ds.send(packet);
if ("886".equals(msg)){
break;
}
}
ds.close();
}
}
/*
TCP 打电话 视频
建立连接,形成传输数据的通道;
在连接中进行大数据量传输;
需要连接所以可靠协议;
必须建立连接,效率会稍低
类 Socket 此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号
*/
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket sk = new Socket("192.168.80.1", 7777);
//获取通道中的输出流
OutputStream out = sk.getOutputStream();
//写出数据
out.write("你好TCP我来了".getBytes());
//释放资源
sk.close();
}
}
/*
类 ServerSocket 此类实现服务器套接字。服务器套接字等待请求通过网络传入。
它基于该请求执行某些操作,然后可能向请求者返回结果。
*/
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建TCP服务端的Socket 并向外暴露端口号
ServerSocket ss = new ServerSocket(7777);
System.out.println("服务器已经开启,等待连接.....");
//侦听客户端的连接 侦听并接受到此套接字的连接。
//侦听并接受到此套接字的连接,此方法在连接传入之前一直阻塞
Socket sk = ss.accept();
//获取通道中的输入流
InputStream in = sk.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String s = new String(bytes, 0, len);
System.out.println(s);
//释放资源
ss.close();
}
}
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.80.1", 5555);
OutputStream out = socket.getOutputStream();
out.write("你好服务器,我来了".getBytes());
//读取服务器返回的消息
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String msg = new String(bytes, 0, len);
System.out.println(msg);
socket.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(5555);
System.out.println("服务器已经开启,等待连接.....");
Socket sk = ss.accept();
InputStream in = sk.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String msg = new String(bytes, 0, len);
System.out.println(msg);
//我们想要给客户端一共反馈
OutputStream out = sk.getOutputStream();
out.write("消息收到,放心".getBytes());
ss.close();
}
}
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.80.1", 5555);
OutputStream out = socket.getOutputStream();
//把通道中的字节流包装为一个字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = in.readLine()) != null){
System.out.println("请输入消息:");
writer.write(line);
writer.newLine();
writer.flush();
if ("886".equals(line)){
break;
}
}
socket.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(5555);
System.out.println("服务器已经开启,等待连接.....");
Socket sk = ss.accept();
InputStream in = sk.getInputStream();
//把通道中的字节流,包装成字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("msg.txt"));
//获取客户端的ip
String ip = sk.getInetAddress().getHostAddress();
while ((line = reader.readLine()) != null){
System.out.println(ip + "发来消息:" + line);
if ("886".equals(line)){
break;
}
//把发来的消息保存到文本文件中
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
ss.close();
}
}
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.80.1", 5555);
OutputStream out = socket.getOutputStream();
//把通道中的字节流包装为一个字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
BufferedReader in = new BufferedReader(new FileReader("msg.txt"));
String line = null;
while ((line = in.readLine()) != null){
writer.write(line);
writer.newLine();
writer.flush();
}
socket.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(5555);
System.out.println("服务器已经开启,等待连接.....");
Socket sk = ss.accept();
InputStream in = sk.getInputStream();
//把通道中的字节流,包装成字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
//获取客户端的ip
String ip = sk.getInetAddress().getHostAddress();
while ((line = reader.readLine()) != null){
System.out.println(ip + "发来消息:" + line);
}
ss.close();
}
}
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.80.1", 5555);
OutputStream out = socket.getOutputStream();
//把通道中的字节流包装为一个字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
BufferedReader in = new BufferedReader(new FileReader("msg.txt"));
String line = null;
while ((line = in.readLine()) != null){
writer.write(line);
writer.newLine();
writer.flush();
}
//客户端把文件上传完毕了,那么给服务端手写一个标记
//手写一个文件上传完的标记,可以解决,但是不够好
/*writer.write("over");
writer.newLine();
writer.flush();*/
/*
void shutdownInput
此套接字的输入流置于 “流的末尾”
void shutdownOutput
禁用此套接字的输出流
*/
socket.shutdownOutput();
//读取服务端,写过来的反馈
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(5555);
System.out.println("服务器已经开启,等待连接.....");
Socket sk = ss.accept();
InputStream in = sk.getInputStream();
//把通道中的字节流,包装成字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("msg22.txt"));
//获取客户端的ip
String ip = sk.getInetAddress().getHostAddress();
while ((line = reader.readLine()) != null){
//把发来的消息保存到文本文件中
bw.write(line);
bw.newLine();
bw.flush();
}
//服务端保存文件完毕后,给客户端一个反馈
OutputStream outputStream = sk.getOutputStream();
outputStream.write("文件保存成功".getBytes());
bw.close();
ss.close();
}
}