多线程聊天

该博客介绍如何使用Java创建一个能同时服务多个客户端的聊天服务器。通过在服务端开启多线程,每当有新的客户端连接时,都会创建一个新线程为其提供服务。服务器监听9999端口,接收到客户端消息后,将消息广播给所有已连接的客户端。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
*作者:呆萌老师
*☑csdn认证讲师
*☑51cto高级讲师
*☑腾讯课堂认证讲师
*☑网易云课堂认证讲师
*☑华为开发者学堂认证讲师
*☑爱奇艺千人名师计划成员
*在这里给大家分享技术、知识和生活
*各种干货,记得关注哦!
*vx:it_daimeng
*/

        基于TCP协议书写的服务端,服务端开启之后,只能给一个客户端提供服务,在服务结束之后,服务端就关闭了,其他的客户端就无法在连接到当前这个服务端。

解决一个服务端,可以同时(并发)给多个客户端提供服务:

         我们需要在服务端开启多线程,只要有一个客户端连接到服务端,那么这是服务端内部就应该开启一个线程,为这个客户端服务,然后服务端继续等待下一个客户端的连接,只要有客户端连接到服务端,服务端就需要开启线程为当前连接到的这个客户端进行服务。

开启线程:直接new Thread 调用start,获取使用线程池都可以完成。

线程的任务:在服务端获取到客户端对象之后,后续的所有操作,都是基于当前这个客户端而进行,那么当前这些操作都属于线程的任务。

服务端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;


//聊天室服务器端
public class Server {
    
    //存放所有链接上当前服务器的客户端
    private List<Socket> clientSockets=new ArrayList<Socket>();
    
    
    public Server()
    {
        
        try {
            //1.创建服务器端socket
            ServerSocket serverSocket=new ServerSocket(9999);
            
            while(true)
            {
                //2.接收客户端的socket
                Socket socket= serverSocket.accept();
                
                //3.存入集合中
                this.clientSockets.add(socket);
                
                //4.开一个线程处理客户端发送过来的消息
                ReceiveThread thread=new ReceiveThread(socket);
                
                thread.start();
            }
            
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
    //创建一个线程 接收客户端的socket
    class ReceiveThread extends Thread
    {
          private Socket currentSocket;
        
          public ReceiveThread(Socket socket)
          {              
              this.currentSocket=socket;              
          }          
          public void run()
          {
             
              try {
                
                //获得当前客户端中拿到的消息
                InputStream is=  this.currentSocket.getInputStream();                
                //获得输入流
                BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(is));
                
                String msg=null;
                
                while((msg=bufferedReader.readLine())!=null)
                {                
                      //群发给所有的客户端
                      for(Socket socket :clientSockets)
                      {
                            PrintWriter pw =new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                            
                            pw.println(msg);
                            
                            pw.flush(); //发送到客户端
                            
                            //不要关闭输出流   ftp协议中 规定 如果关闭当前socket输出流 则意味着对应的socket关闭
                      }
                    
                    
                }
                
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
              
          }
          
    }
    

}

客户端

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;


public class Login extends JFrame{
	
	private JLabel unameJLabel;
	
	private JLabel pwdJLabel;
	
	private JTextField unameJTextField;
	
	private JTextField pwdJTextField;
	
	private JButton loginJButton;
	
	private JButton cancelJButton;
	
	public Login()
	{
		super("IT全明星聊天室");
		
		this.unameJLabel= new JLabel("用户名:");
		
		this.pwdJLabel=new JLabel("密码:");
		
		this.unameJTextField=new JTextField();
		
		this.pwdJTextField=new JTextField();
		
		this.loginJButton=new JButton("登录");
		
		this.cancelJButton=new JButton("取消");
		
		this.setSize(300,200);
		
		this.setLayout(new GridLayout(3,2));
		
		this.add(unameJLabel);
		
		this.add(unameJTextField);
		
		this.add(pwdJLabel);
		
		this.add(pwdJTextField);
		
		this.add(loginJButton);
		
		this.add(cancelJButton);
		
		//给按钮做监听事件 
		MyEvent myEvent=new MyEvent();
		this.loginJButton.addActionListener(myEvent);
		
		
		this.setLocationRelativeTo(null);
		
		this.setVisible(true);
		
		
		
		
	}
	
	//监听单击事件
	class MyEvent implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent arg0) {
			// TODO Auto-generated method stub
			
			//1.获得用户名
			
			String loginUname=unameJTextField.getText();
			
			
			try {
				//2.创建socket链接服务器端
				Socket socket=new Socket("127.0.0.1", 9999);
				
				//3.跳转到聊天室页面
				new Client(socket,loginUname);
				
				//4.当前登录窗口可以关闭
				dispose(); 
				
				
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				JOptionPane.showMessageDialog(null,"找不到服务器");
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		
			
			
		}
		
	}
	
	
	

}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;


public class Client extends JFrame {

	private JScrollPane topPanel; //滚动面板 用来放消息列表
	
	private JPanel bottomPanel; //发送消息的面板
	
	private JTextArea msgList; //存放消息列表  不可编辑
	
	private JTextField msgText; //写消息的文本框
	
	private JButton sendButton; //发送按钮	
	
	private Socket socket;
	
	private String uname;
	
	
	public Client(Socket socket,String uname)
	{		  
		  super(uname);
		  
		  this.socket=socket;
		  this.uname=uname;
		
		
		   //创建组件对象
           this.topPanel=new JScrollPane();
           this.bottomPanel=new JPanel();
           this.msgList=new JTextArea();
           this.msgText=new JTextField();
           this.sendButton=new JButton("发送");
           
           //设置属性 (绝对布局)
           this.topPanel.setLayout(null);
           this.bottomPanel.setLayout(null);
           
           this.topPanel.setBounds(0, 0, 1000, 500);
           this.msgList.setBounds(30,30,940,440);
           this.bottomPanel.setBounds(0, 500, 1000, 100);
           this.msgText.setBounds(30, 510, 700, 80);
           this.sendButton.setBounds(750, 510, 200, 80);
           
           //添加组件到窗口中
           this.topPanel.add(msgList);
           this.bottomPanel.add(msgText);
           this.bottomPanel.add(sendButton);
           
           this.add(topPanel);
           this.add(bottomPanel);
                      
           //设置窗口属性
           this.setSize(1000,600);
           this.setLocationRelativeTo(null);
           this.setVisible(true);
           
           //开启一个线程 接收服务器端发回的消息
           ReceiveThread receiveThread=new ReceiveThread();
           receiveThread.start();
           
           //对发送按钮做监听器
          MyEvent myEvent=new MyEvent();
          this.sendButton.addActionListener(myEvent);
           
	}
	
	class MyEvent implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent arg0) {
			// TODO Auto-generated method stub
			
			  //1.获得文本框的消息内容
			  String msg= msgText.getText();
			  
			  //格式化日期
			  SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
			  
			  String time=simpleDateFormat.format(new Date());
			  
			  msg=time+uname+"说:"+msg;
			
			  //2.发送到服务器端
			  try {
				PrintWriter pw=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
				
				pw.println(msg);
				
				pw.flush();  //不能关 socket中的输出流
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
		   
	}
	
	//创建接收从服务器端返回的消息 的线程类
	class ReceiveThread extends Thread{
		
		public void run()
		{
			  BufferedReader bufferedReader;
			try {
				//从服务器端读消息进来
				 bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				  
				  String msg=null;
				  
				  while((msg=bufferedReader.readLine())!=null)
				  {
					  msgList.append(msg+"\n");
					  
				  }
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
		
	}
	
	
	
	
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值