Java中UDP和TCP的使用(简单介绍和示例)

UDP和TCP

UDP通信程序介绍

UDP通信程序是基于UDP协议实现的网络通信程序。UDP(User Datagram Protocol)是一种无连接的通信协议,与TCP协议不同,UDP在传输数据时不需要建立连接,可以直接将数据报发送到目标主机。UDP协议简单高效,适用于一些实时性要求高、数据量小、容忍数据包丢失的应用场景,如游戏、媒体流传输等。

UDP通信程序可以实现点对点或广播通信。发送方将数据报放入UDP数据包中,指定目标主机的IP地址和端口号,通过网络发送给目标主机。接收方从网络中接收数据报,根据源IP地址和源端口号确定数据报的来源,从数据包中提取数据并进行处理。

UDP通信程序常见的实现方式是使用网络套接字(socket)API。发送方创建一个UDP套接字,设置目标IP地址和端口号,将数据报发送给目标主机;接收方创建一个UDP套接字,绑定到指定的本地IP地址和端口号,从网络接收数据报并进行处理。在数据交换过程中,需要注意数据报长度、分包重组、错误处理等问题,以确保数据的正确性和可靠性。

java中UDP的相关方法:’

Java中实现UDP通信需要使用Java提供的网络编程API,主要包括以下几个相关方法:

  1. DatagramSocket类:Java提供的实现UDP通信的类,用于发送和接收数据包。
  2. DatagramPacket类:Java提供的用于打包数据和地址的类,用于构建发送和接收的数据包。
  3. InetAddress类:Java提供的用于处理IP地址的类,用于获取本机和远程主机的IP地址。
  4. send()方法:用于发送数据包,该方法需要指定数据包和目标地址。
  5. receive()方法:用于接收数据包,该方法会阻塞直到收到数据包。
  6. setSoTimeout()方法:设置接收超时时间,若在指定时间内未收到数据包则返回异常。
  7. close()方法:关闭数据包的发送和接收。
  8. setSoTimeout()方法:设置接收超时时间,若在指定时间内未收到数据包则返回异常。
  9. close()方法:关闭数据包的发送和接收。

示例代码:

  1. 创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
  1. 创建DatagramPacket对象,用于存储发送的数据和目标地址
byte[] sendData = "hello world".getBytes();
InetAddress targetAddress = InetAddress.getByName("192.168.0.1");
int targetPort = 8000;
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, targetAddress, targetPort);
  1. 发送数据包
socket.send(sendPacket);
  1. 创建DatagramPacket对象,用于存储接收的数据
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
  1. 接收数据包
socket.receive(receivePacket);
String message = new String(receivePacket.getData());
  1. 关闭DatagramSocket对象
socket.close();

java中TCP的相关方法:

在Java中,使用Socket和ServerSocket类来实现TCP通信。

在客户端实现TCP通信时需要使用Socket类。通过Socket类可以连接到服务端,打开输入输出流并进行数据传输。以下是Socket类常用的方法:

  1. Socket(String host, int port):创建一个连接到指定主机和端口号的Socket对象。

  2. getInputStream():获取Socket的输入流。

  3. getOutputStream():获取Socket的输出流。

  4. close():关闭Socket对象,释放相应的资源。

在服务端实现TCP通信时需要使用ServerSocket类。通过ServerSocket类可以监听客户端的连接请求,并返回连接的Socket对象。以下是ServerSocket类常用的方法:

  1. ServerSocket(int port) :创建一个绑定到指定端口号的ServerSocket对象。

  2. accept():阻塞等待客户端的连接请求,并返回连接的Socket对象。

  3. close():关闭ServerSocket对象,释放相应的资源。

在TCP通信中,需要使用输入输出流来实现数据的发送和接收。Java中提供了DataOutputStream和DataInputStream类来支持TCP数据的传输。以下是这两个类常用的方法:

  1. DataOutputStream.write(byte[] b):向输出流写入字节数组b。

  2. DataOutputStream.flush():清空输出流缓冲区。

  3. DataInputStream.read(byte[] b):从输入流中读取指定长度的字节数组。

  4. DataInputStream.readInt():从输入流中读取一个Int类型的数据。

