[Java] 网络编程

avatarplhDigital nomad

Java 网络编程

什么是TCP/IP? 什么是IP

TCP -> Transmission Control Protocol

IP -> Internet Protocol

UDP -> User Datagram Protocol

ICMP -> Internet Control Message Protocol

SMTP -> Simple Mail Transfer Protocol

SNMP -> Simple Network manage Protocol

FTP -> File Transfer Protocol

ARP -> Address Resolation Protocol

TCP和UDP的区别

TCP Transmission Control Protocol

UDP User Datagram Protocol

利用socket获取主机信息

import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class NetworkTest {
    public static void main(String[] args) {
        System.out.println("IP Address" + getLocalHostIP());
        System.out.println("Host Name: " + getLocalHostName());

        String[] localIP = getAllLocalHostIP();

        for (int i = 0; i < localIP.length; i++) {
            System.out.println("Local IP Address " + (i + 1) + ": " + localIP[i]);
        }

        try {
            ServerSocket ss = new ServerSocket(8085);
            Socket s = ss.accept();
            InetAddress address = s.getInetAddress();
            System.out.println(address.getHostName() + " connected from " + address.getHostAddress());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getLocalHostIP() {
        try {
            java.net.InetAddress localHost = java.net.InetAddress.getLocalHost();
            return localHost.getHostAddress();
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return "Unknown Host";
        }
    }

    private static String getLocalHostName() {
        try {
            java.net.InetAddress localHost = java.net.InetAddress.getLocalHost();
            return localHost.getHostName();
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return "Unknown Host";
        }
    }

    private static String[] getAllLocalHostIP() {
        try {
            java.net.InetAddress[] allLocalIPs = java.net.InetAddress.getAllByName(java.net.InetAddress.getLocalHost().getCanonicalHostName());
            String[] ipAddresses = new String[allLocalIPs.length];
            for (int i = 0; i < allLocalIPs.length; i++) {
                ipAddresses[i] = allLocalIPs[i].getHostAddress();
            }
            return ipAddresses;
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return new String[]{"Unknown Host"};
        }
    }
}

如何利用Socket实现基于TCP的通讯

服务端

public class NetworkTest {
    public static void main(String[] args) {
        System.out.println("IP Address" + getLocalHostIP());
        System.out.println("Host Name: " + getLocalHostName());

        String[] localIP = getAllLocalHostIP();

        for (int i = 0; i < localIP.length; i++) {
            System.out.println("Local IP Address " + (i + 1) + ": " + localIP[i]);
        }

        try {
            ServerSocket ss = new ServerSocket(8085);
            Socket s = ss.accept();
            InetAddress address = s.getInetAddress();
            System.out.println(address.getHostName() + " connected from " + address.getHostAddress());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getLocalHostIP() {
        try {
            java.net.InetAddress localHost = java.net.InetAddress.getLocalHost();
            return localHost.getHostAddress();
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return "Unknown Host";
        }
    }

    private static String getLocalHostName() {
        try {
            java.net.InetAddress localHost = java.net.InetAddress.getLocalHost();
            return localHost.getHostName();
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return "Unknown Host";
        }
    }

    private static String[] getAllLocalHostIP() {
        try {
            java.net.InetAddress[] allLocalIPs = java.net.InetAddress.getAllByName(java.net.InetAddress.getLocalHost().getCanonicalHostName());
            String[] ipAddresses = new String[allLocalIPs.length];
            for (int i = 0; i < allLocalIPs.length; i++) {
                ipAddresses[i] = allLocalIPs[i].getHostAddress();
            }
            return ipAddresses;
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
            return new String[]{"Unknown Host"};
        }
    }
}

客户端

class Client {
    public static void main(String[] args) {
        Socket client;
        PrintStream ps;
        try {
            client = new Socket("localhost", 8085);
            System.out.println("connect success");
            ps = new PrintStream(client.getOutputStream());
            ps.println("Hello Server!");
            ps.flush();
            client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

先启动服务端,等待接受客户端连接,最后如下,屏幕在服务端应用下面打印出了connect success

connect success

如何利用 TCP传输中文字符

客户端代码

class Client {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("localhost", 8888);
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
        dos.writeUTF("HI , how are you");
        dos.flush();
    }
}

服务端代码

class Server {
    public static void main(String[] args) throws Exception {
        try {
            int port = 8888; // Example port number, can be changed as needed
            ServerSocket ss = new ServerSocket(port);
            System.out.println("Server started at port " + port);
            Socket s = ss.accept();
            System.out.println("Client connected: ");
            DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));
            String message = dis.readUTF();
            System.out.println("Received message: " + message);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

运行服务端,之后运行客户端,之后服务端会打印如下消息

Server started at port 8888
Client connected: 
Received message: HI , how are you

如何在socket读取数据的时候设置超时

客户端代码

public class ReadTimeoutClient {
    public static void main(String[] args) {
        int bytesRead = 0;
        byte[] buffer = new byte[1024];
        try {
            Socket s = new Socket("localhost", 8888);
            System.out.println(s.getSoTimeout());
            s.setSoTimeout(5000);
            InputStream in = s.getInputStream();
            while(true) {
                try {
                    bytesRead = in.read(buffer);
                    if (bytesRead == -1) {
                        System.out.println("End of stream reached");
                        break;
                    }
                    System.out.println("Bytes read: " + bytesRead);
                } catch (java.net.SocketTimeoutException e) {
                    System.out.println("Read timed out after 5 seconds");
                    break;
                } catch (IOException e) {
                    System.out.println("IOException occurred: " + e.getMessage());
                    break;
                }
            }

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }   
}

服务端代码

class ReadTimeoutServer {
    public static void main(String[] args) throws Exception {
        try {
            int port = 8888; // Example port number, can be changed as needed
            ServerSocket ss = new ServerSocket(port);
            System.out.println("Server started at port " + port);
            Socket s = ss.accept();
            System.out.println("Client connected: ");
            DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));
            String message = dis.readUTF();
            System.out.println("Received message: " + message);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

socket 传输信息对象

客户端代码

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

        Socket s = new Socket("localhost", 8888);
        ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(s.getOutputStream()));

        Person msg = new Person("John", 30, "2025-01-01");
        msg.setName(InetAddress.getLocalHost().getHostName() + " - " + InetAddress.getLocalHost().getHostAddress());
        oos.writeObject(msg);
        oos.flush();
        oos.close();
    }

}

服务端代码

class MessageSocketServer {
    public static void main(String[] args) throws Exception {
        int port = 8888; // Example port number, can be changed as needed
        ServerSocket ss = new ServerSocket(port);
        System.out.println("Server started at port " + port);
        Socket s = ss.accept();
        System.out.println("Client connected!");

        ObjectInput ois = new ObjectInputStream(s.getInputStream());
        Person msg = (Person) ois.readObject();

        System.out.println(
                "Received message: " + msg.getName() + ", Age: " + msg.getAge() + ", Date: " + msg.getBirthDate());

        ois.close();
        ss.close();
    }
}

基于socket生成聊天室

客户端代码

class ChatClient {
    JFrame jf = new JFrame("Chat Client");
    JTextArea jt = new JTextArea();
    DataOutputStream dos = null;
    JTextField jtf = new JTextField(15);

    public static void main(String[] args) {
        ChatClient c = new ChatClient();
        try {
            c.createForm();
            c.clientStart();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createForm() {
        // Method to create the chat client form
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.getContentPane().add(jt, BorderLayout.CENTER);

        JButton jb = new JButton("Send");
        SendButtonAction sendAction = new SendButtonAction();
        
        jb.addActionListener(sendAction);
        JPanel jp = new JPanel();
        jp.add(jtf);
        jp.add(jb);

        jf.getContentPane().add(jp, BorderLayout.SOUTH);
        jf.setSize(300, 200);
        jf.setVisible(true);
    }

    public void clientStart() throws Exception {
        Socket s = new Socket("localhost", 8888);
        dos = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
        new MySocketReadServer(s, this).start();
    }

    class SendButtonAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // Example: append the text to the chat area and clear the input field
            String msg = jtf.getText();
            jtf.setText("");
            if ("".equals(msg)) {
                JOptionPane.showMessageDialog(jf, "Please enter a message to send.");
                return;
            }
            try {
                dos.writeUTF(msg);
                dos.flush();
                jt.append("You: " + msg + "\n");
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(jf, "Error sending message: " + ex.getMessage());
            }
        }
    }

    class MySocketReadServer extends Thread {
        private Socket socket;

        public MySocketReadServer(Socket socket, ChatClient client) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                while (true) {
                    String msg = jt.getText() + "\n\r" + dis.readUTF();
                    jt.setText(msg);
                    if ("88".equals(msg)) {
                        break;
                    }
                }
            } catch (IOException e) {
                System.out.println(socket + " disconnected.");
            }
        }
    }
}

服务端代码

class ChatServer {

    private Vector<Socket> vect = new Vector<Socket>();

    public static void main(String[] args) {
        ChatServer server = new ChatServer();
        try {
            server.startServer(8888);
        } catch (Exception e) {
            System.out.println("Server error: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public void startServer(int port) throws Exception {
        ServerSocket ss = new ServerSocket(port);
        System.out.println("Chat server started at port " + port);
        while (true) {
            Socket s = ss.accept();
            vect.add(s);
            System.out.println("Client connected: " + s.getInetAddress());
            new ChatServerOpt(s).start();
        }
    }

    class ChatServerOpt extends Thread {
        private Socket socket;

        public ChatServerOpt(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                while (true) {
                    String msg = dis.readUTF();
                    System.out.println("Received message: " + msg);

                    for(Socket tmp_s : vect) {
                        if (tmp_s != socket) { // Avoid sending the message back to the sender
                            DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(tmp_s.getOutputStream()));
                            dos.writeUTF(msg);
                            dos.flush();
                        }
                    }
                    if ("88".equals(msg)) {
                        break;
                    }
                }
            } catch (IOException e) {
                System.out.println(socket + " disconnected.");
            }
        }
    }    
}

先运行服务端,再运行客户端代码,执行结果如下,

Image

获取资源大小

public class SourceSize {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://avatars.githubusercontent.com/u/14355994?u=4b9ebae91b21a12e40462470e4ab40a31e0a97bd&v=4&size=80");
            URLConnection connection = url.openConnection();
            connection.connect();
            System.out.println(connection.getContentLength() + " bytes");
            // MB
            System.out.println("Size in MB: " + (connection.getContentLength() / (1024.0 * 1024.0)) + " MB");
            System.out.println("Content-Type: " + connection.getContentType());
            System.out.println("Content-Encoding: " + connection.getContentEncoding());
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

返回如下结果

8258 bytes
Size in MB: 0.007875442504882812 MB
Content-Type: image/png
Content-Encoding: null

URL如何实现单线程下载

public class SingleThreadDownload {
    public static void main(String[] args) throws IOException {
        try {
            URL url = new URL("https://avatars.githubusercontent.com/u/14355994?u=4b9ebae91b21a12e40462470e4ab40a31e0a97bd&v=4&size=80");
            URLConnection connection = url.openConnection();
            connection.connect();
            InputStream inputStream = connection.getInputStream();
            String file = url.getFile();
            String fileName = file.substring(file.lastIndexOf('/') + 1);
            String contentType = connection.getContentType();
            fileName = fileName + "." + contentType.substring(contentType.lastIndexOf('/') + 1);
            System.out.println("Downloading: " + fileName);
            FileOutputStream fos = new FileOutputStream("./"+fileName);
            byte[] buffer = new byte[1024];
            int size = -1;
            while ((size = inputStream.read(buffer)) != -1) {
                fos.write(buffer, 0, size);
            }
            fos.close();
            inputStream.close();
            System.out.println("Download completed: " + fileName);
            System.out.println("File size: " + new File("./" + fileName).length() + " bytes");
            System.out.println("Size in MB: " + (new File("./" + fileName).length() / (1024.0 * 1024.0)) + " MB");
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

Java 断点下载

public class Download {
    private long start = 0;
    private long end = 0;

    public Download(long start, long end) {
        this.start = start;
        this.end = end;
    }

    public long getStart() {
        return start;
    }

    public void down() {
        try {
            // 20MB mp4 sample file
            URL url = new URL("https://download.samplelib.com/mp4/sample-30s.mp4");
            URLConnection connection = url.openConnection();
            connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
            String sProperty = "bytes=" + start + "-" + end;
            if (end > 0) {
                sProperty = "bytes=" + start + "-" + end;
            }
            connection.setRequestProperty("Range", sProperty);
            connection.connect();
            InputStream inputStream = connection.getInputStream();
            String file = url.getFile();
            String fileName = file.substring(file.lastIndexOf('/') + 1);
            System.out.println("Downloading: " + fileName + " from " + start + " to " + end);
            FileOutputStream fos = new FileOutputStream("./" + fileName);
            byte[] buffer = new byte[1024];
            int size = -1;
            while ((size = inputStream.read(buffer)) != -1) {
                fos.write(buffer, 0, size);
            }
            fos.close();
            inputStream.close();
            System.out.println("Download completed: " + fileName);
            connection.connect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Main {
    public static void main(String[] args) {
        // Example usage: Downloading the first 10MB of the file
        Download download = new Download(0, 10485760); // 10MB in bytes
        download.down();
        Download download2 = new Download(10485760, 20971520); // Next 10MB
        download2.down();
    }
}

java 多线程下载

public class DownloadThread {
    // url, file, startPosition, endPosition
    private String url;
    private String file;
    private long startPosition;
    private long endPosition;

    public DownloadThread(String url, String file, long startPosition, long endPosition) {
        this.url = url;
        this.file = file;
        this.startPosition = startPosition;
        this.endPosition = endPosition;
    }

    public void run() {
        try {
            URL downloadUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
            connection.setRequestProperty("User-Agent", "NetFox");
            String sPropString = "bytes=" + startPosition + "-" + endPosition;
            if (endPosition > 0) {
                sPropString = "bytes=" + startPosition + "-" + endPosition;
            }
            connection.setRequestProperty("Range", sPropString);
            System.out.println(sPropString);
            RandomAccessFile fileOutput = new RandomAccessFile(file, "rw");
            fileOutput.seek(startPosition);
            InputStream inputStream = connection.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            byte[] buffer = new byte[1024];
            int size = -1;
            while ((size = bis.read(buffer)) != -1) {
                fileOutput.write(buffer, 0, size);
            }
            fileOutput.close();
            bis.close();
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


class MultipleDownload {

    public static void main(String[] args) {
        MultipleDownload download = new MultipleDownload();
        try {
            download.downProcess("https://download.samplelib.com/mp4/sample-30s.mp4","./", 3);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    public void downProcess(String url, String filePath, int threadNum) throws Exception {
        URL downloadUrl = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
        connection.setRequestProperty("User-Agent", "NetFox");
        connection.connect();
        int fileSize = connection.getContentLength();
        System.out.println("File size: " + fileSize);
        connection.disconnect();
        String fileName = url.substring(url.lastIndexOf('/') + 1);
        String file = filePath + fileName;
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        randomAccessFile.setLength(fileSize);
        randomAccessFile.close();
        int blockSize = fileSize / threadNum;
        for (int i = 0; i < threadNum; i++) {
            int startPosition = i * blockSize;
            int endPosition = (i + 1) * blockSize - 1;
            if (i == threadNum - 1) {
                endPosition = fileSize - 1;
            }
            System.out.println("Thread " + (i + 1) + ": " + startPosition + " to " + endPosition);
            DownloadThread downloadThread = new DownloadThread(url, file, startPosition, endPosition);
            new Thread(() -> downloadThread.run()).start();
        }
    }
    
    public long getFileLength(String url) throws Exception {
        URL downloadUrl = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
        connection.setRequestProperty("User-Agent", "NetFox");
        connection.connect();
        int fileSize = connection.getContentLength();
        connection.disconnect();
        return fileSize;
    }
}

输出结果如下

File size: 21657943
Thread 1: 0 to 7219313
Thread 2: 7219314 to 14438627
Thread 3: 14438628 to 21657942
bytes=0-7219313
bytes=7219314-14438627
bytes=14438628-21657942

JAVA解析HTML

public class HTMLParse {
    @SuppressWarnings("rawtypes")
    public Collection searchURL(String url) {
        URL url2 = null;
        URLConnection urlConn = null;
        String nextLine = null;
        StringTokenizer tokenizer = null;
        Collection urlCollection = new ArrayList<>();
        try {
            url2 = new URL(url);
            urlConn = url2.openConnection();
            urlConn.connect();
            BufferedReader Reader1 = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
            while ((nextLine = Reader1.readLine()) != null) {
                tokenizer = new StringTokenizer(nextLine);
                while (tokenizer.hasMoreTokens()) {
                    String urlToken = tokenizer.nextToken();
                    if (hasMatch(urlToken)) {
                        urlCollection.add(trimURL(urlToken));
                    }
                
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return urlCollection;
    }

    // Simple implementation: checks if the token contains "http:"
    private boolean hasMatch(String urlToken) {
        return urlToken.contains("http:");
    }
    
    private String trimURL(String urlToken) {
        int start = urlToken.indexOf("http:");
        int end = urlToken.indexOf("\"", start);
        if (end == -1) {
            end = urlToken.length();
        }
        return urlToken.substring(start, end);
    }

    public static void main(String[] args) {
        HTMLParse t = new HTMLParse();
        Collection urlCollection = t.searchURL("http://www.baidu.com");
        Iterator iter = urlCollection.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
        }
    }
}

上面可以解析通过url获取到的HTML,并获取后面的输出的解析结果

http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head>
http://news.baidu.com
http://www.hao123.com
http://map.baidu.com
http://v.baidu.com
http://tieba.baidu.com
http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1
http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+
http://home.baidu.com>关于百度</a>
http://ir.baidu.com>About
http://www.baidu.com/duty/>使用百度前必读</a>&nbsp;
http://jianyi.baidu.com/