JAVA中TCP和UDP编程

InetAddress类【重点】
继承关系图和构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q6C5l1dV-1647264505155)(E:\Typora笔记\java笔记\img\image-20220312153912773.png)]

InetAddress类常用方法
1.getLocalHost			获取本机InetAddress对象
2.getByName				根据指定主机名、域名获取IP地址对象 
3.getHostName			获取InetAddress对象的主机名
4.getHostAddress		获取InetAddress对象的地址
static InetAddressgetLocalHost() 返回本地主机的地址。
StringgetHostAddress() 返回文本显示中的IP地址字符串。
StringgetHostName() 获取此IP地址的主机名。
static InetAddressgetByName(String host) 确定主机名称的IP地址。

InetAddress类作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VheQIqXL-1647264505156)(E:\Typora笔记\java笔记\img\image-20220312154759829.png)]

InetAddress类的两大作用:

  1. 获取本机的信息【主机名/IP
  2. 通过域名获取远程服务器【或其他主机】的IP
package network_.inerAddress_;

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

/**
 * @author: 海康
 * @version: 1.0
 * 演示 InetAddress类常用方法
 */
public class InetAddress1 {
    public static void main(String[] args) throws UnknownHostException {
        // 使用InetAddress 类的静态方法 getLocalHost 获取一个 InetAddress 对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println("本机名称和IP地址= " + localHost);
        // 返回值是:本机名称和IP地址= DESKTOP-4KJDTLR/172.18.245.88

        // 根据指定主机名获取 ip 地址对象 使用getByName 方法 返回一个 InetAddress 对象
        InetAddress byName = InetAddress.getByName("172.18.245.88");
        System.out.println("byName = " + byName);
        // 返回值是:byName = /172.18.245.88

        // 根据指定域名获取 ip 地址 使用 getByName 方法 返回一个 InetAddress 对象
        InetAddress baidu = InetAddress.getByName("www.baidu.com");
        System.out.println("baidu = "+baidu);
        // 返回值是:baidu = www.baidu.com/14.215.177.39

        // 获取主机名 使用 getHostName 方法 返回一个主机名 或者 域名
        String hostName = baidu.getHostName();
        System.out.println("hostName = " +hostName );
        // 返回值:hostName = www.baidu.com

        // 获取对象的地址 使用 getHostAddress 方法 返回一个 IP 地址
        String hostAddress = baidu.getHostAddress();
        System.out.println("hostAddress = " + hostAddress);
        // 返回值:hostAddress = 14.215.177.39
    }
}
package com.hspedu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 演示InetAddress 类的使用
 */
public class API_ {
    public static void main(String[] args) throws UnknownHostException {

        //1. 获取本机的InetAddress 对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);//DESKTOP-S4MP84S/192.168.12.1

        //2. 根据指定主机名 获取 InetAddress对象
        InetAddress host1 = InetAddress.getByName("DESKTOP-S4MP84S");
        System.out.println("host1=" + host1);//DESKTOP-S4MP84S/192.168.12.1

        //3. 根据域名返回 InetAddress对象, 比如 www.baidu.com 对应
        InetAddress host2 = InetAddress.getByName("www.baidu.com");
        System.out.println("host2=" + host2);//www.baidu.com / 110.242.68.4

        //4. 通过 InetAddress 对象,获取对应的地址
        String hostAddress = host2.getHostAddress();//IP 110.242.68.4
        System.out.println("host2 对应的ip = " + hostAddress);//110.242.68.4

        //5. 通过 InetAddress 对象,获取对应的主机名/或者的域名
        String hostName = host2.getHostName();
        System.out.println("host2对应的主机名/域名=" + hostName); // www.baidu.com

    }
}
Socket

基本介绍:

  1. 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准
  2. 通信的两端都要有Socket,是两台机器通信的端点
  3. 网络通信其实就是Socket间的通信
  4. Socket允许程序把网络连接当成一个流,数据在两个Socket通过IO传输
  5. 一般主动发起通信应用程序属于客户端,等待通信请求的为服务端

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXn4lh0P-1647264505156)(E:\Typora笔记\java笔记\img\image-20220312163109999.png)]

Socket的理解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfJh60WT-1647264505157)(E:\Typora笔记\java笔记\img\image-20220312163143543.png)]

TCP网络通信编程【非常重要】

基本介绍:

  1. 基于客户端 和 服务端的网络通信
  2. 底层使用的是TCP/IP协议
  3. 应用场景举例:客户端发送数据,服务端接受并显示控制台
  4. 基于SocketTCP编程UDP编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vFSPId6C-1647264505157)(E:\Typora笔记\java笔记\img\image-20220312163452536.png)]

ServerSocket

继承关系图和构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7NvR0iaT-1647264505157)(E:\Typora笔记\java笔记\img\image-20220312172337657.png)]

构造器

Constructor and Description
ServerSocket() 创建未绑定的服务器套接字。
ServerSocket(int port) 创建绑定到指定端口的服务器套接字,创建一个监听指定端口服务器对象
ServerSocket(int port, int backlog) 创建服务器套接字并将其绑定到指定的本地端口号,并指定了积压。
ServerSocket(int port, int backlog, InetAddress bindAddr) 创建一个具有指定端口的服务器,侦听backlog和本地IP地址绑定。

常用方法