另外,在Java中还有一个OutputStreamWriter类和一个InputStreamReader类,用于将字节流转化为字符流的方法。

以上是Java中TCP通信中常用的类和方法,可以帮助实现TCP通信的功能。

UDP完成下载文件的服务器和客户端的代码示例:

以下是使用UDP协议实现文件传输的Java代码。代码中包括一个UDP服务器和一个UDP客户端。

UDP服务器代码:

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

public class UDPServer {
    public static void main(String[] args) throws IOException {
        // 创建UDP服务器Socket,监听端口号为8888
        DatagramSocket serverSocket = new DatagramSocket(8888);
        
        // 创建接收数据包的数组
        byte[] receiveData = new byte[1024];
        
        // 创建文件输出流,用于写入接收到的文件数据
        FileOutputStream fileOutputStream = new FileOutputStream("received_file.txt");
        
        while (true) {
            // 创建接收数据包
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            
            // 接收数据包
            serverSocket.receive(receivePacket);
            
            // 获取接收到的数据
            byte[] data = receivePacket.getData();
            
            // 写入数据到文件输出流
            fileOutputStream.write(data, 0, data.length);
            
            // 判断是否已经接收到文件的最后一个数据包
            if (data[data.length - 1] == -1) {
                // 关闭文件输出流和服务器Socket
                fileOutputStream.close();
                serverSocket.close();
                break;
            }
        }
    }
}

UDP客户端代码:

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

public class UDPClient {
    public static void main(String[] args) throws IOException {
        // 创建UDP客户端Socket
        DatagramSocket clientSocket = new DatagramSocket();
        
        // 获取要发送的文件数据
        File file = new File("send_file.txt");
        byte[] fileData = new byte[(int) file.length()];
        FileInputStream fileInputStream = new FileInputStream(file);
        fileInputStream.read(fileData);
        
        // 设置对方的IP地址和端口号
        InetAddress IPAddress = InetAddress.getByName("localhost");
        int port = 8888;
        
        // 发送文件数据
        int dataSize = 1024;
        for (int i = 0; i < fileData.length; i += dataSize) {
            byte[] sendData = new byte[dataSize];
            if (i + dataSize > fileData.length) {
                dataSize = fileData.length - i;
                sendData = new byte[dataSize + 1];
                sendData[dataSize] = -1; // 结束标志
            }
            System.arraycopy(fileData, i, sendData, 0, dataSize);
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, port);
            clientSocket.send(sendPacket);
        }
        
        // 关闭文件输入流和客户端Socket
        fileInputStream.close();
        clientSocket.close();
    }
}

说明:

  1. 服务器将接收到的文件数据写入到received_file.txt文件中。

  2. 客户端从send_file.txt文件中读取数据并发送,发送的数据分成大小为1024的数据包,当发送的最后一个数据包不够1024字节时,将数据包大小改为实际大小加上一个结束标志(即值为-1的字节)。

  3. 使用文件输入流和文件输出流读取和写入文件数据。

注意事项:

  1. 文件名和路径应根据实际情况进行修改。

  2. 发送方和接收方的IP地址和端口号必须相同。

  3. 发送方的文件必须存在且可读。

  4. 该代码仅作为学习UDP协议的文件传输基本原理之用,实际文件传输应使用更为健壮和高效的传输协议,例如TCP。

在Java中用TCP完成下载文件的服务器和客户端的代码:

下面是用TCP协议在Java中实现文件下载的服务器和客户端代码。

TCP服务器代码:

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

public class TCPServer {
    public static void main(String[] args) throws IOException {
        // 创建服务器Socket,监听端口号为8888
        ServerSocket serverSocket = new ServerSocket(8888);
        
        while (true) {
            // 等待客户端连接
            Socket clientSocket = serverSocket.accept();
            System.out.println("Client connected: " + clientSocket.getInetAddress().toString());
            
            // 获取要发送的文件
            File file = new File("file_to_send.txt");
            FileInputStream fileInputStream = new FileInputStream(file);
            
            // 创建输出流,用于向客户端发送数据
            OutputStream outputStream = clientSocket.getOutputStream();
            
            // 发送文件数据
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            
            // 关闭文件输入流、输出流和客户端Socket
            fileInputStream.close();
            outputStream.close();
            clientSocket.close();
        }
    }
}

