Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Socket通信

Android Socket通信

編輯:關於Android編程

Socket是基於Tcp的鏈接,適用於長鏈接
Socke通訊需要客戶端和服務器,客戶端我們在android上編寫,而服務器則選擇在eclipse上編寫

上效果圖;
\

eclipse:
我們一共需要4個類,分別是
Server類,繼承自Thread,用於建立服務器,並監聽Socket的鏈接
MySocket類,繼承自Thread,用於對Socket進行讀寫操作
SocketManager類,單態模式,管理Socket,不過主要的用途其實還是可以將信息發送給所有人
Start類,開啟Server類

Start:

package wkk.server.socket;

public class Start {

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

}

Server:

package wkk.server.socket;

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

public class Server extends Thread {
    private SocketManager manager;

    @Override
    public void run() {
        try {
            // 1-65535
            ServerSocket ss = new ServerSocket(1234);
            manager=SocketManager.getInstance();
            while (true) {
                // 此方法會阻塞線程 直至有人鏈接
                Socket socket = ss.accept();
                System.out.println("有客戶端連接上服務器了");
                MySocket socket1=new MySocket(socket);
                socket1.start();
                manager.add(socket1);
            }

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

new ServerSocket(1234);
這個方法的參數為int型端口號數值在1-65535之間,一般選擇較大值避免沖突
accept(),這個方法會阻塞線程,所以適合在主線程中進行操作,我們循環監聽Socket的鏈接,為每一個Socket開啟一個獨立的線程,並將Socket添加到SocketManager的list集合中

MySocket :

package wkk.server.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class MySocket extends Thread {

    private Socket socket;
    private SocketManager manager;

    public MySocket(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        manager=SocketManager.getInstance();
        try {
            //讀取並發送
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            String messageString = null;
            while ((messageString = reader.readLine()) != null) {
                System.out.println(messageString);
                manager.sendAll(this, messageString);
            }
            reader.close();
            manager.remove(this);
        } catch (Exception e) {
        }
    }
    //寫
    public void out(String out) {
        try {
            socket.getOutputStream().write((out + "\r\n").getBytes("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

在構造方法中傳入所需的Socket,繼承自Thread,在run方法中監聽客戶端發送來的消息,並將消息發送給所有人

SocketManager:

package wkk.server.socket;

import java.util.ArrayList;

public class SocketManager {

    private static SocketManager manager;

    private ArrayList list;

    private SocketManager() {
        list = new ArrayList();
    }

    public static SocketManager getInstance() {
        if (manager == null) {
            manager = new SocketManager();
        }
        return manager;
    }

    public void add(MySocket soc){
        list.add(soc);
    }

    public void remove(MySocket soc){
        list.remove(soc);
    }
    //發送給所有人
    public void sendAll(MySocket soc,String out){
        for (MySocket soc1 : list) {
            if(!soc.equals(soc1)){
                soc1.out(out);
            }
        }
    }

}

這個類就很簡單了,只有一個list並提過對外部的方法,增加,刪除,以及發送給除自己之外的所有人

好eclipse上就這些東西

接下來開始編寫Android的代碼:
 

<code class=" hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="wkk.app4.MainActivity">
 
 
    <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content">
 
        <edittext android:id="@+id/ip" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="輸入ip地址" android:text="192.168.1.110">
        <edittext android:id="@+id/code" android:layout_width="100dp" android:layout_height="wrap_content" android:hint="輸入端口號" android:text="1234">
        <button android:id="@+id/link" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="鏈接">
     
 
 
    <listview android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"></listview>
 
 
    <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content">
 
        <edittext android:id="@+id/message" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="輸入聊天信息">
 
        </edittext></linearlayout></button></edittext></edittext></linearlayout></linearlayout></code><button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="發送"><code class=" hljs xml">
     
 
 
 
</code></button>

 

整個布局很簡單,在上面已經看過效果圖了

listview的item也很簡單,之後一個TextView我就不貼了
適配器什麼的無關緊要,就不占用篇幅了,實體類就一個String和一個boolean,一個是用於顯示內容,一個是用於判斷是自己發出去的信息,還是其他人發出去的信息,來設置TextView的Gravity,實在不懂的等下可以下源碼

MainActivity:

package wkk.app4;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener,Handler.Callback {

    private EditText ip, code, message;
    private Button link, send;
    private ListView listview;
    private Socket socket;
    private InputStream inputStream;
    private OutputStream outputStream;
    private MyAdapter adapter;
    private List list;
    private String[] ipandcode;//裡面的內容分別是ip地址和端口號
    private Handler handler;
    private BufferedWriter writer;//對outputStream包裝用於發送信息
    private static final int MESSAGE=0;
    private static final int SUCCEED=1;
    private static final int FAILURE=2;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化相應數據
        findview();
        adapter = new MyAdapter(this);
        listview.setAdapter(adapter);
        list = adapter.getList();
        handler=new Handler(this);
    }

    private void findview() {
        ip = (EditText) findViewById(R.id.ip);
        code = (EditText) findViewById(R.id.code);
        message = (EditText) findViewById(R.id.message);
        link = (Button) findViewById(R.id.link);
        send = (Button) findViewById(R.id.send);
        listview = (ListView) findViewById(R.id.listview);

        link.setOnClickListener(this);
        send.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.link:
                String ipt = ip.getText().toString().trim();
                String codet = code.getText().toString().trim();
                if (TextUtils.isEmpty(ipt) || TextUtils.isEmpty(codet)) {
                    return;
                }
                if (socket != null) {
                    Toast.makeText(this,"已連接",Toast.LENGTH_SHORT).show();
                    return;
                }
                ipandcode = new String[2];
                ipandcode[0] = ipt;
                ipandcode[1] = codet;
                //使用異步任務來進行網絡操作
                new MyAsyncTask().execute();
                break;
            case R.id.send:
                if(writer==null){
                    Toast.makeText(this,"請先鏈接",Toast.LENGTH_SHORT).show();
                    return;
                }
                try {
                    //發送數據
                    writer.write(message.getText().toString().trim() + "\n");
                    writer.flush();
                    Bean bean=new Bean();
                    bean.setMessage( message.getText().toString().trim());
                    bean.setIsmy(true);
                    list.add(bean);
                    message.setText("");
                    adapter.notifyDataSetChanged();
                } catch (IOException e) {
                    Log.d("測試",e.toString());
                }
                break;
        }
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch(msg.what){
            case MESSAGE:
                //獲取信息刷新界面
                String message= (String) msg.obj;
                Bean bean=new Bean();
                bean.setMessage(message);
                bean.setIsmy(false);
                list.add(bean);
                adapter.notifyDataSetChanged();
                break;
            case SUCCEED:
                Toast.makeText(this,"鏈接成功",Toast.LENGTH_SHORT).show();
                break;
            case FAILURE:
                Toast.makeText(this,"鏈接失敗",Toast.LENGTH_SHORT).show();
                break;
        }

        return true;
    }

    private class MyAsyncTask extends AsyncTask {

        @Override
        protected String doInBackground(Void... params) {
            try {
                //參數 ip地址 端口號
                socket=new Socket(ipandcode[0],Integer.parseInt(ipandcode[1]));
                Message msg= handler.obtainMessage();
                msg.what=SUCCEED;
                handler.sendMessage(msg);
            } catch (IOException e) {
                Message msg= handler.obtainMessage();
                msg.what=FAILURE;
                handler.sendMessage(msg);
                return null;
            }

            try {
                outputStream = socket.getOutputStream();
                inputStream = socket.getInputStream();

                writer=new BufferedWriter(new OutputStreamWriter(outputStream));
                //監聽服務器傳遞過來的信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String message = null;
                while ((message = reader.readLine()) != null) {
                    Message msg= handler.obtainMessage();
                    msg.what=MESSAGE;
                    msg.obj=message;
                    handler.sendMessage(msg);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Void... values) {

        }
    }

}

整個Activity代碼看起來有點復雜,但是邏輯並不多,無非就是連接服務器,向服務器發送數據,監聽服務器傳遞過來的數據並且刷新界面這些而已,核心代碼就那麼多,和服務器上的代碼幾乎一樣,無非就是接收和發送數據罷了:

      //發送數據
      writer.write(message.getText().toString().trim() + "\n");
      writer.flush();

接收:

                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String message = null;
                while ((message = reader.readLine()) != null) {
                    Message msg= handler.obtainMessage();
                    msg.what=MESSAGE;
                    msg.obj=message;
                    handler.sendMessage(msg);
                }

好了,接下來,你只要將eclipse的服務開啟,然後就可以聊天了,當然界面很簡介,有興趣可以給它拓展下…

整個代碼就這麼多,看清楚了真的不難,但是這個demo只能在局域網下進行通訊,如果想放到外網上這些代碼肯定不行,會很麻煩,如果有興趣可以自己去嘗試下,
額…………

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved