Java简单模拟聊天
某公司想组建本公司的客服聊天系统,用于客户与客服人员的点对点的对话,当客户连接到客服服务器时, 客户(客户端)就可以向客服人员(服务器端)进行咨询
题目分析:
- 用户端和客服端之间需要进行对话
- 需要实现一次发送多条消息,同时也可以接受多条消息
拆解:
- 用户端和客服端
- 服务端的线程
- send线程:用于发送消息
- receive线程:用于接受消息
- CloseUtil:线程在使用之后需要进行关闭,而本题涉及到多出需要关闭的资源,因此编写CloseUtil类,实现资源的关闭
CLient(用户端)
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",7080);
//127.0.0.1 为指定本机,7080为端口号
new SendThread(socket).start();
new ReceiveThread("客服",socket).start();
}
}
CustomerService(客服端)
public class CustomerService {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7080);
int i=1;
Socket client = serverSocket.accept();
System.out.println("有用户端连接");
ServerThread serverThread = new ServerThread("用户"+i,client);
serverThread.start();
i++;
}
}
SendThread(服务端线程)
public class SendThread extends Thread{
private Socket socket;
private boolean flag = true;
Scanner input = new Scanner(System.in);
//通过构造方法实现赋值
public SendThread(Socket socket){
this.socket = socket;
}
//一直写
@Override
public void run(){
while(flag){
send(input.next());
}
}
//发送
public void send(String string){
BufferedWriter bw = null;
try {
OutputStream out = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write(string);
bw.newLine();
bw.flush();
} catch (IOException e) {
flag = false;
CloseUtil.close(bw,socket);
}
}
}
SendThread(发送)
使用输出流,实现信息的发送
需要实现一直写的功能
采用循环的模式,即利用死循环
public class SendThread extends Thread{
private Socket socket;
private boolean flag = true;
Scanner input = new Scanner(System.in);
public SendThread(Socket socket){
this.socket = socket;
}
//一直写
@Override
public void run(){
while(flag){
send(input.next());
}
}
//发送
public void send(String string){
BufferedWriter bw = null;
try {
OutputStream out = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write(string);
bw.newLine();
bw.flush();
} catch (IOException e) {
flag = false;
CloseUtil.close(bw,socket);
}
}
}
ReceiveThread(接收)
使用输入流,实现接受信息
和发送信息一样,要实现一直接受信息
public class ReceiveThread extends Thread{
private Socket socket;
private boolean flag = true;
public ReceiveThread(String name,Socket socket){
super(name);
this.socket = socket;
}
@Override
public void run(){
while(flag){
String receive = receive();
System.out.println(receive);
}
}
//接受方法
public String receive(){
BufferedReader br = null;
try {
InputStream in = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
//接收数据
String line = br.readLine();
return this.getName()+"说:"+line;
} catch (IOException e) {
flag=false;
CloseUtil.close(br,socket);
}
return "";
}
}
CloseUtil(关闭资源)
目的:减少代码的重复书写
public class CloseUtil {
public static void close(Closeable... closeables){
//需要关闭的资源很多,如果都写成变量会写很长,因此找共同点:这些资源都继承了Closeable,因此通过父级来关闭
if (closeables != null && closeables.length>0){
for (Closeable closeable : closeables) {
if (closeable!=null){
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
实现效果
客服端:
用户端:
遇到的问题及解决方案
- 启动顺序,一定要先运行服务端,再运行用户端
- 最开始只能实现单次的接受和发送信息,通过利用循环语句,实现聊天
- 代码的优化:将关闭资源的代码合并写在一个关闭资源的类中,减少反复的资源关闭书写