Java implements qq chat (super detailed)

Java language practice course content: chat room applet or QQ

Functional requirements:
Chat room: Using a graphical user interface, it can realize multi-person chat in a chat room, and two people can chat privately.
QQ: Realize functions similar to QQ login and chat.
Note: There are certain levels. Completely copy other people's code, no more than 70 points.
Tips: The use of socket communication
is explained step by step. If you want to see the final code, please go to the bottom of the article directly.
//
Thanks to this up blogger for the video explanation! ! !
Preparatory work
Create packages, classes, and files
To insert pictures, create a folder, which stores the required pictures. For example, the folder I created is image; the
communication between two devices requires the use of socket communication protocol , that is, the client’s content is first transmitted to the server, processed on the server, and returned to

insert image description here
the image stored in the client’s image material file
Link: https://pan.baidu.com/s/1zns86NC6Qm80xKZHMIRSbA
Extraction code: 3f6w
insert image description here

//

1. First, let's build a qq login interface

The finished product picture is as follows:
insert image description here
the detailed code and notes are as follows

// 客户端的登陆界面
package com.qq.client.view;
//抽象窗口工具包
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqClientlLogin  extends JFrame{
    
      //JFrame的子类
	
	  JLabel jup;   //定义上部需要的组件   //标签
	
	//定义中部需要的组件
	  JPanel jmid ;
      JLabel jmid_num1,jmid_key1;
      JTextField jmid_num2;    //文本框
      JPasswordField jmid_key2;   //密码框
      JCheckBox jmid_rember,jmid_automatic;  //复选框
	  
	 JPanel  jdown;         //JPanel 面板
	 JButton jdown_1,jdown_2;    //定义下部需要的组件
	 
	 public  QqClientlLogin()      //构造方法
	 {
    
    
		  //处理上部      
	    jup=new JLabel(new  ImageIcon("image/up3.png"));
	
	    //处理中部
	    jmid=new JPanel(new GridLayout(3,3));//网格布局 3行3列
	    Font font = new Font("宋体", Font.PLAIN, 25);    //创建1个字体实例
	    jmid_num1=new JLabel("QQ号码:",JLabel.CENTER);  
	    jmid_key1=new JLabel("QQ密码:",JLabel.CENTER);
	    jmid_num1.setFont(font);    jmid_key1.setFont(font);  //字体大小
        jmid_num2= new JTextField() ;    
	    jmid_key2=new JPasswordField();
	    jmid_rember=new JCheckBox("自动登录");
	    jmid_automatic=new JCheckBox("记住密码");
	    jmid_rember.setFont(font);    jmid_automatic.setFont(font); //字体大小
	    jmid_rember.setForeground(Color.blue); 	  //设置字体颜色
	    jmid_automatic.setForeground(Color.blue);
	    jmid.add(jmid_num1);
	    jmid.add(jmid_num2);
	    jmid.add(jmid_key1);
	    jmid.add(jmid_key2);
	    jmid.add(jmid_rember);
	    jmid.add(jmid_automatic);
	    
	    //处理下部
	    jdown=new JPanel(new FlowLayout()); //流式布局
	    jdown_1=new JButton(new ImageIcon("image/denglu.png"));
	    jdown_2=new JButton(new ImageIcon("image/tuichu.png"));
	    jdown.add(jdown_1);
	    jdown.add(jdown_2);
	    
	    setLocation(300,300); //窗口的位置
	    add(jup,"North");   //放在最北部    
	    add(jmid,"Center");  //放在中间
	    add(jdown,"South"); //放在南部
	    setSize(700,540);     //设置大小                                  
	    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //结束窗口所在的应用程序  
	    setVisible(true);       //可见,默认是不可见
	 }
	 
	 public static void main(String[]  args)
	 {
    
    
		 QqClientlLogin  qqClientlLogin=new  QqClientlLogin();
	 } 
}

//

2. Friends list interface

The finished product picture is as follows:
insert image description here

To create a conversion between two cards, click "Blacklist" on card one to go to the second card interface, click "My Friends" on the second card to go to the first interface. At this point, you need to
create The class of the listener uses the ActionListener interface.
In addition, I have also established a MouseListener interface for mouse monitoring. When the mouse stays on a friend, the friend number turns red, and when it leaves, it turns back to black. When you double-click a friend, you can get the friend's ID Number (and enter the chat interface with the friend)
detailed code and notes are as follows