TCP客户端代码:

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

public class TCPClient {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket,连接到服务器IP地址为"localhost",端口号为8888
        Socket clientSocket = new Socket("localhost", 8888);
        
        // 创建输入流,用于读取从服务器发送过来的数据
        InputStream inputStream = clientSocket.getInputStream();
        
        // 创建输出流,用于保存下载的文件
        FileOutputStream fileOutputStream = new FileOutputStream("received_file.txt");
        
        // 读取服务器发送过来的文件数据并保存到本地文件中
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            fileOutputStream.write(buffer, 0, bytesRead);
        }
        
        // 关闭输入流、输出流和客户端Socket
        fileOutputStream.close();
        inputStream.close();
        clientSocket.close();
    }
}

说明:

  1. 服务器将要发送的文件数据发送到客户端。客户端将接收到的文件数据保存到本地文件中。

  2. 使用文件输入流和文件输出流读取和写入文件数据。

注意事项:

  1. 文件名和路径应根据实际情况进行修改。

  2. 服务器和客户端必须在文件路径上具有相同的文件。

  3. 此示例仅适用于单个文件,如果需要下载多个文件,则需要在服务器和客户端之间协商传输协议。

多线程的TCP服务器,使用字符流完成TCP

让我们来设计一个多线程的TCP服务器,使用字符流完成TCP通信。

首先,我们需要使用Java中的ServerSocket类来创建一个TCP服务器。ServerSocket接收客户端请求,创建一个Socket实例,并将双方连接在一起。

在多线程环境下,我们需要创建一个Thread类的子类来处理每个客户端连接请求。具体来说,我们需要在Thread中实现以下步骤:

  1. 创建Socket对象来接收客户端请求
  2. 创建InputStream和OutputStream对象用来读取和写入数据
  3. 处理客户端请求并发送回应
  4. 关闭输入流和输出流,并关闭Socket对象

在代码实现上,我们可以这样写:

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

public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(8000);
            System.out.println("TCP Server started on port 8000.");
        } catch (IOException e) {
            System.out.println("Could not start TCP Server on port 8000:" + e.getMessage());
            System.exit(-1);
        }

        while (true) {
            Socket clientSocket = null;

            try {
                clientSocket = serverSocket.accept();
                System.out.println("Accepted connection: " + clientSocket.getInetAddress().toString());
                Thread t = new ClientThread(clientSocket);
                t.start();
            } catch (IOException e) {
                System.out.println("Error accepting connection: " + e.getMessage());
                System.exit(-1);
            }
        }
    }
}

class ClientThread extends Thread {
    private static int counter = 0;

    private final Socket clientSocket;
    private final int clientID;

    public ClientThread(Socket clientSocket) {
        counter++;
        this.clientSocket = clientSocket;
        this.clientID = counter;
    }

    public void run() {
        System.out.println("Handling client " + clientID);

        try {
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String inputLine;

            while ((inputLine = in.readLine()) != null) {
                System.out.println("Received: " + inputLine);
                out.println("Echo: " + inputLine);
            }

            in.close();
            out.close();
            clientSocket.close();
            System.out.println("Closed connection for client " + clientID);
        } catch (IOException e) {
            System.out.println("Error handling client " + clientID + ": " + e.getMessage());
        }
    }
}

在上面的代码中,我们首先创建了一个ServerSocket对象来监听端口8000。接着,我们使用一个while循环来不断接收客户端的连接请求。每当有新的客户端连接请求时,我们会创建一个Socket对象,并将其传递给一个ClientThread线程处理。ClientThread线程处理完毕后,会关闭相应的输入输出流和Socket对象。

在ClientThread线程中,我们使用PrintWriter和BufferedReader来读取和写入数据。当从客户端接收到数据后,我们在控制台上输出这些数据,并将其回传给客户端。

另外需要注意的是,在ClientThread中,我们为每个客户端连接生成一个唯一的ID。这些ID可以帮助我们在控制台中区分不同的客户端连接。

你可能感兴趣的:(JAVA,tcp/ip,网络协议)