多人聊天室

最近学完网络线程协议 ,因此写了一个用java编写的聊天室 话不多说
效果如图

多人聊天室_第1张图片
首先 创建服务器端

package com.yc.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yc.bean.JsonModel;
import com.yc.bean.User;
import com.yc.bean.YcConstants;


public class TalkServer {

    private List<ClientSocket> list=new ArrayList<ClientSocket>();

    public static void main(String[] args) throws IOException {
        TalkServer ts=new TalkServer();
        ts.startServer();
    }

    public void startServer() throws IOException{
        ServerSocket ss=new ServerSocket(9998);
        System.out.println("服务器"+ss.getInetAddress()+"启动了,监听了:"+ss.getLocalPort()+"端口");
        while(true){
            Socket s=ss.accept();
            System.out.println("客户端"+ss.getInetAddress()+"联接上了服务器");
            //将这个s存到一个TalkService中,做成一个线程,处理一个与客户端的联接
            ClientSocket cs=new ClientSocket(s);

            Thread t=new Thread(cs);
            t.start();
        }
    }


    //内部类:实现了Runnable接口的内部类,用于封装对一个客户端的操作
    class ClientSocket implements Runnable{         //不写外部类是因为都要操作这个list,写外部类传这个list较为麻烦
        private Socket s;
        private Scanner sc;
        private PrintWriter pw;
        private boolean flag=false;
        private String nickname;
        private String ip;

