用到Java SE中的Socket进行连接

登陆Server

这是服务器端,需要首先启动且只能启动一次

登陆Client

1号登陆

2号登陆

屏幕下方托盘
这里登陆2个用户,鼠标放在上面会出现如图

鼠标右击

托盘图标要放在 src 目录下,不然查找不到


代码

代码下载
http://download.csdn.net/download/xiao_ma_csdn/10269610

Server4

package com.qqText;import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.swing.event.MouseInputListener;public class Server4 extends Thread {static DataOutputStream dos;static DataInputStream dis;public JFrame frame;public JTextArea viewArea;public JTextField viewField;public JButton button1, buttonLogin, buttonExit;public JLabel jlable;public JTextField MyName;public static DefaultListModel listModel;public static JList userList; // 显示对象列表public JSplitPane centerSplit;public boolean isConnected = false;static Server4 Server4;static Socket s;public static HashMap<String,Socket> hash = new HashMap<String,Socket>();public static void main(String[] args) throws IOException {Server4 = new Server4();Server4.serverSurface("服务器");ServerSocket ss = new ServerSocket(8848);while (true) {Server4.viewArea.append("等待新客户连接......\n");s = ss.accept();Server4.viewArea.append("连接成功......" + s + "\n");new ServerThread(s).start();}}static class ServerThread extends Thread {Socket socket;public ServerThread(Socket socket) {this.socket = socket;}public void run() {String key = null;      try {ObjectInputStream ins = new ObjectInputStream(socket.getInputStream());while(true){Vector v = null;try {v = (Vector)ins.readObject();                   } catch (ClassNotFoundException e) {e.printStackTrace();}if(v!=null){for(int i = 0;i<v.size();i++){String info = (String) v.get(i);                            if(info.startsWith("用户:")){key = info.substring(3);hash.put(key,socket);Set<String> set = hash.keySet();// 获得集合中所有键的Set视图Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器,为每一个key发送所有keywhile(keyIt.hasNext()){String receiveKey = keyIt.next();Socket s = hash.get(receiveKey);PrintWriter out = new PrintWriter(s.getOutputStream(),true);Iterator<String> keyIt1 = set.iterator();while(keyIt1.hasNext()){String receiveKey1 = keyIt1.next();out.println(receiveKey1);out.flush();}                                   }listModel.addElement(info);}else if(info.startsWith("退出:")){key = info.substring(3);hash.remove(key);Set<String> set = hash.keySet();Iterator<String> it = set.iterator();while(it.hasNext()){String recivekey = it.next();Socket s = hash.get(recivekey);PrintWriter out = new PrintWriter(socket.getOutputStream(),true);out.println("退出:"+key);out.flush();}                                   }else{key = info.substring(info.indexOf(":发送给:") + 5,info.indexOf(":的信息是:"));// 获得接收方的key值,即接收方的用户名String sendUser = info.substring(0,info.indexOf(":发送给:"));// 获得发送方的key值,即发送方的用户名Set<String> set = hash.keySet();Iterator<String> it = set.iterator();while(it.hasNext()){String receiveKey = it.next();if(receiveKey.equals(key) && !sendUser.equals(receiveKey)){Socket s = hash.get(key);PrintWriter out = new PrintWriter(s.getOutputStream(),true);out.println("MSG:"+info);   out.flush();                                        }}                                   }}}                                                                           }                                           } catch (IOException e) {e.printStackTrace();}}}public void serverSendMessage() {String message = "";PrintWriter out = null ;message = "服务器说:"+ viewField.getText();viewArea.setText(viewArea.getText() + message + "\n");Set<String> set = hash.keySet();Iterator<String> it = set.iterator();while(it.hasNext()){String receiveKey = it.next();Socket s = hash.get(receiveKey);try {out = new PrintWriter(s.getOutputStream());         } catch (IOException e) {e.printStackTrace();}finally{   String msg = "服务器"+ ":发送给:"+ s + ":的信息是: "+ viewField.getText();// 定义发送的信息out.println("MSG:"+msg);out.flush();}                   }}// 窗体public void serverSurface(String name) {frame = new JFrame("Chat Room");viewArea = new JTextArea(10, 40);jlable = new JLabel();jlable.setText("服务器开始工作");button1 = new JButton("发送");MyName = new JTextField();MyName.setColumns(9);MyName.setText(name);JPanel panel = new JPanel();panel.setLayout(new GridLayout(8, 1));panel.add(jlable);panel.add(MyName);panel.add(button1);JPanel jp_input = new JPanel();jp_input.setBorder(new TitledBorder("发送消息"));viewField = new JTextField(50);jp_input.add(viewField);listModel = new DefaultListModel();userList = new JList(listModel);JScrollPane sp = new JScrollPane(viewArea);sp.setBorder(new TitledBorder("消息显示区"));sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);// 水平滚动轴sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);// 垂直滚动条JScrollPane spFriend = new JScrollPane(userList);spFriend.setBorder(new TitledBorder("在线人员"));spFriend.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);// 垂直滚动条centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, spFriend, sp);centerSplit.setDividerLocation(130);frame.add("Center", centerSplit);frame.add("East", panel);frame.add("South", jp_input);frame.setSize(700, 400);frame.setLocation(200, 100);frame.setVisible(true);// 文本框按回车键时事件viewField.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {serverSendMessage();}});// 发送按钮button1.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if (e.getSource() == button1) {serverSendMessage();}}});}
}

Client4

package com.qqText;import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;public class Client4 {public JFrame frame;
//  public JTextArea viewArea;public JTextPane textPane;public JTextField viewField,jt_login ;public JButton button1,buttonLogin,buttonExit;public JLabel jlable;public JTextField MyName;public DefaultListModel listModel;public static JList userList;       //显示对象列表public JSplitPane centerSplit;public static boolean isConnected = false;static Client4 objClient;static DefaultComboBoxModel model;static ObjectOutputStream out;boolean loginFlag = false;public static void main(String[] args) {EventQueue.invokeLater(new Runnable() {public void run() {objClient = new Client4();objClient.createClientSocket(objClient);}});     }public void createClientSocket(Client4 client) {try {Socket s = new Socket("localhost", 8848);out = new ObjectOutputStream(s.getOutputStream());client.clientSurface(); new MyClientReader(s).start();                                                                                                  } catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}static class MyClientReader extends Thread {Socket socket;public MyClientReader(Socket socket) {this.socket = socket;}public void run() {try {BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));             model = (DefaultComboBoxModel) userList.getModel();// 获得列表框的模型while(true){String info = in.readLine().trim();// 读取信息if (!info.startsWith("MSG:")) {// 接收到的不是消息if (info.startsWith("退出:")) {// 接收到的是退出消息model.removeElement(info.substring(3));// 从用户列表中移除用户} else {// 接收到的是登录用户            boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加for (int i = 0; i < model.getSize(); i++) {// 对用户列表进行遍历if (info.equals((String) model.getElementAt(i))) {// 如果用户列表中存在该用户名itemFlag = true;// 设置为true,表示不添加到用户列表break;// 结束for循环}}if (!itemFlag) {            model.addElement(info);// 将登录用户添加到用户列表}}}else{              DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例String dateString = df.format(new Date()); // 格式化为日期df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例String timeString = df.format(new Date()); // 格式化为时间String id = info.substring(4,info.indexOf(":发送给:"));  //发送端的idString message = info.substring(info.indexOf(":的信息是:")+6);String text = new String("  " + id + "    " + dateString+ "  " + timeString + "\n  " + message+ "\n");SimpleAttributeSet aSet = new SimpleAttributeSet();     StyleConstants.setForeground(aSet, Color.red);    StyleConstants.setBackground(aSet, Color.orange);    StyleConstants.setFontFamily(aSet, "lucida bright italic");    StyleConstants.setFontSize(aSet, 18);                       //StyleConstants.setAlignment(aSet, StyleConstants.ALIGN_LEFT); objClient.textPane.setParagraphAttributes(aSet,false);                  objClient.viewField.setText(null);// 清空文本框  Document docs = objClient.textPane.getDocument();//获得文本对象try {docs.insertString(docs.getLength(), text,aSet);//对文本进行追加} catch (BadLocationException e) {e.printStackTrace();}}}       } catch (IOException e) {e.printStackTrace();}}}public void sendMessage() {if (objClient.viewField.getText().equals("")) {return;// 如果没输入信息则返回,即不发送}Vector<String> v = new Vector<String>();// 创建向量对象,用于存储发送的消息Object[] receiveUserNames = userList.getSelectedValues();// 获得选择的用户数组if (receiveUserNames.length <= 0) {return;// 如果没选择用户则返回}for (int i = 0; i < receiveUserNames.length; i++) {String msg = objClient.jt_login.getText() + ":发送给:"+ (String) receiveUserNames[i] + ":的信息是: "+ objClient.viewField.getText();// 定义发送的信息v.add(msg);// 将信息添加到向量}try {out.writeObject(v);// 将向量写入输出流,完成信息的发送out.flush();// 刷新输出缓冲区} catch (IOException e) {e.printStackTrace();}DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例String dateString = df.format(new Date()); // 格式化为日期df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例String timeString = df.format(new Date()); // 格式化为时间    String text = new String("   " + userList.getSelectedValue() + "    " + dateString+ "  " + timeString + "\n  " + viewField.getText()+ "\n");                        SimpleAttributeSet aSet=new SimpleAttributeSet();       //接受时只改变第一次接收到的方向StyleConstants.setForeground(aSet, Color.blue);        StyleConstants.setFontFamily(aSet, "lucida bright italic");    StyleConstants.setFontSize(aSet, 18);   StyleConstants.setAlignment(aSet, StyleConstants.ALIGN_RIGHT); objClient.textPane.setParagraphAttributes(aSet,false);  Document docs = objClient.textPane.getDocument();//获得文本对象System.out.println(docs);try {docs.insertString(docs.getLength(), text,aSet);//对文本进行追加} catch (BadLocationException e) {e.printStackTrace();}}public void clientSurface() {frame = new JFrame("Chat Room");
//      viewArea = new JTextArea(10, 40);textPane = new JTextPane();jlable = new JLabel();jlable.setText("在线");button1 = new JButton("Send");MyName = new JTextField();      MyName.setColumns(9);JPanel panel = new JPanel(); panel.setLayout(new GridLayout(8, 1));panel.add(jlable);panel.add(MyName);panel.add(button1);JPanel jp_input = new JPanel();jp_input.setBorder(new TitledBorder("发送消息")); viewField = new JTextField(50);jp_input.add(viewField);buttonLogin = new JButton("登录");buttonExit = new JButton("退出");jt_login = new JTextField(20);JPanel panelLogin = new JPanel();panelLogin.setBorder(new TitledBorder("登录区")); panelLogin.add(jt_login);panelLogin.add(buttonLogin);panelLogin.add(buttonExit);listModel = new DefaultListModel();  userList = new JList(listModel);  JScrollPane sp = new JScrollPane(textPane);sp.setBorder(new TitledBorder("消息显示区")); sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);//水平滚动轴sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//垂直滚动条JScrollPane spFriend = new JScrollPane(userList);spFriend.setBorder(new TitledBorder("好友列表")); userList.setModel(new DefaultComboBoxModel(new String[] { "" }));spFriend.setViewportView(userList);spFriend.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//垂直滚动条      centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, spFriend, sp);  centerSplit.setDividerLocation(130);  frame.add("Center", centerSplit);frame.add("North", panelLogin);frame.add("East", panel);frame.add("South", jp_input);frame.setSize(700, 400);frame.setLocation(200,100);frame.setVisible(true);// 文本框按回车键时事件  viewField.addActionListener(new ActionListener() {  public void actionPerformed(ActionEvent e) {  sendMessage();  }  });  //发送按钮button1.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if (e.getSource() == button1) {sendMessage();}}});//单击登录按钮buttonLogin.addActionListener(new ActionListener() {public void actionPerformed(final ActionEvent e) {if (loginFlag) {// 已登录标记为trueJOptionPane.showMessageDialog(null, "在同一窗口只能登录一次。");return;}String userName = jt_login.getText().trim();// 获得登录用户名Vector v = new Vector();// 定义向量,用于存储登录用户v.add("用户:" + userName);// 添加登录用户try {out.writeObject(v);// 将用户向量发送到服务器out.flush();// 刷新输出缓冲区} catch (IOException ex) {ex.printStackTrace();}jt_login.setEnabled(false);// 禁用用户文本框buttonLogin.setEnabled(false);loginFlag = true;// 将已登录标记设置为trueMyName.setText(userName);}});//退出按钮buttonExit.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {String exitUser = jt_login.getText().trim();Vector v = new Vector();v.add("退出:" + exitUser);try {out.writeObject(v);out.flush();// 刷新输出缓冲区} catch (IOException ex) {ex.printStackTrace();}System.exit(0); // 退出系统}});
//      创建托盘if (SystemTray.isSupported()){// 获取图片所在的URLURL url = Client4.class.getResource("qq.jpg");// 实例化图像对象ImageIcon icon = new ImageIcon(url);// 获得Image对象Image image = icon.getImage();// 创建托盘图标TrayIcon trayIcon = new TrayIcon(image);// 为托盘添加鼠标适配器trayIcon.addMouseListener(new MouseAdapter(){// 鼠标事件public void mouseClicked(MouseEvent e){if (e.getClickCount() == 2){JOptionPane.showMessageDialog(null, "已登陆成功");}}});// 添加工具提示文本trayIcon.setToolTip("QQ:本地连接\r\n速度:100.0 Mbps\r\n状态:已连接上");// 创建弹出菜单PopupMenu popupMenu = new PopupMenu();popupMenu.add(new MenuItem("我在线上"));popupMenu.add(new MenuItem("忙碌"));popupMenu.add(new MenuItem("隐身"));popupMenu.add(new MenuItem("离线"));popupMenu.addSeparator();popupMenu.add(new MenuItem("关闭所有声音"));popupMenu.add(new MenuItem("关闭头像闪动"));popupMenu.addSeparator();popupMenu.add(new MenuItem("退出"));// 为托盘图标加弹出菜弹trayIcon.setPopupMenu(popupMenu);// 获得系统托盘对象SystemTray systemTray = SystemTray.getSystemTray();try{// 为系统托盘加托盘图标systemTray.add(trayIcon);}catch (Exception e){e.printStackTrace();}}else{JOptionPane.showMessageDialog(null, "not support");}}
}

