Android Socket連接

efbb 9年前發布 | 44K 次閱讀 Android Android開發 移動開發

注意點:注冊訪問的網絡權限;android中UI線程不能有訪問網絡的操作,否則會報android.os.NetworkOnMainThreadException的異常


<uses-permission   
    android:name="android.permission.INTERNET"/>



實例一

客戶端

Android Socket連接

Java:

package com.android.xiong.simplesocket;  

import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.io.OutputStream;  
import java.net.InetSocketAddress;  
import java.net.Socket;  
import java.net.SocketTimeoutException;  

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

public class MainActivity extends Activity {  
    Socket socket = null;  
    String buffer = "";  
    TextView txt1;  
    Button send;  
    EditText ed1;  
    String geted1;  
    public Handler myHandler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            if (msg.what == 0x11) {  
                Bundle bundle = msg.getData();  
                txt1.append("server:"+bundle.getString("msg")+"\n");  
            }  
        }  

    };  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        txt1 = (TextView) findViewById(R.id.txt1);  
        send = (Button) findViewById(R.id.send);  
        ed1 = (EditText) findViewById(R.id.ed1);  
        send.setOnClickListener(new OnClickListener() {  

            @Override  
            public void onClick(View v) {  
                geted1 = ed1.getText().toString();  
                txt1.append("client:"+geted1+"\n");  
                //啟動線程 向服務器發送和接收信息  
                new MyThread(geted1).start();  
            }  
        });  

    }  

    class MyThread extends Thread {  

        public String txt1;  

        public MyThread(String str) {  
            txt1 = str;  
        }  

        @Override  
        public void run() {  
            //定義消息  
            Message msg = new Message();  
            msg.what = 0x11;  
            Bundle bundle = new Bundle();  
            bundle.clear();  
            try {  
                //連接服務器 并設置連接超時為5秒  
                socket = new Socket();  
                socket.connect(new InetSocketAddress("1.1.9.30", 30000), 5000);  
                //獲取輸入輸出流  
                OutputStream ou = socket.getOutputStream();  
                BufferedReader bff = new BufferedReader(new InputStreamReader(  
                        socket.getInputStream()));  
                //讀取發來服務器信息  
                String line = null;  
                buffer="";  
                while ((line = bff.readLine()) != null) {  
                    buffer = line + buffer;  
                }  

                //向服務器發送信息  
                ou.write("android 客戶端".getBytes("gbk"));  
                ou.flush();  
                bundle.putString("msg", buffer.toString());  
                msg.setData(bundle);  
                //發送消息 修改UI線程中的組件  
                myHandler.sendMessage(msg);  
                //關閉各種輸入輸出流  
                bff.close();  
                ou.close();  
                socket.close();  
            } catch (SocketTimeoutException aa) {  
                //連接超時 在UI界面顯示消息  
                bundle.putString("msg", "服務器連接失敗!請檢查網絡是否打開");  
                msg.setData(bundle);  
                //發送消息 修改UI線程中的組件  
                myHandler.sendMessage(msg);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        // Inflate the menu; this adds items to the action bar if it is present.  
        getMenuInflater().inflate(R.menu.main, menu);  
        return true;  
    }  

}



XML:



<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"  
    android:paddingLeft="@dimen/activity_horizontal_margin"  
    android:paddingRight="@dimen/activity_horizontal_margin"  
    android:paddingTop="@dimen/activity_vertical_margin"  
    tools:context=".MainActivity" >  

    <EditText   
        android:id="@+id/ed1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:hint="給服務器發送信息"/>  
    <Button   
        android:id="@+id/send"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_below="@id/ed1"  
        android:text="發送"/>  
    <TextView   
        android:id="@+id/txt1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_below="@id/send"/>  




</RelativeLayout>



服務端

package com.android.net;  

import java.io.IOException;  
import java.net.ServerSocket;  
import java.net.Socket;  
import java.util.ArrayList;  
import java.util.List;  

public class AndroidService {  


    public static void main(String[] args) throws IOException {  
        ServerSocket serivce = new ServerSocket(30000);  
        while (true) {  
            //等待客戶端連接  
            Socket socket = serivce.accept();  
            new Thread(new AndroidRunable(socket)).start();  
        }  
    }  

}



package com.android.net;  

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.io.PrintWriter;  
import java.net.Socket;  

public class AndroidRunable implements Runnable {  

    Socket socket = null;  

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

    @Override  
    public void run() {  
        // 向android客戶端輸出hello worild  
        String line = null;  
        InputStream input;  
        OutputStream output;  
        String str = "hello world!";  
        try {  
            //向客戶端發送信息  
            output = socket.getOutputStream();  
            input = socket.getInputStream();  
            BufferedReader bff = new BufferedReader(  
                    new InputStreamReader(input));  
            output.write(str.getBytes("gbk"));  
            output.flush();  
            //半關閉socket    
            socket.shutdownOutput();  
            //獲取客戶端的信息  
            while ((line = bff.readLine()) != null) {  
                System.out.print(line);  
            }  
            //關閉輸入輸出流  
            output.close();  
            bff.close();  
            input.close();  
            socket.close();  

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

    }  
}



實例二

客戶端

Java



package com.android.xiong.sockettwotest;  

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

public class MainActivity extends Activity {  

    // 定義界面上的兩個文本框  
    EditText input;  
    TextView show;  
    // 定義界面上的一個按鈕  
    Button send;  
    Handler handler;  
    // 定義與服務器通信的子線程  
    ClientThread clientThread;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        input = (EditText) findViewById(R.id.input);  
        show = (TextView) findViewById(R.id.show);  
        send = (Button) findViewById(R.id.send);  
        handler = new Handler() {  

            @Override  
            public void handleMessage(Message msg) {  
                // 如果消息來自子線程  
                if (msg.what == 0x123) {  
                    // 將讀取的內容追加顯示在文本框中  
                    show.append("\n" + msg.obj.toString());  
                }  
            }  
        };  
        clientThread = new ClientThread(handler);  
        // 客戶端啟動ClientThread線程創建網絡連接、讀取來自服務器的數據  
        new Thread(clientThread).start();  
        send.setOnClickListener(new OnClickListener() {  

            @Override  
            public void onClick(View v) {  
                try {  
                    // 當用戶按下按鈕之后,將用戶輸入的數據封裝成Message  
                    // 然后發送給子線程Handler  
                    Message msg = new Message();  
                    msg.what = 0x345;  
                    msg.obj = input.getText().toString();  
                    clientThread.revHandler.sendMessage(msg);  
                    input.setText("");  

                } catch (Exception e) {  

                }  
            }  
        });  
    }  

    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        getMenuInflater().inflate(R.menu.main, menu);  
        return true;  
    }  

}



