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();
}
}