【计网实验:Socket通信编程TCP/UDP】

计网实验二:Socket通信编程TCP/UDP(Java)

下面的代码还设计了一个简单的登录界面和发送消息界面

TCP

Socket编程客户端的主要步骤

1.创建一个Socket实例,指定连接的服务器Socket地址和端口号。
2.通过Socket实例获取输入输出流,并使用输入输出流进行数据传输。
3.通信完成后,关闭Socket连接。

Socket编程服务器端的主要步骤

1.创建一个服务器Socket实例,指定监听的端口号
2.启动服务器Socket,并等待客户端Socket的连接请求。
3.建立Socket连接后,通过Socket实例进行数据传输。
4.通信完成后,关闭Socket连接

Server:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Server {
    private static Map<String, PrintWriter> clients = new HashMap<>();
    private static Map<String, String> users = new HashMap<>();

    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(12345)) {
            System.out.println("服务器已启动,等待客户端连接...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("客户端连接成功");

                ClientHandler clientHandler = new ClientHandler(clientSocket);
                Thread thread = new Thread(clientHandler);
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class ClientHandler implements Runnable {
        private Socket clientSocket;
        private PrintWriter out;
        private BufferedReader in;
        private String username;
        private long loginTime;

        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        public void run() {
            try {
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                out = new PrintWriter(clientSocket.getOutputStream(), true);

                // 读取用户名和密码
                username = in.readLine();
                String password = in.readLine();

                if (isValidUser(username, password)) {
                    loginTime = System.currentTimeMillis();
                    System.out.println("用户 " + username + " 登录成功"+ "! 登录时间:" + getFormattedTime(loginTime));
                    out.println("登录成功,欢迎 " + username + "! 登录时间:" + getFormattedTime(loginTime));

                    // 添加客户端到客户端列表
                    synchronized (clients) {
                        clients.put(username, out);
                    }

                    // 接收并广播消息
                    String message;
                    while ((message = in.readLine()) != null) {
                        System.out.println(username + ": " + message);
                        broadcastMessage(username + ": " + message);
                    }
                } else {
                    System.out.println("用户 " + username + " 登录失败");
                    out.println("登录失败,请检查用户名和密码");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    // 移除客户端并关闭连接
                    synchronized (clients) {
                        clients.remove(username);
                    }
                    clientSocket.close();
                    System.out.println("用户 " + username + " 已退出");
                    broadcastMessage("用户 " + username + " 已退出");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private static boolean isValidUser(String username, String password) {
            users.put("bu", "21121157");
            users.put("user", "12345");
            return users.containsKey(username) && users.get(username).equals(password);
        }

        private void broadcastMessage(String message) {
            // 向所有客户端广播消息
            synchronized (clients) {
                for (PrintWriter clientWriter : clients.values()) {
                    clientWriter.println(message);
                }
            }
        }

        private String getFormattedTime(long time) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date(time);
            return sdf.format(date);
        }
    }
}

client:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;

public class Client {
    private static Socket socket;
    private static BufferedReader in;
    private static PrintWriter out;
    private static String username;

    private JFrame frame;
    private JTextField usernameField;
    private JPasswordField passwordField;
    private JButton loginButton;
    private JButton exitButton;

    private JTextField messageField;
    private JButton sendButton;
    private JButton sendFileButton;
    private JTextArea chatArea; 

    public Client() {
        initialize();
        connectToServer();
    }

    private void initialize() {
        frame = new JFrame("Chat App");
        frame.setPreferredSize(new Dimension(800, 600));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel loginPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10);

        usernameField = new JTextField(20);
        passwordField = new JPasswordField(20);
        loginButton = new JButton("登录");
        exitButton = new JButton("退出");

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.insets = new Insets(20, 10, 20, 10);
        loginPanel.add(new JLabel("欢迎使用聊天应用"), gbc);

        gbc.gridwidth = 1;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        loginPanel.add(new JLabel("用户名:"), gbc);
        gbc.gridy++;
        loginPanel.add(new JLabel("密码:"), gbc);
        gbc.gridx++;
        gbc.gridy--;
        gbc.anchor = GridBagConstraints.WEST;
        loginPanel.add(usernameField, gbc);
        gbc.gridy++;
        loginPanel.add(passwordField, gbc);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.CENTER;
        loginPanel.add(loginButton, gbc);
        gbc.gridy++;
        loginPanel.add(exitButton, gbc);

        frame.add(loginPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        loginButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                login();
            }
        });

        exitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                exit();
            }
        });
    }

    private void connectToServer() {
        try {
            socket = new Socket("localhost", 12345);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void login() {
        username = usernameField.getText();
        String password = new String(passwordField.getPassword());
        out.println(username);
        out.println(password);

        try {
            String serverResponse = in.readLine();
            if (serverResponse.startsWith("登录成功")) {
                frame.getContentPane().removeAll();
                frame.setLayout(new BorderLayout());

                chatArea = new JTextArea();
                chatArea.setEditable(false);
                chatArea.setLineWrap(true);
                JScrollPane scrollPane = new JScrollPane(chatArea);
                frame.add(scrollPane, BorderLayout.CENTER);

                JPanel inputPanel = new JPanel(new BorderLayout());
                frame.add(inputPanel, BorderLayout.SOUTH);

                messageField = new JTextField();
                inputPanel.add(messageField, BorderLayout.CENTER);

                sendButton = new JButton("发送消息");
                sendButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        sendMessage();
                    }
                });
                inputPanel.add(sendButton, BorderLayout.EAST);

                sendFileButton = new JButton("发送文件");
                sendFileButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        sendFile();
                    }
                });
                inputPanel.add(sendFileButton, BorderLayout.WEST);

                JButton exitChatButton = new JButton("退出");
                exitChatButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        exit();
                    }
                });
                inputPanel.add(exitChatButton, BorderLayout.SOUTH);

                frame.pack();
                frame.setSize(800, 600);
                frame.revalidate();
                frame.repaint();

                displayMessage(serverResponse);
            } else {
                JOptionPane.showMessageDialog(frame, serverResponse, "登录失败", JOptionPane.ERROR_MESSAGE);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void exit() {
        try {
            socket.close();
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendMessage() {
        String message = messageField.getText();
        if (!message.isEmpty()) {
            out.println(username + ": " + message);
            messageField.setText("");
            displayMessage(username + ": " + message);
        }
    }

    private void sendFile() {
        JFileChooser fileChooser = new JFileChooser();
        int result = fileChooser.showOpenDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            try {
                BufferedReader fileReader = new BufferedReader(new FileReader(selectedFile));
                String fileLine;
                while ((fileLine = fileReader.readLine()) != null) {
                    out.println(fileLine);
                }
                fileReader.close();
                displayMessage("文件已发送: " + selectedFile.getName());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void displayMessage(String message) {
        chatArea.append(message + "\n");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Client();
            }
        });
    }
}

UDP

Server

import java.io.IOException;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class ServerU {
    private static Map<String, InetAddress> clients = new HashMap<>();
    private static Map<String, String> users = new HashMap<>();

    public static void main(String[] args) {
        DatagramSocket socket = null;

        try {
            socket = new DatagramSocket(12345);
            byte[] receiveData = new byte[1024];

            System.out.println("服务器已启动,等待客户端连接...");

            while (true) {
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                socket.receive(receivePacket);

                InetAddress clientAddress = receivePacket.getAddress();
                int clientPort = receivePacket.getPort();
                String message = new String(receivePacket.getData(), 0, receivePacket.getLength());

                if (message.startsWith("LOGIN:")) {
                    String[] loginInfo = message.split(":");
                    if (loginInfo.length == 3) {
                        String username = loginInfo[1];
                        String password = loginInfo[2];

                        if (isValidUser(username, password)) {
                            long loginTime = System.currentTimeMillis();
                            System.out.println("用户 " + username + " 登录成功" + "! 登录时间:" + getFormattedTime(loginTime));
                            sendMessage("登录成功,欢迎 " + username + "! 登录时间:" + getFormattedTime(loginTime), clientAddress, clientPort);

                            // 添加客户端到客户端列表
                            synchronized (clients) {
                                clients.put(username, clientAddress);
                            }
                        } else {
                            System.out.println("用户 " + username + " 登录失败");
                            sendMessage("登录失败,请检查用户名和密码", clientAddress, clientPort);
                        }
                    }
                } else if (message.startsWith("MSG:")) {
                    String[] msgInfo = message.split(":");
                    if (msgInfo.length == 3) {
                        String username = msgInfo[1];
                        String msg = msgInfo[2];
                        String formattedMessage = username + ": " + msg;

                        // 接收并广播消息
                        System.out.println(formattedMessage);
                        broadcastMessage(formattedMessage, username);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }

     // 这里简单设计了一个用户验证,创建了两个用户信息
    private static boolean isValidUser(String username, String password) {
        users.put("bu", "211211");  
        users.put("user", "12345");
        return users.containsKey(username) && users.get(username).equals(password);
    }

    private static void sendMessage(String message, InetAddress address, int port) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        byte[] sendData = message.getBytes();
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, address, port);
        socket.send(sendPacket);
        socket.close();
    }

    private static void broadcastMessage(String message, String senderUsername) throws IOException {
        // 向所有客户端广播消息
        synchronized (clients) {
            for (Map.Entry<String, InetAddress> entry : clients.entrySet()) {
                if (!entry.getKey().equals(senderUsername)) {
                    sendMessage(message, entry.getValue(), 12345);
                }
            }
        }
    }

    private static String getFormattedTime(long time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(time);
        return sdf.format(date);
    }
}

Client

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;

public class ClientU {
    private static DatagramSocket socket;
    private static InetAddress serverAddress;
    private static int serverPort = 12345;
    private static String username;

    private JFrame frame;
    private JTextField usernameField;
    private JPasswordField passwordField;
    private JButton loginButton;
    private JButton exitButton;

    private JTextField messageField;
    private JButton sendButton;
    private JButton sendFileButton;
    private JTextArea chatArea;

    public ClientU() {
        initialize();
        connectToServer();
    }

    private void initialize() {
        frame = new JFrame("Chat App");
        frame.setPreferredSize(new Dimension(800, 600));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel loginPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10);

        usernameField = new JTextField(20);
        passwordField = new JPasswordField(20);
        loginButton = new JButton("登录");
        exitButton = new JButton("退出");

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.insets = new Insets(20, 10, 20, 10);
        loginPanel.add(new JLabel("欢迎使用"), gbc);

        gbc.gridwidth = 1;
        gbc.gridy++;
        gbc.anchor = GridBagConstraints.EAST;
        loginPanel.add(new JLabel("用户名:"), gbc);
        gbc.gridy++;
        loginPanel.add(new JLabel("密码:"), gbc);
        gbc.gridx++;
        gbc.gridy--;
        gbc.anchor = GridBagConstraints.WEST;
        loginPanel.add(usernameField, gbc);
        gbc.gridy++;
        loginPanel.add(passwordField, gbc);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.CENTER;
        loginPanel.add(loginButton, gbc);
        gbc.gridy++;
        loginPanel.add(exitButton, gbc);

        frame.add(loginPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        loginButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                login();
            }
        });

        exitButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                exit();
            }
        });
    }

    private void connectToServer() {
        try {
            socket = new DatagramSocket();
            serverAddress = InetAddress.getByName("localhost");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void login() {
        username = usernameField.getText();
        String password = new String(passwordField.getPassword());

        String loginMessage = "LOGIN:" + username + ":" + password;
        sendUDPMessage(loginMessage);

        try {
            byte[] receiveData = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(receivePacket);

            String serverResponse = new String(receivePacket.getData(), 0, receivePacket.getLength());
            if (serverResponse.startsWith("登录成功")) {
                frame.getContentPane().removeAll();
                frame.setLayout(new BorderLayout());

                chatArea = new JTextArea();
                chatArea.setEditable(false);
                chatArea.setLineWrap(true);
                JScrollPane scrollPane = new JScrollPane(chatArea);
                frame.add(scrollPane, BorderLayout.CENTER);

                JPanel inputPanel = new JPanel(new BorderLayout());
                frame.add(inputPanel, BorderLayout.SOUTH);

                messageField = new JTextField();
                inputPanel.add(messageField, BorderLayout.CENTER);

                sendButton = new JButton("发送消息");
                sendButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        sendMessage();
                    }
                });
                inputPanel.add(sendButton, BorderLayout.EAST);

                sendFileButton = new JButton("发送文件");
                sendFileButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        sendFile();
                    }
                });
                inputPanel.add(sendFileButton, BorderLayout.WEST);

                JButton exitChatButton = new JButton("退出");
                exitChatButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        exit();
                    }
                });
                inputPanel.add(exitChatButton, BorderLayout.SOUTH);

                frame.pack();
                frame.setSize(800, 600);
                frame.revalidate();
                frame.repaint();

                displayMessage(serverResponse);
            } else {
                JOptionPane.showMessageDialog(frame, serverResponse, "登录失败", JOptionPane.ERROR_MESSAGE);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void exit() {
        socket.close();
        System.exit(0);
    }

    private void sendMessage() {
        String message = messageField.getText();
        if (!message.isEmpty()) {
            String chatMessage = "MSG:" + username + ":" + message;
            sendUDPMessage(chatMessage);
            messageField.setText("");
            displayMessage(username + ": " + message);
        }
    }

    private void sendFile() {
        JFileChooser fileChooser = new JFileChooser();
        int result = fileChooser.showOpenDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            try {
                BufferedReader fileReader = new BufferedReader(new FileReader(selectedFile));
                String fileLine;
                while ((fileLine = fileReader.readLine()) != null) {
                    String fileMessage = "MSG:" + username + ":" + fileLine;
                    sendUDPMessage(fileMessage);
                }
                fileReader.close();
                displayMessage("文件已发送: " + selectedFile.getName());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void displayMessage(String message) {
        chatArea.append(message + "\n");
    }

    private void sendUDPMessage(String message) {
        try {
            byte[] sendData = message.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, serverPort);
            socket.send(sendPacket);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ClientU();
            }
        });
    }
}