如果有误可以查看进行下载
http://download.csdn.net/download/xiao_ma_csdn/10269610
或者
https://github.com/mmaagithub/ChatRoom

JavaSE写仿QQ聊天室相关推荐

  1. java仿qq群聊_[转载]仿QQ聊天室群聊的练习心得

    javase的学习即将告一段落,作为最后的一个项目练习,仿聊天室的程序编写让我很是头疼了一阵子.说起来还是自己java基础不牢的缘故导致的,虽然整体框架都已经很清晰了但是实际编写过程中却依然磕磕绊绊, ...

  2. 网络编程-基于MFC的仿QQ聊天室-2020

    基于MFC的仿QQ聊天室(2020) 有幸学习过网络编程的一些知识,出于对编程的热爱,把曾经的一次简单实践编程作业进行了自定义的完成. 编程所需: 编程工具为VS 2010,需要掌握MFC的基本操作以 ...

  3. win32 API &winsock c++架构实现仿QQ聊天室

    由于时间紧迫,我决定学习opengl的同时学习winsock,看了两个星期的windows socket编程,发现动手比看书效果好啊,于是,我决定写一个QQ聊天室的小程序,仿照书上的服务器端和客户端代 ...

  4. vue仿QQ聊天室|vue聊天实例,直播聊天室

    图片压缩 百亿站点 基于vue2.0+vue-cli+vuex+vue-router+webpack+es6+wcPop等技术开发的仿微信聊天界面|仿微信聊天室vue-chatRoom,实现了微信聊天 ...

  5. java仿QQ聊天室群聊(快速写一个简易QQ)

    [mie haha的博客]转载请注明出处(万分感谢!): https://blog.csdn.net/qq_40315080/article/details/83052689 用java写聊天室实现群 ...

  6. 仿QQ聊天室【方案】

    消息格式 struct MSG {     struct in_addr fromAdress;//源地址     struct in_addr toAdress;  //目的地址     union ...

  7. 基于 vue.js 的仿QQ聊天室

    简介 这是一款基于 vue.js 开发的聊天室组件库,在提供基础封装的同时,最大程度的增加扩展性. 下面是效果演示图: MChat组件效果图: IChat组件效果图: 如何安装 使用 npm 安装 n ...

  8. 仿QQ聊天室项目功能总结

    项目源码开源在gitee(码云) 地址:https://gitee.com/xiaoclgitee/imitation-qq-chat-room 项目功能总结: 1.页面制作 采用Java 的Swin ...

  9. java qq通信,Java通信-仿QQ聊天项目

    前后历时一个多月的Java实现聊天通信项目-仿QQ聊天室基本告一段落,期间面对了很多问题,也有不同的解决方案,重写了几次核心代码,等等问题.现在在项目的结束之时,给自己做一个总结,算是一个回顾,算是一 ...

最新文章

  1. 数据结构实验——中缀表达式转为后缀表达式
  2. 前端问题多行点点点的问题
  3. linux修改系统时间为北京时间(CentOS)
  4. 16-Understanding the Armv8.x extensions
  5. OSPF在企业网的应用
  6. python读取文件内容操作_Python 3.6 读取并操作文件内容
  7. python 三维曲线拟合_基于三维数据和参数的Scipy曲线拟合
  8. C语言程序设计double,C语言中double类型数据占字节数为
  9. UIWindowLevel详解
  10. 拼多多黄铮长文自述:用常识判断未来
  11. 小米首场开发者大会:宣布IoT开发者计划,联手百度提升AI能力
  12. 二十一天学通JavaScript:cookie的安全性
  13. gridview的sort_GRIDVIEW排序的方法
  14. 启明星系统使用在线视频教程
  15. QQ空间密码破解技术
  16. codesys 实现冒泡排序
  17. 无线路由器连接有线路由器设置
  18. Temporary ASP.NET Files 写访问权限
  19. 帆软报表写switch函数
  20. FTX交易平台与AZA Finance达成合作,推动非洲数字经济发展

热门文章

  1. SQL存储过程参数默认值
  2. 对链路负载均衡与应用负载均衡的通俗理解
  3. Navicat如何连接MySQL
  4. 循环 — 你必须要会的十五道编程题
  5. Mac下Android的Eclipse开发环境的搭建
  6. 谷歌浏览器插件最新版 v0.2.0 抓取1688、京东 商品图片|文描|视频|规格|属性等信息 并打包下载
  7. PHP+PHPQRcode写一个二维码接口api
  8. 知识产权及保护措施是受到法律保护的吗
  9. bfo java_Java操作PDF文件(BFO)
  10. 仿抖音短视频项目笔记 (一)产品介绍与数据库设计