网络编程复习(java)


前言

网络编程我个人觉得难度还是不大的,主要就是理清楚连接和发送需要哪些过程,还有需要 io 流基础。

网络编程三要素

Ip

ip 是上网设备在网络中的地址,是唯一的,就是分配给上网设备的数字标签

因为 ip 地址太难记了,所以 ip 地址会映射成 域名/主机名
采用 http 协议



Ipv4

互连网通信协议第四版
采用32位地址长度,分成四组,每组最大 255


Ipv4 地址分类

  • 公网地址(万维网使用)和私有地址(局域网使用)
  • 192.168 开头就是私有地址

127.0.0.1 表示本机


采用点分十进制表示法
在这里插入图片描述


常见 CMD 命令:

  • ipconfig: 查看本机 ip 地址
  • ping:检查网络是否连通


Ipv6

由于 Ipv4 模式下 Ip 的总数优先,所以采用 128 位置长度,分成八组,足以给地球上每一粒沙子分配


采用 冒分十六进制表示法

在这里插入图片描述
在这里插入图片描述




端口号

  • 应用程序在设备中唯一的标识
  • 由两个字节表示整数,取值返回:0 ~ 65535

其中 0 ~ 1023 之间的端口号被一些知名网络服务或应用占用,比如:ssh 22,ftp 21,所以我们自己使用的话,使用 1024 及以上端口

一个端口号只能被一个应用程序使用


常见的网络程序端口号

  • tomcat:8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1433



协议

人交流依靠的语言也算一种协议,所以网络也有自己的协议,程序才懂

这里就不谈 OSI 和 TCP/IP 模型了



TCP 协议

  • 面向连接 的通信协议
  • 速度慢,没有大小显示,数据安全

三次握手(连接)

  • 第一次握手客户端 向 服务器 发出 连接请求(等待服务器确认)
  • 第二次握手服务器 向 客户端 返回 一个响应(告诉客户端收到了请求)
  • 第三次握手客户端 向 服务器 再次发出 确认信息 (连接建立

简单来说就是

  • 客户端 发 请求
  • 服务端 收到 请求, 响应回去
  • 客户端 再次请求,(建立连接)

四次挥手(断开连接)

  • 第一次挥手客户端 向 服务端 发出 取消连接请求
  • 第二次挥手服务器 向 客户端 返回 一个响应
  • 第三次挥手服务器 向 客户端 发出 确认取消信息(将最后的数据处理完毕后
  • 第三次挥手客户端 发送 确认取消连接了信息

简单来说就是

  • 客户端 发 请求
  • 服务端 收到 请求,响应回去
  • 服务端 处理完信息,再次确认
  • 客户端 取人 (取消连接)


UDP 协议

  • 面向无连接 的通信协议
  • 速度快,一次最多发送 64 k , 数据不完全,容易丢数据



InetAddress 类

InetAddress 类就代表一个 ip 对象


获取 ip 对象

  • public static InetAddress getByName(String host)
public class client {
    public static void main(String[] args) throws IOException {
        
        //通过 ip 地址获取 ip 对象
       InetAddress ip1 = InetAddress.getByName("127.0.0.1");

       //通过 主机名 获取 ip 对象
       InetAddress ip2 = InetAddress.getByName("DESKTOP-B88KGEA");
        
       //通过 域名获取 ip 对象
       InetAddress ip3 = InetAddress.getByName("www.baidu.com");
    }
}

InetAddress.getLocalHost(); 是获取本地 ip 对象,也就是 127.0.0.1


获取到 ip 对象后,得到信息相关方法

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

        //通过 ip 地址获取 ip 对象
       InetAddress ip1 = InetAddress.getByName("127.0.0.1");
       
       //获取 ip 对象的域名/主机名
       String hostName = ip1.getHostName();
       System.out.println(hostName);

       //获取 ip 对象 对应的地址
       String ipAddress = ip1.getHostAddress();
       System.out.println(ipAddress);

    }
}



netstat 常用指令

  1. netstat -an 可以查看当前主机网络情况,包括端口监听情况,网络连接情况
  2. netstat -an | more 可以分页显示
  3. 要求在 dos 控制台下执行
  4. ctrl + c 退出

在这里插入图片描述
0 0 0 0 也表示本机,冒号后面是端口

外部地址:连接到主机的连接,也显示 ip 地址和端口号

如果由一个外部程序(客户端)连接到该端口,就会显示一条连接信




Socket(套接字)

  • 网络应用程序一般 都用 Socket 开发
  • 通信的两端都要有 Socket,它是两台机器通信的端点
  • Socket 运行程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输。

在这里插入图片描述




TCP 编程

获取 Socket类 中 获取字节输入输出流的两个方法

  • public InputStream getInputStream()
  • public OutputStream getOutStream()

