网络编程

1. 获取网络地址ip/domin

InetAddress获取

public class TestInetAddress {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
        InetAddress localhost = InetAddress.getByName("localhost");
        InetAddress localHost = InetAddress.getLocalHost();
        InetAddress localhost1 = InetAddress.getByName("DESKTOP-146VINF");  // 本机用户名
        InetAddress localhost2 = InetAddress.getByName("www.baidu.com");
        byte[] address = new byte[]{(byte) 192, (byte) 168,5,2};
        InetAddress byAddress = InetAddress.getByAddress(address);

        System.out.println(inetAddress);
        System.out.println(localhost);
        System.out.println(localHost);
        System.out.println(localhost1);
        System.out.println(localhost2);
        System.out.println(byAddress);

        System.out.println(localhost.getAddress());
        System.out.println(localhost.getCanonicalHostName());   // 获取规范名
        System.out.println(localhost.getHostAddress());         // ip
        System.out.println(localhost.getHostName());             // 域名 主机名


    }
}

Port 端口

  • 计算机端口号用于区分不同的进程

  • 计算机端口按端口号可分为3大类:

    (1)公认端口:从0到1023,它们紧密绑定于一些服务。通常这些端口的通讯明确表明了某种服务的协议。常用的有:http: 80  https: 443  ftp: 21 ssh: 22  telnet: 23

(2)注册端口:从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些 端口同样用于许多其它目的。常用的有:TomCat: 8080  MySql: 3306 Oracle:1506

(3)动态和/或私有端口:从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从 1024起分配动态端口。

  • 对于不同的传输层传输协议,在进行数据封装时包头信息不一样,即使UDP包和TCP包使用同一个端口,也不会导致端口冲突。

  • 查看端口命令

    netstat -a # 
    netstat -ano|findstr "7024" #查看指定端口
    tasklist|findstr "7024" # 查看指定端口进程
  • InetSocketAddress

    public class TestInetSocketAddress {
        public static void main(String[] args) {
            InetSocketAddress localhost = new InetSocketAddress("192.168.5.3", 8080); // ip/主机+创建端口对象
            System.out.println(localhost.getAddress());
            System.out.println(localhost.getHostName());
            System.out.println(localhost.getPort()); // 获得端口号
            System.out.println(localhost.getHostString());
        }
    }

通信协议

传输层通信协议

  • TCP:面向连接
  • UDP:非面向连接

TCP编程实现

Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示

Java学习笔记--网络编程_网络编程

TCP编程简单C/S通信示例

1、客户端Socket的工作过程包含以下四个基本的步骤:

创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。

打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输

按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TestTcpClient {
    public static void main(String[] args) throws IOException {

        Socket socket = new Socket("localhost",8888);
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("小逼崽子,是不是没见过黑社会,敢不敢跟我比划比划".getBytes(StandardCharsets.UTF_8));
        if (outputStream!=null){
            outputStream.close();
        }
        if (socket!=null){
            socket.close();
        }

    }
}

2、服务器(服务端)程序的工作过程包含以下四个基本的步骤:

调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。

调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。

调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。

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

public class TestTcpServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("连接建立中");
        Socket clientSocket = serverSocket.accept();
        System.out.println("与"+clientSocket.getInetAddress()+"成功建立连接");
        InputStream inputStream = clientSocket.getInputStream();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len=0;
        while ((len=inputStream.read(buffer))!=-1){
            out.write(buffer,0,len);
            System.out.println(out.toString());![](https://img2020.cnblogs.com/blog/2300439/202104/2300439-20210419235830981-132043291.png)


        File received = new File("test.png");
        FileOutputStream output = new FileOutputStream(received);
        while ((len=inputStream.read(bufferFile))!=-1){
            output.write(bufferFile,0,len);
        }


        // 接受完毕,告知客户断开连接
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("接收成功".getBytes(StandardCharsets.UTF_8));


        output.close();
        inputStream.close();
        socket.close();
        serverSocket.close();

    }

}

TCP编程实现C/S文件传输

Server:

import java.io.*;
import java.net.Socket;
public class TestTcpFileTransportClient {
    public static void main(String[] args) throws IOException {
        // 创建socket
        Socket socket = new Socket("localhost",4396);
        // 创建流
        OutputStream outputStream = socket.getOutputStream();
        // 读取文件
        File file = new File("./StaticSrc/images/img.png");

        byte[] buffer = new byte[1024];
        // 文件输入流
        FileInputStream fileInputStream = new FileInputStream(file);
        // 写入流
        int len;
        while ((len=fileInputStream.read(buffer))!=-1){
            outputStream.write(buffer);
        }
        // 文件传输结束,关闭输出
        socket.shutdownOutput();

        InputStream inputStream = socket.getInputStream();
        byte buffer2[] = new byte[20];
        ByteArrayOutputStream msg = new ByteArrayOutputStream();
        while ((len=inputStream.read(buffer2))!=-1){
            msg.write(buffer2,0,len);
        }

        System.out.println(msg);
        msg.close();
        inputStream.close();
        fileInputStream.close();
        outputStream.close();
        socket.close();
    }
}

