Java 网络

Posted AmyZheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 网络相关的知识,希望对你有一定的参考价值。

网络基础知识

1、计算机网络

计算机网络的概念:把分布在不同地理区域的计算机通过专门的通信线路连接在一起形成的规模庞大的、功能强大的网络系统,一个非常著名的网络万维网( World Wide Web , 即www )。

计算机网络的作用:

  • 资源共享
  • 信息传输和集中处理
  • 均衡负荷与分布处理
  • 综合信息服务

计算机网络的分类:

  • 按照网络结构划分

    星型网络、总线型网络、环线型网络、树形网络、星型环线网络

  • 按照介质来分

    双绞线网络、同轴电缆网络、光纤网、无线网、电力线网

  • 按照规模来划分

    局域网( LAN )、城域网( MAN )、广域网( WAN )

2、通信网络协议

通信网络协议的概念:网络通信协议是一种网络通用语言,为连接不同操作系统和不同硬件体系结构的互联网络引提供通信支持,是一种网络通用语言。

常见协议:

  • OSI

    OSI是Open System Interconnect的缩写,意为开放式系统互联。
    国际标准组织(国际标准化组织)制定了OSI模型,这个模型把网络通信的工作分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

  • TCP/IP

    IP是英文Internet Protocol(网络之间互连的协议)的缩写中,文简称为“网协”,是为计算机网络相互连接进行通信而设计的协议。
    TCP:Transmission Control Protocol 传输控制协议,是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明。       在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。
    UDP是同一层内另一个重要的传输协议。

3、IP地址

IP 地址是根据IP 协议为某个通信实体分配的地址

  • 这个通信实体,有可能是计算机、打印机、路由器的某个端口。

IP地址是数字型的,是个32 位( 32bit ) 的整数

  • 通常为了方便记忆,把这32 位分成4 个部分,每个部分存放8 位。
  • 因此我们实际上看到的ip 地址形式为:192.168.95.27。

NIC 负责全球的IP 地址的规划、管理

  • NIC : Internet Network Information Center。
  • NIC 下属Inter NIC 、APNIC、PIPE 机构负责美国及其他地区的IP 地址分配。
  • APNIC 总部在日本东京大学,负责亚太地区的IP地址分配。

IP地址被分成A、B、C、D、E 五类

  • A类: 10.0.0.0 ~ 10.255.255.255
  • B类: 172.16.0.0 ~ 172.31.255.255
  • C类: 192.168.0.0 ~ 192.168.255.255

一个特殊的IP 地址

  • 127.0.0.1 : 代表当前计算机本身。

查询IP地址的命令:

  •  Windows :  ipconfig  /all
  •  Unix / Linux / Mac OS :  ifconfig  -a

 IP v4 :

  • 采用 32 bit 的数字表示一个地址    ------->  java.net.Inet4Address
  • 通常看到的 192.168.100.100 形式是将 32bit 拆分成 4 各部分,每个部分 8bit
  • 不同的部分之间 用 圆点 进行分隔

IP v6 :

  • 采用 128bit 的数字表示一个地址    ------->  java.net.Inet6Address
  • 通常看到的 FEC0:0:0:ffff::1
  • 每个部分由 4 位 十六进制 表示的 整数 组成,比如 FEC0 , 每部分占 16 bit
  • 不同的部分之间 用 冒号 进行分隔 ,( 分成 8 个部分 )
  •  如果 某个部分 的 4 个十六进制数字都是 0 ,可以只写一个 ,比如  0000 可以写成 0
  •  FEC0:0:0:ffff::1 ------>  FEC0:0000:0000:FFFF:0000:0000:0000:0001

4、端口

端口的作用:一个IP 地址可以唯一地确定一个通信实体,一个通信实体上可以有多个程序提供服务比如一台服务器上可以有多个DBMS,如mysql 、DB2、Oracle,为了区别同一个通信实体上的不同服务(程序),还要使用端口。

端口的概念:

  • 端口是一个16 bit的整数,用于表示数据交给哪个通信程序处理。
  • 端口是应用程序与外界交流的出入口,是种抽象的软件结构。

