Android的Socket通信分为两块,它们分别是TCP和UDP。

  TCP与UDP两者相较而言,TCP是重量级长连接,可靠的,有序的,无边界的,速度较慢;而UDP是轻量级无连接,不可靠,无序,有边界,速度较快。目前的应用场景来说,TCP用于不能出错的场合,如金融、文件传输(其中,金融的FIX协议是基于TCP协议的)。而UDP则是主要运用在语音通话、直播等速度要求很高的地方,中间即便出现小错误,如串音,卡顿一两帧,也不要紧。

  这篇介绍Android端的TCP通信。

  首先,TCP通信是长连接,所以,在开始通信前要三次握手。设备通过IP找到接收端,对指定端口发出数据。接收端需要在指定端口监听,如果接收端没有监听,握手就会失败,发送端能够获知连接被拒。

  然后,我需要知道端收端的IP和监听端口,假设接收的IP是192.168.0.50,监听端口是4444(如果是手机的IP可以在设置中的关于手机里面的手机状态里查看到IP信息)。

  先上发送部分代码

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.send_btn:
                String content = editText.getText().toString();
                if (content == null) {
                    content = "null";
                }

                final String finalContent = content;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        connectServerWithTCPSocekt(finalContent, "192.168.0.50", 4444);
                    }
                }).start();

                break;
        }
    }

    private void connectServerWithTCPSocekt(String str, String address, int port) {
        Socket socket = null;
        OutputStream ou = null;
        try {
            //连接服务器 并设置连接超时为5秒
            socket = new Socket();
            socket.connect(new InetSocketAddress(address, port), 5000);
            //获取输出流
            ou = socket.getOutputStream();
            //向服务器发送信息
            if (str != null) {
                ou.write(str.getBytes("utf-8"));
            } else {
                ou.write("null".getBytes("utf-8"));
            }

        } catch (SocketTimeoutException e) {
            //连接超时 在UI界面显示消息
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (ou != null) {
                    ou.flush();
                    //关闭各种输出流
                    ou.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 

 

   我们可以从上面的代码中发现,关于TCP的发送,我们需要写在一个新线程中,不能放入UI线程。因为网络连接不能保证过程的顺利,有可能造成线程阻塞,所以,不能放在UI线程中阻塞UI线程的响应。

  上面代码大致的过程是,新键Socket接,设置连接的IP和端口,后面的5000是超时时间即5秒。然后获取socket的输出流。将想要发送的字符串转成"utf-8"格式的字符数组,然后输出流写字符数组。最后确认输出完毕,关闭输出流、关闭socket连接。

  

  发送部分比较简单,我们再来看看接收部分

 EditText editText;
    Button sendButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.display_window);
        sendButton = (Button) findViewById(R.id.send_btn);
        sendButton.setOnClickListener(this);
        new Thread(new Runnable() {
            @Override
            public void run() {
                receiveServerSocketData(4444);
            }
        }).start();
    }

    private void receiveServerSocketData(int port) {
        BufferedReader bff = null;
        InputStream input = null;
        Socket socket = null;
        try {
            ServerSocket serivce = new ServerSocket(port);
            while (true) {
                socket = serivce.accept();
                String line = null;

                // 获取socket输入流
                input = socket.getInputStream();
                bff = new BufferedReader(new InputStreamReader(input));
                StringBuilder sb = new StringBuilder();
                // 获取客户端的信息
                while ((line = bff.readLine()) != null) {
                    // 拼接内容信息
                    sb.append(line);
                    sb.append("\n");
                }
                if (!sb.toString().isEmpty()){
                    sb.deleteCharAt(sb.length() - 1);
                    Message message = Message.obtain();
                    Bundle bundle = new Bundle();
                    bundle.putString("content", sb.toString());
                    message.setData(bundle);
                    message.what = 1001;
                    handler.sendMessage(message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭输入流
            try {
                if (bff != null) {
                    bff.close();
                }
                if (input != null) {
                    input.close();
                }
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1001:
                    if (msg.getData().getString("content") != null) {
                        editText.setText(msg.getData().getString("content"));
                    } else {
                        editText.setText("null");
                    }
                    break;
            }
        }
    };

  上面的代码分三部分:

  一、开启线程,监听4444端口的消息。

 

  二、接收Socket数据:

  1、先建ServerSocket;

  2、打开监听阻塞线程,只有接收到消息,线程才会继续;

  3、获取Socket的输入流;

  4、新建BufferedReader;

  5、读取输入流的内容并拼接字符串;

  6、如果读取的内容不为空,将内容通过handler发往UI线程,用于显示;

  7、关闭输入流和Socket。

  三、显示内容。

 

至此,就完成了一次简单的TCP发送和接收的过程。

 

 Done!

 

 

 

 

 

 

Socket 

socket = null;
OutputStream ou = null;
try {
//连接服务器 并设置连接超时为5
socket = new Socket();
socket.connect(new InetSocketAddress(address, port), 5000);
//获取输出流
ou = socket.getOutputStream();
//向服务器发送信息
if (str != null) {
ou.write(str.getBytes("utf-8"));
} else {
ou.write("null".getBytes("utf-8"));
}

} catch (SocketTimeoutException e) {
//连接超时 在UI界面显示消息
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (ou != null) {
ou.flush();
//关闭各种输出流
ou.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
posted on 2015-11-29 21:29  Fishbonell  阅读(297)  评论(0编辑  收藏  举报