在Java中我們可以利用socket編程實現聊天室,在Android中也一樣,因為Android完全支持JDK本身的TCP、UDP網絡通信API。我們可以使用ServerSocket、Socket來建立基於TCP/IP協議的網絡通信;也可以使用DatagramSocket、Datagrampacket、MulticastSocket來建立基於UDP協議的網絡通信。下面實現一個簡單的聊天室,服務器端完全用Java代碼實現,跟Android無關,客戶端用Android應用來實現。
服務器不斷讀取來自客戶端的信息,並即時地將信息發送給每個連接到本服務器上的客戶端,每個客戶端可以向服務器發送消息,並不斷地接收來自服務器的消息,並將消息顯示在界面上。這樣就實現了客戶端與客戶端之間的即時聊天功能。代碼如下:
服務器端:
創建服務器的主類:
服務器的線程類:
客戶端主類(Activity):
客戶端線程類:
Activity的佈局XML:
權限:
服務器不斷讀取來自客戶端的信息,並即時地將信息發送給每個連接到本服務器上的客戶端,每個客戶端可以向服務器發送消息,並不斷地接收來自服務器的消息,並將消息顯示在界面上。這樣就實現了客戶端與客戶端之間的即時聊天功能。代碼如下:
服務器端:
創建服務器的主類:
- package com.home.server;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.ArrayList;
- public class MyServer {
- // 定義保存所有Socket的集合
- public static ArrayList<Socket> socketList = new ArrayList<Socket>();
- public static void main(String[] args) throws IOException {
- ServerSocket ss = new ServerSocket( 20000 );
- System.out.println( "服務器創建成功!" );
- System.out.println( "等待客戶端的連接。。。" );
- while ( true ) {
- // 此行代碼會阻塞,等待用戶的連接
- Socket socket = ss.accept();
- System.out.println( "有客戶端連接進來!" );
- socketList.add(socket);
- // 每當客戶端連接後啟動一條ServerThread線程為該客戶端服務
- new Thread( new ServerThread(socket)).start();
- }
- }
- }
- package com.home.server;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.Socket;
- public class ServerThread implements Runnable {
- // 定義當前線程所處理的Socket
- private Socket socket = null ;
- // 該線程所處理的Socket所對應的輸入流
- BufferedReader br = null ;
- public ServerThread(Socket socket) throws IOException {
- this .socket = socket;
- // 初始化該Socket對應的輸入流
- br = new BufferedReader( new InputStreamReader(socket.getInputStream(),
- "utf-8" ));
- }
- @Override
- public void run() {
- try {
- String content = null ;
- // 採用循環不斷從Socket中讀取客戶端發送過來的數據
- while ((content = readFromClient()) != null ) {
- // 遍歷socketList中的每個Socket,將讀到的內容向每個Socket發送一次
- for (Socket s : MyServer.socketList) {
- OutputStream os = s.getOutputStream();
- os.write((content + "\n" ).getBytes( "utf-8" ));
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 定義讀取客戶端數據的方法
- *
- * @return
- */
- private String readFromClient() {
- try {
- return br.readLine();
- }
- // 如果捕捉到異常,表明該Socket對應的客戶端已經關閉
- catch (Exception e) {
- // 刪除該Socket
- MyServer.socketList.remove(socket);
- e.printStackTrace();
- }
- return null ;
- }
- }
- package com.home.activity;
- import java.io.OutputStream;
- import java.net.Socket;
- 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 com.home.R;
- import com.home.util.ClientThread;
- public class MultiThreadClient extends Activity {
- private EditText input, show;
- private Button sendBtn;
- private OutputStream os;
- private Handler handler;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super .onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- input = (EditText) findViewById(R.id.main_et_input);
- show = (EditText) findViewById(R.id.main_et_show);
- sendBtn = (Button) findViewById(R.id.main_btn_send);
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // 如果消息來自子線程
- if (msg.what == 0x234 ) {
- // 將讀取的內容追加顯示在文本框中
- show.append( "\n" + msg.obj.toString());
- }
- }
- };
- Socket socket;
- try {
- socket = new Socket( "192.168.0.101" , 20000 );
- // 客戶端啟動ClientThread線程不斷讀取來自服務器的數據
- new Thread( new ClientThread(socket, handler)).start();
- os = socket.getOutputStream();
- } catch (Exception e) {
- e.printStackTrace();
- }
- sendBtn.setOnClickListener( new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- // 將用戶在文本框內輸入的內容寫入網絡
- os.write((input.getText().toString() + "\r\n" ).getBytes());
- // 清空input文本框數據
- input.setText( "" );
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- package com.home.util;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.Socket;
- import android.os.Handler;
- import android.os.Message;
- public class ClientThread implements Runnable {
- private Handler handler;
- // 該線程所處理的Socket所對應的輸入流
- private BufferedReader br = null ;
- public ClientThread(Socket socket, Handler handler) throws IOException {
- this .handler = handler;
- br = new BufferedReader( new InputStreamReader(socket.getInputStream()));
- }
- @Override
- public void run() {
- try {
- String content = null ;
- // 不斷讀取Socket輸入流的內容
- while ((content = br.readLine()) != null ) {
- // 每當讀到來自服務器的數據之後,發送消息通知程序界面顯示該數據
- Message msg = new Message();
- msg.what = 0x234 ;
- msg.obj = content;
- handler.sendMessage(msg);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
- android:layout_width = "match_parent"
- android:layout_height = "match_parent"
- android:orientation = "vertical" >
- < LinearLayout
- android:layout_width = "match_parent"
- android:layout_height = "wrap_content"
- android:orientation = "horizontal" >
- < EditText
- android:id = "@+id/main_et_input"
- android:layout_width = "240dp"
- android:layout_height = "wrap_content" />
- < Button
- android:id = "@+id/main_btn_send"
- android:layout_width = "match_parent"
- android:layout_height = "wrap_content"
- android:paddingLeft = "10dp"
- android:text = "發送" />
- </ LinearLayout >
- < EditText
- android:id = "@+id/main_et_show"
- android:layout_width = "match_parent"
- android:layout_height = "match_parent"
- android:cursorVisible = "false"
- android:editable = "false"
- android:gravity = "top" />
- </ LinearLayout >
- < uses-permission android:name = "android.permission.INTERNET" />
沒有留言:
張貼留言