如何利用协议编写一个简单的聊天室

1.先建立两个项目,一个是客户端,一个是服务器端。
   项目搭建如下所示:
   其中YcChart 为客户端,YcChatServer为服务器端。
项目搭建如下所示

2.编写协议类(两边的协议要一样,即自定义的YCCP协议)

package com.yc.entity;

public class YCCP {
    public static final int LOGIN = 1;      //登录处理
    public static final int SEND_MSG = 2;   //消息处理
    public static final int USER_LIST = 3;  //登录用户处理
    private int code;           // 区分不同的消息
    private String content;     // 发送的内容

    public YCCP() {
    }

    public YCCP(int code, String content) {
        this.code = code;
        this.content = content;
    }

    public int getCode() {
        return code;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

3.Java是面向对象编程,所以我们把一个用户定义为一个User类(两边的User类相同)

package com.yc.entity;

public class User {
    private String name;   //用户名称
    private String ip;     //用户IP地址

    public User() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIp() {
        return ip;
    }

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

4.编写服务器(Server)

package com.yc.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    private ServerSocket server;

    public static void main(String[] args) {
        new Server().startServer();
    }

    private void startServer() {
        try {
            server = new ServerSocket(9090);
            System.out.println("服务器启动,,端口9090成功...");
            while(true){    //接收多个请求客户端
                Socket client = server.accept();    //接受客户请求,没有请求就等待
                System.out.println("接收请求: " + client);
                new Thread( new ClientStack(client)).start();   //每一个客户请求,都一个线程,这样就不会相互影响了
            }
        } catch (IOException e) {
            System.err.println("服务器启动失败");
        }
    }
}

5.编写客户端接收处理类(ClientStack)

package com.yc.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import com.google.gson.Gson;
import com.yc.entity.User;
import com.yc.entity.YCCP;

public class ClientStack implements Runnable {
    private static List<ClientStack> clients = new ArrayList<ClientStack>();
    private static List<User> users = new ArrayList<User>();
    private Socket client;
    private Scanner in;
    private PrintWriter out;
    private User user;
    public ClientStack(Socket client) {
        try {
            this.client = client;
            in = new Scanner(client.getInputStream());  //接收客户端发送过来的数据输入流
            out = new PrintWriter( client.getOutputStream());   //向客户端发送响应数据输出流
            clients.add(this);  //加入当前请求的客户端到集合
        } catch (IOException e) {
            System.err.println( client.getInetAddress() + ":" + client.getPort() + "断开与服务器连接!!!");  //拼接客户端发送过来的数据
        }
    }

    @Override
    public void run() {
        boolean isExit= true;
        while(isExit){
            String line=null;
            YCCP yccp=null;
            try {
                line = in.nextLine(); //拼接客户端发送过来的数据
                yccp =new Gson().fromJson(line, YCCP.class);
                switch(yccp.getCode()){
                    case YCCP.LOGIN:
                        line = doLogin(yccp);
                        break;

                    case YCCP.SEND_MSG:
                        line = acceptMsg(yccp);
                        break;
                }
            } catch (Exception e) {
                line = user.getName() + "退出了聊天室...\r\n";
                clients.remove(this);
                users.remove(user);
                isExit = false;
            }   

            boardcast(YCCP.SEND_MSG,line);

            if(yccp != null && yccp.getCode() == YCCP.LOGIN || !isExit){
                boardcast(YCCP.USER_LIST, new Gson().toJson(users));
            }
        }


    }

    private void boardcast(int code,String line){
        Gson gson = new Gson();
        line = gson.toJson(new YCCP(code, line));  //转换成json格式输出
        for (ClientStack clientStack:clients) {
            clientStack.out.println(line); //给客户端写入的内容
            clientStack.out.flush();
        }
    }


    //接收发送消息处理
    private String acceptMsg(YCCP yccp) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        String msg = String.format("%s  %s : \r\n %s \r\n", user.getName(),sdf.format(new Date()),yccp.getContent());
        return msg;
    }

    //登录处理
    private String doLogin(YCCP yccp) {
        String uname = yccp.getContent();
        String ip = client.getInetAddress() +":" +client.getPort();
        user=new User(uname, ip); 
        users.add(user);
        return uname + "加入聊天室... \r\n";
    }

}

6.编写客户端ui界面(TalkView)

package com.yc.ui;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Scanner;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.wb.swt.SWTResourceManager;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yc.entity.User;
import com.yc.entity.YCCP;

import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;


public class TalkView {
    protected Shell shell;
    private Text uname;
    private Text text_1;
    private Text text_2;
    private Text chatMessage;
    private Table table;
    private Text message;