Client:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TestTcpFileTransportServer {
    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(4396);
        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();


        byte[] bufferFile = new byte[1024];
        int len;

        File received = new File("test.png");
        FileOutputStream output = new FileOutputStream(received);
        while ((len=inputStream.read(bufferFile))!=-1){
            output.write(bufferFile,0,len);
        }


        // 接受完毕,告知客户断开连接
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("接收成功".getBytes(StandardCharsets.UTF_8));


        output.close();
        inputStream.close();
        socket.close();
        serverSocket.close();

    }

}

UDP 编程

1、类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。

2、UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。

UDP网络通信流程

1、DatagramSocket与DatagramPacket

2、建立发送端,接收端

3、建立数据包

4、调用Socket的发送、接收方法

5、关闭Socket

接收方:

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


public class TestUdpGet {
    public static void main(String[] args) throws IOException {

        // 开放端口
        DatagramSocket socket = new DatagramSocket(2200);
        while (true) {
            // 接收数据
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

            socket.receive(packet);// 阻塞接收
            System.out.println(packet.getAddress().getHostAddress());
            String msg = new String(packet.getData(), 0, packet.getLength());
            if (msg.equals("shutdown")){
                System.out.println("Connection has been closed");
                socket.close();
                return;
            }
            System.out.println(msg);

        }

    }
}

发送方

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class TestUdpSend {
    public static void main(String[] args) throws IOException, InterruptedException {
       // 建立一个socket
        DatagramSocket socket = new DatagramSocket(1111);//Ctrl+Alt+V
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            String data = reader.readLine();
            byte[] msgBytes = data.getBytes(StandardCharsets.UTF_8);
            InetAddress localhost = InetAddress.getByName("localhost");
            DatagramPacket datagramPacket = new DatagramPacket(msgBytes, 0, msgBytes.length, localhost, 2200);
            socket.send(datagramPacket);

            if (data.equals("shutdown")){
                System.out.println("Connection is closed ");
                reader.close();
                socket.close();
                return;
            }
        }
    }
}

多线程实现聊天功能

/*
	发送消息线程
*/
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;
import java.nio.charset.StandardCharsets;

public class MsgSender implements Runnable{
    private int destinationPort;
    private String destinationAddress;

    DatagramSocket socket = null;
    BufferedReader reader = null;

    public MsgSender(int sourcePort, int destinationPort, String destinationAddress) throws SocketException {
        this.destinationPort = destinationPort;
        this.destinationAddress = destinationAddress;
        socket = new DatagramSocket(sourcePort);
        reader = new BufferedReader(new InputStreamReader(System.in));
    }

    @Override
    public void run() {
        while (true){
            try {
                String data = reader.readLine();
                byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
                DatagramPacket packet = new DatagramPacket(dataByte,0,dataByte.length,
                        new InetSocketAddress(this.destinationAddress,this.destinationPort));
                socket.send(packet);
                if(data.equals("shutdown")){
                    reader.close();
                    socket.close();
                    return;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
/*
	消息接收线程
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class MsgReceiver implements Runnable{
     private int port;
     private String msgSeeder;
     DatagramSocket socket = null;

    public MsgReceiver(int port, String msgSeeder) throws SocketException {
        this.port = port;
        this.msgSeeder = msgSeeder;
        socket = new DatagramSocket(port);
    }

    @Override
    public void run() {
        while (true){

            try {
                byte[] msgBuffer = new byte[1024];
                DatagramPacket packet = new DatagramPacket(msgBuffer,0,msgBuffer.length);
                socket.receive(packet);
                byte[] data = packet.getData();
                String msg = new String(data,0, packet.getLength());
                if (msg.equals("shutdown")) {
                    socket.close();
                    return;
                }
                System.out.println(msgSeeder+": "+msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
/*用户1主线程*/
public class TestCli02 {
    public static void main(String[] args) throws SocketException {
        new Thread(new MsgSender(1233,
                8888,"localhost")).start();
        new Thread(new MsgReceiver(9999,"T")).start();
    }
}
/*用户2 主线程*/
public class TestCli02 {
    public static void main(String[] args) throws SocketException {
        new Thread(new MsgSender(1233,
                8888,"localhost")).start();
        new Thread(new MsgReceiver(9999,"T")).start();
    }
}

URL 编程

url:统一资源定位符

格式:<协议>://<主机><端口>/<路径>

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class TestUrl {
    public static void main(String[] args) throws IOException {

//        1.资源地址
        URL url = new URL("https://m701.music.126.net/20210419223947/bf29e2e59430cbc33e13485d38ac54e0/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/7748121407/a09e/914d/bae7/0d34f4fab6d02c177c9fd38402f127b0.mp3");
//        2.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()); // 参数
        System.out.println(url.getAuthority()); // The Authority part of the URL is the host name and the port of the URI
        System.out.println(url.getContent()); // 内容
//        3.连接资源url
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream stream = urlConnection.getInputStream();
//        4. 文件输出流到 test.mp3
        FileOutputStream outputStream = new FileOutputStream("test.mp3");
        byte[] bytes = new byte[1024];
        int len;
        while ((len=stream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }
//        下载完毕关闭流和url连接
        stream.close();
        outputStream.close();
        urlConnection.disconnect();
    }
}