//好友列表(也包括黑名单)
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqFriendList extends JFrame implements ActionListener,MouseListener {
    
       
	//负责创建监听器的类,  点击按钮触发ActionListener事件;  鼠标监听MouseListener 
	
    // 第一张卡片(我的好友);
		JPanel jup1,jmid1,jdown1;   //jup1即为总JPanel;
		JButton jup1_1,jdown1_1;
		JScrollPane jmid1_1;      //滑动窗口;
	
	//第二张卡片(黑名单);
		JPanel jup2,jup2_button,jmid2;
		JButton jup2_1,jup2_2;
		JScrollPane jmid2_1;      //滑动窗口;
		
  //把整个JFrame设置成CardLayout布局
		CardLayout cl;

   public  QqFriendList ()
   {
    
             Font font = new Font("宋体", Font.PLAIN, 35);    //创建字体实例

	
	   //处理第一张卡片(我的好友);
	    jup1=new JPanel(new BorderLayout());   //第一张卡片的总JPane,BorderLayout()布局;
	   jup1_1=new JButton("我的好友");
	   jup1_1.setFont(font);  //字体
	
	   //假设有50个好友,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid1=new JPanel(new  GridLayout(50,1,4,4));  //(4,4)行间距和列间距
       //给jmid1初始化50个好友
	   JLabel []jlist1=new JLabel [50];  //数组;
	   for ( int i=0; i<jlist1.length ; i++ )
	   {
    
    
		   jlist1[i]=new JLabel(i+1+" ",new ImageIcon("image/touxiang.png"),JLabel.LEFT);
		   jlist1[i].addMouseListener(this);
		   jmid1.add(jlist1[i]);  
	   }
	   jmid1_1=new JScrollPane(jmid1);
	   
	   jdown1_1=new JButton("黑名单");
	   jdown1_1.addActionListener(this);     //给jdown1_1按钮增加一个监听器,这个监听器对象就是“QqFriendList ”类型的,
	                          //当用户点击了jdown1_1按钮时,会程序自动前往QqFriendList类的“actionPerformed”方法中,处理产生的事件。
	   jdown1_1.setFont(font);        //字体
	   jdown1=new JPanel(new GridLayout(1,1));//黑名单按钮
	   jdown1.add(jdown1_1);  //加入按钮;
	   
       jup1.add(jup1_1,"North");
       jup1.add(jmid1_1,"Center");
       jup1.add(jdown1,"South");
   

       
       //处理第二张卡片(黑名单)	   
       jup2=new JPanel(new BorderLayout());   //第二张卡片的总JPane,BorderLayout()布局;
       jup2_1=new JButton("我的好友");
       jup2_1.addActionListener(this);   //监听
       jup2_2=new JButton("黑名单");
	   jup2_1.setFont(font);  //字体
       jup2_2.setFont(font);
       jup2_button=new JPanel(new GridLayout(2,1));//黑名单按钮
       jup2_button.add(jup2_1);
       jup2_button.add(jup2_2);
       
	   //假设有20个黑名单,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid2=new JPanel(new  GridLayout(20,1,4,4));  //(4,4)行间距和列间距
       //给jmid2初始化20个好友
	   JLabel []jlist2=new JLabel [20];  //数组;
	   for ( int i=0; i<jlist2.length ; i++ )
	   {
    
    
		   jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);
		   jmid2.add(jlist2[i]);
	   }
	   jmid2_1=new JScrollPane(jmid2);
	   
       jup2.add(jup2_button,"North");
       jup2.add(jmid2_1);
  
       cl=new CardLayout();
       setLayout(cl);
       add(jup1,"1");  //第一张卡片jup1;
       add(jup2,"2");  //第二张卡片jup2;
       setLocation(300,300); //窗口的位置
       setSize(440,800);
       setVisible(true);     
   }
  
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		QqFriendList  qqFriendList=new  QqFriendList();
	}
	
	public void actionPerformed(ActionEvent arg0)
	{
    
     
		//如果点击了黑名单按钮,就显示第二张卡片
		if(arg0.getSource()==jdown1_1)
		{
    
    
			cl.show(this.getContentPane(), "2");  //用getContentPane()方法获得JFrame的内容面板
		}
		else
			if(arg0.getSource()==jup2_1)
			{
    
    
				cl.show(this.getContentPane(), "1");
			}
	}
	public void mouseEntered(MouseEvent arg0) {
    
        //进入组件触发鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource(); //变成JLable形式
                                              //getSource()获取鼠标事件的事件源;
		jl.setForeground(Color.red);   //设置前景色
	}

	public void mouseExited(MouseEvent arg0) {
    
      //鼠标离开组件触发的鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource();   
		jl.setForeground(Color.black);
	}
	
	public void mouseClicked(MouseEvent arg0) {
    
       //点击鼠标触发鼠的标事件
		// TODO Auto-generated method stub
		//响应用户双击的事件,并得到好友的编号.
		if(arg0.getClickCount()==2)   //getClickCount() 获取鼠标被单机的次数
		{
    
    
			//得到该好友的编号 
			//getText() 的意思是:返回数据窗口控件中 悬浮在当前行列之上的
			String friendNum=((JLabel)arg0.getSource()).getText();
			
			//System.out.println("你希望和 "+friendNum+" 聊天");
		}
	}


	public void mousePressed(MouseEvent arg0) {
    
     //按下按鼠标键触发的鼠标事件
		// TODO Auto-generated method stub
		
	}

	public void mouseReleased(MouseEvent arg0) {
    
       //释放鼠标键触发的鼠标事件
		// TODO Auto-generated method stub
		
	}

} 

3. Chat interface, use the server to judge login qq, object flow

The code result map of this part:
insert image description here

Note: Normally there is a database to store the qq account password information. Adhering to the principle of simple to difficult, we will not design the database here, and directly use the server to judge the settings of the two interfaces of the appeal. I believe that setting up the chat interface should be very easy
. Good simulation exit
Chat interface preliminary results:insert image description here

//与好友聊天的界面
package com.qq.client.view;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class QqChat extends JFrame {
    
    
	 Font font = new Font("宋体", Font.PLAIN, 20); 
	JTextArea jta;    //文本域  存聊天内容
	JTextField jtf;    //文本框
	JButton jb;
	JPanel jp;
	String ownerId;
	String friendId;
	
	public QqChat(String owner,String friend)
	{
    
    
		jta=new JTextArea();
		jtf=new JTextField(25);     //25个字符那么宽
		jb=new JButton("发送");
		jb.setFont(font);
		jp=new JPanel();
		jp.add(jtf);
		jp.add(jb);	
		add(jta,"Center");
		add(jp,"South");
		setTitle(owner+"正在和 "+friend+" 聊天");  //设置标题
		setIconImage((new ImageIcon("image/qq.png").getImage())); //获取图像
		setLocation(800,400); //窗口的位置
		setSize(600, 500);
		setVisible(true);
	}
	
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
	    QqChat qqChat=new QqChat("1");   //传入好友1,你正在和1聊天;
	}

Think about it, if you want to chat with other friends, how should you express it?
In QqFriendList, we double-click to get the number of friends, and only need to pass the number to QqChat
insert image description here
. The number and password are sent to QqServer (server) for verification. If the user is legal, return true, otherwise return false;
read the account number and password sent by the client in the form of object flow, and transfer object flow between networks to
avoid direct reading The input is disturbed by special symbols, spaces, newlines, etc.

对象流是一种高级流,可以方便我们将java中的任何对象进行读写操作。
java.io.objectoutputstream对象输出流,可以将对象转换为一组字节写出。
java.io.objectinputstream对象输入流,可以读取一组字节转换为原对象,
还原为原对象的条件是读取这个字节应该是对象输出流将一个对象转换的字节。

