Java 网络编程

网络编程

网络编程是 Java 最擅长的方向之一,使用 Java 进行网络编程时,由虚拟机实现了底层复杂的网络协议,Java 程序只需要调用 Java 标准库提供的接口,就可以简单高效地编写网络程序。

TCP 编程

在开发应用程序时,会遇到 Socket 这个概念。Socket 是一个抽象概念,一个应用程序通过一个 Socket 来建立一个远程连接,而 Socket 内部通过 TCP/IP 协议把数据传输到网络:
在这里插入图片描述

Socket,TCP 和部分 IP 的功能都是由操作系统提供的,不同的编程语言只是提供了对操作系统调用的简单封装。例如,Java 提供的几个 Socket 相关的类就封装了操作系统提供的接口。

为什么需要 Socket 进行通信?

因为仅仅通过 IP 地址进行通信是不够的,同一台计算机同一时间会运行多个网络应用程序,例如浏览器,QQ,邮件客户端等。当操作系统接收到一个数据包的时候,如果只有 IP 地址,它没法判断应该发给那个应用程序,所以,操作系统抽象出 Socket 接口,每个应用程序需要各自对应到不同的 Socket,数据包才能根据 Socket 正确地发送到相应的应用程序。

一个 Socket 就是由 IP 地址和端口号组成,可以把 Socket 简单理解为 IP 地址加端口号。

使用 Socket 进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的 IP 地址和指定端口,如果连接成功,服务器端和客户端就成功地建立一个 TCP 连接,双方后续就可以随时发送和接收数据。
因此,当 Socket 连接成功地在服务器端和客户端之间建立后:

  • 对服务器端来说,它的 Socket 是指定的 IP 地址和指定的端口号。
  • 对客户端来说,它的 Socket 是它所在计算机的 IP 地址和一个由操作系统分配的随机端口号。

服务器端

package net;

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

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(6666);//监听指定端口
        System.out.println("server is running...");

        //使用无限循环来处理客户端连接
        for (;;) {
            Socket sock = ss.accept();//每当有新的客户端连接进来,就返回一个 Socket 实例
            System.out.println("connected from " + sock.getRemoteSocketAddress());
            Thread t = new Handler(sock);
            t.start();
        }

    }
}
package net;

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

public class Handler extends Thread{
    Socket sock;

    public Handler(Socket sock) {
        this.sock = sock;
    }

    public void run() {
        try (InputStream input = this.sock.getInputStream()) {
            try (OutputStream output = this.sock.getOutputStream()) {
                handle(input,output);
            }
        } catch (Exception e) {
            try {
                this.sock.close();
            } catch (IOException ioe) {

            }
            System.out.println("client disconnected.");
        }
    }

    private void handle(InputStream input,OutputStream output) throws IOException {
        var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
        var reader = new BufferedReader(new InputStreamReader(input,StandardCharsets.UTF_8));

        writer.write("hello\n");
        writer.flush();

        for (;;) {
            String s = reader.readLine();
            if (s.equals("bye")) {
                writer.write("bye\n");
                writer.flush();
                break;
            }
            writer.write("ok: " + s + "\n");
            writer.flush();
        }
    }
}

客户端

package net;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket sock = new Socket("localhost",6666);//连接指定服务器和端口

        try (InputStream input = sock.getInputStream()) {
            try (OutputStream output = sock.getOutputStream()) {
                handle(input,output);
            }
        }

        sock.close();
        System.out.println("disconnected.");
    }

    private static void handle(InputStream input,OutputStream output) throws IOException {
        var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
        var reader = new BufferedReader(new InputStreamReader(input,StandardCharsets.UTF_8));

        Scanner scanner = new Scanner(System.in);
        System.out.println("[server] " + reader.readLine());

        for (;;) {
            System.out.print(">>>");
            String s = scanner.nextLine();//读取一行输入
            writer.write(s);
            writer.newLine();
            writer.flush();

            String resp = reader.readLine();
            System.out.println("<<< " + resp);
            if (resp.equals("bye")) {
                break;
            }
        }
    }
}

UDP 编程

和 TCP 编程相比,UDP 编程就简单的多,因为 UDP 没有创建连接,数据包也是一次收发一个,所以没有流的概念。
在 Java 中使用 UDP 编程,仍然需要使用 Socket,因为应用程序在使用 UDP 时必须指定网络接口(IP)和端口号。
注意:UDP 端口和 TCP 端口虽然都使用 0 ~ 65535,但它们是两套独立的端口,即一个应用程序用 TCP 占用了端口 1234,不影响另一个应用程序用 UDP 占用端口 1234。

服务端

package net;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;

public class UdpServer {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(6666); //监听指定端口

        for (;;) {
            //数据缓冲区
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            ds.receive(packet);//收取一个 UDP 数据包

            String s = new String(packet.getData(),packet.getOffset(),packet.getLength(), StandardCharsets.UTF_8);
            //发送数据
            byte[] data = "ACK".getBytes(StandardCharsets.UTF_8);
            packet.setData(data);
            ds.send(packet);
        }

    }
}

客户端

package net;

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

public class UdpClient {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        ds.setSoTimeout(1000);
        ds.connect(InetAddress.getByName("localhost"),6666);//不是真的连接

        //发送
        byte[] data = "Hello".getBytes();
        DatagramPacket packet = new DatagramPacket(data,data.length);
        ds.send(packet);

        //接收
        byte[] buffer = new byte[1024];
        packet = new DatagramPacket(buffer, buffer.length);
        ds.receive(packet);
        String resp = new String(packet.getData(), packet.getOffset(), packet.getLength());
        ds.disconnect();
    }
}

参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值