将客户端发给服务器的字符串大写后回显到客户端

Server:
import java.net.*;
import java.util.Arrays;

public class UDPServer {
    public static void main(String[] args) {
        DatagramSocket socket = null;

        try {
            socket = new DatagramSocket(12345);

            while (true) {
                byte[] receiveData = new byte[1024];
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

                socket.receive(receivePacket);

                InetAddress clientAddress = receivePacket.getAddress();
                int clientPort = receivePacket.getPort();

                String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());

                // 转换字符串为大写
                String uppercaseMessage = receivedMessage.toUpperCase();

                byte[] sendData = uppercaseMessage.getBytes();
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientAddress, clientPort);

                socket.send(sendPacket);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }
}

Client:
import java.net.*;
import java.util.Scanner;

public class UDPClient {
    public static void main(String[] args) {
        DatagramSocket socket = null;

        try {
            socket = new DatagramSocket();

            InetAddress serverAddress = InetAddress.getByName("localhost");
            int serverPort = 12345;

            Scanner scanner = new Scanner(System.in);

            while (true) {
                System.out.print("输入消息 (或输入 'exit' 退出): ");
                String message = scanner.nextLine();

                if (message.equals("exit")) {
                    break;
                }

                byte[] sendData = message.getBytes();
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, serverPort);

                socket.send(sendPacket);

                byte[] receiveData = new byte[1024];
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);

                socket.receive(receivePacket);

                String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());
                System.out.println("服务器响应: " + receivedMessage);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }
}

