分割线

借物表

在此文章记录了: 😍Weidows-の成长路线#网络编程


简介

分割线

IP

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Ip {

public static void main(String[] args) {
// write your code here
try {
// 获取本机内网IP地址
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress1);
InetAddress inetAddress2 = InetAddress.getByName("localhost");
System.out.println(inetAddress2);
InetAddress inetAddress3 = InetAddress.getLocalHost();
System.out.println(inetAddress3);

//查询网站ip地址
InetAddress inetAddress4 = InetAddress.getByName("www.bilibili.com");
System.out.println(inetAddress4);

//常用方法
System.out.println(inetAddress4.getAddress());
System.out.println(inetAddress4.getCanonicalHostName()); //规范的名字
System.out.println(inetAddress4.getHostAddress()); //ip
System.out.println(inetAddress4.getHostName()); //域名,或者自己电脑的名字
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
/**
/127.0.0.1
localhost/127.0.0.1
DESKTOP-CTDDD3K/192.168.114.1
www.bilibili.com/121.17.123.130
[B@2a3046da
121.17.123.130
121.17.123.130
www.bilibili.com
*/
}

端口

  • TCP 与 UDP 各有 65535 个端口

    • 两个协议间不冲突

    • 但是一个协议下的一个端口只能同时被一个软件占用.


  • 端口分类

    • 公有端口 0 ~ 1023

      • HTTP:80

      • HTTPS:443

      • FTP:21

      • Telent:23

    • 程序注册端口:1024 ~ 49151,分配给用户或者程序

      • Tomcat:8080

      • MySQL:3306

      • Oracle:1512

    • 动态、私有:49152 ~ 65535


  • 常用 shell 指令

    netstat -ano #查看所有的端口
    netstat -ano | finstr "5900" #查看指定的端口
    tasklist | findstr "8696" #查看指定端口的进程
  • InetSocketAddress

    import java.net.InetSocketAddress;

    public class Port {
    public static void main(String[] args) {
    InetSocketAddress socketAddress = new InetSocketAddress("localhost", 8080);
    System.out.println(socketAddress);

    System.out.println(socketAddress.getAddress());
    System.out.println(socketAddress.getHostName());
    System.out.println(socketAddress.getPort());
    }
    /**
    localhost/127.0.0.1:8080
    localhost/127.0.0.1
    localhost
    8080
    */
    }

分割线

通信协议

  • 通过约定协议来管控通信的速率,码率等问题

  • 并通过协议分层来简化复杂度


  • 几种协议

    • TCP:用户传输协议

    • UDP:用户数据报协议

    • IP:网络互连协议

    • TCP/IP 协议簇:是一组协议 (四层概念模型)


TCP

  • TCP 是客户端<–>服务端双向的信息沟通,可长时间稳定连接

  • 稳定连接最小验证三次握手,四次挥手

    最少需要三次,保证稳定连接!
    A:你瞅啥?
    B:瞅你咋地?
    A:干一场!

    至少四次,双方才能都断开连接
    A:我要走了
    B:你真的要走了吗?
    B:你真的真的要走了吗?
    A:我真的要走了

UDP

  • 单向的信息传递

  • 没有客户端与服务端界限

  • 无论有没有接收方,无论接收方是否接收,发送方只管发送

  • 常见的DDOS攻击,让大量垃圾信息污染服务器接收端口,使其瘫痪.

分割线

TCP 连接

  • Server 服务端与 Client 客户端通过 TCP 方式创建数据连接.

Server 端

  • 建立服务的端口 ServerScoket

  • 等待用户的连接 accept

  • 接收用户的消息

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) throws IOException {
//1、我得有一个地址
ServerSocket serverSocket = new ServerSocket(9999);

while (true) { // 连续接收数据
//2、等待客户端连接过来
Socket accept = serverSocket.accept();

//3、读取客户端的消息
InputStream inputStream = accept.getInputStream();

/**
* 通常IO方式,如果是长数据传输,会导致出错
*
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
String s = new String(buffer, 0, length);
System.out.println(s);
}
*/

//4. 管道流接收数据
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, length);
}
if (byteArrayOutputStream.toString().matches("quit")) {
break;
} else {
System.out.println(byteArrayOutputStream.toString());
byteArrayOutputStream.close();
inputStream.close();
accept.close();
}
}

