Java简易聊天工具(网络通信)

项目结构:分为客户端和服务端,客户端与服务端使用Socket建立连接,服务端接收客户端发来的信息然后转发至目标客户。

Java简易聊天工具(网络通信)_第1张图片

一、服务端

1.自定义服务端

package chatroom.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//自定义服务端
public class MServer {
    public static void main(String[] args) {
        try{
            new MServer().createServer();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void createServer()throws Exception{

            //创建服务器
            ServerSocket server=new ServerSocket(8899);
            System.out.println("启动服务器");

            //保存所有上线好友
            Map map=new HashMap<>();

            //默认注册好友
        ArrayList userList=new ArrayList<>();
        for(int i=1;i<=5;i++){
            userList.add(new User(i+"0",i+"0"));
        }

        while(true){
                //阻塞监听连接过来的客户端
                Socket socket=server.accept();

                //启动线程,保存跟客户端通信
                ServerThread st=new ServerThread(socket,map,userList);
                new Thread(st).start();
        }
    }
}

2、服务类(使用IO读写数据等功能)

package chatroom.server;

import java.io.*;
import java.net.Socket;

public class Server {
    private Socket socket;
    private OutputStream os;
    private InputStream is;
    private BufferedReader br;
    private BufferedWriter bw;
    public ObjectOutputStream oos;

    public Server(Socket socket){
        this.socket=socket;
        try {
            is=socket.getInputStream();
            os=socket.getOutputStream();
            br=new BufferedReader(new InputStreamReader(is));
            bw=new BufferedWriter(new OutputStreamWriter(os));
            //对象流
            oos=new ObjectOutputStream(os);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //读取数据
    public String readMsg()throws Exception{
        String line= br.readLine();
        return line;
    }
    //写入数据
    public void sendMsg(String msg){
        try{
            bw.write(msg);
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void sendMsg(String msg,BufferedWriter bw){
        try{
            bw.write(msg);
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void sendObj(Object obj){
        try {
            oos.writeObject(obj);
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void sendByte(int b){
        try {
            os.write(b);
            os.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void sendByte(int b,OutputStream os){
        try {
            os.write(b);
            os.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public int readByte(){
        int b=0;
        try {
            b=is.read();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return b;
    }
}

3、用户类

package chatroom.server;

import java.io.Serializable;
import java.rmi.server.UID;
//用户类
//获取用户名、密码
//设置用户名、密码
public class User implements Serializable {
    private String username;
    private String password;
    private String chatMsg;//保存每个用户的聊天记录

    private static final long serialVersionUID=1L;

    public User(String username,String password) {
        this.username = username;
        this.password=password;
    }
    public User(){

    }

    public String getUsername() {
        return username;
    }//获取用户名

    public String getPassword() {
        return password;
    }//获取密码

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getChatMsg() {
        return chatMsg;
    }

    public void setChatMsg(String chatMsg) {
        this.chatMsg = chatMsg;
    }
}

4、接口

package chatroom.server;

public interface MsgType {
    //登录
    public static final byte LOGIN=1;
    //注册
    public static final byte REGISTER=2;
    public static final byte SUCCESS=3;
    public static final byte ERROR=4;
    public static final byte DUPLICATE_LOGIN=5;
    public static final byte DUPLICATE_REGISTER=6;
    public static final byte MESSAGE=7;
}

5、服务端线程(保存与客户端通信)

package chatroom.server;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Map;

//保存跟客户端通信的线程
public class ServerThread implements Runnable,MsgType {
    private Socket socket;
    private Server server;
    private Map map;//上线好友
    private ArrayList userList;//注册好友
    private User user;

    public ServerThread(Socket socket, Map map, ArrayList userList){
        this.socket=socket;
        this.map=map;
        this.userList=userList;

        server=new Server(socket);
    }
    @Override
    public void run() {
        while(true){
            int head=0;
            try{
                head=server.readByte();
            } catch (Exception e) {
                System.out.println("客户端下线...");
                //移除用户
                break;
            }
            try{
                String msg=server.readMsg();
                System.out.println("msg:"+msg);
                //消息内容:消息头:消息内容
                String[] msgArr=msg.split(":");
                switch (head){
                    case LOGIN:
                        handleLogin(msgArr[0],msgArr[1]);
                        break;
                    case REGISTER:
                        handleRegister(msgArr[0],msgArr[1]);
                        break;
                    case MESSAGE:
                        handleMessage(msgArr[0],msgArr[1]);
                        break;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    //验证登录,重复登录
    private void handleLogin(String username,String password){
        System.out.println(username+" login  "+password);
        //验证是否重复登录
        for(Map.Entry entry: map.entrySet()){
            User u=entry.getKey();
            if(u.getUsername().equals(username)){
                server.sendByte(DUPLICATE_LOGIN);
                return;
            }
        }
        for(User user:userList){

            System.out.println(user.getUsername()+" login  "+user.getPassword());
            if(user.getUsername().equals(username)&&user.getPassword().equals(password)){
                server.sendByte(SUCCESS);
                try {
                    server.oos.writeObject(userList);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                //添加上线好友
                map.put(user,socket);
                this.user=user;
                break;
            }
        }
        server.sendByte(ERROR);
    }
//    注册,重复注册
    private void handleRegister(String username,String password){
        //验证是否重复注册
//        for(Map.Entry entry: map.entrySet()){
//            User us=entry.getKey();
//            if(us.getUsername().equals(username)){
//                server.sendMsg(DUPLICATE_REGISTER);
//                return;
//            }
//        }
//        for(User user:userList){//遍历注册好友列表
//            if(user.getUsername().equals(username)){//用户名存在
//                server.sendByte(DUPLICATE_REGISTER);//重复注册
//
//                try {
//                    server.oos.writeObject(new User("1","1"));
//                    server.oos.flush();
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            }
//            //添加上线好友
//            userList.add(user);
//            break;
//        }
//        server.sendByte(ERROR);
    }

    //处理聊天消息
    private void handleMessage(String chatUser,String chatMsg){
        System.out.println(chatUser+"server"+chatMsg);
        Socket chatSocket=null;//聊天对象Socket
        //把消息转发给接收用户
        //检查聊天对象(chatUser)是否上线
        //离线消息处理
        for(Map.Entry entry:map.entrySet()){
            User user=entry.getKey();
            if(chatUser.equals(user.getUsername())){
                chatSocket=entry.getValue();
                break;
            }
        }

        //根据在线对象找到对应的Socket
        if(chatSocket!=null){
            try {
                OutputStream os=chatSocket.getOutputStream();
                BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(os));

                //把消息转发给聊天对象
                //发送者+聊天内容
                server.sendByte(MESSAGE,os);
                server.sendMsg(user.getUsername()+":"+chatMsg,bw);
                System.out.println("转发消息成功..."+user.getUsername()+":"+chatMsg);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

二、客户端

1、自定义客户端

package chatroom.client;

import java.io.*;
import java.net.Socket;

//自定义客户端
public class MClient {
    private Socket socket;
    private OutputStream os;
    private InputStream is;
    private BufferedReader br;
    private BufferedWriter bw;
    public ObjectInputStream ois;

    public MClient(){
        try{
            socket=new Socket("127.0.0.1",8899);
            os=socket.getOutputStream();
            is=socket.getInputStream();
            br=new BufferedReader(new InputStreamReader(is));
            bw=new BufferedWriter(new OutputStreamWriter(os));
            ois=new ObjectInputStream(is);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //读取数据
    public String readMsg(){
        String line="";
        try{
            line=br.readLine();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return line;
    }
    //写入数据
    public void sendMsg(String msg){
        try{
            bw.write(msg);
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //读取对象
    public Object readObject(){
        Object obj=null;
        try{
            obj=ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

    public void sendByte(int b){
        try {
            os.write(b);
            os.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public int readByte(){
        int b=0;
        try {
            b=is.read();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return b;
    }
}

2、用户管理类(登录注册功能)

package chatroom.client;

import chatroom.server.User;

import javax.swing.*;
import java.io.IOException;
import java.util.ArrayList;

//用户管理类:登录注册功能
public class UserManage implements MsgType{
    private MClient mClient;
    private ArrayList userList;


    public UserManage(MClient mClient){
        this.mClient=mClient;
    }


    //获取好友名字数据
    public String[] getUserName(){
        String[] usernameArr=new String[userList.size()];
        for(int i=0;i< userList.size();i++){
            usernameArr[i]=userList.get(i).getUsername();
        }
        return usernameArr;
    }
    //获取聊天好友
    public User selectUser(int index) {
        User u=userList.get(index);
        return u;
    }

    //登录
    public boolean login(String username,String password){
        //发送账号密码
        mClient.sendByte(LOGIN);
        mClient.sendMsg(username+":"+password);

        //读取服务端结果
        int response=mClient.readByte();

        System.out.println(response);

        if(SUCCESS==response){
            //读取好友列表
            try {
                userList=(ArrayList) mClient.ois.readObject();
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            return true;
        } else if (DUPLICATE_LOGIN==response) {
            JOptionPane .showMessageDialog(null,"账号已登录");
            return false;
        }
        JOptionPane.showMessageDialog(null,"账号或密码错误");
        return false;
    }
//    注册
//    public boolean register(String username,String password){
//        User u=new User(username,password);//新用户
//        //设置新用户的用户名和密码
//        u.setPassword(password);
//        u.setUsername(username);
//        //发送账号密码
//        mClient.sendMsg(REGISTER+":"+username+":"+password);
//        //读取客户端结果
//        int response=mClient.readByte();
//        if(SUCCESS==response){
//            try {
//                User user=(User) mClient.ois.readObject();
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            } catch (ClassNotFoundException e) {
//                throw new RuntimeException(e);
//            }
//            return true;
//        } else if (DUPLICATE_REGISTER==response) {
//            JOptionPane .showMessageDialog(null,"账号已注册");
//            return false;
//        }
//        JOptionPane.showMessageDialog(null,"账号或密码不符合规定");
//        return false;
//    }
}

3、接口

package chatroom.client;

public interface MsgType {
    //登录
    public static final byte LOGIN=1;
    //注册
    public static final byte REGISTER=2;
    public static final byte SUCCESS=3;
    public static final byte ERROR=4;
    public static final byte DUPLICATE_LOGIN=5;
    public static final byte DUPLICATE_REGISTER=6;
    public static final byte MESSAGE=7;
}

4、客户端线程

package chatroom.client;

import javax.swing.*;

public class ClientThread implements Runnable,MsgType{
    private MClient mClient;
    private String msg;
    private JTextArea jta;

    public ClientThread(MClient mClient,JTextArea jta){
        this.mClient=mClient;
        this.jta=jta;
    }
    public String getMsg(){
        return msg;
    }
    @Override
    public void run() {
        while(true){
            System.out.println("等待服务端发来信息...");
            int head= mClient.readByte();
            System.out.println("head:"+head);

            switch (head){
                case MESSAGE :
                    msg=mClient.readMsg();
                    String[] msgArr=msg.split(":");
                    System.out.println("server:"+msgArr[0]+" "+msgArr[1]);
                    jta.setText(jta.getText()+msgArr[1]);
                    break;
            }
        }
    }
}

5、登陆界面(在用户登录后启动聊天界面)

package chatroom.client;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class LoginUI {
    public static void main(String[] args) {
        MClient mClient=new MClient();
        UserManage userManage=new UserManage(mClient);
        new LoginUI(userManage,mClient).showUI();
    }
    private UserManage userManage;
    private MClient mClient;

    public LoginUI(UserManage userManage,MClient mClient){
        this.mClient=mClient;
        this.userManage=userManage;
    }
    public void showUI(){
        //窗体
        JFrame jf=new JFrame();
        jf.setSize(450,550);
        jf.setTitle("登录界面");
        jf.setLocationRelativeTo(null);//设置居中
        jf.setDefaultCloseOperation(3);//退出进程

        //流式布局管理器
        FlowLayout flow=new FlowLayout();
        jf.setLayout(flow);

        //提示信息
        JLabel user=new JLabel("账号:");
        jf.add(user);
        //账号框
        JTextField usernameFeild=new JTextField();
        Dimension dm=new Dimension(370,30);
        usernameFeild.setPreferredSize(dm);
        jf.add(usernameFeild);

        JLabel pass=new JLabel("密码:");
        jf.add(pass);
        //密码框
        JTextField passwordFeild=new JTextField();
        passwordFeild.setPreferredSize(dm);
        jf.add(passwordFeild);

        //按钮
        JButton loginBtn=new JButton("登录");
        jf.add(loginBtn);
        JButton registerBtn=new JButton("注册");
        jf.add(registerBtn);

//        匿名内部类
        //注册
//        registerBtn.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                //获取账号 密码 发送给服务器验证
//                String username=usernameFeild.getText();
//                String password=passwordFeild.getText();
//
//                if(userManage.register(username,password)){
//                    System.out.println("注册成功并登录");
//
//                    new chatUI(username,userManage,mClient);
//                }else{
//                    System.out.println("注册失败");
//                }
//            }
//        });

        //登录
        loginBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取账号 密码 发送给服务器验证
                String username=usernameFeild.getText();
                String password=passwordFeild.getText();

                if(userManage.login(username,password)){
                    System.out.println("登录成功");
                    chatUI ui=new chatUI(username,userManage,mClient);
                    ui.usernameJlist.setListData(userManage.getUserName());
                }else{
                    System.out.println("登录失败");
                }
            }
        });
        //设置可见
        jf.setVisible(true);
    }
}

6、聊天界面

package chatroom.client;

import chatroom.server.User;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class chatUI implements MsgType{
    public JList usernameJlist;
    private UserManage userManage;
    private MClient mClient;
    private ClientThread ct;
    private JTextArea jta;

    public chatUI(String username,UserManage userManage,MClient mClient){
        this.userManage=userManage;
        this.mClient=mClient;
        initUI(username);

        //启动线程读取数据
        ct=new ClientThread(mClient,jta);
        new Thread(ct).start();
    }
    public void initUI(String username){
        JFrame jf=new JFrame(username);
        jf.setSize(580,600);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(3);


        //JPanel 默认流式布局
        JPanel centerPanel=new JPanel();
        centerPanel.setBackground(Color.WHITE);
        jf.add(centerPanel,BorderLayout.CENTER);

        //显示消息
        jta=new JTextArea();
        jta.setPreferredSize(new Dimension(450,480));
        jta.setEditable(false);
        centerPanel.add(jta);

        //消息发送框
        JTextField jtf=new JTextField();
        jtf.setPreferredSize(new Dimension(400,40));
        centerPanel.add(jtf);

        JButton sendBtn=new JButton("发送");
        centerPanel.add(sendBtn);

        //好友列表面板
        JPanel westPanel=new JPanel();
        westPanel.setBackground(Color.white);
        westPanel.setSize(new Dimension(80,0));
        jf.add(westPanel,BorderLayout.WEST);

        //显示好友数据
        usernameJlist=new JList<>();
        usernameJlist.setFont(new Font("楷体",0,20));
        westPanel.add(usernameJlist,BorderLayout.CENTER);


        jf.setVisible(true);
        usernameJlist.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
//                jta.setText(user.getChatMsg());
            }
        });
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //确定选择好友
                int index=usernameJlist.getSelectedIndex();
                User user=userManage.selectUser(index);//聊天对象
                String chatName=user.getUsername();
                String chatMsg=jtf.getText();//聊天内容


                mClient.sendByte(MESSAGE);
                mClient.sendMsg(chatName+":"+chatMsg);

            }
        });
    }
}

你可能感兴趣的:(java,开发语言,ide)