端口的分类:

  • 不同的应用程序处理不同端口上的数据同一个计算机上,不允许有两个以上程序使用同一个端口。
  • 我们自己在使用端口时,尽量使用1024 以上的端口,同时还要注意避开已经被已有的服务占用的端口。
  • 端口的范围从0 到65535 ,被分成三类

    公认端口: 从0 到1023
      他们紧密绑定一些特定服务,如80 端口、23端口、21端口等等
    注册端口: 从1024 到49151
      松散地绑定一些服务,比如
        » Oracle 数据库默认的端口是1521
        » MySQL 数据库默认的端口是3306
        » Tomcat 默认的端口是8080
    动态或私有端口: 从49152 到65535
      应用程序使用的动态端口,应用程序一般不会主动去使用这些端口

InetAddress

 1、InetAddress 用来代表IP 地址

它有两个子类

  • Inet4Address : 对应IPv4 地址
  • Inet6Address : 对应IPv6 地址

没有构造,通过以下静态方法获取该类的实例

  • getByName( String hostName ) :根据指定主机名称得到对应的InetAddress 实例
  • getByAddress( byte[] address ) :根据指定的IP 地址获取对应的InetAddress 实例

常用方法

  • String getCanonicalHostName()获取此IP 地址的完全限定域名
  • String getHostAddress()返回IP 地址字符串(以文本表现形式)
  • String getHostName()获取此IP 地址的主机名
  • static InetAddress getLocalHost()返回本地主机对应的InetAddress 实例
  • boolean isReachable(int timeout)测试是否可以达到该地址

InetAddress测试案例一:

package ecut.network;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

public class InetAddressTest1 {

    public static void main(String[] args) throws UnknownHostException {
        
        // 构造方法私有,通过静态方法获得 当前主机的 一个 IP 地址 对应的 InetAddress 实例
        InetAddress local = InetAddress.getLocalHost() ;
        
        System.out.println( local );
        
        System.out.println( "主机名称: " + local.getHostName()  );
        
        System.out.println( "主机地址: " + local.getHostAddress()  );
        
        byte[] address = local.getAddress(); // 以 byte 数组形式表示的 IP 地址
        System.out.println( address.length );
        System.out.println( Arrays.toString( address ) );

    }

}

InetAddress测试案例二:

package ecut.network;

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

public class InetAddressTest2 {

    public static void main(String[] args) throws UnknownHostException {
        
        System.out.println( (byte)172 );
        
        // byte[] address = { 1 , 0 , 0 , 100 };
        byte[] address = { (byte)172 , 26 , 28 , 55 };
        
        InetAddress remote = InetAddress.getByAddress( address );
        
        System.out.println( remote.getHostAddress() );
        
    }

}

InetAddress测试案例三:

package ecut.network;

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

public class InetAddressTest3 {

    public static void main(String[] args) throws UnknownHostException {
        
        InetAddress ia = InetAddress.getByName( "V-AIMEIZHENGX" );
        System.out.println( ia.getHostAddress() );
        
        System.out.println( "~~~~~~~~~~~~~~~~~~" );
        
        InetAddress[]  addresses = InetAddress.getAllByName( "V-AIMEIZHENGX" );
        
        for( int i = 0 , n = addresses.length ; i < n ;i++){
            InetAddress a = addresses[ i ] ;
            System.out.println( a.getHostAddress() );
        }
        
    }

}

InetSocketAddress

1、java.net.InetSocketAddress 类型的实例表示 ( IP + Port )

构造方法

  •  InetSocketAddress(InetAddress addr, int port)根据 IP 地址和端口号创建套接字地址。
  • InetSocketAddress(String hostname, int port)根据主机名和端口号创建套接字地址。

 InetSocketAddress 测试案例一:

package ecut.network;

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

public class InetSocketAddressTest1 {

    public static void main(String[] args) throws UnknownHostException {
        
        InetAddress address = InetAddress.getByName( "1.0.0.2" );//传ip地址和主机名都可以
        System.out.println( address.getHostName() );
        
        int port = 9527 ;
        
        InetSocketAddress isa = new InetSocketAddress( address , port );
        
        System.out.println( isa );
        
        System.out.println( isa.getHostName() );
        System.out.println( isa.getAddress().getHostAddress() );
        System.out.println( isa.getPort() );
        
    }

}

  InetSocketAddress 测试案例二:

package ecut.network;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;

public class InetSocketAddressTest2 {