//5. 最后关闭
serverSocket.close();
}
}

Client 端

  • 连接服务器 Socket

  • 发送消息

import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class Client {
public static void main(String[] args) throws Exception {
//1、要知道服务器的地址,端口号
InetAddress address = InetAddress.getLocalHost();

int port = 9999;

//2、创建一个socket连接
Socket socket = new Socket(address, port);

//3、发送消息 IO流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("Weidows connecting here.".getBytes());
// outputStream.write("quit".getBytes());

//4.关闭通道
outputStream.close();
socket.close();
}
}

分割线

文件传输

Server

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) throws Exception {
//1、创建服务
ServerSocket serverSocket = new ServerSocket(9999);

//2、监听客户端的连接
Socket socket = serverSocket.accept(); //阻塞式监听,会一直等待客户端连接
System.out.println("Server开始监听.");

//3、获取输入流
InputStream is = socket.getInputStream();

//4、文件输出
FileOutputStream fos = new FileOutputStream(new File("Java/src/main/java/twenty_one/net/file_upload/receive.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("Server接收完毕.");

//通知客户端我接收完毕了
OutputStream os = socket.getOutputStream();
os.write("Server通知:接受完毕,Client可以断开了".getBytes());

//5、关闭资源
fos.close();
is.close();
socket.close();
serverSocket.close();
System.out.println("Server已发送验证并断开连接.");
}
/**
Server开始监听.
Server接收完毕.
Server已发送验证并断开连接.
*/
}

Client

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class Client {
public static void main(String[] args) throws Exception {
//1、创建一个Socket连接
Socket socket = new Socket(InetAddress.getByName("localhost"), 9999);

//2、创建一个输出流
OutputStream os = socket.getOutputStream();

//3、读取文件
FileInputStream fis = new FileInputStream(new File("Java/src/main/java/twenty_one/net/file_upload/upload.png"));

//4、写出文件
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
System.out.println("Client传输完毕.");

//通知服务器,我已经结束了
socket.shutdownOutput(); //我已经传输完了!

//确定服务器接收完毕,才能够断开连接
InputStream inputStream = socket.getInputStream();
//String byte[]
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while ((len2 = inputStream.read(buffer2)) != -1) {
baos.write(buffer2, 0, len2);
}
System.out.println(baos.toString());

//5、关闭资源
baos.close();
inputStream.close();
fis.close();
os.close();
socket.close();
System.out.println("Client已接收到验证并断开连接");
}
/**
Client传输完毕.
Server通知:接受完毕,Client可以断开了
Client已接收到验证并断开连接
*/
}

分割线

UDP 连接

Server

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
public static void main(String[] args) throws Exception {
// 1.开放端口
DatagramSocket datagramSocket = new DatagramSocket(9999);
System.out.println("等待数据传入中...");

// 2.接收数据
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(datagramPacket); //阻塞接收

// 3.输出
System.out.println("Server接收到数据:" + new String(datagramPacket.getData()));

// 4.关闭
datagramSocket.close();
}
}

Client

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Client {
public static void main(String[] args) throws Exception {
// 1.创建数据包
InetAddress localHost = InetAddress.getLocalHost();
int port = 9999;
byte[] data = "这是Client发送的数据.".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data, data.length, localHost, port);

// 2.创建Socket
DatagramSocket datagramSocket = new DatagramSocket();

// 3.发送数据
datagramSocket.send(datagramPacket);
System.out.println("传输成功.");

// 4.关闭连接
datagramSocket.close();
}
}

UDP 循环发送

Server

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server2 {
public static void main(String[] args) throws Exception {
// 1.准备连接
DatagramSocket datagramSocket = new DatagramSocket(9999);
while (true) {
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
System.out.println("Server准备接收数据中.");

// 2.接收数据
datagramSocket.receive(datagramPacket);
String string = new String(datagramPacket.getData());
System.out.println("接收到数据:\t" + datagramPacket.getAddress() + ":" + datagramPacket.getPort() + "\t" + string);

// 这里的string="quitxxxxxxxxxxxxxx",总长为上面的1024,用.equals()无法判断.
if (string.contains("quit")) {
break;
}
}

// 3.断开连接
datagramSocket.close();
System.out.println("Server已关闭连接.");
}
}