Modifier and TypeMethod and Description
Socketaccept() 侦听要连接到此套接字并接受它,获取一个连接
voidbind(SocketAddress endpoint)ServerSocket绑定到特定地址(IP地址和端口号)。
voidbind(SocketAddress endpoint, int backlog)ServerSocket绑定到特定地址(IP地址和端口号)。
voidclose() 关闭此套接字。
ServerSocketChannelgetChannel() 返回与此套接字相关联的唯一的ServerSocketChannel对象(如果有)。
InetAddressgetInetAddress() 返回此服务器套接字的本地地址。
intgetLocalPort() 返回此套接字正在侦听的端口号,返回正在监听端口 >
SocketAddressgetLocalSocketAddress() 返回此套接字绑定到的端点的地址。
intgetReceiveBufferSize() 获取此 ServerSocketSO_RCVBUF选项的值,即将用于从该 ServerSocket接受的套接字的建议缓冲区大小。
booleangetReuseAddress() 测试是否启用了 SO_REUSEADDR
intgetSoTimeout() 检索 SO_TIMEOUT设置。
protected voidimplAccept(Socket s) ServerSocket的子类使用这个方法来覆盖accept()来返回自己的套接字子类。
booleanisBound() 返回ServerSocket的绑定状态。
booleanisClosed() 返回ServerSocket的关闭状态。
voidsetPerformancePreferences(int connectionTime, int latency, int bandwidth) 设置此ServerSocket的性能首选项。
voidsetReceiveBufferSize(int size) 设置从 ServerSocket接受的套接字的 SO_RCVBUF选项的默认建议值。
voidsetReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR套接字选项。
static voidsetSocketFactory(SocketImplFactory fac) 设置应用程序的服务器套接字实现工厂。
voidsetSoTimeout(int timeout) 启用/禁用 SO_TIMEOUT带有指定超时,以毫秒为单位。
StringtoString() 将该套接字的实现地址和实现端口返回为 String
Socket

Socket类继承关系图和构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGDfVtqF-1647264505158)(E:\Typora笔记\java笔记\img\image-20220312173315758.png)]

构造器

ModifierConstructor and Description
Socket() 创建一个未连接的套接字,并使用系统默认类型的SocketImpl
Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。 绑定指定服务器和指定端口
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建套接字并将其连接到指定的远程端口上指定的远程地址。
Socket(Proxy proxy) 创建一个未连接的套接字,指定应该使用的代理类型(如果有的话),无论其他任何设置如何。
protectedSocket(SocketImpl impl) 使用用户指定的SocketImpl创建一个未连接的Socket。
Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
Socket(String host, int port, boolean stream) 已弃用 使用DatagramSocket代替UDP传输。
Socket(String host, int port, InetAddress localAddr, int localPort) 创建套接字并将其连接到指定远程端口上的指定远程主机。

常用方法

OutputStreamgetOutputStream() 返回此套接字的输出流。
intgetPort() 返回此套接字连接到的远程端口号。
InetAddressgetInetAddress() 返回套接字所连接的地址。
InputStreamgetInputStream() 返回此套接字的输入流。
InetAddressgetLocalAddress() 获取套接字所绑定的本地地址。
intgetLocalPort() 返回此套接字绑定到的本地端口号。
voidshutdownInput() 将此套接字的输入流放置在“流的末尾”。 设置结束标记
voidshutdownOutput() 禁用此套接字的输出流。设置结束标记

应用案例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2s8o6SG-1647264505158)(E:\Typora笔记\java笔记\img\image-20220312174335606.png)]

思路分析:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXmsiLJJ-1647264505158)(E:\Typora笔记\java笔记\img\image-20220312174400714.png)]

服务端代码

package network_.inerAddress_.socket_;

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

/**
 * @author: 海康
 * @version: 1.0
 * 演示:服务器监听,并接收打印
 */
public class TCPServer01 {
    public static void main(String[] args) throws IOException {
        // 在本机的 9999 端口监听,等待连接
        ServerSocket serverSocket= new ServerSocket(9999);

        // 通过 accept 方法返回一个 Socket 对象
        Socket socket = serverSocket.accept();

        // 当没有客户连接 9999 端口时,程序会阻塞,等待连接
        System.out.println("服务器的 Socket = " + socket.getClass());

        // 获取一个 InputStream 读取数据
        InputStream ips = socket.getInputStream();

        // 读取客户端发来 数据
        byte[] by = new byte[1024*8];
        int length = 0;
        while ((length = ips.read(by))!=-1){
            System.out.println(new String(by,0,length));
        }

        // 在使用完成后,一定要关闭流 从内层向外层关闭
        if (ips != null){
            ips.close();
        }

        if (socket != null){
            socket.close();
        }

        if (serverSocket != null){
            serverSocket.close();
        }
    }
}

客户端代码

package network_.inerAddress_.socket_;

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

/**
 * @author: 海康
 * @version: 1.0
 * 演示:客户端
 */
public class TCPClient01 {
    public static void main(String[] args) throws IOException {
        // 连接服务端(IP + 端口)  连接上后,生成一个 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        // 获取一个 OutputStream 流
        OutputStream ops = socket.getOutputStream();
        // 通过输出流 ,写入数据到 数据通道中
        ops.write("hello Server".getBytes());

        // 使用完成后,一定要关闭流,从内层流开始关闭
        if (ops != null){
            ops.close();
        }

        if (socket != null){
            socket.close();
        }
        System.out.println("客户访问服务端,结束。。。");
    }
}

应用案例2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tuqJumYb-1647264505158)(E:\Typora笔记\java笔记\img\image-20220312195711345.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0TzUjBO-1647264505159)(E:\Typora笔记\java笔记\img\image-20220312195945559.png)]

服务器端

package network_.inerAddress_.socket_;

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

/**
 * @author: 海康
 * @version: 1.0
 */
public class TCPServer02 {
    public static void main(String[] args) throws IOException {
        // 在本机的 9999 端口进行监听
        ServerSocket socket = new ServerSocket(9999);

        // 获取一个获取Socket对象 使用accept 方法
        Socket accept = socket.accept();// 如果没有客户端进行连接程序直接阻塞在此处

        System.out.println("服务器端的Socket运行态="+socket.getClass());
        // 获取一个 InputStream 对象 读取客户端发送的信息
        InputStream isp = accept.getInputStream();

        int length = 0;
        byte[] by = new byte[1024*8];
        while ((length = isp.read(by))!=-1){
            System.out.println(new String(by,0,length));
        }

        // 接收到客户端发来的信息后,给客户端发回数据
        // 获取 OutputStream 对象
        OutputStream ops = accept.getOutputStream();
        ops.write("hello Client".getBytes());
        // 设置一个结束标记
        accept.shutdownInput();

        // 关闭流 资源
        if (ops != null){
            ops.close();
        }

        if (isp != null){
            isp.close();
        }

        if (accept != null){
            accept.close();
        }

        System.out.println("服务器端退出程序!!!");
    }
}

客户端代码

package network_.inerAddress_.socket_;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 海康
 * @version: 1.0
 */
@SuppressWarnings({"all"})
public class TCPClient02 {
    public static void main(String[] args) throws IOException {
        // 连接服务器,获取一个请求返回一个 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        System.out.println("客户端Socket运行态="+socket.getClass());

        // 获取一个 OutputStream
        OutputStream ops = socket.getOutputStream();

        // 写入数据
        ops.write("hello  Server".getBytes());
        // 设置一个结束标记
        socket.shutdownOutput();

        // 获取一个 InputStream 对象 用于读取服务器发回数据
        InputStream ips = socket.getInputStream();

        byte[] by = new byte[1024*8];
        int length = 0;
        while ((length = ips.read(by))!= -1){
            System.out.println(new String(by,0,length));
        }

        // 在使用完成后,一定要关闭流
        if (ips != null){
            ips.close();
        }

        if (ops != null){
            ops.close();
        }

        if (socket != null){
            socket.close();
        }

        System.out.println("客户端退出程序 !!!");
    }
}

客户端代码

package com.hspedu.socket;

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

/**
 * 客户端,发送 "hello, server" 给服务端
 */
@SuppressWarnings({"all"})
public class SocketTCP02Client {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        //   设置结束标记
        socket.shutdownOutput();

        //4. 获取和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));
        }

        //5. 关闭流对象和socket, 必须关闭
        inputStream.close();
        outputStream.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

服务器端代码

package com.hspedu.socket;

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

/**
 * 服务端
 */
@SuppressWarnings({"all"})
public class SocketTCP02Server {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //
        //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));//根据读取到的实际长度,显示内容.
        }
        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        //   设置结束标记
        socket.shutdownOutput();

        //6.关闭流和socket
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();//关闭

    }
}

应用案例3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B1Ru7BRI-1647264505159)(E:\Typora笔记\java笔记\img\image-20220312200954741.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMFy4M7c-1647264505159)(E:\Typora笔记\java笔记\img\image-20220312212715049.png)]

注意是:在使用BufferedWriter时,一定要刷新内容到管道中,否则不能写入数据,在写入结束标记有两种方式:writer.newLine()// 换行符,注意需要接收方也要使用readLine()的方式读取 或 这种方式写入结束标记:``shutdownOutput()`

服务器端代码

package network_.inerAddress_.socket_;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author: 海康
 * @version: 1.0
 */
@SuppressWarnings({"all"})
public class TCPServer3 {
    public static void main(String[] args) throws IOException {
       // 使用 ServerSocket 监听 一个端口
        ServerSocket serverSocket = new ServerSocket(9999);

        System.out.println("服务器正在 9999 端口监听!!!");

        // 获取一个连接
        Socket accept = serverSocket.accept();

        // 获取一个 InputStream 对象
        InputStream isp = accept.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(isp));
        String line = "";
        while ((line = br.readLine())!=null){
            System.out.println(line);
        }

        // 获取一个 OutputStream 对象
        OutputStream ops = accept.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ops));

        bw.write("hello Clinet  字符流!!!");
        // 写入后,一定要刷新管道,否则内容不能正常写入
        bw.flush();
        // 写入结束标记有两种方式:
        // 方式一:
        accept.shutdownInput();
        // 方式二:
//        bw.newLine();//注意用这种方式,要求对象在读取时,一定要使用 ReadLine 方式读取

        // 关闭流 也是 只需要关闭外层 流
        bw.close();
        br.close();
        accept.close();
        serverSocket.close();

    }
}

客户端代码

package network_.inerAddress_.socket_;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 海康
 * @version: 1.0
 */
@SuppressWarnings({"all"})
public class TCPClient03 {
    public static void main(String[] args) throws IOException {
        // 连接服务器,获取 一个 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        // 获取 一个写入对象 InputStream 并转成 BufferedWriter 对象
        OutputStream ops = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ops));

        bw.write("hello server 字符流");
        // 写入后 一定要刷新 否则内容进入管道
        bw.flush();
        // 写入结束标记有两种方式
        // 方式一:
        socket.shutdownOutput();
        // 方式二:

//        bw.newLine();// 注意是这种方式要求对方 一定要使用 ReadLine 方式读取


        // 获取 InputStream 对象
        InputStream ips = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(ips));

        String line = "";

        while ((line= br.readLine())!= null){
            System.out.println(line);
        }

        // 关闭流,只需要关闭外层 流 后开先关
        bw.close();
        br.close();
        socket.close();

        System.out.println("客户端结束 !!!");
    }
}
package com.hspedu.socket;

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

/**
 * 客户端,发送 "hello, server" 给服务端, 使用字符流
 */
@SuppressWarnings({"all"})
public class SocketTCP03Client {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道, 使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello, server 字符流");
        bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
        bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道


        //4. 获取和socket关联的输入流. 读取数据(字符),并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 关闭流对象和socket, 必须关闭
        bufferedReader.close();//关闭外层流
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

package com.hspedu.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端, 使用字符流方式读写
 */
@SuppressWarnings({"all"})
public class SocketTCP03Server {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);//输出

        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
       //    使用字符输出流的方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello client 字符流");
        bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//注意需要手动的flush


        //6.关闭流和socket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();//关闭

    }
}

上传文件

应用案例4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xS0cKgbg-1647264505160)(E:\Typora笔记\java笔记\img\image-20220313085845336.png)]