    public static void main(String[] args) throws UnknownHostException {
        
        
        String hostname = "1.0.0.2";//传ip地址和主机名都可以
        int port = 9527 ;
        
        InetSocketAddress isa = new InetSocketAddress( hostname , port );
        
        System.out.println( isa );
        
        System.out.println( isa.getHostName() );
        System.out.println( isa.getAddress().getHostAddress() );
        System.out.println( isa.getPort() );
        
    }

}

 URL

1、URL 对象代表Uniform Resource Locator 统一资源定位符(协议://主机:端口/资源路径和名称)
它是指向互联网"资源"的指针

  • 这里的资源可以是简单的文件或目录。
  • 也可以是更为复杂的对象(比如数据库对象)。

URL 通常由协议名、主机名、端口和资源组成,格式如下:

  • protocol : // host : port / resourceName。
  • 常见的URL 如:http://www.baidu.com:80/index.html。
  • ftp://ftp.baidu.com:xx/金刚.mkv 、 jdbc:mysql://localhost:3306/ecut?useUnicode=true&characterEncoding=utf8、jdbc:oracle:thin:@localhost:1521:ecut

2、URL 类的构造
该类有很多重载的构造

  • 但不外乎就是指定协议名、主机名、端口、资源名等参数

可以根据已有的URL 创建全新的URL 对象

  • URL(URL context, String spec)
  • URL(URL context, String spec, URLStreamHandler handler)

3、URL 类中常用方法

String getFile() 获取此URL 的文件名。

String getHost() 获取此URL 的主机名(如果适用)。

String getPath() 获取此URL 的路径部分。

int getPort() 获取此URL 的端口号。

String getProtocol() 获取此URL 的协议名称。

String getQuery() 获取此URL 的查询部分。

URLConnection openConnection()返回一个URLConnection 对象,它表示到URL 所引用的远程对象的连接。

InputStream openStream()打开到此URL 的连接并返回一个用于从该连接读入的InputStream。

 URL 测试案例:

package ecut.network;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public class URLTest {

    public static void main(String[] args) throws IOException  {
        
        // http://www.baidu.com:80/index.html
        //MalformedURLException  如果指定了未知协议。
        URL u = new URL( "http", "www.baidu.com", 80, "/customer/account/change/password.do?date=20170506" );
        
        System.out.println( u );
        
        System.out.println( "协议: " + u.getProtocol() );
        
        System.out.println( "主机: " + u.getHost() );
        
        System.out.println( "端口: " + u.getPort() );
        
        System.out.println( "File :" + u.getFile() );
        System.out.println( "Path : " + u.getPath()  );
        System.out.println( "Query : " + u.getQuery() );
        
        System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~" );
        
        InputStream in =  u.openStream() ; 
        System.out.println( in );

    }

}

运行结果如下:

http://www.baidu.com:80/customer/account/change/password.do?date=20170506
协议: http
主机: www.baidu.com
端口: 80
File :/customer/account/change/password.do?date=20170506
Path : /customer/account/change/password.do
Query : date=20170506
~~~~~~~~~~~~~~~~~~~~~~~~~
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@3e3abc88

TCP 协议

1、TCP 协议
使用IP 协议可以将一个消息从一个通信主体发送到另一个通信主体,消息在传输过程中被分割成一个一个的小数据包。
虽然解决了数据发送和接受问题,但是不能解决数据分组在传输过程中可能出现的问题。
为了解决以上问题,需要提供一整套保障无差错通信的措施或协议,这就是目前使用广泛的TCP 协议。
TCP 协议被称作端对端协议,通过该协议建立了两个通信实体之间用于发送和收取数据的虚拟链路。

2、TCP 协议的可靠性
TCP 协议负责收集被分割的数据分组,并将其按照适当的次序发送;对方在接受到数据分组后再将其正确还原。
为了保证数据包传送中准确无误,TCP 协议使用重发机制。

  • 通信实体A发送一个消息给通信实体B后,会等待通信实体B返回的确认信息,如果A没有收到B的确认信息,则A会再次发送该消息
  • 这种重发机制,保证了数据传输的可靠性和完整性。

ServerSocket

1、使用ServerSocket 创建TCP 服务器端
ServerSocket 类的对象用于监听来自其它通信实体的连接

  • 该类的accept() 方法用于监听来自外部的连接。
  • 如果没有任何通信实体连接该ServerSocket 对象,它将永远等待下去。

获得ServerSocket 对象

  • 该类中提供了许多重载的构造方法,可以用于实例化ServerSocket。
  • 一般而言需要指定IP 和port。

Socket

1、获得Socket 进行通信
ServerSocket 实例只负责监听来自其它通信实体的连接

  • 如果accept() 方法监听到来自外部的通信实体的连接,它将返回一个Socket。
  • Socket accept() : 返回监听到的连接对应的Socket 的实例。

使用Socket 类的实例才能实现通信,该类中有两个非常重要的方法

  • InputStream getInputStream()返回当前的Socket 对应的输入流,让程序通过该流从Socket 中读取数据。
  • OutputStream getOutputStream()返回当前的Socket 对应的输出流,让程序通过该流向Socket 中写入数据。

使用Socket 创建另外一个通信实体

  • 构造一个Socket 实例,让它去连接前面建好的ServerSocket
  • Socket 类构造有多种重载形式,但一般需要指定连接哪个主机或哪个ip,另外还要指定端口号,比如:Socket s = new Socket("127.0.0.1" , 8888 );

服务端监听一次测试案例:

package ecut.network;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

public class ServerV1 {

    public static void main(String[] args) throws Exception {
        
        // 创建一个 ServerSocket 对象,用来对外提供服务
        ServerSocket server = new ServerSocket();
        System.out.println( server );
        System.out.println( server.isBound() );
        
        SocketAddress endpoint = new InetSocketAddress( "10.10.12.72",  5555 );
        server.bind( endpoint );
        
        System.out.println( "server ip : " + server.getInetAddress().getHostAddress());
        System.out.println( "server port : " +server.getLocalPort() );
        
        // 监听来自客户端的连接 ( 会阻塞当前线程 )
        Socket socketFromClient = server.accept();
        System.out.println( "socket : " + socketFromClient );
        
        System.out.println( "server ip ( local ) : " + socketFromClient.getLocalAddress().getHostAddress() );
        System.out.println( "server port ( local ) : " + socketFromClient.getLocalPort() );
        
        InetSocketAddress sa = (InetSocketAddress) socketFromClient.getRemoteSocketAddress();
        System.out.println( "client ip : " + sa.getHostString() );
        System.out.println( "client port : " + sa.getPort() );
        
        server.close();
    }

}
package ecut.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

public class ClientV1 {

    public static void main(String[] args) throws IOException {
        
        // 创建一个 Socket 对象,充当客户端程序
        Socket client = new Socket();
        
        SocketAddress bindpoint = new InetSocketAddress( "10.10.12.72",  3333 );
        // 为客户端绑定本地的IP地址和端口
        client.bind( bindpoint );
        
        System.out.println( client );
        System.out.println( client.getLocalAddress().getHostAddress() );
        System.out.println( client.getLocalPort() );
        
        
        SocketAddress remote = new InetSocketAddress( "10.10.12.72",  5555 );
        // 连接 "远程" 服务
        client.connect( remote );
        
        System.out.println( client );

    }

}

运行结果如下:

ServerSocket[unbound]
false
server ip : 10.10.12.72
server port : 5555
socket : Socket[addr=/10.10.12.72,port=3333,localport=5555]
server ip ( local ) : 10.10.12.72
server port ( local ) : 5555
client ip : 10.10.12.72
client port : 3333
Socket[unconnected]
10.10.12.72
3333
Socket[addr=/10.10.12.72,port=5555,localport=3333]

服务端持续监听测试案例:

package ecut.network;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

public class ServerV2 {

    @SuppressWarnings("resource")
    public static void main(String[] args) throws Exception {
        
        // 创建一个 ServerSocket 对象
        ServerSocket server = new ServerSocket();
        
        SocketAddress endpoint = new InetSocketAddress( "10.10.12.72",  6666 );
        server.bind( endpoint );
        
        while( true ) {
            // 监听来自客户端的连接 ( 会阻塞当前线程 )
            Socket socketFromClient = server.accept();
            
            InetSocketAddress sa = (InetSocketAddress) socketFromClient.getRemoteSocketAddress();
            System.out.print( "client ip : " + sa.getHostString() );
            System.out.println( " , client port : " + sa.getPort() );
        }
        
    }

}
package ecut.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

public class ClientV2 {

    public static void main(String[] args) throws IOException {
        
        // 创建一个 Socket 对象,充当客户端程序
        Socket client = new Socket();//默认指定为当地的IP地址,将一个空闲的端口号用于使用
        
        SocketAddress remote = new InetSocketAddress( "10.10.12.72",  6666 );
        // 连接 "远程" 服务
        client.connect( remote );
        
        System.out.println( client );

    }

}

运行结果如下:

Socket[addr=/10.10.12.72,port=6666,localport=50688]
Socket[addr=/10.10.12.72,port=6666,localport=50699]
client ip : 10.10.12.72 , client port : 50688
client ip : 10.10.12.72 , client port : 50699

 服务端持续监听测试案例:

package ecut.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;

public class ServerV3 {

    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException {

        // 创建一个 ServerSocket 对象
        System.out.println("服务器启动中...");
        ServerSocket server = new ServerSocket();

        SocketAddress endpoint = new InetSocketAddress("10.10.12.72", 6666);
        System.out.println("服务器正在初始化...");
        server.bind(endpoint);

        System.out.println("服务器初始化完成,准备对外提供服务");
        while (true) {
            System.out.println("服务器正在监听来自客户端的连接..."); // ( 会阻塞当前线程 )
            Socket socket = server.accept();

            try {
                // 获得 可以从 当前监听到的 客户端连接 中 读取数据的 字节输入流
                InputStream in = socket.getInputStream();
                Reader reader = new InputStreamReader(in);
                BufferedReader br = new BufferedReader(reader);

                while (true) {
                    String s = br.readLine();
                    System.out.println("来自客户端的信息: [ " + s + " ]");
                    if ("byebyebye".equalsIgnoreCase(s)) {
                        break;
                    }
                }
            } catch (IOException e) {
                if (e instanceof SocketException) {
                    SocketException se = (SocketException) e;
                    String message = se.getMessage();
                    System.out.print("message"+message);
                    if ("Connection reset".equalsIgnoreCase(message)) {
                        System.out.println("客户端断开");
                    } else {
                        se.printStackTrace();
                    }
                } else {
                    e.printStackTrace();
                }
            }

        }

    }

}
package ecut.network;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Scanner;

public class ClientV3 {

    public static void main(String[] args) throws IOException {
        
        final Scanner scanner = new Scanner( System.in );
        
        // 1、创建一个可以连接远程服务器的一个 Socket 对象 ( 充当客户端 )
        Socket client = new Socket();
        
        SocketAddress remote = new InetSocketAddress( "10.10.12.72",  6666 );
        // 2、连接 "远程" 服务器上的指定程序
        client.connect( remote );
        
        // 3、获得可以向服务器输出数据的 字节输出流
        OutputStream out = client.getOutputStream();
        PrintStream ps = new PrintStream( out );
        
        while( true ){
            System.out.println( "请输入你要向服务器发送的信息:" );
            String s = scanner.nextLine();
            ps.println( s );
            if( "byebyebye".equalsIgnoreCase( s ) ){
                break ;
            }
        }
        // end
        client.close();
        scanner.close();

    }

}

 实现群聊测试案例:

package ecut.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class ServerV4 {
    
    private static final Map<String,Socket> SOCKETS = new HashMap<>() ;

    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException {
        
        // 创建一个 ServerSocket 对象
        System.out.println( "服务器启动中..." );
        ServerSocket server = new ServerSocket();
        
        SocketAddress endpoint = new InetSocketAddress( "192.168.0.106",  6666 );
        System.out.println( "服务器正在初始化..." );
        server.bind( endpoint );
        
        System.out.println( "服务器初始化完成,准备对外提供服务" );
        while( true ) {
            System.out.println( "服务器正在监听来自客户端的连接..."); // ( 会阻塞当前线程 )
            Socket socket = server.accept();
            
            InetSocketAddress remote = (InetSocketAddress) socket.getRemoteSocketAddress();
            String name = remote.getHostString() + ":" + remote.getPort() ;
            
            // 将当前监听到的 客户端  name ( ip:port ) 跟 响应的 Socket 对象建立 "映射"
            SOCKETS.put( name , socket ) ;
            
            System.out.println( "创建为[ " + name + " ]提供服务的线程" );
            ServerThread t = new ServerThread( socket , name ) ;
            System.out.println( "启动为[ " + name + " ]提供服务的线程" );
            t.start();
        }
        
    }
    
    public static class ServerThread extends Thread {
        
        private String name ;
        private Socket socket ;
        
        public ServerThread(Socket socket , String name ) {
            super( name );
            this.name = name ;
            if( socket == null ) {
                throw new RuntimeException( "Socket不能是null" );
            }
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                // 获得 可以从 当前监听到的 客户端连接 中 读取数据的 字节输入流
                InputStream in = socket.getInputStream();
                Reader reader = new InputStreamReader( in ) ; 
                BufferedReader br = new BufferedReader( reader );
                
                while( true ) {
                    String message = br.readLine();
                    String msg = message ;
                    message = "[ " + name +" ] 说 : [ " + message  + " ]";
                    System.out.println( message );
                    
                    for( Socket s :SOCKETS.values() ){
                        OutputStream out = s.getOutputStream();
                        PrintStream ps = new PrintStream( out );
                        ps.println( message ) ;
                    }
                    
                    if( "byebyebye".equalsIgnoreCase( msg ) ){
                        SOCKETS.remove( name );
                        break ;
                    }
                }
            } catch (IOException e) {
                if( e instanceof SocketException ){
                    SocketException se = (SocketException)e ;
                    String message = se.getMessage() ;
                    if( "Connection reset".equalsIgnoreCase( message ) ) {
                        System.out.println( "客户端断开" );
                        // 将已经废弃的 Socket 对象从 Map 集合中移除
                        SOCKETS.remove( name );
                    } else {
                        se.printStackTrace();
                    }
                } else {
                    e.printStackTrace();
                }
            }
        }
    }

}
package ecut.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Scanner;

