分享一波新浪java面試題與參考答案解析

點關注,不迷路;持續更新Java相關技術及資訊!!!

在這裏插入圖片描述

本文主要介紹了新浪java面試題與參考答案,總結分析了新浪java面試網絡編程題目與參考答案,涉及java socket通信客戶端與服務器端功能實現技巧,需要的朋友可以參考下

在服務器端 用一個HashMap<userName,socket> 維護所有用戶相關的信息,從而能夠保證和所有的用戶進行通訊。

客戶端的動作:
(1)連接(登錄):發送userName 服務器的對應動作:1)界面顯示,2)通知其他用戶關於你登錄的信息, 3)把其他在線用戶的userName通知當前用戶 4)開啓一個線程專門爲當前線程服務
(2)退出(註銷):
(3)發送消息

※※發送通訊內容之後,對方如何知道是幹什麼,通過消息協議來實現:

客戶端向服務器發的消息格式設計:
命令關鍵字@#接收方@#消息內容@#發送方

1)連接:userName ----握手的線程serverSocket專門接收該消息,其它的由服務器新開的與客戶進行通訊的socket來接收

2)退出:exit@#全部@#null@#userName

3)發送: on @# JList.getSelectedValue() @# tfdMsg.getText() @# tfdUserName.getText()
服務器向客戶端發的消息格式設計:
命令關鍵字@#發送方@#消息內容

登錄:

  1. msg @#server @# 用戶[userName]登錄了 (給客戶端顯示用的)
  2. cmdAdd@#server @# userName (給客戶端維護在線用戶列表用的)
    退出:
  3. msg @#server @# 用戶[userName]退出了 (給客戶端顯示用的)
  4. cmdRed@#server @# userName (給客戶端維護在線用戶列表用的)
    發送:
    msg @#消息發送者( msgs[3] ) @# 消息內容 (msgs[2])
    運行結果如下:
package cn.hncu;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.border.TitledBorder;
public class ServerForm extends JFrame{
    private DefaultListModel lm;
    private JTextArea area;
    private final static int PORT=10010;
    private Map<String, Socket> map=new HashMap<String, Socket>();
        public ServerForm() {
                setDefaultCloseOperation(EXIT_ON_CLOSE);
                //setBounds(x, y, width, height)
                final int winWidth=(int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
                final int winHeight=(int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
                setBounds(winWidth/4, winHeight/4, winWidth/2, winHeight/2);
                //加聊天面板
                area=new JTextArea();
                area.setEditable(false);
                this.getContentPane().add(new JScrollPane(area),BorderLayout.CENTER);
                lm=new DefaultListModel();
                JList list=new JList(lm);
                JScrollPane js=new JScrollPane(list);
                js.setBorder(new TitledBorder("在線"));
                js.setPreferredSize(new Dimension(180, this.getHeight()));
                getContentPane().add(js,BorderLayout.EAST);
                JMenuBar bar=new JMenuBar();
                JMenu menu=new JMenu("控制");
                menu.setMnemonic('C');//助記符
                final JMenuItem run=new JMenuItem("開啓");
                run.setAccelerator(KeyStroke.getKeyStroke('R',KeyEvent.CTRL_MASK));//設置快捷鍵ctrl+R
                run.setActionCommand("run");
                menu.add(run);
                menu.addSeparator();
                JMenuItem exit=new JMenuItem("退出");
                exit.setAccelerator(KeyStroke.getKeyStroke('E',KeyEvent.CTRL_MASK));
                exit.setActionCommand("exit");
                menu.add(exit);
                bar.add(menu);
                setJMenuBar(bar);
                //監聽
                ActionListener action=new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                if(e.getActionCommand().equals("run")){
                        startServer();
                        run.setEnabled(false);
                }else{
                        System.exit(0);
                }
                        }
                };
                run.addActionListener(action);
                exit.addActionListener(action);
                setVisible(true);
        }
        public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        new ServerForm();
        }
        private void startServer() {
                try {
                        ServerSocket server=new ServerSocket(PORT);
                        area.setText("啓動服務"+server);
                        new ServerThread(server).start();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
        class ServerThread extends Thread{
        private ServerSocket server;
                public ServerThread(ServerSocket server) {
                        this.server = server;
                }
                @Override
                public void run() {
                        while(true){
                                //握手,第一次。專門來接待客戶端第一次鏈接。
                                try {
                                        Socket socketClient=server.accept();
                                        Scanner sc=new Scanner(socketClient.getInputStream());
                                        if(sc.hasNext()){
                                                //System.out.println("..........");
                                                String userName=sc.nextLine();
                                                area.append("\r\n用戶"+userName+"登錄"+socketClient);
                                                lm.addElement(userName);
                                                new ClientThread(socketClient).start();
                                                msgAll(userName);//把當前用戶登陸的消息通知給所有在線的人。
                                                msgSelf(socketClient);//通知自己當前在線的所有人。
                                                //把當前登陸的用戶加到在線用戶列表中
                                                map.put(userName,socketClient);
                                        }
                                } catch (IOException e) {
                                        e.printStackTrace();
                                }
                        }
                }
                class ClientThread extends Thread{
            private Socket socketClient;
                        public ClientThread(Socket socketClient) {
                                this.socketClient = socketClient;
                        }
                        @Override
                        public void run() {
                                System.out.println("一個與客戶端通訊的線程啓動");
                                try {
                                        Scanner sc=new Scanner(socketClient.getInputStream());
                                        while(sc.hasNext()){
                                                String msg=sc.nextLine();
                                                String msgs[]=msg.split("@#");
                                                //防黑
                                                if(msgs.length!=4){
                                                        System.out.println("防黑處理");
                                                }
                                                if("on".equals(msgs[0])){
                                                        sendMsgToSb(msgs);
                                                }
                                                if("exit".equals(msgs[0])){
                                                        //從在線用戶map中把該用戶刪掉
                                                        map.remove(msgs[3]);
                                                        //從服務器的在線列表中把該用戶刪除
                                                        lm.removeElement(msgs[3]);
                                                        //通知其他在線用戶有關退出的消息
                                                        sendExitMsgToAll(msgs);
                                                        //在服務器窗口顯示該用戶退出的消息
                                                        area.append("\r\n用戶"+msgs[3]+"退出了");
                                                }
                                        }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                }
        }
        //服務器把客戶端的聊天消息轉發給相應的其它客戶端
        private void sendMsgToSb(String[] msgs) throws Exception {
                if("全部".equals(msgs[1])){
                        Iterator it=map.keySet().iterator();
                        while(it.hasNext()){//遍歷每一個在線用戶,把聊天消息轉發給他
                                String userName=(String) it.next();
                                Socket s=map.get(userName);
                                PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
                                String str="msg@#"+msgs[3]+"@#"+msgs[2];
                                pw.println(str);
                                pw.flush();
                        }
                }else{
                        Socket s=map.get(msgs[1]);
                        PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
                        String str="msg@#"+msgs[3]+"@#"+msgs[2];
                        pw.println(str);
                        pw.flush();
                }
        }
        //通知其他在線用戶有人退出了
        private void sendExitMsgToAll(String[] msgs) throws IOException {
        Iterator<String> it=map.keySet().iterator();
        while(it.hasNext()){
                String userName=it.next();
                Socket s=map.get(userName);
                PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
                String str="msg@#server@#用戶["+msgs[3]+"]退出了";
                pw.println(str);
                pw.flush();
                str="cmdRed@#server@#"+msgs[3];
                pw.println(str);
                pw.flush();
        }
        }
        private void msgAll(String userName) {
                 Iterator<Socket> it=map.values().iterator();
                 while(it.hasNext()){
                         Socket s=it.next();
                         PrintWriter pw;
                        try {//把服務器要我們做的事情變成協議格式,由我們來解析
                                pw = new PrintWriter(s.getOutputStream(),true);
                                String msg="msg@#server@#用戶["+userName+"]登陸了";
                                pw.println(msg);
                                //pw.flush();
                                msg="cmdAdd@#server@#"+userName;
                                pw.println(msg);
                                //pw.flush();
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                 }
        }
        private void msgSelf(Socket socketClient) {
                try {
                        PrintWriter pw=new PrintWriter(socketClient.getOutputStream(),true);
                        Iterator it=map.keySet().iterator();
                        while(it.hasNext()){
                                pw.println("cmdAdd@#server@#"+it.next());
                                //pw.flush();
                        }
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}


客戶端

package cn.hncu;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.border.TitledBorder;
public class ClientForm  extends JFrame implements ActionListener{
        private JButton btnConn;
        private JButton btnExit;
        private DefaultListModel lm;
        private JTextArea allMsg;
        private JTextField text;
        private JTextField userText;
        private JList list;
        private  static String HOST="127.0.0.1";
        private  static int PORT=10010;
        public ClientForm() {
                //菜單條
                addMenu();
                setBounds(300, 200, 500, 400);
                //上部面板
                JPanel panel=new JPanel();
                panel.add(new JLabel("用戶標識"));
                panel.add(this.userText=new JTextField(10));
                panel.add(this.btnConn=new JButton("連接"));
                btnConn.addActionListener(this);
                btnConn.setActionCommand("conn");
                //btnConn.addActionListener(this);
                panel.add(this.btnExit=new JButton("退出"));
                btnExit.addActionListener(this);
                btnExit.setActionCommand("exit");
                this.getContentPane().add(panel,BorderLayout.NORTH);
                //中部面板
                //lm=new ListModel() ;
                //JList list=new JList(dataModel)
                JPanel panelC=new JPanel(new BorderLayout());//默認是FlowLayout
                this.getContentPane().add(panelC,BorderLayout.CENTER);
                lm=new DefaultListModel();
                list=new JList(lm);
            lm.addElement("全部");
            list.setSelectedIndex(0);
            list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            list.setVisibleRowCount(2);
            JScrollPane js=new JScrollPane(list);
            js.setBorder(new TitledBorder("在線"));
            //注意,在使用佈局方式控制組件時,最好使用setPreferredSize來控制大小,使用setSize有時會失效。
            js.setPreferredSize(new Dimension(150, panelC.getHeight()));
            //js.setSize(150, panelC.getHeight());
            panelC.add(js,BorderLayout.EAST);
            allMsg=new JTextArea();
            allMsg.setEditable(false);
            panelC.add(new JScrollPane(allMsg),BorderLayout.CENTER);
            //消息發送面板
            JPanel panelS=new JPanel();
            panelS.add(new JLabel("消息"));
            text=new JTextField(20);
            panelS.add(text);
                JButton btnSend=new JButton("發送");
                panelS.add(btnSend);
                btnSend.addActionListener(this);
                btnSend.setActionCommand("send");
                panelC.add(panelS,BorderLayout.SOUTH);
                //給窗口右上角的關閉按鈕添加事件處理
                addWindowListener(new WindowAdapter() {
                        @Override
                        public void windowClosing(WindowEvent e) {
                                sendExitMsg();
                        }
                });
                setVisible(true);
        }
        private void addMenu() {
        JMenuBar menuBar=new JMenuBar();
        JMenu menu=new JMenu("選項");
        JMenuItem item=new JMenuItem("設置");
        JMenuItem help=new JMenuItem("幫助");
        setJMenuBar(menuBar);
        menuBar.add(menu);
        menu.add(item);
        menu.add(help);
        help.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                JDialog dlg=new JDialog(ClientForm.this);
                                dlg.setBounds(ClientForm.this.getX(), ClientForm.this.getY(),300, 100);
                                dlg.setLayout(new FlowLayout());
                                dlg.add(new JLabel("版本所有@城院杜雅倩qq:1115179167"));
                                dlg.setVisible(true);
                        }
                });
        item.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                final JDialog dlg=new JDialog(ClientForm.this);
                                dlg.setBounds(ClientForm.this.getX(), ClientForm.this.getY(),300, 100);
                                dlg.setLayout(new FlowLayout());
                                dlg.add(new JLabel("服務器"));
                                final JTextField host=new JTextField(10);
                                host.setText(HOST);
                                dlg.add(host);
                                dlg.add(new JLabel(":"));
                                final JTextField port=new JTextField(5);
                                port.setText(""+PORT);
                                dlg.add(port);
                                JButton btnSet=new JButton("設置");
                                dlg.add(btnSet);
                                btnSet.addActionListener(new ActionListener() {
                                        @Override
                                        public void actionPerformed(ActionEvent e) {
                                                //按理應該先解析並判斷端口號是否合法,此處省略了
                        HOST=host.getText();
                        //System.out.println(HOST);
                        PORT=Integer.parseInt(port.getText());
                        //System.out.println(PORT);
                        dlg.dispose();//關閉並銷燬該對話框,清理內存
                                        }
                                });
                                dlg.setVisible(true);
                        }
                });
        }
        public static void main(String[] args) {
                JFrame.setDefaultLookAndFeelDecorated(true);
        new ClientForm();
        }
        @Override
        public void actionPerformed(ActionEvent e) {
                if(e.getActionCommand().equals("conn")){
                        System.out.println("連接服務器。。。");
                        try {
                                connecting();
                                ((JButton)e.getSource()).setEnabled(false);
                                //setEnabled(false);
                                userText.setEditable(false);
                        } catch (IOException e1) {
                                JOptionPane.showMessageDialog(this, "服務器連接失敗,請檢查網絡或者查看服務器地址與端口號");
                        }
                }
                if(e.getActionCommand().equals("send")){
                        if(text.getText()==null || text.getText().trim().length()==0){
                                JOptionPane.showMessageDialog(this, "請輸入聊天消息");
                                return;
                        }
                        String msg="on@#"+list.getSelectedValue()+"@#"+text.getText()+"@#"+userText.getText();
                        pw.println(msg);
                }
                if(e.getActionCommand().endsWith("exit")){
                        sendExitMsg();
                        //((JButton)e.getSource()).setEnabled(false);
                        System.exit(0);
                }
        }
        //向服務器發送退出消息
        private void sendExitMsg() {
                 if(client==null){
                         System.exit(0);
                 }
                 String msg="exit@#全部@#null@#"+userText.getText();
                 System.out.println("退出"+msg);
                 pw.println(msg);
                 pw.flush();
                 System.exit(0);
        }
        private Socket client;
        private PrintWriter pw;
        private void connecting() throws IOException {
                        client=new Socket(HOST, PORT);
                        String userName=userText.getText();
                        pw=new PrintWriter(client.getOutputStream(),true);
                        pw.println(userName);
                        this.setTitle("用戶"+"["+userName+"]"+"在線");
                        //服務器也要給我們發消息的,比如說誰在線等消息。這裏是在圖形界面線程,最好另外開一個線程來相應。
                        new ClientThread().start();
        }
    class ClientThread extends Thread{
                @Override
                public void run() {
                        //用來接收服務器給我們發送的消息
                        try {
                                Scanner sc = new Scanner(client.getInputStream());
                                while(sc.hasNext()){
                                        String str=sc.nextLine();
                                        //拆分服務器發送過來的消息,並解析
                                        String[] msgs=str.split("@#");
                                        if("msg".equals(msgs[0])){
                                                if("server".equals(msgs[1])){
                                                        str="[通知]:"+msgs[2];
                                                }else {//服務器轉發的聊天消息
                                                        str=msgs[1]+"說"+msgs[2];
                                                }
                                                allMsg.append("\r\n"+str);//在用戶聊天面板裏添加消息
                                        }else if("cmdAdd".equals(msgs[0])){
                                                lm.addElement(msgs[2]);        //實時維護用戶在線列表
                                        }else{
                                                lm.removeElement(msgs[2]);
                                        }
                                }
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章