思路分析:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWuBru1Q-1647264505160)(E:\Typora笔记\java笔记\img\image-20220313104835089.png)]

下面的代码存在Bug

package network_.inerAddress_.socket_;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 海康
 * @version: 1.0
 */
public class TCPFIleClient01 {
    public static void main(String[] args) throws IOException {
        // 请求服务器 获取连接
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

        // 读取一个文件【图片】
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\rose.jpg"));

        // 获取一个 getOutputStream 对象
        OutputStream ops = socket.getOutputStream();
        BufferedOutputStream bop = new BufferedOutputStream(ops);

        int length = 0;
        byte[] by = new byte[1024*8];
        while ((length = bis.read(by))!=-1){
            bop.write(by,0,length);
        }

        // 结束标记
        socket.shutdownOutput();

        InputStream ips = socket.getInputStream();
        BufferedInputStream bip = new BufferedInputStream(ips);
        int le = 0;
        byte[] bytes = new byte[1024*8];
        while ((le=bip.read(bytes))!=-1){
            System.out.println(new String(bytes,0,le));
        }

        // 关闭流
        bip.close();
        bis.close();
        ops.close();
        socket.close();

        System.out.println("客户端结束 !!! ");
    }
}
package network_.inerAddress_.socket_;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;

/**
 * @author: 海康
 * @version: 1.0
 */
public class TCPFileServer01 {
    public static void main(String[] args) throws IOException {
        // 服务器在 8888 端口监听
        ServerSocket serverSocket = new ServerSocket(8888);

        // 获取到一个连接
        Socket accept = serverSocket.accept();

        System.out.println("服务器在 8888 端口监听!!!");

        // 获取一个输入流
        InputStream ips = accept.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(ips);

        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("src\\myRose.jpg"));

        byte by[] = new byte[1024*8];
        int length = 0;
        while ((length = bis.read(by))!=-1){
            bos.write(by,0,length);
        }


        // 写完数据后,获取一个输出流
        OutputStream ops = accept.getOutputStream();
        ops.write("收到图片".getBytes());
        // 如果在使用 Buffered字符流,一定要刷新
        accept.shutdownOutput();

        // 关闭流
        ops.close();
        bos.close();
        bis.close();
        accept.close();
        serverSocket.close();

        System.out.println("服务器端结束 !!! ");
    }
}

优化代码:

package network_.inerAddress_.socket_.upload_;

import java.io.*;

/**
 * @author: 海康
 * @version: 1.0
 */
public class StreamUtils {
    /**
     * 功能:将输入流转换成byte[]
     * @param is
     * @return
     * @throws IOException
     */
    public static byte[] streamToByArray(InputStream is) throws IOException {
        // 创建一个 ByteArrayOutputStream 对象用于存储读取到的数据
        ByteArrayOutputStream baop = new ByteArrayOutputStream();

        byte[] by = new byte[1024*8];
        int length = 0;
        while ((length=is.read(by))!=-1){
             baop.write(by,0,length);
        }

        byte[] bytes = baop.toByteArray();
        // 使用完成后,关闭流
        if (baop!=null)
            baop.close();
        return bytes;
    }


    /**
     * 功能:将InputStream转换成String
     * @param is
     * @return
     * @throws IOException
     */
    public static String streamToString(InputStream is) throws IOException {
        // 创建一个读取对象
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        // 创建一个 StringBuilder 对象
        StringBuilder sb = new StringBuilder();
        String line = "";
        while ((line=reader.readLine())!=null){
            sb.append(line);
            sb.append("\r\n");
        }
        return sb.toString();
    }
}
package network_.inerAddress_.socket_.upload_;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author: 海康
 * @version: 1.0
 */
public class TCPFileServer01 {
    public static void main(String[] args) throws IOException {
        // 服务器端在 8888 端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器端在 8888 端口监听!!!");
        // 获取一个 连接
        Socket accept = serverSocket.accept();
        // 获取一个 InputStream 对象 读取数据
        InputStream inputStream = accept.getInputStream();
        byte[] bytes = StreamUtils.streamToByArray(inputStream);
        // 写入到指定位置
        String copyFilePath = "src\\myRose3.jpg";
        BufferedOutputStream bs = new BufferedOutputStream(new FileOutputStream(copyFilePath));
        bs.write(bytes);

        // 获取一个 OutputStream 对象
        OutputStream outputStream = accept.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        writer.write("图片收到");
        // 记得一定要刷新内容,否则内容无法进入管道
        writer.flush();
        // 设置结束标记
        accept.shutdownOutput();

        // 关闭流
        writer.close();
        bs.close();
        inputStream.close();
        accept.close();
        serverSocket.close();
    }
}
package network_.inerAddress_.socket_.upload_;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 海康
 * @version: 1.0
 */
public class TCPFileClient01 {
    public static void main(String[] args) throws IOException {
        // 获取一个 服务器端对象 Socket
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        // 读取图片
        String filePath = "e:\\rose.jpg";
        FileInputStream fileInputStream = new FileInputStream(filePath);
        byte[] bytes = StreamUtils.streamToByArray(fileInputStream);

        // 获取一个写入管道对象
        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);
        bos.write(bytes);
        // 设置结束标记
        socket.shutdownOutput();

        // 获取服务器端回话
        InputStream inputStream = socket.getInputStream();
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);

        // 关闭流
        inputStream.close();
        bos.close();
        fileInputStream.close();
        socket.close();
    }
}

优化代码2

package com.hspedu.upload;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
	/**
	 * 功能:将输入流转换成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){ //当读取到 null时,就表示结束
			builder.append(line+"\r\n");
		}
		return builder.toString();
		
	}

}
package com.hspedu.upload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 文件上传的服务端
 */
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. 读取客户端发送的数据
        //   通过Socket得到输入流
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //4. 将得到 bytes 数组,写入到指定的路径,就得到一个文件了
        String destFilePath = "src\\abc.mp4";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
        bos.write(bytes);
        bos.close();

        // 向客户端回复 "收到图片"
        // 通过socket 获取到输出流(字符)
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("收到图片");
        writer.flush();//把内容刷新到数据通道
        socket.shutdownOutput();//设置写入结束标记

        //关闭其他资源
        writer.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}