public class ClientV4 {

    public static void main(String[] args) throws IOException {
        
        final Scanner scanner = new Scanner( System.in );
        
        // 1、创建一个可以连接远程服务器的一个 Socket 对象 ( 充当客户端 )
        Socket client = new Socket();
        
        SocketAddress remote = new InetSocketAddress( "192.168.0.106",  6666 );
        // 2、连接 "远程" 服务器上的指定程序
        client.connect( remote );
        
        // 3、创建一个独立的线程,专门用来读取服务器发送的数据
        ClientThread t = new ClientThread( client );
        t.start();
        
        // 4、获得可以向服务器输出数据的 字节输出流
        OutputStream out = client.getOutputStream();
        PrintStream ps = new PrintStream( out );
        
        while( true ){
            System.out.println( "请输入你要向服务器发送的信息:" );
            String s = scanner.nextLine();
            ps.println( s );
            if( "byebyebye".equalsIgnoreCase( s ) ){
                break ;
            }
        }
        // end
        client.close();
        scanner.close();

    }
    
    public static class ClientThread extends Thread {
        
        private Socket socket ;
        
        public ClientThread(Socket socket) {
            super();
            this.setDaemon( true );//应该设置为精灵线程
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                // 获得 可以从 当前监听到的 客户端连接 中 读取数据的 字节输入流
                InputStream in = socket.getInputStream();
                Reader reader = new InputStreamReader( in ) ; 
                BufferedReader br = new BufferedReader( reader );
                
                while( true ) {
                    String s = br.readLine();
                    System.out.println( s );
                }
            } catch (IOException e) {
                if( e instanceof SocketException ){
                    SocketException se = (SocketException)e ;
                    String message = se.getMessage() ;
                    if( "Connection reset".equalsIgnoreCase( message ) ) {
                        System.out.println( "服务器已关闭" );
                    } else {
                        se.printStackTrace();
                    }
                } else {
                    e.printStackTrace();
                }
            }
        }
    }

}

ServerSocket / Socket
        Socket 插板
        服务器:被动地、对外提供某种服务或多种服务
       &

以上是关于Java 网络的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段14——Vue的axios网络请求封装

java代码在片段活动中不起作用

java 代码片段【JAVA】

# Java 常用代码片段

# Java 常用代码片段

创建片段而不从 java 代码实例化它