实现多客户聊天
实际应用中,应该是客户端与客户端聊天,而不是客户端与服务器聊天。客户端与客户端聊天的本质是信息由服务器转发。
编写服务器程序:
要使服务器可以接收多个客户的连接,需要注意以下几个问题:
1.由于事先不知道客户端什么时候连过来,因此,服务器必须首先有一个线程负责多个客户端连接。
结构如下:
public class Server extends JFrame implements Runnable{
public Server(){
//服务器打开端口
//服务器开启线程,接收客户端连接
}
pubic void run(){
//不断接收客户端连接
while(true){
//接收客户端连接
//开一个聊天线程给这个客户端
//将该聊天线程对象添加进集合
//聊天线程启动
}
}
}
2.当客户端连接上之后,服务器端要等待这些客户端传送信息过来,而事先并不知道客户端什么时候会发信息过来。所以,每一个客户端连上之后,必须为这个客户端单独开一个线程,来读取它发过来的信息。因此,需要再编写一个线程类。
3.服务器收到某个客户端信息之后,需要将其转发给各个客户端,这就需要在服务器端保存各个客户端的输入输出流的引用(实际上,这些引用可以保存在为客户端服务的线程中)。
编写客户端程序:
客户端编程相对简单,只需要编写发送信息,连接服务器,接收服务器传输的信息即可。
运行结果:
首先运行服务器端代码
再运行一次客户端代码:
输入昵称后点击确定显示连接成功
这时就有一个客户Lucy连接上服务器了,类似的再运行几次客户端代码使多个客户连接上该服务器得到
在下面的粉色输入框中输入需要进行通信的内容,按下回车,信息将会发送并且每个连接该服务器的客户均能收到消息
服务器端代码:
package 多人聊天;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JTextArea;
public class Server extends JFrame implements Runnable{
private Socket s = null;
private ServerSocket ss = null;
private ArrayList clients = new ArrayList();//保存客户端的线程
private JTextArea text = new JTextArea();
public Server() throws Exception{
this.setTitle("服务器端");
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setBackground(Color.YELLOW);
this.setSize(300, 400);
this.add(text);
this.setVisible(true);
ss = new ServerSocket(8080);//服务器开辟端口,接收连接
new Thread(this).start();//接受客户的死循环开始运行
}
@Override
public void run() {
while(true) {
try {
s = ss.accept();
//s即为当前连接对应的Socket,对应一个客户端
//该客户端随时可能发信息过来,必须要接收
//另开辟一个线程,专门为这个s服务,负责接受信息
ChatThread ct = new ChatThread(s);
clients.add(ct);
ct.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ChatThread extends Thread{//为某个Socket负责接收信息
private Socket s = null;
private BufferedReader br = null;
public PrintStream ps = null;
public ChatThread(Socket s) throws Exception{
this.s = s;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps = new PrintStream(s.getOutputStream());
}
public void run() {
while(true) {
try {
String str = br.readLine();
sendMessage(str);//将str转发给所有的客户端
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//读取该Socket传来额ix信息
}
}
}
public void sendMessage(String msg) {//将信息发给所有的客户端
for(int i = 0;i<clients.size();i++) {
ChatThread ct = (ChatThread)clients.get(i);
//向ct内的Socket内写msg
ct.ps.println(msg);
}
}
public static void main(String[] args)throws Exception{
Server server = new Server();
}
}
客户端代码:
package 多人聊天;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Client extends JFrame implements ActionListener,Runnable{
private JTextArea taMsg = new JTextArea("以下是聊天记录\n");
private JTextField tfMsg = new JTextField();
private Socket s = null;
private String nickName = null;
public Client() {
this.setTitle("客户端");
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.add(taMsg,BorderLayout.CENTER);
tfMsg.setBackground(Color.PINK);
this.add(tfMsg, BorderLayout.SOUTH);
tfMsg.addActionListener(this);
this.setSize(650, 500);
this.setVisible(true);
nickName = JOptionPane.showInputDialog("请输入昵称");
try {
s = new Socket("192.168.32.1",8080);
JOptionPane.showMessageDialog(this, "连接成功");
this.setTitle("客户端:"+nickName);
new Thread(this).start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
while(true) {
InputStream in;
try {
in = s.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String str = br.readLine();
taMsg.append(str+"\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
try {
OutputStream os = s.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println(nickName+":"+tfMsg.getText());
tfMsg.setText("");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
Client client = new Client();
}
}