package com.hspedu.upload;

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


/**
 * 文件上传的客户端
 */
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {

        //客户端连接服务端 8888,得到Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        //创建读取磁盘文件的输入流
        //String filePath = "e:\\qie.png";
        String filePath = "e:\\abc.mp4";
        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);//将文件对应的字节数组的内容,写入到数据通道
        bis.close();
        socket.shutdownOutput();//设置写入数据的结束标记

        //=====接收从服务端回复的消息=====

        InputStream inputStream = socket.getInputStream();
        //使用StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);


        //关闭相关的流
        inputStream.close();
        bos.close();
        socket.close();

    }


}
netstat指令【重点】
1.  netstat  -an  			// 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
2.  netstat  -an  | more   // 可以分页显示
3.  netstat  -anb          // 可以查看当机主机网络情况和那个应用程序在监听【内容显示更加全】【前提是需要管理员权限】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJd0he6P-1647264505160)(E:\Typora笔记\java笔记\img\image-20220313115507373.png)]

netstat -anb | more查看的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0MoxAkk9-1647264505160)(E:\Typora笔记\java笔记\img\image-20220313115606834.png)]

TCP网络通讯端口问题【重点】

当客户端连接到服务端后,实际上客户端是通过一个端口和服务端进行通讯的,这个端是TCP/IP来分配的,是不确定的,是随机的,意思就是客户端也有一个端口,这个端口是TCP/CP分配的,是随机的;不像服务器端的端口是固定的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hx4njwmC-1647264505161)(E:\Typora笔记\java笔记\img\image-20220313121616188.png)]

UDP网络通信编程
基本介绍

1.类DatagramSocket 【数据报套接字】 和 DatagramPacket【数据包/数据报】实现了基于UDP协议网络程序

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

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

4.UDP协议中每个数据报都给出了完整地址信息,因此无须建立发送方和接收方的连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7WGHlfMA-1647264505161)(E:\Typora笔记\java笔记\img\image-20220313145955310.png)]

基本流程
  1. 核心的两个类【对象】DatagramSocketDatagramPacket
  2. 建立发送端,接收端【没有服务端和客户端概念】
  3. 发送数据前,建立数据包【数据报】DatagramPacket对象
  4. 调用DatagramSocket的发送,接收方法
  5. 关闭DatagramSocket

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wZqIGg7f-1647264505161)(E:\Typora笔记\java笔记\img\image-20220313150241147.png)]

UDP网络编程原理示意图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2dRqiAFu-1647264505161)(E:\Typora笔记\java笔记\img\image-20220313150315226.png)]

DatagramSocket

继承关系和构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KPRwXYdO-1647264505162)(E:\Typora笔记\java笔记\img\image-20220313161416121.png)]

构造器

ModifierConstructor and Description
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口。
protectedDatagramSocket(DatagramSocketImpl impl) 使用指定的DatagramSocketImpl创建一个未绑定的数据报套接字。
DatagramSocket(int port) 构造数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr) 创建一个数据报套接字,绑定到指定的本地地址。
DatagramSocket(SocketAddress bindaddr) 创建一个数据报套接字,绑定到指定的本地套接字地址。

常用方法

voidreceive(DatagramPacket p) 从此套接字接收数据报包。
voidsend(DatagramPacket p) 从此套接字发送数据报包。
DatagramPacket

继承关系和构造器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wqGaKJi2-1647264505162)(E:\Typora笔记\java笔记\img\image-20220313162614557.png)]

构造器

Constructor and Description
DatagramPacket(byte[] buf, int length) 构造一个 DatagramPacket用于接收长度的数据包 length
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int offset, int length) 构造一个 DatagramPacket用于接收长度的分组 length ,指定偏移到缓冲器中。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造用于发送长度的分组数据报包 length具有偏移 ioffset指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造用于发送长度的分组数据报包 length具有偏移 ioffset指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。

方法

Modifier and TypeMethod and Description
InetAddressgetAddress() 返回该数据报发送或接收数据报的计算机的IP地址。
byte[]getData() 返回数据缓冲区。
intgetLength() 返回要发送的数据的长度或接收到的数据的长度。
intgetOffset() 返回要发送的数据的偏移量或接收到的数据的偏移量。
intgetPort() 返回发送数据报的远程主机上的端口号,或从中接收数据报的端口号。
SocketAddressgetSocketAddress() 获取该数据包发送到或正在从其发送的远程主机的SocketAddress(通常为IP地址+端口号)。
voidsetAddress(InetAddress iaddr) 设置该数据报发送到的机器的IP地址。
voidsetData(byte[] buf) 设置此数据包的数据缓冲区。
voidsetData(byte[] buf, int offset, int length) 设置此数据包的数据缓冲区。
voidsetLength(int length) 设置此数据包的长度。
voidsetPort(int iport) 设置发送此数据报的远程主机上的端口号。
voidsetSocketAddress(SocketAddress address) 设置该数据报发送到的远程主机的SocketAddress(通常是IP地址+端口号)。

应用案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvvjsNeY-1647264505162)(E:\Typora笔记\java笔记\img\image-20220313174359340.png)]

package network_.inerAddress_.UDP_;

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

/**
 * @author: 海康
 * @version: 1.0
 */
public class UDPReceiverA {
    public static void main(String[] args) throws IOException {
        // 接收端A 在 本机 9999 端监听 接收数据
        DatagramSocket socket = new DatagramSocket(9999);
        // 需要创建 DatagramPacket 对象 用于接收数据
        // 创建一个 byte 数组用于构建 DatagramPacket 对象
        byte[] bytes = new byte[1024*64];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        // 在 receiver 接收到的数据会填充到 packet 中
        // 如果没有接收到数据程序会一直阻塞在此处
        socket.receive(packet);

        // 获取到接收数据的长度
        int length = packet.getLength();
        // 获取数据
        byte[] data = packet.getData();
        // 创建一个字符串,打印出信息
        String s = new String(data, 0, length);
        System.out.println(s);

        // 接收到数据到向发送端回话
        byte[] bytes1 = "好的  明天见!!!".getBytes();
        DatagramPacket packet1 = new
                DatagramPacket(bytes1, bytes1.length,
                    InetAddress.getByName("127.0.0.1"), 9998);
        socket.send(packet1);

        // 关闭流
        socket.close();
        System.out.println("程序A 退出!!!");
    }
}
package network_.inerAddress_.UDP_;


import java.io.IOException;
import java.net.*;

/**
 * @author: 海康
 * @version: 1.0
 */
public class UDPSendB {
    public static void main(String[] args) throws IOException {
        // 创建一个DatagramSocket 对象并在 9998 端口监听
        DatagramSocket socket = new DatagramSocket(9998);
        // 创建一个DatagramPacket 对象用于封装数据
        byte[] bytes = "hello  明天去吃火锅?".getBytes();
        DatagramPacket packet =
                new DatagramPacket(bytes, bytes.length,
                        InetAddress.getByName("127.0.0.1"),9999);

        // 使用 send 方法进行发送
        socket.send(packet);

        // 创建一个 DatagramPacket 对象用于接收数据
        byte[] bytes1 = new byte[1024*8];
        DatagramPacket packet1 = new DatagramPacket(bytes1, bytes1.length);
        socket.receive(packet1);
        int length = packet1.getLength();
        byte[] data = packet1.getData();
        String s = new String(data, 0, length);
        System.out.println(s);

        // 发送完成后 关闭流
        socket.close();

        System.out.println("程序B 退出!!!");
    }
}
练习题目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6r6b2w2-1647264505162)(E:\Typora笔记\java笔记\img\image-20220313174419505.png)]

package network_.inerAddress_.homeWork_;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 海康
 * @version: 1.0
 */
public class HomeWork01Client {
    public static void main(String[] args) throws IOException {
        // 获取一个连接 就是请求服务器
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        // 获取一个 OutputStream 对象
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
        bw.write("hobby");
        bw.flush();// 一定要刷新内容,否则内容无法进入管道中
        socket.shutdownOutput();// 设置一个结束标记

        InputStream inputStream = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        String lien = "";
        while ((lien=br.readLine())!=null){
            System.out.println(lien);
        }

        // 关闭流
        br.close();
        bw.close();
        socket.close();

        System.out.println("客户端结束 !!!");
    }
}
package network_.inerAddress_.homeWork_;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author: 海康
 * @version: 1.0
 */@SuppressWarnings({"all"})
public class HomeWork01Server {
    public static void main(String[] args) throws IOException {
        // 服务器在 9999 端监听
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务器在 9999 端口监听!!!");
        // 获取一个连接
        Socket accept = serverSocket.accept();

        // 获取一个 OutputStream 对象
        OutputStream outputStream = accept.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        // 获取一个 InputStream 对象
        InputStream inputStream = accept.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        String lent = "";
        while ((lent = br.readLine())!=null){
            if (lent.equals("name")){
                writer.write("我是服务器nova!!!");
            }else if (lent.equals("hobby")){
                writer.write("编写java程序 哈哈!!!");
            }else {
                writer.write("你说啥呢?");
            }

            // 刷新内容
            writer.flush();
            System.out.println(lent);
        }

        // 设置结束标记
        accept.shutdownOutput();

        // 关闭流
        br.close();
        writer.close();
        accept.close();
        serverSocket.close();

        System.out.println("服务端结束 !!!");
    }
}
package com.hspedu.homework;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端, 使用字符流方式读写
 */
@SuppressWarnings({"all"})
public class Homework01Server {
    public static void main(String[] args) throws IOException {
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        String answer = "";
        if ("name".equals(s)) {
            answer = "我是明天";
        } else if("hobby".equals(s)) {
            answer = "编写java程序";
        } else {
            answer = "你说的啥子";
        }


        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        //    使用字符输出流的方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write(answer);
        bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//注意需要手动的flush


        //6.关闭流和socket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();//关闭

    }
}
package com.hspedu.homework;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
 * 客户端,发送 "hello, server" 给服务端, 使用字符流
 */
@SuppressWarnings({"all"})
public class Homework01Client {
    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. 通过输出流,写入数据到 数据通道, 使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));

        //从键盘读取用户的问题
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的问题");
        String question = scanner.next();

        bufferedWriter.write(question);
        bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
        bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道


        //4. 获取和socket关联的输入流. 读取数据(字符),并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 关闭流对象和socket, 必须关闭
        bufferedReader.close();//关闭外层流
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9fERU5gp-1647264505163)(E:\Typora笔记\java笔记\img\image-20220313192338514.png)]

package network_.inerAddress_.homeWork_;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/**
 * @author: 海康
 * @version: 1.0
 */
public class HomeWork02Send {
    public static void main(String[] args) throws IOException {
        // 创建 DatagramSocket 对象 并在 9999 监听
        DatagramSocket socket = new DatagramSocket(9999);
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入您的问题?");
        String s = sc.nextLine();
        byte[] bytes = s.getBytes();
        // 获取 DatagramPacket 对象 用于封装数据
        DatagramPacket datagramPacket = new DatagramPacket(bytes,
                bytes.length, InetAddress.getByName("127.0.0.1"),8888);

        socket.send(datagramPacket);


        // 创建一个 DatagramPacket 对象用于接收数据
        byte[] bytes1 = new byte[1024*8];
        DatagramPacket packet = new DatagramPacket(bytes1, bytes1.length);
        socket.receive(packet);// 接收数据填充到 packet 中
        // 拆包取出数据
        System.out.println(new String(packet.getData(),0,packet.getLength()));

        // 关闭流
        socket.close();

        System.out.println("发送端 结束 哈哈!!!");
    }
}
package network_.inerAddress_.homeWork_;

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