    private Button connetBtn; // 联接
    private Button breakBtn; // 断开
    private Button sendBtn; // 发送

    private boolean flag = false;   //标识变量,控制接收消息处理

    private Socket client;
    private Scanner in;
    private PrintWriter out;
    public static void main(String[] args) {
        try {
            TalkView window = new TalkView();
            window.open();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

    protected void createContents() {
        shell = new Shell();
        shell.setSize(856, 619);
        shell.setText("源辰聊天室");
        shell.setImage(SWTResourceManager.getImage(TalkView.class, "/images/yc.ico"));
        shell.setLayout(new FillLayout(SWT.HORIZONTAL));
        SashForm sashForm = new SashForm(shell, SWT.NONE);
        sashForm.setOrientation(SWT.VERTICAL);

        Group group = new Group(sashForm, SWT.NONE);
        group.setText("连接配置");

        Label label = new Label(group, SWT.NONE);
        label.setBounds(10, 38, 54, 18);
        label.setText("昵称:");

        uname = new Text(group, SWT.BORDER);
        uname.setText("random");
        uname.setBounds(78, 38, 70, 18);

        Label lblip = new Label(group, SWT.NONE);
        lblip.setBounds(177, 38, 54, 18);
        lblip.setText("服务器IP:");

        text_1 = new Text(group, SWT.BORDER);
        text_1.setText("127.0.0.1");
        text_1.setBounds(260, 38, 167, 18);

        Label label_2 = new Label(group, SWT.NONE);
        label_2.setBounds(446, 38, 54, 18);
        label_2.setText("端口");

        text_2 = new Text(group, SWT.BORDER);
        text_2.setText("9090");
        text_2.setBounds(521, 38, 70, 18);

        connetBtn = new Button(group, SWT.NONE);
        connetBtn.setBounds(614, 38, 72, 22);
        connetBtn.setText("联接");

        breakBtn = new Button(group, SWT.NONE);
        breakBtn.setEnabled(false);
        breakBtn.setBounds(719, 38, 72, 22);
        breakBtn.setText("断开");

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

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

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

        chatMessage = new Text(composite, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP
                | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
        chatMessage.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));


        Group group_3 = new Group(sashForm_1, SWT.NONE);
        group_3.setText("在线用户列表");
        group_3.setLayout(new FillLayout(SWT.HORIZONTAL));

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

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

        TableColumn tblclmnIp = new TableColumn(table, SWT.NONE);
        tblclmnIp.setWidth(200);
        tblclmnIp.setText("IP");
        sashForm_1.setWeights(new int[] { 470, 369 });

        Group group_2 = new Group(sashForm, SWT.NONE);
        group_2.setText("聊天信息");

        Label label_1 = new Label(group_2, SWT.NONE);
        label_1.setBounds(36, 29, 54, 18);
        label_1.setText("内容");

        message = new Text(group_2, SWT.BORDER);
        message.setBounds(111, 23, 519, 70);

        sendBtn = new Button(group_2, SWT.NONE);
        sendBtn.setBounds(700, 51, 72, 22);
        sendBtn.setText("发送");
        sendBtn.setEnabled(false);
        sashForm.setWeights(new int[] { 82, 384, 113 });
        doEvent();

    }

     //事件的集中地
     public void doEvent(){

         //联接
         connetBtn.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    String ipStr=text_1.getText();
                    String portStr=text_2.getText();
                    InetAddress address;
                    try {
                        address = InetAddress.getByName(ipStr);
                    } catch (UnknownHostException e1) {
                        MessageBox mb = new MessageBox(shell);
                        mb.setText("连接服务器信息");
                        mb.setMessage("服务连接地址有问题!!!");
                        mb.open();
                        return;
                    }
                    try {
                        client = new Socket(address, Integer.parseInt(portStr));    //建立与服务器的连接通道
                        flag = true;
                        in = new Scanner(client.getInputStream());  //通道的输入流
                        out = new PrintWriter(client.getOutputStream());    //通道的输出流
                        doLogin();

                        acceptMessage();
                        breakBtn.setEnabled(true);
                        connetBtn.setEnabled(false);
                    } catch (NumberFormatException | IOException e1) {
                        MessageBox mb = new MessageBox(shell);
                        mb.setText("连接服务器信息");
                        mb.setMessage("连接服务器失败,请检查服务器信息");
                        mb.open();
                        return;
                    }
                }
            });