package com.android.xiong.sockettwotest;  

import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.io.OutputStream;  
import java.net.InetSocketAddress;  
import java.net.Socket;  
import java.net.SocketTimeoutException;  

import android.os.Handler;  
import android.os.Looper;  
import android.os.Message;  

public class ClientThread implements Runnable {  
    private Socket s;  
    // 定義向UI線程發送消息的Handler對象  
    Handler handler;  
    // 定義接收UI線程的Handler對象  
    Handler revHandler;  
    // 該線程處理Socket所對用的輸入輸出流  
    BufferedReader br = null;  
    OutputStream os = null;  

    public ClientThread(Handler handler) {  
        this.handler = handler;  
    }  

    @Override  
    public void run() {  
        s = new Socket();  
        try {  
            s.connect(new InetSocketAddress("1.1.9.30", 3000), 5000);  
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));  
            os = s.getOutputStream();  
            // 啟動一條子線程來讀取服務器相應的數據  
            new Thread() {  

                @Override  
                public void run() {  
                    String content = null;  
                    // 不斷的讀取Socket輸入流的內容  
                    try {  
                        while ((content = br.readLine()) != null) {  
                            // 每當讀取到來自服務器的數據之后,發送的消息通知程序  
                            // 界面顯示該數據  
                            Message msg = new Message();  
                            msg.what = 0x123;  
                            msg.obj = content;  
                            handler.sendMessage(msg);  
                        }  
                    } catch (IOException io) {  
                        io.printStackTrace();  
                    }  
                }  

            }.start();  
            // 為當前線程初始化Looper  
            Looper.prepare();  
            // 創建revHandler對象  
            revHandler = new Handler() {  

                @Override  
                public void handleMessage(Message msg) {  
                    // 接收到UI線程的中用戶輸入的數據  
                    if (msg.what == 0x345) {  
                        // 將用戶在文本框輸入的內容寫入網絡  
                        try {  
                            os.write((msg.obj.toString() + "\r\n")  
                                    .getBytes("gbk"));  
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }  

            };   
            // 啟動Looper  
            Looper.loop();  

        } catch (SocketTimeoutException e) {  
            Message msg = new Message();  
            msg.what = 0x123;  
            msg.obj = "網絡連接超時!";  
            handler.sendMessage(msg);  
        } catch (IOException io) {  
            io.printStackTrace();  
        }  

    }  
}



XML:



<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"  
    android:paddingLeft="@dimen/activity_horizontal_margin"  
    android:paddingRight="@dimen/activity_horizontal_margin"  
    android:paddingTop="@dimen/activity_vertical_margin"  
    tools:context=".MainActivity" >  

    <EditText  
        android:id="@+id/input"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:hint="@string/input" />  
    <Button   
        android:id="@+id/send"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="@string/send"  
        android:layout_below="@id/input"/>  
    <TextView   
        android:id="@+id/show"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_below="@id/send"/>  

