前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >android聊天室

android聊天室

作者头像
提莫队长
发布2019-02-21 10:49:53
3.4K0
发布2019-02-21 10:49:53
举报
文章被收录于专栏:刘晓杰刘晓杰刘晓杰

1.编写PC端工程代码:

这是一个Java工程,分为客户端和服务器端。两者的关系如图;

这里写图片描述
这里写图片描述

工程目录:

这里写图片描述
这里写图片描述

Server.java(这里面有java swing生成界面的代码,和Android-layout有点像)

package com.example.pcchat.server;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Server extends JFrame implements ActionListener {
    //服务器端主线程负责界面以及服务端主线程ServerThread启动
    //ServerThread又产生BroadCast和ClientThread线程
    private static final long serialVersionUID = 1L;

    JPanel jPanel1 = new JPanel();
    JButton jButton1 = new JButton("启动服务器");
    JButton jButton2 = new JButton("关闭服务器");

    JPanel jPanel2 = new JPanel();
    JScrollPane jScrollPane = new JScrollPane();
    static JTextArea jTextArea = new JTextArea();

    boolean bool = false, start = false;

    ServerThread serverThread;
    Thread thread;

    public Server(){
        super("Server");

        jButton1.addActionListener(this);
        jButton2.addActionListener(this);

        getContentPane().setLayout(new BorderLayout());

        //头部布局
        getContentPane().add(jPanel1, BorderLayout.NORTH);
        jPanel1.add(jButton1);
        jPanel1.add(jButton2);

        //头部以下布局
        getContentPane().add(jPanel2, BorderLayout.CENTER);
        jPanel2.setLayout(new BorderLayout());
        jPanel2.add(jScrollPane, BorderLayout.CENTER);
        jScrollPane.getViewport().add(jTextArea);

        setSize(400, 400);
        setVisible(true);
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    //按钮事件处理
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == jButton1){//启动服务器
            serverThread = new ServerThread();
            serverThread.start();
        } else if (e.getSource() == jButton2) {//关闭服务器
            bool = false;
            start = false;
            serverThread.finalize();
            setVisible(false);
        }
    } 
}

ServerThread.java

package com.example.pcchat.server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

public class ServerThread extends Thread {
    ServerSocket serverSocket;

    // ClientThread维持服务器与单个客户端的连接
    // 负责接收客户端发来的信息
    Vector<ClientThread> clients;

    // 用于接收客户端发来的信息
    Vector<Object> messages;

    // BroadCast类负责服务端向客户端广播消息
    BroadCast broadcast;

    String ip;
    InetAddress myInetAddress = null;

    public ServerThread() {
        clients = new Vector<ClientThread>();
        messages = new Vector<Object>();

        try {
            serverSocket = new ServerSocket(8521);
            myInetAddress = InetAddress.getLocalHost();
            ip = myInetAddress.getHostAddress();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Server.jTextArea.append("服务器地址:" + ip + "端口号:"
                + String.valueOf(serverSocket.getLocalPort()) + "\n");

        broadcast = new BroadCast(this);
        broadcast.start();
    }

    //一旦监听到有new Socket(ip, port)就创建ClientThread来维持服务器与客户端的连接
    @Override
    public void run() {
        while (true) {
            try {
                Socket socket = serverSocket.accept();
                System.out.println(socket.getLocalAddress().getHostAddress());

                //启动ClientThread可以监听对应的客户端是否发来信息
                ClientThread clientThread = new ClientThread(socket, this);
                clientThread.start();

                if(socket != null){
                    synchronized (this) {
                        clients.add(clientThread);
                    }
                }
            } catch (IOException e) {
                System.exit(2);
            }

        }
    }

    public void finalize() {
        try {
            if(serverSocket != null){
                serverSocket.close();
            }
        } catch (IOException e1) {
            serverSocket = null;
        }
    }
}

ClientThread.java

package com.example.pcchat.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class ClientThread extends Thread {
    // 服务器和单个客户端的连接
    //接收message并保存
    Socket clientSocket;

    DataInputStream in;
    DataOutputStream out;

    ServerThread serverThread;
    String str;

    static int ConnectedNumber = 0;

    public ClientThread(Socket socket, ServerThread serverThread) {
        clientSocket = socket;
        this.serverThread = serverThread;

        try {
            in = new DataInputStream(clientSocket.getInputStream());
            out = new DataOutputStream(clientSocket.getOutputStream());
        } catch (IOException e) {
            System.out.println("建立IO通道失败!");
            System.exit(3);
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                // 读取客户端发来的信息
                String message = in.readUTF();
                synchronized (serverThread.messages) {
                    if (message != null) {
                        // 将客户端发来的数据存在serverThread的messages数组中
                        serverThread.messages.add(message);
                        // 在服务器端的文本框中显示新消息
                        Server.jTextArea.append(message + "\n");

                        if(message.startsWith("#")){//从Client接收到下线消息
                            serverThread.clients.remove(this);
                        }
                    }
                }
            } catch (IOException e) {
                break;
            }
        }
    }
}

BroadCast.java

