实现Android下简单的Socket通信功能

  • Post author:
  • Post category:其他



1,Socket通信的实现步骤

Socket 通信和 Binder 通信类似,也是一种 C(Clent)/S(Server) 模型的通信方式。


1.1 Server 服务端


步骤一: 建立一个服务器 Socket

常见的一个服务器 Socket 类是 ServerSocket,ServerSocket 类常用三个方法:binder 、accept、close。

bind 方法为 ServerSocket 绑定 IP 地址和端口号,并开始监听该端口;accept 方法为 ServerSocket 接收请求并返回一个Socket 对象,accept 方法调用之后将一直阻塞,直到有请求达到;close 方法关闭一个 ServerSocket 对象。

初始化是一般需要设定 IP 地址和端口号


步骤二: 通过监听获取一个用于通信的 Socket 对象

执行 accept 方法即可实现


步骤三:

在一个新线程中,通过对 Socket 对象进行封装,分别得到输入、输出流的引用对象,通过这两个对象向 Client 端发送或者从 Client 端接收数据,进而实现 Socket 通信。

一般选择在循环中读取 Client 发送过来的信息,并作出对应的处理,比如反馈 Client 端:自己已成功收到相应的消息。


步骤四:

在适当的时机关闭 Socket 连接。


服务器端代码:

public class SocketTest {
 
    private static final int PORT = 9999;
    private List<Socket> mList = new ArrayList<Socket>();
    private ServerSocket server = null;
    private ExecutorService mExecutorService = null;
    private String receiveMsg;
    private String sendMsg;
 
    public static void main(String[] args) {
        new SocketTest();
    }
 
    public SocketTest() {
        try {
            server = new ServerSocket(PORT);                         //步骤一
            mExecutorService = Executors.newCachedThreadPool();
            System.out.println("服务器已启动...");
            Socket client = null;
            while (true) {
                client = server.accept();         //步骤二,每接受到一个新Socket连接请求,就会新建一个Thread去处理与其之间的通信
                mList.add(client);
                mExecutorService.execute(new Service(client));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    class Service implements Runnable {
        private Socket socket;
        private BufferedReader in = null;
        private PrintWriter printWriter=null;
 
        public Service(Socket socket) {                         //这段代码对应步骤三
            this.socket = socket;
            try {
                printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(), "UTF-8")), true);
                in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream(),"UTF-8"));
                printWriter.println("成功连接服务器"+"(服务器发送)");
                System.out.println("成功连接服务器");
            } catch (IOException e) {
                e.printStackTrace();
            }
 
        }
 
        @Override
        public void run() {
            try {
                while (true) {                                   //循环接收、读取 Client 端发送过来的信息
                    if ((receiveMsg = in.readLine())!=null) {
                        System.out.println("receiveMsg:"+receiveMsg);
                        if (receiveMsg.equals("0")) {
                            System.out.println("客户端请求断开连接");
                            printWriter.println("服务端断开连接"+"(服务器发送)");
                            mList.remove(socket);
                            in.close();
                            socket.close();                         //接受 Client 端的断开连接请求,并关闭 Socket 连接
                            break;
                        } else {
                            sendMsg = "我已接收:" + receiveMsg + "(服务器发送)";
                            printWriter.println(sendMsg);           //向 Client 端反馈、发送信息
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

1.2 Client 客户端


步骤一:

初始化 Socket 对象

客户端一般选择在一个新的线程中,初始化一个 Socket 对象,初始化是需要设置 IP 和端口号,以帮助低层网络路由找到相应的服务端进程。


步骤二:

获取与 Server 端通信的引用

此步和 Server 端建立连接后的步骤类似:根据步骤一中获取的 Socket 对象,进行封装,得到相应的输入、输出流对象,这些输入、输出流对象就是和 Server 端进行通信的引用。


步骤三:

通过步骤二中得到的引用,循环的读取(在新线程中) Server 端发送过来的消息,并做相应的处理


步骤四:

在合适的时机关闭与 Server 端的 Socket 连接。


客户端代码:

public class SocketActivity extends AppCompatActivity {
 
    private EditText mEditText;
    private TextView mTextView;
    private static final String TAG = "TAG";
    private static final String HOST = "192.168.23.1";
    private static final int PORT = 9999;
    private PrintWriter printWriter;
    private BufferedReader in;
    private ExecutorService mExecutorService = null;
    private String receiveMsg;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);
        mEditText = (EditText) findViewById(R.id.editText);
        mTextView = (TextView) findViewById(R.id.textView);
        mExecutorService = Executors.newCachedThreadPool();
    }
 
    public void connect(View view) {
        mExecutorService.execute(new connectService());  //在一个新的线程中请求 Socket 连接
    }
 
    public void send(View view) {
        String sendMsg = mEditText.getText().toString();
        mExecutorService.execute(new sendService(sendMsg));
    }
 
    public void disconnect(View view) {
        mExecutorService.execute(new sendService("0"));
    }
 
    private class sendService implements Runnable {
        private String msg;
 
        sendService(String msg) {
            this.msg = msg;
        }
 
        @Override
        public void run() {
            printWriter.println(this.msg);
        }
    }
 
    private class connectService implements Runnable {
        @Override
        public void run() {//可以考虑在此处添加一个while循环,结合下面的catch语句,实现Socket对象获取失败后的超时重连,直到成功建立Socket连接
            try {
                Socket socket = new Socket(HOST, PORT);      //步骤一
                socket.setSoTimeout(60000);
                printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(   //步骤二
                        socket.getOutputStream(), "UTF-8")), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                receiveMsg();
            } catch (Exception e) {
                Log.e(TAG, ("connectService:" + e.getMessage()));   //如果Socket对象获取失败,即连接建立失败,会走到这段逻辑
            }
        }
    }
 
    private void receiveMsg() {
        try {
            while (true) {                                      //步骤三
                if ((receiveMsg = in.readLine()) != null) {
                    Log.d(TAG, "receiveMsg:" + receiveMsg);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mTextView.setText(receiveMsg + "\n\n" + mTextView.getText());
                        }
                    });
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "receiveMsg: ");
            e.printStackTrace();
        }
    }
}

基本的实现步骤就是这样。