/**
 * @author: 海康
 * @version: 1.0
 */
public class HomeWork02Receiver {
    public static void main(String[] args) throws IOException {
        // 创建一个 DatagramSocket 对象 并且在 8888 端品监听
        DatagramSocket socket = new DatagramSocket(8888);

        // 创建一个 DatagramPacket 对象 用于封装数据
        byte[] bytes = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        socket.receive(packet);// 接收到数据会填充到 packet 中
        String s = new String(packet.getData(), 0,packet.getLength());

        // 重新创建一个 DatagramPacket 对象 用于封装数据用于发送
        DatagramPacket datagramPacket = null;
        if (s.equals("四大名著是哪些?")){
            byte[] bytes1 = "《红楼梦》,《西游记》,...".getBytes();
            datagramPacket = new DatagramPacket(bytes1,
                    bytes1.length, InetAddress.getByName("127.0.0.1"),9999);
            socket.send(datagramPacket);
        }else {
            byte[] bytes1 = "what?".getBytes();
            datagramPacket = new DatagramPacket(bytes1,
                    bytes1.length ,InetAddress.getByName("127.0.0.1"),9999 );
            socket.send(datagramPacket);
        }

        // 关闭流
        socket.close();

        System.out.println("接收方结束 !!!");
    }
}
package com.hspedu.homework;

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

/**
 * UDP接收端
 */
@SuppressWarnings({"all"})
public class Homework02ReceiverA {
    public static void main(String[] args) throws IOException {
        //1. 创建一个 DatagramSocket 对象,准备在8888接收数据
        DatagramSocket socket = new DatagramSocket(8888);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        System.out.println("接收端 等待接收问题 ");
        socket.receive(packet);

        //4. 可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        byte[] data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        //判断接收到的信息是什么
        String answer = "";
        if("四大名著是哪些".equals(s)) {
            answer = "四大名著 <<红楼梦>> <<三国演示>> <<西游记>> <<水浒传>>";
        } else {
            answer = "what?";
        }


        //===回复信息给B端
        //将需要发送的数据,封装到 DatagramPacket对象
        data = answer.getBytes();
        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9998);

        socket.send(packet);//发送

        //5. 关闭资源
        socket.close();
        System.out.println("A端退出...");

    }
}
package com.hspedu.homework;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
 * 发送端B ====> 也可以接收数据
 */
@SuppressWarnings({"all"})
public class Homework02SenderB {
    public static void main(String[] args) throws IOException {

        //1.创建 DatagramSocket 对象,准备在9998端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);

        //2. 将需要发送的数据,封装到 DatagramPacket对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的问题: ");
        String question = scanner.next();
        byte[] data = question.getBytes(); //

        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 8888);

        socket.send(packet);

        //3.=== 接收从A端回复的信息
        //(1)   构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //(2)    调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //   提示: 当有数据包发送到 本机的9998端口时,就会接收到数据
        //   如果没有数据包发送到 本机的9998端口, 就会阻塞等待.
        socket.receive(packet);

        //(3)  可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //关闭资源
        socket.close();
        System.out.println("B端退出");
    }
}
文件下载

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fcKpt9JU-1647264505163)(E:\Typora笔记\java笔记\img\image-20220313200655892.png)]

思路分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tnnVvhZu-1647264505163)(E:\Typora笔记\java笔记\img\image-20220313212101471.png)]

代码区:

package network_.inerAddress_.homeWork_;

import java.io.*;

/**
 * @author: 海康
 * @version: 1.0
 */
@SuppressWarnings({"all"})
public class StreamUtils {
    /**
     * 功能:将输入流转换成byte[]
     * @param is
     * @return
     * @throws IOException
     */
    public static byte[] streamToByArray(InputStream is) throws IOException {
        // 创建一个 ByteArrayOutputStream 对象用于存储读取到的数据
        ByteArrayOutputStream baop = new ByteArrayOutputStream();

        byte[] by = new byte[1024*8];
        int length = 0;
        while ((length=is.read(by))!=-1){
             baop.write(by,0,length);
        }

        byte[] bytes = baop.toByteArray();
        // 使用完成后,关闭流
        if (baop!=null)
            baop.close();
        return bytes;
    }


    /**
     * 功能:将InputStream转换成String
     * @param is
     * @return
     * @throws IOException
     */
    public static String streamToString(InputStream is) throws IOException {
        // 创建一个读取对象
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        // 创建一个 StringBuilder 对象
        StringBuilder sb = new StringBuilder();
        String line = "";
        while ((line=reader.readLine())!=null){
            sb.append(line);
            sb.append("\r\n");
        }
        return sb.toString();
    }
}
package network_.inerAddress_.homeWork_;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * @author: 海康
 * @version: 1.0
 */
public class HomeWork03Server {
    public static void main(String[] args) throws IOException {
        // 创建一个 ServerSocket 并且在 9999 端口监听
        ServerSocket serverSocket = new ServerSocket(9999);
        // 获取一个连接 返回一个 Socket 对象
        Socket accept = serverSocket.accept();

        // 获取一个 InputStream 对象
        InputStream inputStream = accept.getInputStream();
        String s = StreamUtils.streamToString(inputStream);

        // 文件的路径
        String parentPath = "src//";
        String childrenPath = "";
        if (s.equals("高山流水")) {
            childrenPath = "高山流水"+".mp3";
        }else {
            childrenPath = "无名"+".mp3";
        }
        File file = new File(parentPath, childrenPath);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = StreamUtils.streamToByArray(fileInputStream);

        // 获取一个 OutputStream 对象
        OutputStream outputStream = accept.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);
        bos.write(bytes);
        accept.shutdownOutput();// 设置结束标记