TCP和UDP编程的主要差异和特点。

连接的建立与终止:
TCP:TCP是一种面向连接的协议。在数据传输之前,它需要通过“三次握手”过程建立连接。在数据传输完成后,需要通过“四次挥手”过程终止连接。
UDP:UDP是无连接的协议。发送数据之前不需要建立连接,也无需终止连接。
数据传输:
TCP:TCP提供可靠的数据传输。它使用确认、超时和重传等机制来确保数据包的顺序和完整性。
UDP:UDP不保证数据传输的可靠性。数据包可能会丢失或在接收方处以不同的顺序到达。
数据检查:
TCP:TCP提供错误检查机制,能够检测数据在传输过程中是否发生了损坏。
UDP:UDP没有错误检查机制。
流量控制:
TCP:TCP提供流量控制机制,可以防止发送方超过接收方的处理能力。
UDP:UDP没有流量控制机制。
传输方式:
TCP:TCP是面向字节流的。它将数据看作是无边界的字节流,不关心数据的内部结构。
UDP:UDP是面向数据报的。它保留数据的边界,每个数据报都被单独处理。
头部开销:
TCP:TCP的头部开销比UDP大。TCP头部固定为20字节,而UDP头部固定为8字节。
UDP:UDP的头部开销较小,因此更适合于传输小数据包。
编程接口:
TCP:TCP使用套接字(socket)编程接口,常用的编程语言都提供了对套接字的支持。
UDP:UDP同样使用套接字编程接口,但使用不同的套接字类型(DGRAM套接字)。
应用场景:
TCP:TCP适用于需要可靠、有序和错误检查的数据传输场景,如网页浏览、电子邮件等。
UDP:UDP适用于对实时性要求较高的应用,如视频通话、在线游戏等,其中数据包丢失或重排对应用的影响较小。

注:以上代码和信息主要是本人对实验的简单记录,还有如果不知道怎么运行的,我用的是eclipse,使用的时候可以开两个IDE,一个用来运行Server,一个用来运行Client。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值