多人聊天室

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

首先 创建服务器端

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;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿份到

浅谈Retrofit 源码

现在的项目界面都是按iOS的风格,虽然界面无法发挥出我们大Android的风格,网络框架动不动就是mvp+ okhttp +retrofit+rxjava,m...

3648
来自专栏向治洪

viewpager循环滚动和自动轮播的问题

ViewPager是一个常用的android组件,不过通常我们使用ViewPager的时候不能实现左右无限循环滑动,在滑到边界的时候会看到一个不能翻页的动画,...

3406
来自专栏酷玩时刻

Retrofit2+Rxjava+MVP 实践

此博文根据前面两篇文章 Android MVP 架构初试 Android MVP 架构封装 再结合主流框架Retrofit2+Rxjava来个实践(实现聚合网...

3594
来自专栏码匠的流水账

micrometer自定义metrics

spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframewor...

2322
来自专栏王磊的博客

react-native绑定优酷SDK-附效果图和源码

ReactNative绑定优酷SDK需要用到两部分知识: 优酷本身的sdk绑定; RN与原生界面的交互; 效果: ? RN版本:0.49.3 代码更新日期:20...

3936
来自专栏Android群英传

不需要再手写 onSaveInstanceState 了,因为你的时间非常值钱

901
来自专栏程序员宝库

Android屏幕截图,View截图(干货)

821
来自专栏项勇

笔记69 | Android获取MP3文件的ID3信息工具类

1775
来自专栏Android工程师的修仙之旅

自己动手写Android插件化框架

本文旨在通过两个实例直观的说明插件的实现原理以加深对插件内开发的理解,因此不会深入探讨背景和原理,代码也尽量专注于核心逻辑。

6033
来自专栏向治洪

仿淘宝收货地址,本地数据库

谁说咱们攻城狮不能写出既幽默又能懂的博客呢,本人想推出一系列博文,可以给刚接触Android开发的做一个参考,也可以与接触Android已久的各路大神比较一下,...

1.3K7

扫码关注云+社区

领取腾讯云代金券