注意

  • 如果 socket 端点相关的 IO 输出,必须用 socket.shutdownOutput,打上结束标记,不然不知道啥时候输出完,一直等着,如果是 BufferedWriter 且使用了readLine 可以用 newLine 当结束标记

  • 如果是有缓冲区的流记得,写出完第一时间刷新

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

        Socket socket = new Socket();
        
        //两个 socket端点 之间的输出流 
        InputStream is = socket.getInputStream();
        
         //两个 socket端点 之间的输入流 
        OutputStream os = socket.getOutputStream();
        //结束标记
        socket.socket.shutdownOutput();
    }
}


经常配合转换流,和缓冲流使用

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

        Socket socket = new Socket();
        InputStream is = socket.getInputStream();

        OutputStream os = socket.getOutputStream();
        
        //包装成字符缓冲流提升效率
        BufferedOutputStream bos = new BufferedOutputStream(os);
        
        //转化成字符流,再用缓冲流包装
        OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter bw = new BufferedWriter(osw); 
    }
}


服务端

  • public ServerSocket(int port) : 在某端口监听
  • public Socket accept() ServerSocket 类中的方法:连接到端口返回 socket 对象
public class Main {
    public static void main(String[] args) throws IOException {

        //在 8888 端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        
        //有人连接,就返回一个 socket 对象,否则就阻塞在这里
        Socket socket = serverSocket.accept();
        
        
    }
}

客户端

  • public Socket(String host, int port):连接某个端口
//连接 本机的 10022 端口
 Socket socket = new Socket("127.0.0.1", 10022);


总结

  • 服务端 监听,客户端连接后,就可以开始 IO 操作

  • 先要运行服务端,因为连接端口的时候,服务端都没启动,端口咋链接

  • 当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是 TCP/IP 来分配的,是随机的
  • 用完后记得关闭流 包括 socket

  • ServerScoket 可以创建多个 Socket, 只要由一次 accept 就会返回一个 socket, 多个客户端连接,那就要多个 socket

实例

客户端

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

        //1. 连接服务端 (ip, 端口)
        //写服务器的ip地址或者域名
        //解读:连接这台主机 的 9999 端口,连接成功返回 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        //2. 连接上后,生成Socket,通过socket.getOutputStrem()
        //得到和 这个socket 关联的 输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到数据通道
        outputStream.write("hello server".getBytes());

        //4. 关闭流对象和 socket 必须关闭
        outputStream.close();
        socket.close();

    }

}

服务端

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

        //1. 在本机 9999端口监听,等待连接
        //   细节: 要求本机没有其他服务在监听999
        ServerSocket serverSocket = new ServerSocket(9999);

        //2. 当没有客户端连接 9999 端口时,程序会阻塞,等待连接
        // 如果由客户端连接,则会返回 Socket 对象,程序继续
        Socket socket = serverSocket.accept();

        //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.关闭流
        inputStream.close();
        socket.close();
        serverSocket.close();


    }

}


UDP 编程

  • DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址 和 端口号 以及 接收端的 IP 地址和端口号
  • UDP 协议中每一个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接

UDP 没有所谓的 客户端 和 服务端,两边是等价地位


相关 类和方法

  • public DatagramSocket(int port)【Packet中的方法】:准备在哪个端口接收数据

  • public DatagramPacket(byte buf[], int length)【Packet中的方法】:把数据放进某个 byte 数组内,length 是指,最大接收的数据量

  • void receive(DatagramPacket p [Socket中的方法]):接收 packet 的数据

  • void send(DatagramPacket p [Socket中的方法]):发送 packet 的数据

  • int getLength()【Packet中的方法】:返回实际接收到的数据字节长度

  • packet.getData();【Packet中的方法】==返回接收到的数据

  • public DatagramPacket(byte buf[], int length, InetAddress address, int port)【Packet中的方法】:指定 byte[] 数组及大小,把数据装好,发送到指定的 ip 的 端口


基本流程

  1. 核心的两个类/对象 DatagramSocket 与 DatagramPacket
  2. 建立发送端,接收端(没有)
  3. 发送数据前,建立数据包,接收数据前,建立数据包
  4. 调用DatagramSocket 的发送,接收方法
  5. 关闭 DatagramSocket数据

发送的数据包
在这里插入图片描述
接收的数据包
在这里插入图片描述



实例

A

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

        //1. 创建一个 DatagramSocket 对象,准备在9999接收数C据
        DatagramSocket socket = new DatagramSocket(9999);

        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9999端口时,就会接收到数据
        //   如果没有数据包发送到 本机的9999端口, 就会阻塞等待.
        System.out.println("接收端A 等待接收数据..");
        socket.receive(packet);

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


        //===回复信息给B端
        //将需要发送的数据,封装到 DatagramPacket对象
        data = "好的, 明天见".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端退出...");

    }
}

B

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

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

        //2. 将需要发送的数据,封装到 DatagramPacket对象
        byte[] data = "hello 明天吃火锅~".getBytes(); //

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

        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端退出");
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值