Client

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Client2 {
public static void main(String[] args) throws Exception {
// 0.准备连接
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
DatagramSocket datagramSocket = new DatagramSocket();

while (true) {
// 1.准备数据
System.out.println("Client准备读取Terminal数据:");
String readLine = bufferedReader.readLine();
byte[] bytes = readLine.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, new InetSocketAddress("localhost", 9999));

// 2.发送数据
datagramSocket.send(datagramPacket);
System.out.println("Client已经发送数据.");

if (readLine.equals("quit")) {
break;
}
}

// 3.断开连接
datagramSocket.close();
System.out.println("Client已关闭连接.");
}
}

分割线

双向聊天

  • 实现发送,接收两个线程类

  • 老师和学生各开上面两个线程,实现发,收功能.

发送线程

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class TalkSend implements Runnable {
BufferedReader bufferedReader = null;
DatagramSocket datagramSocket = null;

private String targetIP;
private int targetPort;

public TalkSend(String targetIP, int targetPort) {
this.targetIP = targetIP;
this.targetPort = targetPort;

try {
// 0.准备连接
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
datagramSocket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {

}

@Override
public void run() {
while (true) {
// 1.准备数据
System.out.println("Client准备读取Terminal数据:");
try {
String readLine = bufferedReader.readLine();
byte[] bytes = readLine.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length,
new InetSocketAddress(targetIP, targetPort));

// 2.发送数据
datagramSocket.send(datagramPacket);
System.out.println("Client已经发送数据.");

if (readLine.equals("quit")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}

// 3.断开连接
datagramSocket.close();
System.out.println("Client已关闭连接.");
}
}

接收线程

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class TalkReceive implements Runnable {
DatagramSocket datagramSocket = null;
private int localPort;

public TalkReceive(int localPort) {
this.localPort = localPort;

try {
datagramSocket = new DatagramSocket(this.localPort);
} catch (SocketException e) {
e.printStackTrace();
}
}

@Override
public void run() {
// 1.准备连接
while (true) {
try {
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
System.out.println("Server准备接收数据中.");

// 2.接收数据
datagramSocket.receive(datagramPacket);

String string = new String(datagramPacket.getData());
System.out.println("接收到数据:\t" + datagramPacket.getAddress() + ":" + datagramPacket.getPort() + "\t" + string);

// 这里的string="quitxxxxxxxxxxxxxx",总长为上面的1024,用.equals()无法判断.
if (string.contains("quit")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}

// 3.断开连接
datagramSocket.close();
System.out.println("Server已关闭连接.");
}

public static void main(String[] args) {

}
}

老师

public class Teacher {
public static void main(String[] args) {
// 老师
new Thread(new TalkReceive(7777)).start();
new Thread(new TalkSend("localhost", 8888)).start();
}
/**
Server准备接收数据中.
Client准备读取Terminal数据:
接收到数据: /127.0.0.1:50277 15465
Server准备接收数据中.
123456
Client已经发送数据.
Client准备读取Terminal数据:
*/
}

学生

public class Student {
public static void main(String[] args) {
// 学生
new Thread(new TalkReceive(8888)).start();
new Thread(new TalkSend("localhost", 7777)).start();
}
/**
Server准备接收数据中.
Client准备读取Terminal数据:
15465
Client已经发送数据.
Client准备读取Terminal数据:
接收到数据: /127.0.0.1:50279 123456
Server准备接收数据中.
*/
}

分割线

URL

  • 文件下载
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;

public class GetURL {
public static void main(String[] args) throws Exception {
// 1.设置URL和文件路径
URL url = new URL("https://cdn.jsdelivr.net/gh/Weidows/Weidows/image/divider.png");
String path = "Java/src/main/java/twenty_one/net/";
String fileName = url.getPath().substring(url.getPath().lastIndexOf('/') + 1);

/**
* ! URL类用法
*
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort());
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getQuery());
*
https
cdn.jsdelivr.net
/gh/Weidows/Images@master/img/divider.png
/gh/Weidows/Images@master/img/divider.png
null
*/

// 2.输入输出流
InputStream openStream = url.openStream();
FileOutputStream fileOutputStream = new FileOutputStream(new File(path + fileName));

// 3.传输数据
byte[] bytes = new byte[1024];
int length;
while ((length = openStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, length);
}

// 4.关闭连接
fileOutputStream.close();
openStream.close();
}
}