首页 > 代码库 > Android入门笔记 - 网络通信 - Socket

Android入门笔记 - 网络通信 - Socket

今天来学习一下android中通信方式中的socket。上两次我们分别使用了HttpURLConnection , 和 HttpClient来实现通信,他们都是在使用HTTP协议,Socket被称为套接字,使用的协议有TCP和UDP,TCP和UDP的区别在于TCP是可靠稳定的,自带容错处理等优点,所以效率要低一点。然后UDP就不那么稳定了,当使用UDP发送数据的时候,每次send,那么socket只管send,不会管send之后对方是否收到,是否顺序正确,所以UDP被称为不稳定的传输,但是其效率却很高,因为做的事情很简单。

今天我们学习socket是使用tcp协议,在android中使用socket其实就是使用java中的socket,看应用的包 java.net.*; 就知道。


我们来完成一个小的局域网聊天的程序,包含一个服务器,android应用作为客户端,一台手机发送信息后,服务器会转发给其他手机,很简单。代码比较多,后面附上下载地址,我们先来看怎么使用socket。


客户端:

客户端Socket使用步骤:

(1)Socket mSocket = new Socket( SERVER_IP, SERVER_PORT); // 两个参数分别为服务器ip地址,和服务器监听的端口号

(2)BufferedReader  mBufferReader = new BufferedReader(new InputStreamReader( mSocket.getInputStream()));  // 通过socket.getInputStream() 可以得到输入流,可从socket获取服务器发送的数据。为了能一行一行读取,我们将其转化为 BufferReader,可以使用BufferReader.readLine() 一行一行得去取等待在socket上的数据。

(3)PrintWriter  mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true); // 通过socket.getOutputStream() 可以得到输入流,就可以通过socket向服务器发送数据, 这里需要套上 PrintWriter 标准的接口,就可以使用 mPrintWriter.println(“ ..." ),直接发送数据。

(4)使用完后断开连接。

我们来看一看实例:

mSocket = new Socket(SERVER_IP, SERVER_POART);
mBufferReader = new BufferedReader(new InputStreamReader(
	mSocket.getInputStream()));
mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true);
如果没有报 Exception那就表示链接服务器已经成功,这时就可以使用 mBufferReader和 mPrintWrinter 来实现数据的收发。

读取数据:

                while (true) {
                    if (null != (mStrMsg = mBufferReader.readLine())) {
                        mStrMsg += "\n";
                        if(mStrMsg.trim().equals("exit")){
                            mHandler.sendMessage(mHandler.obtainMessage(2));
                            return ;
                        }
                        mHandler.sendMessage(mHandler.obtainMessage(0));
                    }
                }
发送数据:

    private View.OnClickListener sendListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String str = mEtMessage.getText().toString().trim();
            if(mPrintWriter == null){
                showToast("请先连接服务器!");
                return ;
            }
            mPrintWriter.println(str);
            mPrintWriter.flush();
            mEtMessage.setText("");
        }
    };
断开连接:

showToast("断开连接");
    try {
	mBufferReader.close();
	mPrintWriter.close();
	mSocket.close();
	mSocket = null;
	if (mGetMessageThread != null) {
	    mGetMessageThread = null;
	}
     } catch (IOException e) {
          e.printStackTrace();
     }

服务端:

在服务端我们需要有一个ServerSocket,这是用来接收连接请求的,当每接收到一个一个请求后就会返回一个Socket套接字,就可以使用这个套接字与客户端通信。注意:服务器端应该是一直运行,且可以接收很多连接的程序,服务器程序一定不能被关闭或者崩掉,所以在设计服务器的时候要考虑很多很多事情,我们这里只是简单的处理收到客户端请求连接,然后将其加入到list当中,如果收到消息,就将收到的消息转发给列表中其他所有socket,很简单的处理。

使用步骤:

(1)ServerSocket mServerSocket = new ServerSocket(SERVERPORT); // 创建监听连接ServerSocket

(2)不停监听 mServerSocket, 使用accept() 接收连接,如果侦测到连接,就启动一个线程,将返回值socket传入,那么每个线程就对应一个客户端,可以与客户端通信了。

(3)接下来就是 每个线程如果收到数据,就需要将消息转发给 客户单列表中所有其他用户。

(4)客户端断开链接后,清除客户socket信息。

启动监听连接,并启动一个线程池,当监听到连接请求时创建启动线程,并放入到线程池中运行:

        try {
            mServerSocket = new ServerSocket(SERVERPORT);
            mExecutorService = Executors.newCachedThreadPool();
            System.out.println("Server Start...");
            Socket client = null;
            while (true) {
                client = mServerSocket.accept();
                mClientList.add(client);
                mExecutorService.execute(new ThreadServer(client));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
线程中接收消息,以及转发消息:

    private class ThreadServer implements Runnable {
        private Socket mClient;
        private BufferedReader mBufferedReader;
        private PrintWriter mPrintWriter;
        private String mStrMsg;

        public ThreadServer(Socket client) throws IOException {
            this.mClient = client;
            mBufferedReader = new BufferedReader(new InputStreamReader(
                    mClient.getInputStream()));
            mStrMsg = "usr:" + this.mClient.getInetAddress() + " connected"
                    + ",total:" + mClientList.size();
            sendMessage(mStrMsg);
        }

        private void sendMessage(String msg) throws IOException {
            System.out.println(msg);
            for (Socket client : mClientList) {
                mPrintWriter = new PrintWriter(client.getOutputStream(), true);
                mPrintWriter.println(msg);
            }
        }

        @Override
        public void run() {
            try {
                while (null != (mStrMsg = mBufferedReader.readLine())) {
                    if (mStrMsg.trim().equals("exit")) {
                        mStrMsg = "user:" + mClient.getInetAddress() + " exit!"
                                + "total:" + (mClientList.size() - 1);
                        sendMessage(mStrMsg);

                        mPrintWriter = new PrintWriter(
                                mClient.getOutputStream(), true);
                        mPrintWriter.println("exit");

                        mBufferedReader.close();
                        mPrintWriter.close();
                        mClientList.remove(mClient);
                        mClient.close();
                        break;
                    } else {
                        mStrMsg = mClient.getInetAddress() + ":" + mStrMsg;
                        sendMessage(mStrMsg);
                    }
                }
            } catch (SocketException e) {
                // e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


如果没有网络基础,这个理解起来还是有点复杂的,下面贴了项目代码,大家自己去体会一下吧,使用socket其实很简单,主要是逻辑处理。

这里有几点需要注意的:

(1)android2.3之后不能再UI主线程中调用网络请求,会直接崩溃,所以需要使用handler来发送消息处理

(2)实例代码放在你的机子上不一定能使用,SERVER_IP为计算机在局域网的本机地址,需要自己修改。 android客户端需要连上计算机,这样客户端就能找到服务器了。


代码下载地址:

http://download.csdn.net/detail/u013647382/8273861


Android入门笔记 - 网络通信 - Socket