點關注,不迷路;持續更新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()
服務器向客戶端發的消息格式設計:
命令關鍵字@#發送方@#消息內容
登錄:
- msg @#server @# 用戶[userName]登錄了 (給客戶端顯示用的)
- cmdAdd@#server @# userName (給客戶端維護在線用戶列表用的)
退出: - msg @#server @# 用戶[userName]退出了 (給客戶端顯示用的)
- 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();
}
}
}
}