这个小玩意儿很早之前就弄完了,计算机网络课设时候写的,最近才想起来还有个csdn账号,统一一下学习历程一并更新发了(这半年头发掉的太多了)。
那我们这个聊天室都由什么组成呢?
首先,基于B/S模型,你肯定得有一个server,然后至少两个client吧,我们先来看看server端怎么实现。ps:主要还是用socket通信那一套。
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class ChatServer {
ArrayList clientOutPutStreams = new ArrayList();
public static void main(String[] args) {
new ChatServer().go();
}
public void go() {
try {
//server端创建出与client端通信的socket
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器启动成功!");
while (true) {
//服务器创建出与客户端通信的socket
Socket clientSocket = serverSocket.accept();
String ip=clientSocket.getInetAddress().getHostAddress();
System.out.println(ip+"加入了聊天室!");//控制台打印进入到聊天室的用户地址并提示
//与客户端建立输出流,为以后给客户端写数据做准备
PrintWriter printWriter = new PrintWriter(clientSocket.getOutputStream());
clientOutPutStreams.add(printWriter);
//开启一个线程用于与一个客户端进行通信
Thread thread = new Thread(new clientHandler(clientSocket));
//开启线程,使服务器一直处于接受消息并转发给所有人
thread.start();
System.out.println("有新连接加入");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public class clientHandler implements Runnable {
BufferedReader reader;
Socket socket;
/**clientHandler的构造方法*/
public clientHandler(Socket socket) {
//与客户端建立通信并定义接受数据的输入流
try {
this.socket = socket;
InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
reader = new BufferedReader(inputStreamReader);
} catch (IOException e) {
e.printStackTrace();
}
}
/**开启线程之后要执行的run()方法*/
@Override
public void run() {
//定义准备接受消息变量
String message = null;
try {
//使线程不断从socket上读取数据的状态
while ((message= reader.readLine())!=null){
System.out.println("MESSAGE_Receive: "+message);
//将数据发送给每一个客户端
sendEveryone(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**给客户端发送消息的方法*/
public void sendEveryone(String message){
for (Object COPStreams: clientOutPutStreams) {
try {
PrintWriter writer = (PrintWriter) COPStreams;
writer.println(message);
writer.flush();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
然后是客户端
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ChatClient1 {
JTextArea incoming; //文本域,用来显示消息
JTextField outgoing; //输入框
BufferedReader reader; //缓冲字符输入流,用于读取服务器转发的消息
PrintWriter writer; //输出字符流,用于给服务器发消息
Socket socket; //创建准备与服务器连接的套接字
public static void main(String[] args) {
new ChatClient1().go();
}
public void go() {
JFrame jFrame = new JFrame("聊天室客户端1");
JPanel jPanel = new JPanel();
//创建文本域
incoming = new JTextArea(15, 22);
incoming.setFont(new Font("微软雅黑",Font.BOLD,16));
incoming.setLineWrap(true); //设置在行过长时自动换行
incoming.setWrapStyleWord(true); //设置在单词过长时,将单词移到下一行
incoming.setEditable(false);
//创建滚动面板,并将文本域放入其中
JScrollPane jScrollPane = new JScrollPane(incoming);
jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//创建输入框
outgoing = new JTextField(20);
//创建发送按钮,并创建监听器
JButton sendButton = new JButton("发送");
sendButton.addActionListener(new sendButtonListener());
//将上述定义组件放入JPanel容器中
jPanel.add(jScrollPane);
jPanel.add(outgoing);
jPanel.add(sendButton);
//将JPanel容器放入JFrame面板中
jFrame.getContentPane().add(BorderLayout.CENTER, jPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(400,450);
jFrame.setVisible(true);
//与服务器建立连接
setUpNetworking();
//开启一个线程,并执行其中run()方法
Thread thread = new Thread(new IncomingReader());
thread.start();
}
/**
* 与服务器建立socket连接,并在socket基础上建立输入流和输出流
*/
private void setUpNetworking() {
try {
//与服务器socket建立连接
socket = new Socket("127.0.0.1", 8888);
//与socket建立字符缓冲输入流,用于接受发送框中的消息
InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
reader = new BufferedReader(inputStreamReader);
//与socket建立字符缓冲输出流,用于发送消息
writer = new PrintWriter(this.socket.getOutputStream());
incoming.append("客户端1成功连接到服务器......" + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 监听器与发送消息给服务器模块
*/
class sendButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//当发送按钮点击,出发事件,将输入框中的文字获取,并发送给服务器
writer.println("客户端1: " + outgoing.getText());
writer.flush();
//输入框文字清空
outgoing.setText("");
outgoing.requestFocus();
}
}
/**
* 该线程任务是不断读取服务器发送的信息,并将其加入到文本域中
*/
class IncomingReader implements Runnable {
public IncomingReader() {
}
@Override
public void run() {
String message; //用于接受从服务器与客户端1建立的输入流中读出的信息
try {
while ((message = reader.readLine()) != null) {
System.out.println("接收到消息: " + message);
incoming.append(message + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
当然,再加一个客户端的话就是cv工作了,这里面可能有些对于多线程的把握还不是很好,后面可以再找时间优化优化。