新浪 java_新浪java面试题与参考答案解析

在服务器端 用一个HashMap 维护所有用户相关的信息,从而能够保证和所有的用户进行通讯。

客户端的动作:

(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 (给客户端维护在线用户列表用的)

退出:

1) msg   @#server @# 用户[userName]退出了  (给客户端显示用的)

2) 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 map=new HashMap();

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 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 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();

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值