Android TCP通讯
在移动应用开发中,网络通讯是一项基本且重要的功能,Android平台提供了多种方式来实现网络通讯,其中传输控制协议(TCP)因其可靠性和面向连接的特性,被广泛应用于需要稳定数据传输的场景,本文将详细介绍如何在Android平台上实现TCP通讯,包括客户端和服务端的实现过程、注意事项以及常见问题的解决方案。
一、TCP通讯基础简介
1. 关于IP
IP地址:TCP通讯时,客户端Socket在与服务端建立连接时需要知道服务器的IP地址,这里设置的是服务端IP,而不是客户端设备的IP。
2. 关于端口
端口范围:端口号的范围是0-65535,一般选择较大的数值以避免端口使用冲突。
常用端口:一些常用的端口如80(HTTP)、443(HTTPS)等已被广泛使用,自定义应用应避免使用这些端口。
二、TCP客户端的封装类TcpClient简介
为了让TCP客户端Socket连接在Android上使用更加方便,我们封装了一个工具类——TcpClient,下面是TcpClient的几个主要方法:
设置连接超时时间:public TcpClient setConnectTimeOut(int timeOut)
设置建立连接的参数:public TcpClient setSocket(String ip, int port)
发送消息:public void sendMessage(String message, String charsetName)
接收消息:public String receiveMessage(String charsetName)
关闭连接:public void close()
其在Android中的使用流程大致如下:
// 声明 private TcpClient mTcpClient; // 初始化并设置连接参数 mTcpClient = new TcpClient(); mTcpClient.setConnectTimeOut(5000).setSocket("192.168.50.152", 12345); // 点击按钮时发送消息并接收返回数据 @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn1: //测试 test(); break; default: break; } } private void test() { new Thread(new Runnable() { @Override public void run() { String message = "我是客户端a"; message = SocketHelper.getMessageByReadLine(message); mTcpClient.sendMessage(message, SocketConfig.UTF_8); String result = mTcpClient.receiveMessage(SocketConfig.UTF_8); runOnUiThread(new Runnable() { @Override public void run() { LogUtil.i("========我来了====="); mTextView.setText(result); } }); LogUtil.i("=====客户端收到结果===result=" + result); } }).start(); }
三、TcpClient在MainActivity中的使用
下面贴出TcpClient在MainActivity中使用代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final int PERMISSION_CODE = 1234; private TextView mTextView; private Button mButton1; private TcpClient mTcpClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化控件 initView(); // 设置监听 setListener(); // 申请权限 requestPermission(); } private void initView() { mTextView = findViewById(R.id.tv_show); mButton1 = findViewById(R.id.btn1); } private void setListener() { mButton1.setOnClickListener(this); } private void requestPermission() { // Android 6.0及以上版本需要动态申请权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, PERMISSION_CODE); } else { initData(); } } @Override public void onRequestPermissionsResult(int requestCode, int[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initData(); } else { Toast.makeText(this, "请授予网络权限", Toast.LENGTH_SHORT).show(); } } private void initData() { // 初始化TcpClient并设置连接参数 mTcpClient = new TcpClient(); mTcpClient.setConnectTimeOut(5000).setSocket("192.168.50.152", 12345); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn1: //测试 test(); break; default: break; } } private void test() { new Thread(new Runnable() { @Override public void run() { String message = "我是客户端a"; message = SocketHelper.getMessageByReadLine(message); mTcpClient.sendMessage(message, SocketConfig.UTF_8); String result = mTcpClient.receiveMessage(SocketConfig.UTF_8); runOnUiThread(new Runnable() { @Override public void run() { LogUtil.i("========我来了====="); mTextView.setText(result); } }); LogUtil.i("=====客户端收到结果===result=" + result); } }).start(); } }
四、TcpClient源码解析
为了更好地理解TcpClient的工作原理,下面对其源码进行解析:
public class TcpClient { private Socket socket; private PrintWriter printWriter; private BufferedReader bufferedReader; private int connectTimeOut; private String ip; private int port; private boolean isClose = false; public TcpClient setConnectTimeOut(int timeOut) { this.connectTimeOut = timeOut; return this; } public TcpClient setSocket(String ip, int port) { this.ip = ip; this.port = port; return this; } public void connect() throws IOException { if (isClose) return; new Thread(new Runnable() { @Override public void run() { try { InetSocketAddress address = new InetSocketAddress(ip, port); socket = new Socket(); socket.connect(address, connectTimeOut); isClose = false; printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (IOException e) { e.printStackTrace(); isClose = true; if (socket != null) { try { socket.close(); } catch (IOException ex) { ex.printStackTrace(); } } } } }).start(); } public void sendMessage(String message, String charsetName) { if (isClose) return; try { printWriter.println(message); printWriter.flush(); } catch (Exception e) { e.printStackTrace(); } } public String receiveMessage(String charsetName) { if (isClose) return null; try { return bufferedReader.readLine(); } catch (IOException e) { e.printStackTrace(); return null; } } public void close() { if (!isClose) { isClose = true; try { if (printWriter != null) { printWriter.close(); } if (bufferedReader != null) { bufferedReader.close(); } if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
五、Tcp通讯客户端使用注意事项及问题排查参考
1. 通讯权限
在Android项目中使用网络功能需要在AndroidManifest.xml
文件中添加以下权限:
<uses-permission android:name="android.permission.INTERNET" />
对于Android 6.0及以上版本,还需要动态申请权限:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, PERMISSION_CODE); } else { initData(); }
2. 问题排查参考:无法连接到服务器?确保以下几点: IP地址和端口号正确 防火墙设置允许相应端口通过 服务器正在运行并监听指定端口 检查日志输出,确认错误信息
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1260304.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复