         //断开连接
         breakBtn.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    MessageBox mb = new MessageBox(shell,SWT.YES| SWT.NO | SWT.ICON_WARNING);
                    mb.setText("连接服务器信息");
                    mb.setMessage("是否断开与服务器的连接?");
                    if(mb.open()==SWT.YES){
                            try {
                                flag = false;
                                client.close();
                                chatMessage.setText("");
                                breakBtn.setEnabled(false);
                                connetBtn.setEnabled(true);
                                table.removeAll();
                            } catch (IOException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                    }
                }
            });

         //发送消息
         sendBtn.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    SendMessage();

                }
            });

         //发送信息框处理
         message.addModifyListener(new ModifyListener() {
                public void modifyText(ModifyEvent arg0) {
                    sendBtn.setEnabled("".intern() != message.getText().trim());
                }
            });

         //按Enter键发送
         message.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    if(e.keyCode==13){
                        SendMessage();
                    }
                }
            });

     }

    //接收服务器发送过来的消息
    public void acceptMessage() {
        new Thread(){
            public void run() {
                while(flag){
                    if(in.hasNextLine()){
                        String line = in.nextLine();
                        YCCP yccp =new Gson().fromJson(line, YCCP.class);
                        switch(yccp.getCode()){
                            case YCCP.USER_LIST:
                                doUserList(yccp);
                                break;

                            case YCCP.SEND_MSG:
                                doMsg(yccp);
                                break;
                        }

                    }
                }
            };
        }.start();
    }

    public void doMsg(YCCP yccp) {
        final String line = yccp.getContent();
        Display.getDefault().asyncExec(new Runnable(){
            @Override
            public void run() {
                chatMessage.setText(chatMessage.getText() + "\r\n" + line);
            }
        });
    }

    public void doUserList(YCCP yccp) {
        Gson gson = new Gson();
        Type t=new TypeToken<List<User>>(){}.getType(); //json复杂类型的转换
        final List<User> users = gson.fromJson(yccp.getContent(), t);
        Display.getDefault().asyncExec(new Runnable(){
            @Override
            public void run() {
                table.removeAll();
                for(User user : users){
                    TableItem ti = new TableItem(table,SWT.NONE);
                    ti.setText(new String[]{user.getName(),user.getIp()});
                }
            }
        });

    }



    //向服务器发送消息
    public void SendMessage() {
        YCCP yccp = new YCCP(YCCP.SEND_MSG,message.getText());
        String msg = new Gson().toJson(yccp);
        out.println(msg);
        out.flush();
        message.setText("");
    }

    public void SendMessage(String msg) {
        out.println(msg);
        out.flush();
    }

    //第一次连接做登录
    public void doLogin(){
        String user = uname.getText();
        YCCP yccp = new YCCP(YCCP.LOGIN,user);
        SendMessage(new Gson().toJson(yccp));
    }
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值