服务端Socket配置 private static Map<String, Socket> sockets = new HashMap<>();//定义静态map集合 public static void main(String[] args) {//主函数 ServerSocket serverSocket = null;//服务端套接字定义 try { serverSocket = new ServerSocket(8888); // 指定服务器端口号为8888,端口范围0-65535 while (true) {//循环执行 Socket socket = s.accept();// 建立连接 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); //获取对象输入流 Message message = (Message) ois.readObject();//读取流 sockets.put(message.getFrom(), socket);//将客户端查询的数据返回,并放入集合 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //获取对象输出流 Set<String> sets = sockets.keySet(); List<String> list = new ArrayList<>();//定义list集合 String [] strs = new String[sets.size()];//获取sets的长度 for (String string : sets) {//循环sets集合 list.add(string);//将无序的set数组循环存入list集合 } for (int i = 0; i < strs.length; i++) { strs[i] = list.get(i);//无序集合有序化 } message.setFirends(strs);//将集合中的数据加入好友列表集合中 oos.writeObject(message);//将流写入到客户端 new Thread() {//独立线程设置,防止线程冲突 public void run() { while(true) {//循环流 ObjectInputStream ois;//定义输入流 try { ois = new ObjectInputStream(socket.getInputStream()); //将客户端输入流写入服务器流 Message message = (Message) ois.readObject();//读取输入流 if(message.getType() == Message.SEND) {//判断客户端是否请求发送信息 String to = message.getTo();//获取用户发送给的用户 Set<String> sets = sockets.keySet();//获取map存的数据 List<String> list = new ArrayList<>();//定义list字符串集合 String [] strs = new String[sets.size()];//定义字符串数组 for (String string : sets) { list.add(string);//将循环数组放入集合 } for (int i = 0; i < strs.length; i++) { strs[i] = list.get(i);//集合有序化 } message.setFirends(strs);//设置好友的信息 Socket socket = sockets.get(to);//获取发送给的人 if(socket != null) {//判断需要发送的人有没有 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //获取输出流 oos.writeObject(message);//如果有就输出内容 oos.close();//关流 iso.close();//关流 } } } catch (IOException e) {//异常捕获 e.printStackTrace(); } catch (ClassNotFoundException e) {//异常捕获 e.printStackTrace(); } } }; }.start(); } } catch (IOException e) {//异常捕获 e.printStackTrace(); } catch (ClassNotFoundException e) {//异常捕获 e.printStackTrace(); }finally { } 客户端Socket 发送消息 public class Talk extends JFrame{//继承JFrame private Socket socket;//定义套接字 private JTextArea show;//定义消息的显示内容 private JTextArea send;//发送消息的内容 private JButton sendButton;//定义发送按钮 private String username;//定义现在用户 private String to;//发送给的人 public Talk(String from ,String to,Socket socket) { this.username = from;//给定义变量赋值 this.to = to; this.setTitle(to); this.socket = socket; this.setSize(500, 500);//设置frame窗口大小 this.setLocationRelativeTo(null);//定义窗体位置 show = new JTextArea();//定义多行文本框对象 show.setPreferredSize(new Dimension(0, 250));//设定文本框大小 send = new JTextArea(); send.setBorder(BorderFactory.createLineBorder(Color.black));//设定边框颜色 sendButton = new JButton("发送");//定义按钮 sendButton.addActionListener(new ActionListener() {//设定按钮点击事件 @Override public void actionPerformed(ActionEvent e) { Message message = new Message(); message.setFrom(username);//设定窗体名字,登录用户名字 message.setTo(to);//发送给的人 message.setContent(send.getText());//发送的内容 message.setType(Message.SEND);//设定请求内容 ObjectOutputStream oos;//定义输出流 try { oos = new ObjectOutputStream(socket.getOutputStream());oos.writeObject(message); //将内容写入服务器 oos.flush();//清空流 showMessage(message.getContent());//展示消息文本框内容获取 send.setText("");//将发送文本框清空 } catch (IOException e1) { e1.printStackTrace(); //捕获异常 } } }); send.setPreferredSize(new Dimension(0, 50));//设定按钮大小 this.add(show,BorderLayout.NORTH);//消息展示框位置 this.add(send,BorderLayout.CENTER); //发送框内容 this.add(sendButton,BorderLayout.SOUTH);//按钮位置 this.setVisible(true);//显示窗体 } public void showMessage (String content) {//定义方法 show.append(content+"\n"); //将内容放入消息框 } } 登录 // 创建socket对象,指定服务器的ip地址,和服务器监听的端口号 客户端在new的时候,就发出了连接请求,服务器端就会进行处理,如果服务器端没有开启服务,那么 这时候就会找不到服务器,并同时抛出异常 public class Login extends JFrame{//登录类继承JFrame private JTextField userNameField; //定义文本框 private JButton loginButton; //定义登录按钮 public Login() { //定义构造函数 setTitle("登录"); //窗体名设定 setSize(200,180); //设定窗体大小 setLocationRelativeTo(null); //居中 位置 Toolkit.getDefaultToolkit().getScreenSize(); //怎么获取屏幕的宽高 获取屏幕的尺寸 JPanel panel = new JPanel(); //显示内容 add(panel); //窗体添加panel panel.setLayout(null); //账号框 userNameField = new JTextField(); //文本框 userNameField.setBounds(50, 30, 100, 30); //标签定位大小设定 panel.add(userNameField); //文本框加入panel loginButton = new JButton("登录"); //登录按钮 loginButton.addActionListener(new ActionListener() { //登录按钮事件 @Override public void actionPerformed(ActionEvent e) { String username = userNameField.getText(); //获取文本框内容 Message message = new Message(); message.setFrom(username); //设定当前用户 message.setType(Message.LOGIN); //设定功能 Socket socket = null; //设定套接字 try { socket = new Socket("127.0.0.1", 8888);//连接服务器 host,port ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); //获取输出流 oos.writeObject(message);//写出到客户端messge } catch (UnknownHostException e1) { //捕获异常 e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } Login.this.setVisible(false); //关闭登录框 new FriendList(username,socket); //好友列表调用 } }); loginButton.setBounds(50, 60, 100, 30); //设定按钮位置大小 panel.add(loginButton); //将按钮加入panel setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击关闭结束线程 setVisible(true); //显示窗体 }} 好友列表 public class FriendList extends JFrame{//好友列表类 private Socket socket; //定义是套接字 private JPanel jPanel ; //定义显示 private String username; //定义显示的用户 private Map<String, Talk> talks = new HashMap<>();//定义map集合 存取聊天 private JList list; //列表显示定义 public FriendList(String username,Socket socket) {//定义好友列表构造 this.username = username; //给当前显示的用户赋值 this.socket = socket; //套接字赋值 setTitle(username); //设定窗体标题 jPanel = new JPanel(); //定义显示 this.add(jPanel); //将panel放入frame ObjectInputStream ois; //定义输入了流 try { //读取好友列表 ois = new ObjectInputStream(socket.getInputStream());//获取服务器值 Message message = (Message) ois.readObject();//将服务器的值放入对象 init(message.getFirends()); //调用方法 } catch (IOException e) { //捕获异常 e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } //开启线程接收聊天消息 new Thread() { public void run() { while(true) { ObjectInputStream ois; //获取输入流 try { //读取好友列表 ois = new ObjectInputStream(socket.getInputStream()); Message message = (Message) ois.readObject(); //读取服务器流内容流 init(message.getFirends()); //调用方法 Talk talk = talks.get(message.getFrom()); //从对象中获取当前用户 if(talk == null) { //判断 talk = new Talk(username,message.getFrom(), socket);//如果为空放入内容 talks.put(message.getFrom(), talk); } talk.showMessage(message.getContent()); 将内容传给talk } catch (IOException e) { //捕获异常 e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }; }.start(); setSize(230, 500); //设定窗体大小 setLocation(600,100); //设定窗体位置 setVisible(true); //显示窗体 } public void init(String[] firends) { jPanel.removeAll(); //情况好友列表 for (String string : firends) { System.out.println(string); //将更新内容显示在控制窗体 } list = new JList<>(firends); //将好友存入集合 list.addMouseListener(new MouseListener() { //鼠标事件 @Override public void mouseReleased(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { if(e.getClickCount() == 2) { //双击 int index =list.locationToIndex(e.getPoint());//当前鼠标位置 Talk talk = talks.get(firends[index]); //当前鼠标点击项 if(talk == null) { //判断 talk = new Talk(username,firends[index], socket);//显示聊天窗体 talks.put(firends[index], talk); //将内容放入集合 }else { talk.setVisible(true); //显示窗体 } } } }); jPanel.add(list); //显示好友 jPanel.updateUI(); //刷新 }}