• JAVA Socket API与LINUX Socket API探究


    代码

    这是一个带有UI界面的JAVA网络聊天程序,使用Socket连接完成通信。

    JAVA服务端程序

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * Server
     */
    public class Server {
        private static final int PORT = 4000;   // 指定通信端口
        public final String END_OF_MESSAGE = "$$";
    
        public void launch() throws IOException {
            ServerSocket server = new ServerSocket(PORT);
            Socket requSocket = server.accept();
            
            InputStream inStream = requSocket.getInputStream();
            OutputStream outputStream = requSocket.getOutputStream();
    
            Scanner in = new Scanner(inStream);
            PrintWriter out = new PrintWriter(outputStream, true /* autoFlush */);
    
            out.println("Welcome! Let's talk.");
            while (in.hasNextLine()) {
                String line = in.nextLine();
                if (line.equals("Hello")) {
                    out.println("Hi");
                } else if (line.equals("Bye")) {
                    out.println("Bye");
                    out.println(END_OF_MESSAGE);
                    break;
                } else {
                    out.println("Can't understand what you said!");
                }
            }
            in.close();
            out.close();
            server.close();
        }
    
        public static void main(String[] args) throws IOException {
            new Server().launch();
        }
    }
    

    客户端程序

    import java.io.*;
    import java.awt.event.*;
    import java.net.*;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class Client {
    
        private static final String IP = "127.0.0.1";   // 使用本机地址
        private static final int PORT = 4000;
        private final String LINK_FAIL = "====================
     Connection build failed!
    ";
        private final String UNKOWN_HOST = "====================
     Unkown host!
    ";
        private final String IO_EXCEPTION = "====================
     I/O wrong!
    ";
        public static final String END_OF_MESSAGE = "$$";
    
        private Socket userSocket;
        private String userName;
        private InputStream inStream;
        private Scanner in;
        private OutputStream outStream;
        private PrintWriter out;
        protected boolean serverStop;
    
        public Client(String name) {
            userName = name;
        }
    
        public void launch() {
            UserInterface.creatUI(userName);    // 创建一个用户界面
            boolean error = false;
            try {
                creatConnection();
            } catch (ConnectException e) {
                UserInterface.chatWindow.append(LINK_FAIL);
                error = true;
            } catch (UnknownHostException e) {
                UserInterface.chatWindow.append(UNKOWN_HOST);
                error = true;
            } catch (IOException e) {
                UserInterface.chatWindow.append(IO_EXCEPTION);
                error = true;
            }
            if (error) {
                shutDown();
                return;
            }
            String greeting;
            while ((greeting = in.nextLine()) == null)
                ;
            serverStop = false;
            UserInterface.chatWindow
                    .append(new SimpleDateFormat("MM-dd HH:mm").format(new Date()) + "
    " + "Server: " + greeting + "
    
    ");
            UserInterface.sendButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    String message = UserInterface.inputText.getText();
                    if (serverStop || message.equals(""))
                        return;
    
                    out.println(message);
    
                    String currentTime = new SimpleDateFormat("MM-dd HH:mm").format(new Date());
                    UserInterface.chatWindow.append(currentTime + "
    " + userName + ": " + message + "
    
    ");
                    UserInterface.inputText.setText("");
                    UserInterface.inputText.requestFocus();
    
                    String line = in.nextLine();
                    if (line.equals(END_OF_MESSAGE)) {
                        serverStop = true;
                        shutDown();
                        UserInterface.sendButton.setEnabled(false);
                    } else {
                        currentTime = new SimpleDateFormat("MM-dd HH:mm").format(new Date());
                        UserInterface.chatWindow.append(currentTime + "
    " + "Server: " + line + "
    
    ");
                    }
                }
            });
    
        }
    
        private void creatConnection() throws ConnectException, NullPointerException, IOException {
            try {
                userSocket = new Socket(IP, PORT);
                inStream = userSocket.getInputStream();
                in = new Scanner(inStream);
                outStream = userSocket.getOutputStream();
                out = new PrintWriter(outStream, true /* autoFlush */);
            } catch(ConnectException connectException) {
                throw connectException;
            } catch(NullPointerException nullPointerException) {
                throw nullPointerException;
            } catch(IOException ioException) {
                throw ioException;
            }
        }
    
        private void shutDown() {
            in.close();
            out.close();
            try {
                userSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            Client client = new Client("Tinshine");
            client.launch();
        }
    }
    

    用户界面

    使用JAVA的swing组件实现一个简单的聊天窗口

    import javax.swing.*;
    import java.awt.*;
    
    /**
     * UserInteface
     */
    public class UserInterface {
    
        private final static String APP_NAME = "MSN";
        public static String nameOfUser;
    
        private static JFrame frame;
        private static JPanel background;
        private static JPanel sendPanel;
        public static JTextArea chatWindow;
        public static JTextField inputText;
        public static JButton sendButton;
        public static JScrollPane chatWinJScrollPane;
        public static JScrollBar chatWinJScrollBar;
        public static Point chatWinJScrollPoint;
    
        public static void creatUI(String userName) {
            nameOfUser = userName;
            
            frame = new JFrame(APP_NAME);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            background = new JPanel();
            background.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
            background.setLayout(new BoxLayout(background, BoxLayout.Y_AXIS));
    
            chatWindow = new JTextArea(10, 10);
            chatWindow.setLineWrap(true);
            chatWinJScrollPane = new JScrollPane(chatWindow);
            chatWinJScrollBar = chatWinJScrollPane.getVerticalScrollBar();
            chatWinJScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
            chatWinJScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            background.add(chatWinJScrollPane);
    
            sendPanel = new JPanel();
            sendPanel.add(new JLabel(userName + ": "));
            inputText = new JTextField(20);
            inputText.requestFocus();
            sendPanel.add(inputText);
            sendButton = new JButton("Send");
            sendPanel.add(sendButton);
            background.add(sendPanel);
    
            frame.getContentPane().add(background);
            frame.pack();
            frame.setVisible(true);
        }
    }
    

    设计过程

    1. 服务端使用ServerSocket()类创建一个Socket通信连接,使用accept()方法等待客户端请求。
    2. 客户端使用Socket()类,根据指定的IP地址和端口号创建一个到服务端的Socket连接,随后就可以与服务端进行通信。
    3. UI界面主要负责打印客户端和服务端之间发送的消息,显示客户端用户姓名以及消息的发送时间。
      效果如下:
      Step1: 启动客户端

      Step2: 发送问候语句,得到服务器答复

      Step3:发送告别语句,结束Socket连接

    API调用栈追踪

    以服务端为例,设置断点,追踪调用栈,得到如下所示的调用关系:

    在实例化ServerSocket类的时候,构造函数会调用ServerSocket类的bind()方法,后者会调用继承自抽象类AbstractPlainSocketImplPlainSocketImplsocketBind()方法。在socketBind()中会调用用native关键字标注的bind0()方法。从而实现将一个socket连接绑定到指定的本地IP地址和端口号。

    • native关键字标注的方法为原生方法,一般是用其他语言写成的函数,常用来实现java语言对操作系统底层接口的访问。JAVA语言本身不能直接对操作系统底层进行操作,但是JAVA允许程序通过JAVA本机接口JNI,使用C/C++等其他语言实现这种操作。

    接着,同样的步骤,从ServerSocket类的listen()一直追溯到PlainSocketImplsocketListen()方法的listen0()。该方法主要为了设置允许的最大连接请求队列长度,当请求队列满时,拒绝后来的连接请求。

    最后,同样,从ServerSocket类的accept()追溯到accept0(),等待连接请求的到来。

    JAVA Socket接口与LINUX Socket接口对比

    作为对比,LINUX提供的相应Socket API分别为:

    // 创建一个套接字
    int socket(itn domain, int type, int protocol);
    // 将套接字绑定到地址上
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addelen);
    // 监听连接
    int listen(int sockfd, int backlog);
    // 接收一个连接请求
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    

    JAVA通过调用这些系统API来实现它的底层功能。不同之处在于,JAVA将这一切全都封装起来,这使得面向网络的编程对于JAVA程序员来说变得十分简单,我们只需要知道使用哪一个类(实际上就是ServerSocketSocket两个类),为它们传入必要的地址参数,就能够轻松实现Socket通信。

    • 在window操作系统中,使用native标注的本地方法在编译时会生成一个动态链接库(.dll文件)为JAVA语言提供相应的本地服务。
  • 相关阅读:
    latex 简单应用
    激光相机数据融合(6)--激光相机标定
    激光相机数据融合(5)--Gazebo仿真数据融合
    激光相机数据融合(4)--KITTI数据集中matlab接口说明及扩展
    激光相机数据融合(3)--KITTI数据集
    激光相机数据融合(2)--激光及相机位置投影关系
    激光相机数据融合(1)--前言
    Linux查找命令总结:find、locate、whereis、which、type
    Linux netstat命令详解
    超级好用的浏览器API测试插件-浏览器版的postman
  • 原文地址:https://www.cnblogs.com/Mr-Tiger/p/11969934.html
Copyright © 2020-2023  润新知