一个对象要想序列化,该类必须实现java.io.Serializable 接口
Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中

Here, we also use socket. A socket is a connection between two hosts.
Two programs on the network exchange data through a two-way communication connection. One end of this connection is called a socket.
A pair of sockets is required to establish a network communication connection, and a pipe (channel) is formed between the two sockets for the transmission of information flow (reading and writing between files and programs in Lenovo IO flow).

Detailed explanation of getting started with ServerSocket and Socket
Create the com.qq.common package in the Qqclient (client) and QqServe (server) projects respectively, and store Message.java and User.java in the package. The
User class is to obtain the account number and password

//用户信息类
package com.qq.common;

public class User  implements java.io.Serializable{
    
    
	 
	private String userId;
	private String passwd;
	public String getUserId()
	{
    
    
		return userId;
	}
	public void setUserId(String userId) {
    
    
		this.userId = userId;
	}
	public String getPasswd()
	{
    
    
		return passwd;
	}
	public void setPasswd(String passwd)
	{
    
    
		this.passwd=passwd;
	}
}

Specify some rules for the information sent by the server.
mesType is true, indicating that the login is successful,
and mesType is false, indicating that the login failed
, so Message is used to judge

package com.qq.common;
public class Message implements java.io.Serializable {
    
     //序列化     
	private String mesType;
	public String getMesType()
	{
    
    
		return mesType;
	}
	public void setMesType(String mesType)
	{
    
    
		this.mesType =mesType;
	}
}

The main idea
insert image description here
is to add monitoring (login button) to the code of the first part of the qq login interface, and gradually transfer the obtained account and password information to the broken server, and then the server returns to judge whether it is possible to log in, and if so, open the friend List interface,
otherwise, the prompt box "username or password error" will be triggered.
Client
Note: I judge that if the password is "123456", it is correct

// 客户端的登陆界面
package com.qq.client.view;
//抽象窗口工具包
import javax.swing.*;
import java.awt.*;  
import java.awt.event.*;
import com.qq.client.model.*;
import com.qq.common.*;
public class QqClientlLogin  extends JFrame implements ActionListener{
    
      //JFrame的子类
	
	  JLabel jup;   //定义上部需要的组件   //标签
	
	//定义中部需要的组件
	  JPanel jmid ;
      JLabel jmid_num1,jmid_key1;
      JTextField jmid_num2;    //文本框
      JPasswordField jmid_key2;   //密码框
      JCheckBox jmid_rember,jmid_automatic;  //复选框
	  
	 JPanel  jdown;         //JPanel 面板
	 JButton jdown_1,jdown_2;    //定义下部需要的组件
	 
	 public  QqClientlLogin()      //构造方法
	 {
    
    
		  //处理上部      
	    jup=new JLabel(new  ImageIcon("image/up3.png"));
	
	    //处理中部
	    jmid=new JPanel(new GridLayout(3,3));//网格布局 3行3列
	    Font font = new Font("宋体", Font.PLAIN, 25);    //创建1个字体实例
	    jmid_num1=new JLabel("QQ号码:",JLabel.CENTER);  
	    jmid_key1=new JLabel("QQ密码:",JLabel.CENTER);
	    jmid_num1.setFont(font);    jmid_key1.setFont(font);  //字体大小
        jmid_num2= new JTextField() ;    
	    jmid_key2=new JPasswordField();
	    jmid_rember=new JCheckBox("自动登录");
	    jmid_automatic=new JCheckBox("记住密码");
	    jmid_rember.setFont(font);    jmid_automatic.setFont(font); //字体大小
	    jmid_rember.setForeground(Color.blue); 	  //设置字体颜色
	    jmid_automatic.setForeground(Color.blue);
	    jmid.add(jmid_num1);
	    jmid.add(jmid_num2);
	    jmid.add(jmid_key1);
	    jmid.add(jmid_key2);
	    jmid.add(jmid_rember);
	    jmid.add(jmid_automatic);
	    
	    //处理下部
	    jdown=new JPanel(new FlowLayout()); //流式布局
	    jdown_1=new JButton(new ImageIcon("image/denglu.png"));
	    
	    //响应用户点击登录
	    jdown_1.addActionListener(this);  //监控
	    
	    jdown_2=new JButton(new ImageIcon("image/tuichu.png"));
	    jdown.add(jdown_1);
	    jdown.add(jdown_2);
	    
	    setLocation(300,300); //窗口的位置
	    add(jup,"North");   //放在最北部    
	    add(jmid,"Center");  //放在中间
	    add(jdown,"South"); //放在南部
	    setSize(700,540);     //设置大小                                  
	    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //结束窗口所在的应用程序  
	    setVisible(true);       //可见,默认是不可见
	 }
	 
	 public static void main(String[]  args)
	 {
    
    
		 QqClientlLogin  qqClientlLogin=new  QqClientlLogin();
	 } 
	public void actionPerformed(ActionEvent arg0)
	{
    
    
		if(arg0.getSource()==jdown_1);   //请求登录
		{
    
    
	     	User u=new User();
	     	u. setUserId(jmid_num2.getText().trim());   //trim() 方法用于 删除字符串的头尾空白符
	     	u. setPasswd(new String (jmid_key2.getPassword()));   //字符串;
	    	QqClientUser qqclientuser=new QqClientUser();
	    	
	     	if(qqclientuser.checkUser(u))
	     	{
    
    
	     		new QqFriendList(u.getUserId());  //好友列表
	     		this.dispose();  //关闭登陆界面
	     	}
	     	else
	     	{
    
    
	     		JOptionPane.showMessageDialog(this,"用户名或密码错误");
	     		//JOptionPane弹窗,消息提示框
	     		//showMessageDialog这个方法里有两个参数
	     		//第一个参数-确定Frame在其中显示的对话框
	     		//第二个参数message就是我们要在提示框里显示的信息
	     	}
		}
	}
}


