Java网络编程基础:TCP Socket套接字编程 IntAddress UDP等...

本文详细介绍了网络基础知识,包括IP地址、端口、TCP/UDP协议,以及基于Java的套接字编程,重点讲解了TCP单服务器与客户端通信、多客户端并发处理,以及基于UDP的DatagramSocket发送和接收消息。
摘要由CSDN通过智能技术生成

目录

一,网络基础

1.IP地址

2.端口

3.TCP/UDP协议

4.网络编程开发模式

 二,基于套接字的Java网络编程

1.Socket

 2.InetAddress

三.基于TCP的Socket网络编程

1.单服务器端与单Socket客户端一次通讯

2.单服务器端接收多次通讯

 3.TCP网络通讯补充

四,基于UDP的网络编程

1. DatagramSocket:收发消息对象

2. DatagramPacket:数据包对象


一,网络基础

1.IP地址

        为了准确地定位网络上的目标主机,网络中的每个设备都会有一个唯一的数字标识,即网络设备的IP地址,通过ip地址,可以精确地匹配目标主机,是网络中资源共享、数据传输的依据。

2.端口

        一台主机上可能运行着许多应用程序,通过端口号可以精确地确定客户访问的是哪一个应用程序。在一台主机上,应用程序可以占用任何一个端口号;一旦应用程序占据这个端口号,其它应用将不能再占用该端口。在主机中,端口号1~1024是系统保留端口号,用来为常用的网络服务程序所占用。用户自定义应用程序,最好占用其它端口号。

3.TCP/UDP协议

网络传输过程中,数据的传递有两种最常见的形式:

  • TCP协议,是一种面向连接的可靠的基于字节流的传输层通信协议 需要首先在网络两端建立安全连接,再进行数据传递,确保网络双方完整无误地传输数据。
  • UDP协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务 无需建立网络双方连接,直接发送数据包(包含目的地址信息),可能会因为网络问题导致数据传输失败等问题,但是传输速度很快,常用于局域网中传输数据

4.网络编程开发模式

  • 客户端/服务器端模式(C/S模式):对于不同的服务器端程序建立不同的客户端程序
  • 浏览器/服务器段模式(B/S模式):对于不同的服务器端程序使用统一的“客户端”(即浏览器)即可 

 二,基于套接字的Java网络编程

1.Socket

客户端与服务器端建立连接后,连接两端将会建议一个虚拟“线缆”,称之为Socket(套接字);

通信的两端都要有Socket,是两台机器间通信的端口,网络通信其实就是Socket间的通信;

Socket借助IP地址和端口号,对应某一台主机中的某一个应用程序,Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输;

 2.InetAddress

 Java提供了InetAddress类,以便于获取域名和ip地址:

        //1.获取本机 InetAddress 对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);

        //2.根据主机名获取指定的 InetAddress 对象
        InetAddress host1 = InetAddress.getByName("LAPTOP-TE6QI6K6");
        System.out.println(host1);

        //3.根据域名获取 InetAddress 对象
        InetAddress host2 = InetAddress.getByName("www.baidu.com");
        System.out.println(host2);

        //4.根据 InetAddress 对象,获取ip地址
        String hostAddress = host2.getHostAddress();
        System.out.println(hostAddress);

        //5.根据 InetAddress 对象,获取域名
        String hostName = host2.getHostName();
        System.out.println(hostName);

三.基于TCP的Socket网络编程

1.单服务器端与单Socket客户端一次通讯

        对于客户端Socket应用程序来说,需要与服务器端建立连接(通过ip和端口号确定主机上的程序),并向服务器端发送数据,接收服务器端数据;

        对于服务器端来说,服务器端需用SeverSocket类来监听特定端口,接收客户端连接,接收客户端请求,向客户端发送响应;

客户端示例:

public class MyClient1 {
    public static void main(String[] args) throws IOException {
        //1.通过IP地址和端口号连接到服务端
        //2.成功连接后,生成Socket
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        //3.得到和Socket对象关联的输出流
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream =socket.getOutputStream();
        //4.通过输出流,向数据通道中写入数据
        outputStream.write("yuanshenqidong!".getBytes());
        byte by[] = new byte[1024];
        int len = inputStream.read(by);
        System.out.println(new String(by, 0, len));
        socket.close();
        outputStream.flush();
        outputStream.close();
    }
}

服务器端示例:

public class MyServer1 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        //1.在本机的9999端口进行监听,等待连接,(要求没有其他服务在监听9999)
        //2.当没有客户端连接进来时,程序会阻塞,等待连接,有客户端连接时就会返回Socket对象,连接成功
        Socket socket = serverSocket.accept();
        //3.通过getOutputStream()获取客户写入数据通道的数据
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream =socket.getOutputStream();

        byte by[] = new byte[1024];
        int len = inputStream.read(by);
        System.out.println(new String(by, 0, len));
        outputStream.write("yuanshenqidong".getBytes());
        socket.close();
        serverSocket.close();
        inputStream.close();
        outputStream.flush();
        outputStream.close();
    }
}