package com.example.pcchat.server;

import java.io.IOException;

public class BroadCast extends Thread {

    ClientThread clientThread;
    ServerThread serverThread;
    String str;

    public BroadCast(ServerThread serverThread) {
        this.serverThread = serverThread;
    }

    // 不停地向所有客户端发送消息
    @Override
    public void run() {
        while (true) {
            // 同步化serverThread.messages
            synchronized (serverThread.messages) {
                if (!serverThread.messages.isEmpty()) {
                    str = (String) serverThread.messages.firstElement();

                    // 利用循环获取所有连接
                    for (int i = 0; i < serverThread.clients.size(); i++) {
                        clientThread = (ClientThread) serverThread.clients
                                .elementAt(i);
                        try {
                            // 向每个客户端发送信息
                            clientThread.out.writeUTF(str);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    // 删除已经发送的数据
                    serverThread.messages.removeElement(str);
                }
            }
        }
    }
}

客户端Client.java

package com.example.pcchat.client;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.sql.Date;
import java.text.SimpleDateFormat;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Client extends JFrame implements ActionListener, Runnable {
    private static final long serialVersionUID = 1L;

    Socket socket;
    Thread thread;

    DataInputStream in;
    DataOutputStream out;

    // 是否登陆的标记
    boolean flag = false;
    boolean thread_is_over;

    String name, chat_txt, chat_in;
    // name---nameField, chat_txt---, chat_in---服务器发来的信息
    String ip = null;// -------ipTextField

    // 头部布局
    JPanel jPanel1 = new JPanel();
    JLabel jLabel1 = new JLabel("用户名:");
    JTextField nameField = new JTextField(5);
    JButton loginJButton = new JButton("进入聊天室");
    JButton exitJButton = new JButton("退出聊天室");

    // 中部布局
    JPanel jPanel2 = new JPanel();
    // ------------------左
    JScrollPane jScrollPane = new JScrollPane();
    JTextArea jTextArea = new JTextArea();
    // ------------------右
    JPanel jPanel3 = new JPanel();
    JLabel jLabel2 = new JLabel("服务器地址:");
    JTextField ipTextField = new JTextField(5);

    // 底部
    JPanel jPanel4 = new JPanel();
    JTextField sendTextField = new JTextField(20);
    JButton sendBtn = new JButton("发送消息");

    public Client() {
        thread_is_over = false;
        getContentPane().setLayout(new BorderLayout());

        loginJButton.addActionListener(this);
        exitJButton.addActionListener(this);
        sendBtn.addActionListener(this);

        // 头部布局
        getContentPane().add(jPanel1, BorderLayout.NORTH);
        jPanel1.add(jLabel1);
        jPanel1.add(nameField);
        jPanel1.add(loginJButton);
        jPanel1.add(exitJButton);

        // 中部布局
        getContentPane().add(jPanel2, BorderLayout.CENTER);
        jPanel2.setLayout(new BorderLayout());
        jPanel2.add(jScrollPane, BorderLayout.CENTER);
        jScrollPane.getViewport().add(jTextArea);
        jPanel2.add(jPanel3, BorderLayout.EAST);
        jPanel3.setLayout(new GridLayout(10, 1));// 10行1列
        jPanel3.add(jLabel2);
        jPanel3.add(ipTextField);

        // 底部布局
        getContentPane().add(jPanel4, BorderLayout.SOUTH);
        jPanel4.add(sendTextField);
        jPanel4.add(sendBtn);

        setSize(400, 400);
        setVisible(true);
    }

    public static void main(String[] args) {
        Client client = new Client();
        client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void run() {
        while (!thread_is_over) {
            try {
                // 获取服务器发来的信息
                chat_in = in.readUTF();
                jTextArea.append(chat_in + "\n");
            } catch (IOException e) {
                //e.printStackTrace();
                System.out.println("与服务器断开连接!");
            }
        }
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == loginJButton) {
            // 进入聊天室
            // 获取用户名和ip地址
            name = nameField.getText().toString();
            ip = ipTextField.getText().toString();
            if (!name.equals("") && !ip.equals("")) {
                try {
                    socket = new Socket(ip, 8521);

                    in = new DataInputStream(socket.getInputStream());
                    out = new DataOutputStream(socket.getOutputStream());

                    Date now = new Date(System.currentTimeMillis());
                    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
                    String nowString = sdf.format(now);
                    out.writeUTF("$$" + name + " " + nowString + "上线了!");
                } catch (Exception e1) {
                    //登录失败对话框
                    Toolkit.getDefaultToolkit().beep();
                    JOptionPane.showMessageDialog(null,
                            "login fail! ip address is wrong!",
                            "ERROR_MESSAGE",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                }
                // 开启线程监听server是否有消息
                thread = new Thread(this);
                thread.start();
                flag = true;
            }
        } else if (e.getSource() == sendBtn) {
            // 发送按钮
            chat_txt = sendTextField.getText().toString().trim();
            if ( !chat_txt.equals("")) {
                Date now = new Date(System.currentTimeMillis());
                SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
                String nowString = sdf.format(now);
                try {
                    out.writeUTF("^_^" + name + " " + nowString + "说:"
                            + chat_txt);
                } catch (IOException e1) {
                    System.out.println("服务器断开,无法发送数据!");
                }
            }
        } else if (e.getSource() == exitJButton) {
            // 退出聊天室
            if (flag == true) {
                try {
                    thread_is_over = true;
                    out.writeUTF("##" + name + "下线了");
                    out.close();
                    in.close();
                    if(socket != null){
                        socket.close();
                        socket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            flag = false;
            setVisible(false);
        }
    }
}

当然,客户端可以用android实现(代码相似) MainActivity.java

package com.example.chatandroidclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements Runnable {
    private EditText userName, userIP, message, history;
    private Button loginBtn, sendBtn, leaveBtn;
    private String nameString, IPString, messageString, historyString;

    private Socket socket;
    private Thread thread;

    private DataInputStream inputStream;
    private DataOutputStream outputStream;
    // 是否登录的标记
    private boolean flag = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        userName = (EditText) findViewById(R.id.userName);
        userIP = (EditText) findViewById(R.id.userIP);
        message = (EditText) findViewById(R.id.message);
        history = (EditText) findViewById(R.id.history);

        loginBtn = (Button) findViewById(R.id.loginBtn);
        sendBtn = (Button) findViewById(R.id.sendBtn);
        leaveBtn = (Button) findViewById(R.id.leaveBtn);

        loginBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (flag == true) {
                    Toast.makeText(MainActivity.this, "已登录!",
                            Toast.LENGTH_SHORT).show();
                    return;
                }
                nameString = userName.getText().toString();
                IPString = userIP.getText().toString();
                if (!nameString.equals("") && !IPString.equals("")) {
                    new Thread(new Runnable() {
                        public void run() {
                            try {
                                socket = new Socket(IPString, 8521);

                                inputStream = new DataInputStream(socket
                                        .getInputStream());
                                outputStream = new DataOutputStream(socket
                                        .getOutputStream());

                                Date now = new Date(System.currentTimeMillis());
                                SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss",
                                        Locale.CHINA);
                                String nowString = sdf.format(now);
                                outputStream.writeUTF("$$" + nameString + " "
                                        + nowString + "上线了!");
                            } catch (Exception e) {
                                e.printStackTrace();
                                System.out.println("can't connect");
                            }
                            thread = new Thread(MainActivity.this);
                            thread.start();
                            flag = true;
                        }
                    }).start();
                }
            }
        });

        sendBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (flag == false) {
                    Toast.makeText(MainActivity.this, "未登录!",
                            Toast.LENGTH_SHORT).show();
                    return;
                }
                messageString = message.getText().toString().trim();
                if (!messageString.equals("")) {
                    Date now = new Date(System.currentTimeMillis());
                    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss",
                            Locale.CHINA);
                    String nowString = sdf.format(now);
                    try {
                        outputStream.writeUTF("^_^" + nameString + " "
                                + nowString + "说:" + messageString);
                    } catch (IOException e1) {
                        System.out.println("服务器断开,无法发送数据!");
                    }
                }
            }
        });

        leaveBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (flag == false) {
                    Toast.makeText(MainActivity.this, "未登录!",
                            Toast.LENGTH_SHORT).show();
                    return;
                }
                try {
                    outputStream.writeUTF("##" + nameString + "下线了");
                    outputStream.close();
                    inputStream.close();
                    if (socket != null) {
                        socket.close();
                        socket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                flag = false;
                historyString = "";
                history.setText(historyString);
            }
        });
    }

    @Override
    public void run() {
        while (true) {
            try {
                // 获取服务器发来的信息
                messageString = inputStream.readUTF();
                messageString = messageString + "\n";
                myHandler.sendEmptyMessage(0);
            } catch (IOException e) {
                //System.out.println("与服务器断开连接!");
            }
        }
    }

    private Handler myHandler = new Handler(){
        public void handleMessage(Message msg) {
            if(msg.what == 0){
                historyString += messageString;
                history.setText(historyString);
            }
        };
    };
}

main.xml文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.chatandroidclient.MainActivity" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名" />

        <EditText
            android:id="@+id/userName"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:background="@android:drawable/edit_text" />

        <Button
            android:id="@+id/loginBtn"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="登录" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="IP地址" />

        <EditText
            android:id="@+id/userIP"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:background="@android:drawable/edit_text"
            android:text="10.107.56.64" />

        <Button
            android:id="@+id/leaveBtn"
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="离开" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/message"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:drawable/edit_text" />

        <Button
            android:id="@+id/sendBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="发送" />

        <EditText
            android:id="@+id/history"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:drawable/edit_text"
            android:editable="false"
            android:inputType="textMultiLine"
            android:singleLine="false" />
    </LinearLayout>

</LinearLayout>

测试结果:

这里写图片描述
这里写图片描述

《Android 4.0网络编程详解》书上的不标准,我把它优化了。有什么问题请大神们指出

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年04月08日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.编写PC端工程代码:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档