//好友列表(也包括黑名单)
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqFriendList extends JFrame implements ActionListener,MouseListener {
    
       
	//负责创建监听器的类,  点击按钮触发ActionListener事件;  鼠标监听MouseListener 
	    
	     String owner;      
	     
    // 第一张卡片(我的好友);
		JPanel jup1,jmid1,jdown1;   //jup1即为总JPanel;
		JButton jup1_1,jdown1_1;
		JScrollPane jmid1_1;      //滑动窗口;
	
	//第二张卡片(黑名单);
		JPanel jup2,jup2_button,jmid2;
		JButton jup2_1,jup2_2;
		JScrollPane jmid2_1;      //滑动窗口;
		
  //把整个JFrame设置成CardLayout布局
		CardLayout cl;

   public  QqFriendList (String ownerId)
   {
    
       
	   Font font = new Font("宋体", Font.PLAIN, 35);    //创建字体实例

	    owner=ownerId;
	   //处理第一张卡片(我的好友);
	    jup1=new JPanel(new BorderLayout());   //第一张卡片的总JPane,BorderLayout()布局;
	   jup1_1=new JButton("我的好友");
	   jup1_1.setFont(font);  //字体
	
	   //假设有50个好友,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid1=new JPanel(new  GridLayout(50,1,4,4));  //(4,4)行间距和列间距
       //给jmid1初始化50个好友
	   JLabel []jlist1=new JLabel [50];  //数组;
	   for ( int i=0; i<jlist1.length ; i++ )
	   {
    
    
		   jlist1[i]=new JLabel(i+1+"",new ImageIcon("image/touxiang.png"),JLabel.LEFT);
		   jlist1[i].addMouseListener(this);
		   jmid1.add(jlist1[i]);  
	   }
	   jmid1_1=new JScrollPane(jmid1);
	   
	   jdown1_1=new JButton("黑名单");
	   jdown1_1.addActionListener(this);     //给jdown1_1按钮增加一个监听器,这个监听器对象就是“QqFriendList ”类型的,
	                          //当用户点击了jdown1_1按钮时,会程序自动前往QqFriendList类的“actionPerformed”方法中,处理产生的事件。
	   jdown1_1.setFont(font);        //字体
	   jdown1=new JPanel(new GridLayout(1,1));//黑名单按钮
	   jdown1.add(jdown1_1);  //加入按钮;
	   
       jup1.add(jup1_1,"North");
       jup1.add(jmid1_1,"Center");
       jup1.add(jdown1,"South");
   

       
       //处理第二张卡片(黑名单)	   
       jup2=new JPanel(new BorderLayout());   //第二张卡片的总JPane,BorderLayout()布局;
       jup2_1=new JButton("我的好友");
       jup2_1.addActionListener(this);   //监听
       jup2_2=new JButton("黑名单");
	   jup2_1.setFont(font);  //字体
       jup2_2.setFont(font);
       jup2_button=new JPanel(new GridLayout(2,1));//黑名单按钮
       jup2_button.add(jup2_1);
       jup2_button.add(jup2_2);
       
	   //假设有20个黑名单,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid2=new JPanel(new  GridLayout(20,1,4,4));  //(4,4)行间距和列间距
       //给jmid2初始化20个好友
	   JLabel []jlist2=new JLabel [20];  //数组;
	   for ( int i=0; i<jlist2.length ; i++ )
	   {
    
    
		   jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);
		   jmid2.add(jlist2[i]);
	   }
	   jmid2_1=new JScrollPane(jmid2);
	   
       jup2.add(jup2_button,"North");
       jup2.add(jmid2_1);
  
       cl=new CardLayout();
       setLayout(cl);
       add(jup1,"1");  //第一张卡片jup1;
       add(jup2,"2");  //第二张卡片jup2;
        setTitle(ownerId);//显示自己的编号
       setLocation(300,300); //窗口的位置
       setSize(440,800);
       setVisible(true);     
   }
  
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		QqFriendList  qqFriendList=new  QqFriendList();
	}
	
	public void actionPerformed(ActionEvent arg0)
	{
    
     
		//如果点击了黑名单按钮,就显示第二张卡片
		if(arg0.getSource()==jdown1_1)
		{
    
    
			cl.show(this.getContentPane(), "2");  //用getContentPane()方法获得JFrame的内容面板
		}
		else
			if(arg0.getSource()==jup2_1)
			{
    
    
				cl.show(this.getContentPane(), "1");
			}
	}
	public void mouseEntered(MouseEvent arg0) {
    
        //进入组件触发鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource(); //变成JLable形式
                                              //getSource()获取鼠标事件的事件源;
		jl.setForeground(Color.red);   //设置前景色
	}

	public void mouseExited(MouseEvent arg0) {
    
      //鼠标离开组件触发的鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource();   
		jl.setForeground(Color.black);
	}
	
	public void mouseClicked(MouseEvent arg0) {
    
       //点击鼠标触发鼠的标事件
		// TODO Auto-generated method stub
		//响应用户双击的事件,并得到好友的编号.
		if(arg0.getClickCount()==2)   //getClickCount() 获取鼠标被单机的次数
		{
    
    
			//得到该好友的编号 
			//getText() 的意思是:返回数据窗口控件中 悬浮在当前行列之上的
			String friendNum=((JLabel)arg0.getSource()).getText();
			
			//System.out.println("你希望和 "+friendNum+" 聊天");
			new QqChat(owner,friendNum);  //传入编号
		}
	}

	public void mousePressed(MouseEvent arg0) {
    
     //按下按鼠标键触发的鼠标事件
		// TODO Auto-generated method stub
	}

	public void mouseReleased(MouseEvent arg0) {
    
       //释放鼠标键触发的鼠标事件
		// TODO Auto-generated method stub		
	}
} 

package com.qq.client.model;
import com.qq.common.*;
public class QqClientUser {
    
    
  
	  public boolean checkUser(User u)
	  {
    
    
		 return new QqClientConServer().sendLoginInfotoSSErver(u);
	  }
}

//客户端链接服务器的部分
package com.qq.client.model;

import java.util.*;
import java.net.*;
import java.io.*;
import com.qq.common.*;
public class QqClientConServer{
    
    
 