2.单服务器端接收多次通讯

        如果想要一个服务器与多个客户端建立连接的话,可以让服务器端持续监听特定端口,并将读写功能放入其他线程,便可实现客户端与服务端通信功能。

服务器端:

//服务器端
public class MyServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        while(true){
            Socket socket = serverSocket.accept();
            new Thread(new Read(socket)).start();
            new Thread(new Write(socket)).start();
        }
        //socket.close();
    }
}

客户端: 

//客户端
public class MyClient {
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        new Thread(new Read(socket)).start();
        new Thread(new Write(socket)).start();
        //socket.close();
    }
}

读入数据: 

public class Read implements Runnable{
    Socket socket;
    public Read(Socket socket) throws IOException {
        this.socket = socket;
    }
    Scanner scanner = new Scanner(System.in);

    @Override
    public void run() {
        InputStream inputStream  = null;
        try {
            inputStream = socket.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        while(true){
            String strClient = null;
            try {
                strClient = bufferedReader.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            System.out.println(strClient);
        }
    }
}

写入数据: 

public class Write implements Runnable{
    Socket socket;
    public Write(Socket socket) throws IOException {
        this.socket = socket;
    }

    Scanner scanner = new Scanner(System.in);

    @Override
    public void run() {
        OutputStream outputStream = null;
        try {
            outputStream = socket.getOutputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        while(true){
            String str = scanner.next();
            if(str.equals("退出!")){
                break;
            }
            try {
                bufferedWriter.write(str);
                bufferedWriter.newLine(); //插入一个换行符,表示写入的内容结束,注意对方必须用readline接收;
                bufferedWriter.flush();  //手动刷新
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

 3.TCP网络通讯补充

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

例如,我们让服务器端在9999端口上监听,使用netstat指令可以看到9999端口正在监听:

 启动客户端,可以看到这时客户端被分配了一个端口号:

四,基于UDP的网络编程

        UDP传输协议通过数据包方式向服务器发送数据,在数据包中需要包含服务器的IP信息、端口信息等内容。因此,UDP网络编程必须提供以下对象来完成不同的任务:

  • 网络两端接收消息或发送消息的对象(监听本机端口、发送消息、接收消息)
  • 数据包对象(包含目的地IP和端口信息、数据报文信息)

1. DatagramSocket:收发消息对象

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

2. DatagramPacket:数据包对象

        DatagramPacket对象封装了UDP数据包,在数据包中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。数据包大小不得超过64k(如果超过了64k,数据包会被拆分成若干个小于64k的数据包)。

可以看出:UDP协议中每个数据包都给出了完整的地址信息,因此无需建立发送方和接收方的连接。同时没有明确的服务器端和客户端,演变成了数据的发送端和接收端。

发送端:

public class Sender {
    public static void main(String[] args) throws IOException {
        //1.创建DatagramSocket对象,在8888端口号上接收数据
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        //2.将数据打包,封装到DatagramPacket对象中,指明接收端的ip地址和端口号,类似发邮件时要指明收件人和地址
        byte[] data = "原神启动".getBytes();
        DatagramPacket datagramPacket = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 9999);
        //3.发送,关闭
        datagramSocket.send(datagramPacket);
        byte[] by = new byte[1024];
        DatagramPacket datagramPacket1 = new DatagramPacket(by, by.length);
        datagramSocket.receive(datagramPacket1);

        int length = datagramPacket1.getLength();
        byte[] data1 = datagramPacket1.getData();
        String str = new String(data1, 0, length);
        System.out.println(str);

        datagramSocket.close();
    }
}

接收端: 

public class Receiver {
    public static void main(String[] args) throws IOException {
        //1.创建一个DatagramSocket对象,并在9999端口接收数据;
        DatagramSocket datagramSocket = new DatagramSocket(9999);
        //2.创建一个DatagramPacket对象,准备接收数据,接收数据包的大小最多为64k
        byte by[] = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(by, by.length);//
        //3.调用接收方法,将接收到的数据填充到datagramPacket对象中
        datagramSocket.receive(datagramPacket);
        //4.对数据进行拆包,获取数据字节长度和字节数组
        int length = datagramPacket.getLength();
        byte[] data = datagramPacket.getData();
        //5.输出数据
        String str = new String(data, 0, length).trim();
        System.out.println(str);

        byte[] data1 = "收到,原神启动".getBytes();
        DatagramPacket datagramPacket1 = new DatagramPacket(data1, data1.length, InetAddress.getByName("127.0.0.1"), 8888);
        datagramSocket.send(datagramPacket1);
        //6.关闭资源
        datagramSocket.close();
    }
}
  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值