        // 关闭流
        bos.close();
        fileInputStream.close();
        accept.close();
        serverSocket.close();

        System.out.println("服务器端结束 !!!");
    }
}
package network_.inerAddress_.homeWork_;

import org.junit.platform.commons.util.StringUtils;

import java.awt.*;
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 HomeWork03Client {
    public static void main(String[] args) throws IOException {
        // 创建Socket 对象 获取服务器的连接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);

        // 获取 OutputStream 对象
        OutputStream outputStream = socket.getOutputStream();
        // 输入一个要下载文件名
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入要下载的文件名!");
        String s = sc.nextLine();
        outputStream.write(s.getBytes());
        // 设置结束标记
        socket.shutdownOutput();

        // 获取 InputStream 对象
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = StreamUtils.streamToByArray(inputStream);

        // 创建一个 BufferedOutputStream 对象 将读取到文件写到磁盘中
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\myMp3.mp3"));
        bos.write(bytes);

        // 使用完成后 关闭流
        bos.close();
        inputStream.close();
        socket.close();

        // 完成
        System.out.println("客户端结束 !!!");
    }
}

代码2

package com.hspedu.homework;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 文件下载的客户端
 */
public class Homework03Client {
    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 写入到磁盘文件
        //比如你下载的是 高山流水 => 下载的就是 高山流水.mp3
        //    你下载的是 无名 => 下载的就是 无名.mp3  文件名 无名.mp3
        String filePath = "e:\\" + 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.hspedu.homework;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 先写文件下载的服务端
 */
public class Homework03Server {
    public static void main(String[] args) throws Exception {

        //1 监听 9999端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //2.等待客户端连接
        System.out.println("服务端,在9999端口监听,等待下载文件");
        Socket socket = serverSocket.accept();
        //3.读取 客户端发送要下载的文件名
        //  这里使用了while读取文件名,时考虑将来客户端发送的数据较大的情况
        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);

        //老师在服务器上有两个文件, 无名.mp3 高山流水.mp3
        //如果客户下载的是 高山流水 我们就返回该文件,否则一律返回 无名.mp3

        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());
        //7. 写入到数据通道,返回给客户端
        bos.write(bytes);
        socket.shutdownOutput();//很关键.

        //8 关闭相关的资源
        bis.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("服务端退出...");

    }
}
package com.hspedu.homework;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
	/**
	 * 功能:将输入流转换成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();
		
	}

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TCP(传输控制协议)是一种面向连接的协议,它为两台计算机之间的通信提供了可靠的通信机制。它为应用程序提供了可靠的字节流传输服务,可以保证数据传输的可靠性和安全性。UDP(用户数据报协议)是一种无连接的协议,它可以将数据报文发送到网络上的任何主机,而不需要建立连接。它提供了一个不可靠的数据传输服务,没有保证数据的可靠性和安全性。 ### 回答2: TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常见的传输层协议,它们在Java编程有一些明显的区别。 首先,TCP是一种面向连接的协议,而UDP是一种无连接的协议。在TCP,客户端和服务器之间建立连接,并且在数据传输之前进行握手和断开连接。而在UDP,数据包可以直接发送给接收方,无需建立连接。因此,在需要实时传输并且延迟较低的应用UDP会更适合,而在需要可靠性和顺序性的应用TCP更可靠。 其次,TCP提供可靠的数据传输机制,确保数据的完整性和正确性。它使用了序列号和确认机制来保证数据的顺序和完整性,并且具有自动重发机制,以处理丢失的数据包。而UDP不提供这些机制,数据包可能会在传输过程丢失或乱序,因此需要应用程序自己处理这些问题。 此外,TCP是一种面向字节流的协议,它将数据视为连续的字节流,没有明确的消息边界。因此,在使用TCP传输数据时,需要应用程序设计专门的协议来区分不同的消息。而UDP是一种面向数据报的协议,每个UDP数据包都有固定的大小,可以直接发送和接收,应用程序可以很容易地区分不同的数据包。 最后,TCP具有较高的延迟和较高的网络开销。由于建立连接、保证可靠性等机制的存在,TCP会引入一定的延迟和网络开销。而UDP没有这些机制,因此具有较低的延迟和网络开销。 综上所述,TCPUDPJava的使用有一些明显的区别。TCP适合需要可靠性和顺序性的应用,而UDP适合实时传输和延迟较低的应用。根据实际需求选择合适的协议可以提高程序的性能和效率。 ### 回答3: TCP(传输控制协议)和UDP(用户数据报协议)都是在网络通信使用的传输层协议,它们之间有以下几个区别: 1. 连接和无连接:TCP是一种面向连接的协议,通信双方在数据传输之前需要建立连接,确保数据的可靠传输。而UDP是一种无连接的协议,通信双方之间不需要建立连接,可以直接发送数据。 2. 可靠性:TCP提供可靠的数据传输,通过使用确认和重传机制来确保数据的完整性和可靠性。而UDP不提供可靠性保证,发送端发送的数据包是否能到达接收端是不做任何保证的,也无法检测和恢复丢失的数据包。 3. 数据包的顺序:TCP保证数据包的顺序,即数据包按照发送顺序传输到接收端,接收端可以按照相同的顺序重新组装数据。而UDP不保证数据包的顺序,可能会导致接收端按照不同的顺序接收数据包。 4. 传输效率:TCP需要维护连接状态、进行拥塞控制等,因而比UDP的传输效率稍低。UDP没有这些额外的负载,传输效率较高。 5. 适用场景:TCP适用于需要可靠传输、传输量较大、带宽较高的应用场景,比如网页浏览、邮件收发、文件传输等。UDP适用于实时性要求较高、传输量较小、带宽较低的应用场景,比如语音通话、视频传输、实时游戏等。 综上所述,TCPUDP在可靠性、连接方式、数据包顺序和传输效率等方面存在着明显的差异,并且适用于不同的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值