Java之多人聊天室

 

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

  

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

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

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

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

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

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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();
            }
               
          }
           
    }
     
 
}

  

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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();
        }
         
         
             
             
        }
         
    }
     
     
     
 
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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();
            }
             
             
        }
         
    }
     
     
     
     
}
点击并拖拽以移动

  

 

posted @   呆萌老师  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示