</RelativeLayout>





服務端

package com.android.net;  

import java.io.IOException;  
import java.net.ServerSocket;  
import java.net.Socket;  
import java.util.ArrayList;  
import java.util.List;  

public class MyService {  

    // 定義保存所有的Socket  
    public static List<Socket> socketList = new ArrayList<Socket>();  

    public static void main(String[] args) throws IOException {  
        ServerSocket server = new ServerSocket(3000);  
        while(true){  
            Socket s=server.accept();  
            socketList.add(s);  
            //每當客戶端連接之后啟動一條ServerThread線程為該客戶端服務  
            new Thread(new ServiceThreada(s)).start();  

        }  
    }  

}



package com.android.net;  

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

public class ServiceThreada implements Runnable {  

    // 定義當前線程處理的Socket  
    Socket s = null;  
    // 該線程所處理的Socket所對應的輸入流  
    BufferedReader br = null;  

    public ServiceThreada(Socket s) {  
        this.s = s;  
        try {  
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    @Override  
    public void run() {  

        String content = null;  
        //采用循環不斷的從Socket中讀取客戶端發送過來的數據  
        while((content=readFromClient())!=null){  
            //遍歷socketList中的每個Socket  
            //將讀取到的內容每個向Socket發送一次  
            for(Socket s:MyService.socketList){  
                OutputStream os;  
                try {  
                    os = s.getOutputStream();  
                    os.write((content+"\n").getBytes("gbk"));  
                } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  

            }  
        }  

    }  

    // 定義讀取客戶端的信息  
    public String readFromClient() {  
        try {  
            return br.readLine();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  

}




附:

一些記錄:

把socket寫成一個服務:


public class SocketService extends Service{  
    Thread mServiceThread;  

    Socket client;  

    @Override  
    public IBinder onBind(Intent intent) {  
        // TODO Auto-generated method stub  
        return null;  
    }  

    @Override  
    public void onCreate() {  
        // TODO Auto-generated method stub  
        super.onCreate();  

        mServiceThread = new Thread(new SocketServerThread());  
    }  

    @Override  
    public void onStart(Intent intent, int startId) {  
        // TODO Auto-generated method stub  
        super.onStart(intent, startId);  

        mServiceThread.start();  
    }  

    @Override  
    public void onDestroy() {  
        // TODO Auto-generated method stub  
        super.onDestroy();  
    }  

    public class SocketServerThread extends Thread {  
        private static final int PORT = 54321;  

        private SocketServerThread(){  
        }  

        @Override  
        public void run() {  
            try {  
                ServerSocket server = new ServerSocket(PORT);  

                while(true){  
                    System.out.println("begin client connected");  
                    client = server.accept();  
                    System.out.println("client connected");  

                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));  
                    System.out.println("read from client:");  

                    String textLine = reader.readLine();  
                    if(textLine.equalsIgnoreCase("EXIT")){  
                        System.out.println("EXIT invoked, closing client");  
                        break;  
                    }  

                    System.out.println(textLine);  

                    PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())));  

                    writer.println("ECHO from server: " + textLine);  
                    writer.flush();  

                    writer.close();  
                    reader.close();  
                }                             
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                System.err.println(e);  
            }     
        }  

    }  
}


狀態:

除了isClose方法,Socket類還有一個isConnected方法來判斷Socket對象是否連接成功。 看到這個名字,也許讀者會產生誤解。 其實isConnected方法所判斷的并不是Socket對象的當前連接狀態, 而是Socket對象是否曾經連接成功過,如果成功連接過,即使現在isClose返回true, isConnected仍然返回true。因此,要判斷當前的Socket對象是否處于連接狀態, 必須同時使用isClose和isConnected方法, 即只有當isClose返回false,isConnected返回true的時候Socket對象才處于連接狀態。 雖然在大多數的時候可以直接使用Socket類或輸入輸出流的close方法關閉網絡連接,但有時我們只希望關閉OutputStream或InputStream,而在關閉輸入輸出流的同時,并不關閉網絡連接。這就需要用到Socket類的另外兩個方法:shutdownInput和shutdownOutput,這兩個方法只關閉相應的輸入、輸出流,而它們并沒有同時關閉網絡連接的功能。和isClosed、isConnected方法一樣,Socket類也提供了兩個方法來判斷Socket對象的輸入、輸出流是否被關閉,這兩個方法是isInputShutdown()和isOutputShutdown()。 shutdownInput和shutdownOutput并不影響Socket對象的狀態。

 本文由用戶 efbb 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!