Java 开发一个多线程的TCP网络聊天程序,将聊天记录保存为文本文件。

开发一个多线程的TCP网络聊天程序,将聊天记录保存为文本文件。自写的小程序,不足之处还望斧正。

首先是代码的使用过程,支持多人聊天,可实现私聊

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面是源代码

服务端

package server;
import java.io.*;  
import java.net.*;  
import java.util.HashMap;  
import java.util.Map;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.ThreadPoolExecutor;  
import javax.swing.*;
import java.awt.*;

@SuppressWarnings({
    
     "serial", "unused" })
public class TCPServer extends JFrame{
    
          
    private JTextArea m_display=new JTextArea();
    private ServerSocket serverSocket;  
    //创建线程池来管理客户端的连接线程 避免系统资源过度浪费 
    private ExecutorService exec;  
    // 存放客户端之间私聊的信息  
    private Map<String,PrintWriter> storeInfo;  
    public TCPServer() {
    
      
        super("聊天程序服务器端");
        Container c=getContentPane();
        c.add(new JScrollPane(m_display),BorderLayout.CENTER);
        try {
    
      
            serverSocket = new ServerSocket(6666);  
            storeInfo = new HashMap<String, PrintWriter>();  
            exec = Executors.newCachedThreadPool();  
        } catch (Exception e) {
    
      
            e.printStackTrace();  
        }  
    }  
    // 将客户端的信息以Map形式存入集合中  
    private void putIn(String key,PrintWriter value) {
    
      
        synchronized(this) {
    
      
            storeInfo.put(key, value);  
        }  
    }  
    // 将给定的输出流从共享集合中删除  
    private synchronized void remove(String  key) {
    
      
        storeInfo.remove(key);  
        m_display.append("当前在线人数为:"+ storeInfo.size());
        //for(String name: storeInfo.key)
    }  
    // 将给定的消息转发给所有客户端  
    private synchronized void sendToAll(String message) {
    
      
        for(PrintWriter out: storeInfo.values()) {
    
      
            out.println(message);  
           // m_display.append("已经发送了");
        }  
    }  
    // 将给定的消息转发给私聊的客户端  
    private synchronized void sendToSomeone(String name,String message) {
    
      
        PrintWriter pw = storeInfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去  
        if(pw != null) pw.println("私聊:     "+message);   
    }  
    public void start() {
    
      
        try {
    
      
            m_display.setVisible(true);
            //m_display.append("mayanshuo");
            while(true) {
    
     
            m_display.append("等待客户端连接... ... \n"); 
            Socket socket = serverSocket.accept();  
            // 获取客户端的ip地址  
            InetAddress address = socket.getInetAddress();  
            m_display.append("客户端:“" + address.getHostAddress() + "”连接成功! ");  
            //启动一个线程,由线程来处理客户端的请求,这样可以再次监听 下一个客户端的连接   
            exec.execute(new ListenrClient(socket)); //通过线程池来分配线程  
            }  
        } catch(Exception e) {
    
      
            e.printStackTrace();  
        }  
    }  
    class ListenrClient implements Runnable {
    
      
        private Socket socket;  
        private String name;  
        public ListenrClient(Socket socket) {
    
      
            this.socket = socket;  
        }  
        // 创建内部类来获取昵称  
        private String getName() throws Exception {
    
      
            try {
    
      
                //服务端的输入流读取客户端发送来的昵称输出流  
                BufferedReader bReader = new BufferedReader(  
                    new InputStreamReader(socket.getInputStream(), "UTF-8"));  
                //服务端将昵称验证结果通过自身的输出流发送给客户端  
                PrintWriter ipw = new PrintWriter(  
                    new OutputStreamWriter(socket.getOutputStream(), "UTF-8"),true);  
                //读取客户端发来的昵称  
                while(true) {
    
      
                    String nameString = bReader.readLine();  
                    if ((nameString.trim().length() == 0) || storeInfo.containsKey(nameString)) {
    
      
                        ipw.println("FAIL");  
                    } else {
    
      
                        ipw.println("OK");  
                        return nameString;  
                    }  
                }  
            } catch(Exception e) {
    
      
                throw e;  
            }  
        }        
        public void run() {
    
      
            try {
    
       
                PrintWriter pw = new PrintWriter(  
                    new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);  
                name = getName();  
                putIn(name, pw);  
                Thread.sleep(100);  
                // 服务端通知所有客户端,某用户上线  
                sendToAll("*系统消息* “" + name + "”已上线");   
                BufferedReader bReader = new BufferedReader(  
                    new InputStreamReader(socket.getInputStream(), "UTF-8"));  
                String msgString = null;  
                while((msgString = bReader.readLine()) != null) {
    
      
                    // 检验是否为私聊(格式:@昵称:内容)  
                    if(msgString.startsWith("@")) {
    
      
                        int index = msgString.indexOf(":");  
                        if(index >= 0) {
    
      
                            //获取昵称  
                            String theName = msgString.substring(1, index);  
                            String info = msgString.substring(index+1, msgString.length());  
                            info =  name + ":"+ info;  
                            //将私聊信息发送出去  
                            sendToSomeone(theName, info);
                            sendToSomeone(name,info);
                            continue;  
                        }  
                    }  
                    // 遍历所有输出流,将该客户端发送的信息转发给所有客户端  
                    m_display.append(name+":"+ msgString+"\n");  
                    sendToAll(name+":"+ msgString);  
                    try {
    
    
            			//IO三部曲
            			//1、打开一个文件(用于读还是用于写)
            			FileWriter fileWriter = new FileWriter("D:/liaotian.txt");
            			//2、读写文件
            			String string = msgString ;
            			fileWriter.write(string);
            			//3、关闭文件(真正的实现,把内存程序中的数据写到硬盘文件中)
            			fileWriter.close();
            		} catch (IOException e) {
    
    
            			// TODO Auto-generated catch block
            			e.printStackTrace();
            		}   
                }     
            } catch (Exception e) {
    
      
                // e.printStackTrace();  
            } finally {
    
      
                remove(name);  
                // 通知所有客户端,某某客户已经下线  
                sendToAll("*系统消息* "+name + "已经下线了。\n");  
                if(socket!=null) {
    
      
                    try {
    
      
                        socket.close();  
                    } catch(IOException e) {
    
      
                        e.printStackTrace();  
                    }  
                }     
            }  
        }  
    }  
    public static void main(String[] args) {
    
      
        TCPServer server = new TCPServer();
        server.setSize(400,400);
        server.setVisible(true);
        server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        server.start();  
    }  
}

