当前位置: 代码迷 >> Android >> android客户端容易的聊天程序实现
  详细解决方案

android客户端容易的聊天程序实现

热度:44   发布时间:2016-05-01 17:39:44.0
android客户端简单的聊天程序实现

        暑假第四十二天,我们依然很宅的呆在地下室里生活和学习着,最近虽然每天都起得很早,但是效率貌似没有以前高了,学习的劲头没有以前高了,越来越不想吃学校的独家饭了,每天都是馒头(而且还是好硬的那种),不过想想呢,有的吃就不错了,在这就不抱怨了,看看今天实现的android聊天室的聊天功能吧,先说说服务器端的代码及其功能吧

server.java : 负责服务器的界面,以及更服务器主线程ServerThread的启动,产生了BroadCast广播,产生ClientThread线程

ServerThread.java:服务器监听的端口线程,负责创建ServerSocket及监听是否有新的客户端连接,并记录客户端连接及需要发送的信息,产生了BroadCast广播

BroadCast.java: 服务器向客户端广播线程,负责向客户端发送消息,产生ClientThread线程

ClientThread.java:维持服务器和单个客户端的连接线程,负责接受客户端发来是信息

好了接着就看看他们的代码吧!!

1.server.java-------创建ServerThread对象启动run方法

package com.wang;import java.awt.BorderLayout;import javax.swing.*;import java.awt.event.*;public class Server extends JFrame implements ActionListener {	/****	 *服务器端主程序负责界面,以及服务段主线程ServerThread的启动	 * 服务端主线程ServerThread又产生BroadCast及ClientThread线程 建立服务器端主界面中所用到的布局方式	 ***/	// 边框容器	BorderLayout borderLayout1 = new BorderLayout();	BorderLayout borderLayout2 = new BorderLayout();	// 创建面板	JPanel jPanel1 = new JPanel();	JPanel jPanel2 = new JPanel();	// 创建按钮	JButton jButton1 = new JButton();	JButton jButton2 = new JButton();	JScrollPane jScrollPane1 = new JScrollPane();	// 创建服务器端接收信息文本框	static JTextArea jTextArea1 = new JTextArea();	boolean bool = false, start = false;	// 声明ServerThread线程类对象	ServerThread serverThread;	Thread thread;	// 构造函数,用于初始化	public Server() {		super("Server");		// 设置内容面板布局方式		getContentPane().setLayout(borderLayout1);		// 初始化按钮组件		jButton1.setText("启动服务器");		// 按钮的动作设置监听事件		jButton1.addActionListener(this);		jButton2.setText("关闭服务器");		// 按钮的动作设置监听事件		jButton2.addActionListener(this);		// 初始化jPanel1面板对象,并向其中加入组件,上北		this.getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);		jPanel1.add(jButton1);		jPanel1.add(jButton2);		// 初始化jPanel2面板对象,并向其中加入组件,		jTextArea1.setText("");		jPanel2.setLayout(borderLayout2);		jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);		jScrollPane1.getViewport().add(jTextArea1);		this.getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);		this.setSize(400, 400);		this.setVisible(true);	}	public static void main(String[] args) {		Server sever = new Server();		sever.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	}	// 服务器界面中按钮事件处理	public void actionPerformed(ActionEvent e) {		if (e.getSource() == jButton1) {			// 声明一个ServerThread对象			serverThread = new ServerThread();			serverThread.start();		} else if (e.getSource() == jButton2) {			bool = false;			start = false;			serverThread.finalize();			this.setVisible(false);		}	}}

2.ServerThread.java -----创建Broadcast对象,启动该线程,实现run方法后,不断的向客户端发送消息,ServerThread开启后,不断的获取新的客户端并监听是否发送消息

package com.wang;import java.util.*;import java.io.*;import java.net.*;public class ServerThread extends Thread// 服务器监听端口线程{	// 声明ServerSocket类对象	ServerSocket serverSocket;	// 指定服务器监听端口常量	public static final int PORT = 80;	/**	 * 创建一个Vector对象,用于存储客户端连接的ClientThread对象 , ClientThread类维持服务器与单个客户端的连接线程	 * 负责接收客户端发来的信息,clients负责存储所有与服务器建立连接的客户端	 **/	Vector<ClientThread> clients;	// 创建一个Vector对象,用于存储客户端发送过来的信息	Vector<Object> messages;	// BroadCast类负责服务器向客户端广播消息	BroadCast broadcast;	String ip;	InetAddress myIPaddress = null;	public ServerThread() {		/***		 * 创建两个Vector数组非常重要 , clients负责存储所有与服务器建立连接的客户端,		 * messages负责存储服务器接收到的未发送出去的全部客户端的信息		 * 		 **/		clients = new Vector<ClientThread>();		messages = new Vector<Object>();		try {			// 创建ServerSocket类对象			serverSocket = new ServerSocket(PORT);		} catch (IOException E) {		}		// 获取本地服务器地址信息		try {			myIPaddress = InetAddress.getLocalHost();		} catch (UnknownHostException e) {			System.out.println(e.toString());		}		ip = myIPaddress.getHostAddress();		Server.jTextArea1.append("服务器地址:" + ip + "端口号:"				+ String.valueOf(serverSocket.getLocalPort()) + "\n");		// 创建广播信息线程并启动		broadcast = new BroadCast(this);		broadcast.start();	}	/**	 * 注意:一旦监听到有新的客户端创建即new Socket(ip, PORT)被执行,	 * 就创建一个ClientThread来维持服务器与这个客户端的连接	 **/	public void run() {		while (true) {			try {				// 获取客户端连接,并返回一个新的Socket对象				Socket socket = serverSocket.accept();				System.out.println(socket.getInetAddress().getHostAddress());				// 创建ClientThread线程并启动,可以监听该连接对应的客户端是否发送来消息, 并获取消息				ClientThread clientThread = new ClientThread(socket, this);				clientThread.start();				if (socket != null) {					synchronized (clients) {						// 将客户端连接加入到Vector数组中保存						clients.addElement(clientThread);					}				}			} catch (IOException E) {				System.out.println("发生异常:" + E);				System.out.println("建立客户端联机失败!");				System.exit(2);			}		}	}	public void finalize() {		try {			// 关闭serverSocket方法			serverSocket.close();		} catch (IOException E) {		}		serverSocket = null;	}}

3.BroadCast.java------

package com.wang;import java.io.*;public class BroadCast extends Thread { // 服务器向客户端广播线程	ClientThread clientThread;	// 声明ServerThread对象	ServerThread serverThread;	String str;	public BroadCast(ServerThread serverThread) {		this.serverThread = serverThread;	}	// 该方法的作用是不停地向所有客户端发送新消息	public void run() {		while (true) {			try {				// 线程休眠200 ms				Thread.sleep(200);			} catch (InterruptedException E) {			}			// 同步化serverThread.messages			synchronized (serverThread.messages) {				// 判断是否有未发的消息				if (serverThread.messages.isEmpty()) {					continue;				}				// 获取服务器端存储的需要发送的第一条数据信息				str = (String) this.serverThread.messages.firstElement();			}			// 同步化serverThread.clients			synchronized (serverThread.clients) {				// 利用循环获取服务器中存储的所有建立的与客户端的连接				for (int i = 0; i < serverThread.clients.size(); i++) {					clientThread = (ClientThread) serverThread.clients							.elementAt(i);					try {						// 向记录的每一个客户端发送数据信息						clientThread.out.writeUTF(str);					} catch (IOException E) {					}				}				// 从Vector数组中删除已经发送过的那条数据信息				this.serverThread.messages.removeElement(str);			}		}	}}

4.ClientThread.java----获得Socket的输入输出流,向客户端接收或者发送数据

package com.wang;import java.net.*;import java.io.*;public class ClientThread extends Thread          {		/**	 * 维持服务器与单个客户端的连接线程,负责接收客户端发来的信息,	 * 声明一个新的Socket对象,	 * 用于保存服务器端用accept方法得到的客户端的连接    **/	Socket clientSocket;        //声明服务器端中存储的Socket对象的数据输入/输出流    DataInputStream in = null;    DataOutputStream out = null;        //声明ServerThread对象    ServerThread serverThread;    public ClientThread(Socket socket,ServerThread serverThread)    {    	clientSocket=socket;           this.serverThread=serverThread;        try        {        	//创建服务器端数据输入/输出流            in = new DataInputStream(clientSocket.getInputStream());            out = new DataOutputStream(clientSocket.getOutputStream());        }        catch (IOException e2)        {            System.out.println("发生异常"+e2);            System.out.println("建立I/O通道失败!");            System.exit(3);        }    }    //该方法监听该连接对应得客户端是否有消息发送    public void run()    {        while(true)        {             try            {            	//读入客户端发送来的信息                String message=in.readUTF();                synchronized(serverThread.messages)                {                    if(message!=null)                    {                    	//将客户端发送来得信息存于serverThread的messages数组中                        serverThread.messages.addElement(message);                        //在服务器端的文本框中显示新消息                        Server.jTextArea1.append(message+'\n');                    }                }            }            catch(IOException E){break;}        }    }}
5.接着看看手机客户端的布局main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:orientation="horizontal" >        <EditText            android:id="@+id/username"            android:layout_width="270dp"            android:layout_height="wrap_content"            android:hint="请输入用户名:"            android:maxLength="10" >        </EditText>        <Button            android:id="@+id/LoginButton"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="登陆" />    </LinearLayout>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:orientation="horizontal" >        <EditText            android:id="@+id/ip"            android:layout_width="270dp"            android:layout_height="wrap_content"            android:digits=".1234567890"            android:hint="10.254.1.62" >        </EditText>        <Button            android:id="@+id/LeaveButton"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="退出" />    </LinearLayout>    <EditText        android:id="@+id/history"        android:layout_width="fill_parent"        android:layout_height="280dp" >    </EditText>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:orientation="horizontal" >        <EditText            android:id="@+id/message"            android:layout_width="270dp"            android:layout_height="wrap_content" >        </EditText>        <Button            android:id="@+id/SendButton"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="发送" />    </LinearLayout></LinearLayout>
6.接着看看手机客户端的实现ChatClientActivity.java

package com.wang;import android.app.Activity;import android.os.Bundle;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.InetAddress;import java.net.Socket;import java.sql.Date;import java.text.SimpleDateFormat;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;public class ChatClientActivity extends Activity implements Runnable {	private EditText usernameEdit;	private EditText ipEdit;	private EditText historyEdit;	private EditText messageEdit;	private Button loginButton;	private Button sendButton;	private Button leaveButton;	/**	 * 声明字符串,name存储用户名 chat_txt存储发送信息 chat_in存储从服务器接收到的信息	 ****/	private String username, ip, chat_txt, chat_in;	// 创建Socket通信端口号常量	public static final int PORT = 80;	// 声明套接字对象	Socket socket;	// 声明线程对象	Thread thread;	// 声明客户器端数据输入输出流	DataInputStream dataInputStream;	DataOutputStream dataOutputStream;	// 是否登录的标记	boolean flag = false;	public void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		// 取消标题栏		this.requestWindowFeature(Window.FEATURE_NO_TITLE);		// 设置全屏		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,				WindowManager.LayoutParams.FLAG_FULLSCREEN);		setContentView(R.layout.main);		// 实例化组件		usernameEdit = (EditText) findViewById(R.id.username);		ipEdit = (EditText) findViewById(R.id.ip);		historyEdit = (EditText) findViewById(R.id.history);		messageEdit = (EditText) findViewById(R.id.message);		loginButton = (Button) findViewById(R.id.LoginButton);		sendButton = (Button) findViewById(R.id.SendButton);		leaveButton = (Button) findViewById(R.id.LeaveButton);		// 为三个按钮注册监听器		loginButton.setOnClickListener(listener);		sendButton.setOnClickListener(listener);		leaveButton.setOnClickListener(listener);	}	View.OnClickListener listener = new View.OnClickListener() {		@Override		public void onClick(View v) {			switch (v.getId()) {			// "进入聊天室"按钮的处理			case R.id.LoginButton:				if (flag == true) {					Toast.makeText(ChatClientActivity.this, "亲,你已经登陆过啦!!!",							Toast.LENGTH_LONG).show();					return;				}				// 获取用户名				username = usernameEdit.getText().toString();				// 获取服务器ip				ip = ipEdit.getText().toString();				// 判断用户名是否有效及ip是否为空				if (username != "" && username != null && username != "用户名输入"						&& ip != null) {					try {						// 创建Socket对象						socket = new Socket(ip, PORT);						// 创建客户端数据输入/输出流,用于对服务器端发送或接收数据						dataInputStream = new DataInputStream(socket								.getInputStream());						dataOutputStream = new DataOutputStream(socket								.getOutputStream());						// 得到系统的时间						Date now = new Date(System.currentTimeMillis());						SimpleDateFormat format = new SimpleDateFormat(								"hh:mm:ss");						String nowStr = format.format(now);						// 输出某某上线啦						dataOutputStream.writeUTF("└(^o^)┘: " + username								+ " : " + nowStr + " 上线啦!");					} catch (IOException e1) {						System.out.println("抱歉连接不成功!!!");					}					thread = new Thread(ChatClientActivity.this);					// 开启线程,监听服务器段是否有消息					thread.start();					// 说明已经登录成功					flag = true;				}				break;			// "发送"按钮的处理			case R.id.SendButton:				if (flag == false) {					Toast.makeText(ChatClientActivity.this, "亲,你还没登录,请先登录!",							Toast.LENGTH_LONG).show();					return;				}				// 获取客户端输入的发言内容				chat_txt = messageEdit.getText().toString();				if (chat_txt != null) {					// 得到当前时间					Date now = new Date(System.currentTimeMillis());					SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");					String nowStr = format.format(now);					// 发言,向服务器发送发言的信息					try {						dataOutputStream.writeUTF("(^_^)∠※--->" + username								+ " : " + nowStr + " 说\n" + chat_txt);					} catch (IOException e2) {					}				} else {					try {						dataOutputStream.writeUTF("请发言!!!");					} catch (IOException e3) {					}				}				break;			// "退出聊天室"按钮事件的处理			case R.id.LeaveButton:				if (flag == true) {					if (flag == false) {						Toast.makeText(ChatClientActivity.this,								"亲,你还没登录,请先登录!", Toast.LENGTH_LONG).show();						return;					}					try {						dataOutputStream.writeUTF("(^_^)/~~ " + username								+ "下线了!");						// 关闭socket						dataOutputStream.close();						dataInputStream.close();						socket.close();					} catch (IOException e4) {					}				}				flag = false;				Toast.makeText(ChatClientActivity.this, "已退出!",						Toast.LENGTH_LONG).show();				break;			}		}	};	// 客户端线程启动后的动作	@Override	public void run() {		// 循环执行,作用是一直监听服务器端是否有消息		while (true) {			try {				// 读取服务器发送来的数据信息				chat_in = dataInputStream.readUTF();				chat_in = chat_in + "\n";				// 发送一个消息,要求刷新界面				mHandler.sendMessage(mHandler.obtainMessage());			} catch (IOException e) {			}		}	}	Handler mHandler = new Handler() {		public void handleMessage(Message msg) {			// 将消息并显示在客户端的对话窗口中			historyEdit.append(chat_in);			// 刷新			super.handleMessage(msg);		}	};}

7,亲,别忘了由于需要网络,需要添加联网的权限哦!!

<uses-permission android:name="android.permission.INTERNET"/>
8.如果你完成以上功能,就可以实现android手机客户端上的简单的聊天功能了,运行结果给如下:





  相关解决方案