        public ClientSocket(Socket s){
            this.s=s;
            System.out.println("客户端"+s.getInetAddress()+"连接上了服务器");
            if(s!=null){
                try {
                    sc=new Scanner(s.getInputStream());
                    pw=new PrintWriter(s.getOutputStream()); 
                    flag=true;
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端"+s.getInetAddress()+"掉线了");
                    list.remove(ClientSocket.this);
                    flag=false;
                    sc.close();
                    pw.close();
                    try {
                        s.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }

        @Override
        public void run() {
            while(flag){
                //读取用户传过来的消息
                if(sc.hasNextLine()){
                    String jsonline=sc.nextLine();
                    parseProtocal(jsonline);
                }
            }
        }

        //解析状态码
        private int parseCode(String jsonline){
            if(jsonline.startsWith("{\"code\":1,")){
                return 1;
            }else if(jsonline.startsWith("{\"code\":3,")){
                return 3;
            }else if(jsonline.startsWith("{\"code\":4,")){
                return 4;
            }
            return 404;
        }

        //发送信息到客户端
        private void sendMsgToAllClient(String jsonline){
            for(ClientSocket cs:list){
                cs.pw.println(jsonline);
                cs.pw.flush();      //必须flush()
            }
        }

        //解析协议
        private void parseProtocal(String jsonline) {
            //判断code的值
            int code=parseCode(jsonline);
            if(code==1){
                //1是普通聊天信息,直接向所有的客户端广播
                sendMsgToAllClient(jsonline);
            }else if(code==3){
                //如果是3,表明有新用户登录
                Gson g=new Gson();
                Type type=new TypeToken<JsonModel<User>>(){}.getType();
                JsonModel<User> jsonModel=g.fromJson(jsonline, type);
                //将这个User存入到list中
                User loginuser=jsonModel.getT();
                List<User> userlist=new ArrayList<User>();
                //将新登录的用户存入到list中
                ClientSocket.this.ip=loginuser.getIp();
                ClientSocket.this.nickname=loginuser.getNickname();
                list.add(ClientSocket.this);
                for(ClientSocket cs:list){
                    User u=new User();
                    u.setIp(cs.ip);
                    u.setNickname(cs.nickname);
                    userlist.add(u);
                }
                sendUserListJson(userlist);
            }else if(code==4){
                //如果是code为4,则要从ClientSocket中删除这个用户
                Gson g=new Gson();
                Type type=new TypeToken<JsonModel<User>>(){}.getType();
                JsonModel<User> jsonModel=g.fromJson(jsonline, type);
                List<User> userlist=new ArrayList<User>();
                list.remove(ClientSocket.this);
                for(ClientSocket cs:list){
                    User u=new User();
                    u.setIp(cs.ip);
                    u.setNickname(cs.nickname);
                    userlist.add(u);
                }
                sendUserListJson(userlist);
            }
        }

        //发送用户列表的json字符串
        public void sendUserListJson(List<User> userlist){
            String jsonline;
            JsonModel<List<User>> jm=new JsonModel<List<User>>();
            jm.setCode(YcConstants.SEND_USERLIST);
            jm.setT(userlist);
            Type t=new TypeToken<JsonModel<User>>(){}.getType();
            Gson g=new Gson();
            jsonline=g.toJson(jm,t);
            for(ClientSocket cs:list ){
                cs.pw.println(jsonline);
                cs.pw.flush();
            }
        }


    }
}

客户端

package com.yc.client;
import java.io.IOException;

public class TalkClient implements Runnable{

    protected Shell shell;
    private Text txtCat;
    private Text txtLocalhost;
    private Text text_2;
    private Text text_3;
    private Table table;
    private Button button;
    private Button button_1;
    private Button button_2;
    private Text text_4;

    private Socket s;
    private Scanner sc;
    private PrintWriter pw;

    private String nickname;

    private boolean flag=false;


    /** * Launch the application. * @param args */
    public static void main(String[] args) {
        try {
            TalkClient window = new TalkClient();
            window.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** * Open the window. */
    public void open() {
        Display display = Display.getDefault();
        createContents();
        shell.open();
        shell.layout();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /** * Create contents of the window. */
    protected void createContents() {
        shell = new Shell();
        shell.setSize(744, 671);
        shell.setText("SWT Application");
        shell.setLayout(new FillLayout(SWT.HORIZONTAL));

        SashForm sashForm = new SashForm(shell, SWT.NONE);
        sashForm.setOrientation(SWT.VERTICAL);

        Composite composite = new Composite(sashForm, SWT.NONE);
        composite.setLayout(new FillLayout(SWT.HORIZONTAL));

        Group group = new Group(composite, SWT.NONE);
        group.setText("登录");

        Label label = new Label(group, SWT.NONE);
        label.setBounds(21, 26, 36, 17);
        label.setText("昵称:");

        txtCat = new Text(group, SWT.BORDER);
        txtCat.setText("cat");
        txtCat.setBounds(57, 23, 122, 23);

        Label lblip = new Label(group, SWT.NONE);
        lblip.setBounds(233, 26, 59, 17);
        lblip.setText("服务器IP:");

        txtLocalhost = new Text(group, SWT.BORDER);
        txtLocalhost.setText("localhost");
        txtLocalhost.setBounds(292, 23, 122, 23);

        Label label_2 = new Label(group, SWT.NONE);
        label_2.setBounds(459, 26, 36, 17);
        label_2.setText("端口:");

        text_2 = new Text(group, SWT.BORDER);
        text_2.setText("9998");
        text_2.setBounds(496, 23, 104, 23);

        button = new Button(group, SWT.NONE);
        button.setBounds(448, 61, 80, 27);
        button.setText("登录");

        button_1 = new Button(group, SWT.NONE);

        button_1.setBounds(574, 61, 80, 27);
        button_1.setText("断开");

        Composite composite_1 = new Composite(sashForm, SWT.NONE);
        composite_1.setLayout(new FillLayout(SWT.HORIZONTAL));

        Group group_1 = new Group(composite_1, SWT.NONE);
        group_1.setText("聊天记录");
        group_1.setLayout(new FillLayout(SWT.HORIZONTAL));

        SashForm sashForm_1 = new SashForm(group_1, SWT.NONE);

        Composite composite_3 = new Composite(sashForm_1, SWT.NONE);
        composite_3.setLayout(new FillLayout(SWT.HORIZONTAL));

        text_3 = new Text(composite_3, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);

        Composite composite_4 = new Composite(sashForm_1, SWT.NONE);
        composite_4.setLayout(new FillLayout(SWT.HORIZONTAL));

        table = new Table(composite_4, SWT.BORDER | SWT.FULL_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tableColumn = new TableColumn(table, SWT.NONE);
        tableColumn.setWidth(121);
        tableColumn.setText("用户昵称");

        TableColumn tblclmnIp = new TableColumn(table, SWT.NONE);
        tblclmnIp.setWidth(134);
        tblclmnIp.setText("IP");
        sashForm_1.setWeights(new int[] {448, 271});

        Composite composite_2 = new Composite(sashForm, SWT.NONE);
        composite_2.setLayout(new FillLayout(SWT.HORIZONTAL));

        Group group_2 = new Group(composite_2, SWT.NONE);
        group_2.setText("发送内容");

        text_4 = new Text(group_2, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
        text_4.setBounds(52, 32, 476, 105);

        Label label_3 = new Label(group_2, SWT.NONE);
        label_3.setBounds(10, 35, 36, 17);
        label_3.setText("内容:");

        button_2 = new Button(group_2, SWT.NONE);

        button_2.setBounds(570, 110, 80, 27);
        button_2.setText("发送");
        sashForm.setWeights(new int[] {97, 378, 152});


        //发送
        button_2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                String message=text_4.getText().trim().toString();
                if(message==null || message.length()<0||"".equals(message)){
                    MessageDialog.openError(shell, "出错了", "要发送的信息不能为空");
                    return;
                }
                JsonModel<Content> jsonModel=new JsonModel<Content>();
                jsonModel.setCode(YcConstants.SEND_MESSAGE);
                Content c=new Content();
                c.setNickname(nickname);
                c.setIp(s.getLocalAddress().toString());
                c.setMsg(message);

                jsonModel.setT(c);

                //将jsonModel对象转成json字符串,通过gson转
                //通过TypeToken对象,向Gson来说明这个泛型类的构成
                Gson g=new Gson();
                Type type=new TypeToken<JsonModel<Content>>(){}.getType();
                String jsonstring=g.toJson(jsonModel,type);
                pw.println(jsonstring);
                pw.flush();

                text_4.setText("");
            }
        });

        //断开
        button_1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if(s==null){
                    return;
                }
                JsonModel<User> jsonModel=new JsonModel<User>();
                jsonModel.setCode(YcConstants.USER_LOGIN_OUT_CODE);
                User user=new User();
                user.setNickname(nickname);
                user.setIp(s.getLocalAddress().toString());
                jsonModel.setT(user);

                //将jsonModel对象转成json字符串,通过gson转
                //通过TypeToken对象,向Gson来说明这个泛型类的构成
                Gson g=new Gson();
                Type type=new TypeToken<JsonModel<User>>(){}.getType();
                String jsonstring=g.toJson(jsonModel,type);
                pw.println(jsonstring);
                pw.flush();

                //退出
                String content=text_3.getText();
                Date d=new Date();
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                content="\n"+nickname+"退出聊天\n\t\t\t\t"+sdf.format(d)+content;
                text_3.setText(content);
                pw.close();
                sc.close();
                try {
                    s.close();
                    s=null;
                    txtCat.setEnabled(true);
                    txtLocalhost.setEnabled(true);
                    text_2.setEnabled(true);
                    button.setEnabled(true);
                    button_1.setEnabled(false);
                    button_2.setEnabled(false);
                    flag=false;
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });

        //登录
        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                nickname=txtCat.getText().toString();
                String ip=txtLocalhost.getText().toString();
                String port=text_2.getText().toString();

                int p=Integer.parseInt(port);

                try {
                    s=new Socket(ip, Integer.parseInt(port));
                    sc=new Scanner(s.getInputStream());
                    pw=new PrintWriter(s.getOutputStream());
                    txtCat.setEnabled(false);
                    txtLocalhost.setEnabled(false);
                    text_2.setEnabled(false);
                    button.setEnabled(false);
                    button_1.setEnabled(true);
                    button_2.setEnabled(true);

                    JsonModel<User> jsonModel=new JsonModel<User>();
                    jsonModel.setCode(YcConstants.USER_LOGIN_CODE);
                    User user=new User();
                    user.setNickname(nickname);
                    user.setIp(s.getLocalAddress().toString());
                    jsonModel.setT(user);
                    //将jsonModel对象转成json字符串,通过gson转
                    //通过TypeToken对象,向Gson来说明这个泛型类的构成
                    Gson g=new Gson();
                    Type type=new TypeToken<JsonModel<User>>(){}.getType();
                    String jsonstring=g.toJson(jsonModel,type);
                    pw.println(jsonstring);
                    pw.flush();
                    flag=true;
                    Thread t=new Thread(TalkClient.this);
                    t.start();
                } catch (Exception e1) {
                    e1.printStackTrace();
                    MessageDialog.openError(shell, "出错了", e1.getMessage());
                    txtCat.setEnabled(true);
                    txtLocalhost.setEnabled(true);
                    text_2.setEnabled(true);
                    button.setEnabled(true);
                    button_1.setEnabled(false);
                    button_2.setEnabled(false);
                } 
            }
        });

    }

    @Override
    public void run() {
        //不断的接收服务器的响应
        while( flag ){      //当flag==true
            //接收服务器的回传数据
            if(s!=null&&s.isClosed()==false&&sc!=null&&sc.hasNextLine()){
                String jsonline=sc.nextLine();
                //解析协议
                parseProtocal(jsonline);
            }
        }
    }

    private void parseProtocal(String jsonline) {
        //判断code的值
        int code=parseCode(jsonline);
        if(code==1){
            //如果code==1,则t是content对象,则操作文本显示聊天信息
            Gson g=new Gson();
            Type type=new TypeToken<JsonModel<Content>>(){}.getType();
            JsonModel<Content> jsonModel=g.fromJson(jsonline,type);
            final Content c=jsonModel.getT();
            Display.getDefault().asyncExec(new Runnable(){
                @Override
                public void run() {
                    Date d=new Date();
                    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String txt=text_3.getText().trim();
                    String msg="\n\n"+c.getNickname()+"对大家说:\n"+c.getMsg()+"\n\t\t\t\t发表时间"+sdf.format(d)+"\n";
                    txt=msg+txt;
                    text_3.setText(txt);
                }
            });
        }else if(code==2){
            //如果code==2,则t是userlist集合对象,则更新table
            Gson g=new Gson();
            Type type=new TypeToken<JsonModel<List<User>>>(){}.getType();
            JsonModel<List<User>> jsonModel=g.fromJson(jsonline,type);
            final List<User> list=jsonModel.getT();
            Display.getDefault().asyncExec(new Runnable(){
                @Override
                public void run() {
                    table.removeAll();
                    for(User u:list){
                        TableItem ti=new TableItem(table,SWT.None);
                        ti.setText(new String[]{u.getNickname(),u.getIp()});
                    }
                }
            });
        }
    }

    private int parseCode(String jsonline) {
        if(jsonline.startsWith("{\"code\":1,")){
            return 1;
        }else if(jsonline.startsWith("{\"code\":2,")){
            return 2;
        }
        return 404;
    }
}

其他辅助类 包括聊天人的个人信息和说的内容

package com.yc.bean;

public class Content {

    private String nickname;
    private String ip;
    private String msg;


    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return ip+"\t"+nickname+"\t"+msg;
    }
}
package com.yc.bean;

public class JsonModel<T> {
    private int code;
    private T t;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

}
package com.yc.bean;

//登录或退出的用户信息
public class User {
    private String nickname;
    private String ip;

    public User() {
        super();
    }

    public User(String nickname, String ip) {
        super();
        this.nickname = nickname;
        this.ip = ip;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

}
package com.yc.bean;

public class YcConstants {

    //登录的code值为3
    public static final int USER_LOGIN_CODE=3;

    //退出的code值值为4
    public static final int USER_LOGIN_OUT_CODE=4;

    //发送信息的code值为1
    public static final int SEND_MESSAGE=1;

    //发送用户列表的code值为2
    public static final int SEND_USERLIST=2;
}

你可能感兴趣的:(java,线程,网络,服务器,聊天)