点关注,不迷路;持续更新Java相关技术及资讯!!!
本文主要介绍了新浪java面试题与参考答案,总结分析了新浪java面试网络编程题目与参考答案,涉及java socket通信客户端与服务器端功能实现技巧,需要的朋友可以参考下
在服务器端 用一个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()
服务器向客户端发的消息格式设计:
命令关键字@#发送方@#消息内容
登录:
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();
}
}
}
}