客户端

package server;
import java.io.*;  
import java.net.*;  
import java.util.Scanner;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.ThreadPoolExecutor;  
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
@SuppressWarnings({
    
     "unused", "serial" })
public class TCPClient extends JFrame {
    
      
    private JTextField m_enter=new JTextField();
    private JTextArea m_display=new JTextArea();
    private int m_count=0;
    private static  Socket clientSocket;  
    private BufferedReader br;
    private PrintWriter pw;
    public TCPClient() 
    {
    
    
        super("聊天程序客户端");
        Container c=getContentPane();
        m_enter.setVisible(true);
        m_display.setVisible(true);
        m_enter.requestFocusInWindow();     
        //转移输入焦点到输入区域
        //将光标放置在文本区域的尾部
        m_display.setCaretPosition(m_display.getText().length());
        c.add(m_enter,BorderLayout.SOUTH);
        c.add(new JScrollPane(m_display),BorderLayout.CENTER);  
    }  
    public static void main(String[] args) throws Exception {
    
      
        TCPClient client = new TCPClient();
        client.setVisible(true);
        client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        client.setSize(470,708);
        client.start();  
    }  
    public void start() {
    
      
        try {
    
      
            m_display.append("请创建用户名:");
            clientSocket=new Socket("localhost",6666);
            BufferedReader br = new BufferedReader(  
                    new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); 
            PrintWriter pw = new PrintWriter(  
                    new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true); 
            m_enter.addActionListener(new ActionListener(){
    
    
                public void actionPerformed(ActionEvent event)
                {
    
    
                    try{
    
    
                    String s=event.getActionCommand();
                    m_enter.setText("");
                     if(m_count==0)
                    {
    
    
                         pw.println(s);
                         m_display.append("\n'"+s+"'"+"昵称设置成功。\n");
                    }
                    else
                    {
    
    
                            pw.println(s);
                    }
                    m_count++;
                    }catch(Exception e)
                    {
    
    
                        e.printStackTrace();
                    }
                }
            });
            String msgString;
            while((msgString = br.readLine())!= null) {
    
      
                m_display.append(msgString+"\n");  
            }  
        } catch(Exception e) {
    
      
            e.printStackTrace();  
        } finally {
    
      
            if (clientSocket !=null) {
    
      
                try {
    
      
                    clientSocket.close();  
                } catch(IOException e) {
    
      
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
}  

猜你喜欢

转载自blog.csdn.net/weixin_48874360/article/details/113372000