	//发送第一次请求,登录请求
	public boolean sendLoginInfotoSSErver(Object o) //发送对象到服务器
	{
    
      
		boolean b=false;
		try
		 {
    
     
			 Socket s=new Socket("127.0.0.1",9999);	 //传入要连接主机与端口
			 ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); //输出流
		     oos.writeObject(o);  //把o发出去
			 
		     ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
		     Message ms=(Message)ois.readObject();  
		     if(ms.getMesType().equals("1"))
		    	b=true;
		 }
		 catch (Exception e)
		 {
    
    
			 e.printStackTrace();
		 }
		 finally
		 {
    
    
		 }
		return b;
	}
}


In addition to the required Message.java and User.java classes, the server also needs

//服务器端控制界面,可以完成启动服务器,关闭服务器,可以管理和监控用户
package com.qq.server.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.qq.server.model.MyQqServer;
public class ControlPanel  extends JFrame implements ActionListener{
    
    
    
	JPanel jp1;
	JButton jstart,jend;

	public ControlPanel()
	{
    
       Font font = new Font("宋体",Font.PLAIN,30);
	
		jp1=new JPanel();
		jstart=new JButton("启动服务器");
		jstart.addActionListener(this);
		jend=new JButton("关闭服务器");
		jstart.setFont(font); jend.setFont(font);
		jstart.setForeground(Color.BLUE); jend.setForeground(Color.BLUE);
		
		jp1.add(jstart);
		jp1.add(jend);
		
		add(jp1);
		setLocation(150,150);
		setSize(900,900);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //结束窗口所在的应用程序  
		setVisible(true);
	}
	
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		ControlPanel controlpanel =new ControlPanel();
	}
	
	public void actionPerformed(ActionEvent arg0)
	{
    
    
		if(arg0.getSource()==jstart)
		{
    
    
			new MyQqServer();
		}
	}
}

//qq服务器,监听,等待某个qq客户端链接
package com.qq.server.model;

import java.io.*; //(I/O)流库,提供大量的流类
import java.net.*;//导入网络包
import java.util.*; //实用工具类,提供了一些实用的方法和数据结构
import com.qq.common.*;

public class MyQqServer  {
    
    

	public MyQqServer ()
	{
    
    
		//try-catch语句处理异常
        try
        {
    
     
        	//ServerSocket类表示服务器socket
        	//在9999监听
    		System.out.println("服务器正在9999监听");//简单判断一下是否启动服务端
        	ServerSocket ss=new ServerSocket(9999);
        while(true)   //服务器可多次监听
        {
    
    
            Socket s=ss.accept() ;  //阻塞,等待连接(与客户端)
        	//接收客户端发来的信息
           ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
            User u=(User)ois.readObject();
            System.out.println("用户Id:"+u.getUserId()+"  密码"+u.getPasswd()); 
          	Message m=new Message();
          	 ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
            if(u.getPasswd().equals("123456"))
            {
    
    
            	//返回一个成功登录的信息
            	m.setMesType("1");    //mesType1 =1  表明登陆成功
                oos.writeObject(m);  
            }
            else
            {
    
    
            	m.setMesType("2"); 
                oos.writeObject(m); 
                s.close();  //关闭连接(流)
            }
        }
       }
        catch(Exception e)
        {
    
    
        	e.printStackTrace();//将错误信息全部打印
        }
        finally{
    
    
        	
        }
	}
}

4. One-on-one chat

insert image description here

Process concept: A process is an operation of code on a data set, and is the basic unit for resource allocation and scheduling by the system.
Thread concept: A thread is an execution path of a process. There is at least one thread in a process, and multiple threads in a process share the resources of the process.

Threads are used here to receive messages from the client, because not only one user (multi-user login can be realized)
must be added in the message class, user number, recipient, sending information (that is, to obtain the content of the chat interface text box), etc.
In the chat class, add reading, display the chat code and other content in the text field
Use HashMap<keyword, value> in the management client thread to record the socket between the sender and the server, the keyword records the user number, and the value records the socket

Each package (class) has been changed more or less, the complete code is as follows, I hope it will be helpful to everyone, and please correct me %%%

//
client code

package com.qq.common;

public class Message implements java.io.Serializable {
    
     //序列化
     
	private String mesType;
	
	private String sender;//发送者
	private String getter; //接收者
	private String con;  //信息
	
	public String getSender()
	{
    
    
		return sender;
	}
	public void setSender(String sender)
	{
    
    
		this.sender=sender;
	}
	
	public String getGetter()
	{
    
    
		return getter;
	}
	public void setGetter(String getter)
	{
    
    
		this.getter=getter;
	}
	
	public String getCon()
	{
    
    
		return con;
	}
	public void setCon(String con)
	{
    
    
		this.con=con;
	}
	
	public String getMesType()
	{
    
    
		return mesType;
	}
	public void setMesType(String mesType)
	{
    
    
		this.mesType =mesType;
	}
}

//用户信息类
package com.qq.common;

public class User  implements java.io.Serializable{
    
    
	 
	private String userId;
	private String passwd;
	public String getUserId()
	{
    
    
		return userId;
	}
	public void setUserId(String userId) {
    
    
		this.userId = userId;
	}
	public String getPasswd()
	{
    
    
		return passwd;
	}
	public void setPasswd(String passwd)
	{
    
    
		this.passwd=passwd;
	}
	
}
// 客户端的登陆界面
package com.qq.client.view;
//抽象窗口工具包
import javax.swing.*;
import java.awt.*;  
import java.awt.event.*;
import com.qq.client.model.*;
import com.qq.common.*;
public class QqClientlLogin  extends JFrame implements ActionListener{
    
      //JFrame的子类
	
	  JLabel jup;   //定义上部需要的组件   //标签
	
	//定义中部需要的组件
	  JPanel jmid ;
      JLabel jmid_num1,jmid_key1;
      JTextField jmid_num2;    //文本框
      JPasswordField jmid_key2;   //密码框
      JCheckBox jmid_rember,jmid_automatic;  //复选框
	  
	 JPanel  jdown;         //JPanel 面板
	 JButton jdown_1,jdown_2;    //定义下部需要的组件
	 
	 public  QqClientlLogin()      //构造方法
	 {
    
    
		  //处理上部      
	    jup=new JLabel(new  ImageIcon("image/up3.png"));
	
	    //处理中部
	    jmid=new JPanel(new GridLayout(3,3));//网格布局 3行3列
	    Font font = new Font("宋体", Font.PLAIN, 25);    //创建1个字体实例
	    jmid_num1=new JLabel("QQ号码:",JLabel.CENTER);  
	    jmid_key1=new JLabel("QQ密码:",JLabel.CENTER);
	    jmid_num1.setFont(font);    jmid_key1.setFont(font);  //字体大小
        jmid_num2= new JTextField() ;    
	    jmid_key2=new JPasswordField();
	    jmid_rember=new JCheckBox("自动登录");
	    jmid_automatic=new JCheckBox("记住密码");
	    jmid_rember.setFont(font);    jmid_automatic.setFont(font); //字体大小
	    jmid_rember.setForeground(Color.blue); 	  //设置字体颜色
	    jmid_automatic.setForeground(Color.blue);
	    jmid.add(jmid_num1);
	    jmid.add(jmid_num2);
	    jmid.add(jmid_key1);
	    jmid.add(jmid_key2);
	    jmid.add(jmid_rember);
	    jmid.add(jmid_automatic);
	    
	    //处理下部
	    jdown=new JPanel(new FlowLayout()); //流式布局
	    jdown_1=new JButton(new ImageIcon("image/denglu.png"));
	    
	    //响应用户点击登录
	    jdown_1.addActionListener(this);  //监控
	    
	    jdown_2=new JButton(new ImageIcon("image/tuichu.png"));
	    jdown.add(jdown_1);
	    jdown.add(jdown_2);
	    
	    setLocation(300,300); //窗口的位置
	    add(jup,"North");   //放在最北部    
	    add(jmid,"Center");  //放在中间
	    add(jdown,"South"); //放在南部
	    setSize(700,540);     //设置大小                                  
	    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //结束窗口所在的应用程序  
	    setVisible(true);       //可见,默认是不可见
	 }
	 
	 public static void main(String[]  args)
	 {
    
    
		 QqClientlLogin  qqClientlLogin=new  QqClientlLogin();
	 } 
	public void actionPerformed(ActionEvent arg0)
	{
    
    
		if(arg0.getSource()==jdown_1);   //请求登录
		{
    
    
	     	User u=new User();
	     	u. setUserId(jmid_num2.getText().trim());   //trim() 方法用于 删除字符串的头尾空白符
	     	u. setPasswd(new String (jmid_key2.getPassword()));   //字符串;
	    	QqClientUser qqclientuser=new QqClientUser();
	    	
	     	if(qqclientuser.checkUser(u))
	     	{
    
    
	     		QqFriendList qqList=new QqFriendList(u.getUserId());  //好友列表
	     		this.dispose();  //关闭登陆界面
	     	}
	     	else
	     	{
    
    
	     		JOptionPane.showMessageDialog(this,"用户名或密码错误");
	     		//JOptionPane弹窗,消息提示框
	     		//showMessageDialog这个方法里有两个参数
	     		//第一个参数-确定Frame在其中显示的对话框
	     		//第二个参数message就是我们要在提示框里显示的信息
	     	}
		}
	}
}

