android聊天室

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网络编程详解》书上的不标准,我把它优化了。有什么问题请大神们指出

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

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券