//好友列表(也包括黑名单)
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqFriendList extends JFrame implements ActionListener,MouseListener {
    
       
	//负责创建监听器的类,  点击按钮触发ActionListener事件;  鼠标监听MouseListener 
	    
	     String owner;      
	     
    // 第一张卡片(我的好友);
		JPanel jup1,jmid1,jdown1;   //jup1即为总JPanel;
		JButton jup1_1,jdown1_1;
		JScrollPane jmid1_1;      //滑动窗口;
	
	//第二张卡片(黑名单);
		JPanel jup2,jup2_button,jmid2;
		JButton jup2_1,jup2_2;
		JScrollPane jmid2_1;      //滑动窗口;
		
  //把整个JFrame设置成CardLayout布局
		CardLayout cl;

   public  QqFriendList (String ownerId)
   {
    
       
	   Font font = new Font("宋体", Font.PLAIN, 35);    //创建字体实例

	    owner=ownerId;
	   //处理第一张卡片(我的好友);
	    jup1=new JPanel(new BorderLayout());   //第一张卡片的总JPane,BorderLayout()布局;
	   jup1_1=new JButton("我的好友");
	   jup1_1.setFont(font);  //字体
	
	   //假设有50个好友,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid1=new JPanel(new  GridLayout(50,1,4,4));  //(4,4)行间距和列间距
       //给jmid1初始化50个好友
	   JLabel []jlist1=new JLabel [50];  //数组;
	   for ( int i=0; i<jlist1.length ; i++ )
	   {
    
    
		   jlist1[i]=new JLabel(i+1+" ",new ImageIcon("image/touxiang.png"),JLabel.LEFT);
		   jlist1[i].addMouseListener(this);
		   jmid1.add(jlist1[i]);  
	   }
	   jmid1_1=new JScrollPane(jmid1);
	   
	   jdown1_1=new JButton("黑名单");
	   jdown1_1.addActionListener(this);     //给jdown1_1按钮增加一个监听器,这个监听器对象就是“QqFriendList ”类型的,
	                          //当用户点击了jdown1_1按钮时,会程序自动前往QqFriendList类的“actionPerformed”方法中,处理产生的事件。
	   jdown1_1.setFont(font);        //字体
	   jdown1=new JPanel(new GridLayout(1,1));//黑名单按钮
	   jdown1.add(jdown1_1);  //加入按钮;
	   
       jup1.add(jup1_1,"North");
       jup1.add(jmid1_1,"Center");
       jup1.add(jdown1,"South");
   

       
       //处理第二张卡片(黑名单)	   
       jup2=new JPanel(new BorderLayout());   //第二张卡片的总JPane,BorderLayout()布局;
       jup2_1=new JButton("我的好友");
       jup2_1.addActionListener(this);   //监听
       jup2_2=new JButton("黑名单");
	   jup2_1.setFont(font);  //字体
       jup2_2.setFont(font);
       jup2_button=new JPanel(new GridLayout(2,1));//黑名单按钮
       jup2_button.add(jup2_1);
       jup2_button.add(jup2_2);
       
	   //假设有20个黑名单,具体是服务器返回的结果(好友信息存放在服务器)
	   jmid2=new JPanel(new  GridLayout(20,1,4,4));  //(4,4)行间距和列间距
       //给jmid2初始化20个好友
	   JLabel []jlist2=new JLabel [20];  //数组;
	   for ( int i=0; i<jlist2.length ; i++ )
	   {
    
    
		   jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);
		   jmid2.add(jlist2[i]);
	   }
	   jmid2_1=new JScrollPane(jmid2);
	   
       jup2.add(jup2_button,"North");
       jup2.add(jmid2_1);
  
       cl=new CardLayout();
       setLayout(cl);
       add(jup1,"1");  //第一张卡片jup1;
       add(jup2,"2");  //第二张卡片jup2;
        setTitle(ownerId);//显示自己的编号
       setLocation(300,300); //窗口的位置
       setSize(440,800);
       setVisible(true);     
   }
 
   public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		//QqFriendList  qqFriendList=new  QqFriendList();
	} 
   
	public void actionPerformed(ActionEvent arg0)
	{
    
     
		//如果点击了黑名单按钮,就显示第二张卡片
		if(arg0.getSource()==jdown1_1)
		{
    
    
			cl.show(this.getContentPane(), "2");  //用getContentPane()方法获得JFrame的内容面板
		}
		else
			if(arg0.getSource()==jup2_1)
			{
    
    
				cl.show(this.getContentPane(), "1");
			}
	}
	public void mouseEntered(MouseEvent arg0) {
    
        //进入组件触发鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource(); //变成JLable形式
                                              //getSource()获取鼠标事件的事件源;
		jl.setForeground(Color.red);   //设置前景色
	}

	public void mouseExited(MouseEvent arg0) {
    
      //鼠标离开组件触发的鼠标事件
		// TODO Auto-generated method stub
		JLabel jl=(JLabel)arg0.getSource();   
		jl.setForeground(Color.black);
	}
	
	public void mouseClicked(MouseEvent arg0) {
    
       //点击鼠标触发鼠的标事件
		// TODO Auto-generated method stub
		//响应用户双击的事件,并得到好友的编号.
		if(arg0.getClickCount()==2)   //getClickCount() 获取鼠标被单机的次数
		{
    
    
			//得到该好友的编号 
			//getText() 的意思是:返回数据窗口控件中 悬浮在当前行列之上的
			String friendNum=((JLabel)arg0.getSource()).getText();
			
			//System.out.println("你希望和 "+friendNum+" 聊天");
			QqChat qqChat=new QqChat(owner,friendNum);  //传入编号
		   Thread t=new Thread(qqChat);  
		   t.start();     // 启动线程
		}
	}

	public void mousePressed(MouseEvent arg0) {
    
     //按下按鼠标键触发的鼠标事件
		// TODO Auto-generated method stub
	}

	public void mouseReleased(MouseEvent arg0) {
    
       //释放鼠标键触发的鼠标事件
		// TODO Auto-generated method stub		
	}
} 

//与好友聊天的界面
 //因为客户端,要处于读取的状态,因此我们把它做成一个线程
package com.qq.client.view;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import com.qq.common.*;
import com.qq.client.model.*;
public class QqChat extends JFrame implements ActionListener,Runnable{
    
      //监听发送按钮
	 Font font = new Font("宋体", Font.PLAIN, 20);                                          //实现Runnable接口实现多线程,
	JTextArea jta;    //文本域  存聊天内容
	JTextField jtf;    //文本框
	JButton jb;
	JPanel jp;
	String ownerId;
	String friendId;
	
	public QqChat(String owner,String friend)
	{
    
     
		ownerId= owner;
		friendId=friend;
		jta=new JTextArea();
		jtf=new JTextField(25);     //25个字符那么宽
		jb=new JButton("发送");
		jb.addActionListener(this);
		jb.setFont(font);
		jp=new JPanel();
		jp.add(jtf);
		jp.add(jb);	
		add(jta,"Center");
		add(jp,"South");
		setTitle(owner+"正在和 "+friend+" 聊天");  //设置标题
		setIconImage((new ImageIcon("image/qq.png").getImage())); //获取图像
		setLocation(800,400); //窗口的位置
		setSize(600, 500);
		setVisible(true);
	}
	
	//写一个方法,让它显示消息
	public void showMessage(Message m)
	 {
    
    
		String info=m.getSender()+" 给"+m.getGetter()+" 发送:"+m.getCon()+"\r\n";
		this.jta.append(info);
	}
		
	public void actionPerformed(ActionEvent arg0) {
    
    
		// TODO Auto-generated method stub
		if(arg0.getSource()==jb)//如果用户点击了发送按钮
		{
    
    
			Message m=new Message();
			m.setSender(this.ownerId);
			m.setGetter(this.friendId);
			m.setCon(jtf.getText());   //文本框中得到 
			  
			//发送给服务器  要拿到socket,可以把socket写成静态的,从类里面拿出来;
			try 
			{
    
     
				ObjectOutputStream oos=new ObjectOutputStream(QqClientConServer.s.getOutputStream());
				oos.writeObject(m);
			} 
			catch (Exception e) 
			{
    
    
				e.printStackTrace();
			}	
		}	
	}
	public void run()
	{
    
    
		while(true)
		{
    
       //一直处于读取状态(如果读不到就等待)
			try
			{
    
    
				ObjectInputStream ois=new ObjectInputStream(QqClientConServer.s.getInputStream());
				Message m =(Message)ois.readObject();		
				
				//显示
				String info=m.getSender()+"给"+m.getGetter()+"发送"+m.getCon()+"\r\n";
			    this.jta.append(info);  //(添加)追加到文本域
			}
			catch(Exception e)
			{
    
    
				e.printStackTrace();
			}
		
		}
	}
}

package com.qq.client.model;
import com.qq.common.*;
public class QqClientUser {
    
    
  
	  public boolean checkUser(User u)
	  {
    
    
		 return new QqClientConServer().sendLoginInfotoSSErver(u);
	  }
}

//客户端链接服务器的部分
package com.qq.client.model;

import java.util.*;
import java.net.*;
import java.io.*;
import com.qq.common.*;
public class QqClientConServer{
    
    
    
	public static Socket s;
	
	//发送第一次请求,登录请求
	public boolean sendLoginInfotoSSErver(Object o) //发送对象到服务器
	{
    
      
		boolean b=false;
		try
		 {
    
     
		     s=new Socket("127.0.0.1",9999);	 //传入要连接主机与端口
			 ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); //输出流
		     oos.writeObject(o);  //把o发出去
			 
		     ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
		     Message ms=(Message)ois.readObject();  
		     if(ms.getMesType().equals("1"))
		    	  b=true;
		 }
		 catch (Exception e)
		 {
    
    
			 e.printStackTrace();
		 }
		 finally
		 {
    
    
		 }
		return b;
	}
}

Server code (message, user is the same as the client, it is not written here, just copy it directly)

//服务器端控制界面,可以完成启动服务器,关闭服务器,可以管理和监控用户
package com.qq.server.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.qq.server.model.MyQqServer;
public class ControlPanel  extends JFrame implements ActionListener{
    
    
    
	JPanel jp1;
	JButton jstart,jend;

	public ControlPanel()
	{
    
       Font font = new Font("宋体",Font.PLAIN,30);
	
		jp1=new JPanel();
		jstart=new JButton("启动服务器");
		jstart.addActionListener(this);
		jend=new JButton("关闭服务器");
		jstart.setFont(font); jend.setFont(font);
		jstart.setForeground(Color.BLUE); jend.setForeground(Color.BLUE);
		
		jp1.add(jstart);
		jp1.add(jend);
		
		add(jp1);
		setLocation(150,150);
		setSize(900,900);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //结束窗口所在的应用程序  
		setVisible(true);
	}
	
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		ControlPanel controlpanel =new ControlPanel();
	}
	
	public void actionPerformed(ActionEvent arg0)
	{
    
    
		if(arg0.getSource()==jstart)
		{
    
    
			new MyQqServer();
		}
	}
}

//qq服务器,监听,等待某个qq客户端链接
package com.qq.server.model;

import java.io.*; //(I/O)流库,提供大量的流类
import java.net.*;//导入网络包
import java.util.*; //实用工具类,提供了一些实用的方法和数据结构
import com.qq.common.*;

public class MyQqServer  {
    
    

	public MyQqServer ()
	{
    
    
		//try-catch语句处理异常
        try
        {
    
     
        	//ServerSocket类表示服务器socket
        	//在9999监听
    		System.out.println("服务器正在9999监听");//简单判断一下是否启动服务端
        	ServerSocket ss=new ServerSocket(9999);
        while(true)   //服务器可多次监听
        {
    
    
            Socket s=ss.accept() ;  //阻塞,等待连接(与客户端)
        	//接收客户端发来的信息
           ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
            User u=(User)ois.readObject();
            System.out.println("用户Id:"+u.getUserId()+"  密码"+u.getPasswd()); 
          	Message m=new Message();
          	 ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
            if(u.getPasswd().equals("123456"))
            {
    
    
            	//返回一个成功登录的信息
            	m.setMesType("1");    //mesType1 =1  表明登陆成功
                oos.writeObject(m); 
                
                //单开一个线程,让该线程与该客户端保持通信
                SerConClientThread scct=new SerConClientThread(s);
                ManageClientThread.addClientThread(u.getUserId(),scct);//放到HashMap
                scct.start(); //启动与该客户端通信的线程
            }
            else
            {
    
    
            	m.setMesType("2"); 
                oos.writeObject(m); 
                s.close();  //关闭连接(流)
            }
        }
       }
        catch(Exception e)
        {
    
    
        	e.printStackTrace();//将错误信息全部打印
        }
        finally{
    
    
        	
        }
	}
}
//服务器和某个客户端的通信线程
package com.qq.server.model;

import java.net.*;
import java.io.*;
import com.qq.common.*;
public class SerConClientThread extends Thread    //继承Thread类
{
    
      
	Socket s;
	public SerConClientThread(Socket s)
	{
    
    
		this.s=s;  //把服务器和该客户端的连接赋给s;
	}
	
    public void run()
    {
    
    
	   while(true)
	   {
    
    
		   //这里该线程就可以接受客户端的信息
		   try
		   {
    
    
			     ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
			     Message m=(Message)ois.readObject();
			     
			     System.out.println(m.getSender()+"给 "+m.getGetter()+"发送: "+m.getCon());//判断接受到客户端的信息
		      
			     //拿到发送者与服务器的socket,此时就需要hashmap;
			     SerConClientThread sc=ManageClientThread.getClientThread(m.getGetter());
			     ObjectOutputStream oos=new ObjectOutputStream(sc.s.getOutputStream()); //接受人的通信线程;
		         oos.writeObject(m);
		   }
		   catch(Exception e)
		   {
    
    
			   e.printStackTrace();
		   }
	   }
   }
}

//管理客户端线程
package com.qq.server.model;

import java.util.*;

public class ManageClientThread {
    
     
  
	 public static HashMap hm=new HashMap<String, SerConClientThread>();
	  
	  //向hm中添加一个客户通讯线程
	  public static void addClientThread(String uid,SerConClientThread ct)
	  {
    
    
		   hm.put(uid, ct);
	  }
	  
	  //返回socket
	  public static SerConClientThread getClientThread(String uid)
	  {
    
    
		  return (SerConClientThread) hm.get(uid);
	  }
	  
}

Guess you like

Origin blog.csdn.net/weixin_52879528/article/details/125047165