说明
这节教给大家用Android写一个TCP客户端程序
官方文档
https://www.android-doc.com/reference/java/net/Socket.html
页面
编写连接程序
1.获取控件
EditText editTextIPAddress,editTextPort;//输入IP地址,端口号 Button buttonConnect;//连接按钮 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonConnect = findViewById(R.id.buttonConnect); editTextIPAddress = findViewById(R.id.editTextIPAddress); editTextPort = findViewById(R.id.editTextPort); }
2.添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
3.定义一个socket
Socket socket;
4.编写按钮点击连接/断开程序
MyHandler myHandler;//使用Handler更新控件 myHandler = new MyHandler();
buttonConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (buttonConnect.getText()=="连接"){ new Thread(new Runnable() { @Override public void run() { Message msg = myHandler.obtainMessage();//从消息队列拉取个消息变量 try{ socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString())); if(socket.isConnected()){ msg.what = 1;//设置消息变量的 what 变量值 为1 } }catch (Exception e){ msg.what = 0;//设置消息变量的 what 变量值 为0 } myHandler.sendMessage(msg);//插入消息队列 } }).start(); } else{ try{ socket.close(); }catch (Exception e){} //关闭连接 buttonConnect.setText("连接");//按钮显示连接 } } });
//Handler class MyHandler extends Handler { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(MainActivity.this,"连接出错",Toast.LENGTH_SHORT).show(); break; case 1: buttonConnect.setText("断开");//按钮显示断开 break; default: break; } } }
提示:获取IP地址和端口号,执行连接
socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString()));
当前程序
EditText editTextIPAddress,editTextPort;//输入IP地址,端口号 Button buttonConnect;//连接按钮 Socket socket; MyHandler myHandler;//使用Handler更新控件 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myHandler = new MyHandler(); buttonConnect = findViewById(R.id.buttonConnect); buttonConnect.setText("连接"); editTextIPAddress = findViewById(R.id.editTextIPAddress); editTextPort = findViewById(R.id.editTextPort); buttonConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (buttonConnect.getText()=="连接"){ new Thread(new Runnable() { @Override public void run() { Message msg = myHandler.obtainMessage();//从消息队列拉取个消息变量 try{ socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString())); if(socket.isConnected()){ msg.what = 1;//设置消息变量的 what 变量值 为1 } }catch (Exception e){ msg.what = 0;//设置消息变量的 what 变量值 为0 } myHandler.sendMessage(msg);//插入消息队列 } }).start(); } else{ try{ socket.close(); }catch (Exception e){} //关闭连接 buttonConnect.setText("连接");//按钮显示连接 } } }); } //Handler class MyHandler extends Handler { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(MainActivity.this,"连接出错",Toast.LENGTH_SHORT).show(); break; case 1: buttonConnect.setText("断开");//按钮显示断开 break; default: break; } } }
接收数据
1.定义 InputStream 用于获取数据输入流,定义一个数组用于缓存数据
InputStream inputStream;//获取输入流 byte[] RevBuff = new byte[1460];//缓存数据
2.定义一个函数,里面放一个任务,用于不停的接收数据
public void Recv(){ new Thread(new Runnable() { @Override public void run() { while (socket!= null && socket.isConnected()){ try{ int Len = inputStream.read(RevBuff);//获取数据 if(Len!=-1){ Message msg = myHandler.obtainMessage();//从消息队列拉取个消息变量 msg.what = 3;//设置消息变量的 what 变量值 为3 msg.arg1 = Len;//接收的数据个数 msg.obj = RevBuff;//传递数据 myHandler.sendMessage(msg);//插入消息队列 } else{//连接异常断开 Message msg = myHandler.obtainMessage();//从消息队列拉取个消息变量 msg.what = 0;//设置消息变量的 what 变量值 为0 myHandler.sendMessage(msg);//插入消息队列 break; } }catch (Exception e){//连接异常断开 Message msg = myHandler.obtainMessage();//从消息队列拉取个消息变量 msg.what = 0;//设置消息变量的 what 变量值 为0 myHandler.sendMessage(msg);//插入消息队列 break; } } } }).start(); }
3.调用接收函数
4.在Handle中处理数据,把数据显示在页面
4.1.获取控件
4.2.把接收的消息追加到Textview显示
测试
1.电脑端开启TCP服务器
2.保证手机和电脑在一个局域网内
查看自己的电脑IP
3.手机连接
接收显示16进制数据
1.关于16进制显示和前面的串口上位机显示16进制数据是一样的道理
https://www.cnblogs.com/yangfengwu/p/12382103.html
2.JAVA和C#提供的函数不一样,java的转换程序如下:
/** * 16进制byte转16进制String--用空格隔开 * @param bytes * @return */ public static String byteToHexStr(byte[] bytes) { String str_msg = ""; for (int i = 0; i < bytes.length; i++){ str_msg = str_msg + String.format("%02X",bytes[i])+" "; } return str_msg; }
3.获取16进制选择控件
4.编写处理函数
测试
清除接收
发送数据
1.获取控件,定义输出流变量
2.获取输出流
3.点击发送按钮发送发送文本框里面的数据
4.测试
发送16进制数据
1.文本框里面输入的是字符串
假设输入的是 55FD
那么获取的是 "55FD"
需要转换为 0x55 0xFD
获取第一个字符 5 hexString.charAt(0)
转换为 16进制形式 Character.digit(hexString.charAt(0), 16)
获取第二个字符5 hexString.charAt(1)
转换为 16进制形式 Character.digit(hexString.charAt(1), 16)
然后组合成一个16进制
byte data = (byte) ((Character.digit(hexString.charAt(0), 16) << 4) + Character.digit(hexString.charAt(1), 16))
2.完整的程序如下
/*** *"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF,0xD9} * @param hexString * @return */ public static byte[] hexStringToByteArray(String hexString) { StringBuilder sb = null; hexString = hexString.replaceAll(" ", ""); if ((hexString.length()%2)!=0) {//数据不是偶数 sb = new StringBuilder(hexString);//构造一个StringBuilder对象 sb.insert(hexString.length()-1, "0");//插入指定的字符串 hexString = sb.toString(); } int len = hexString.length(); byte[] bytes = new byte[len / 2]; for (int i = 0; i < len; i += 2) { if (( (hexString.charAt(i)>='0' && hexString.charAt(i)<='9') || (hexString.charAt(i)>='A' && hexString.charAt(i)<='F') || (hexString.charAt(i)>='a' && hexString.charAt(i)<='f') )&& (hexString.charAt(i+1)>='0' && hexString.charAt(i+1)<='9') || (hexString.charAt(i+1)>='A' && hexString.charAt(i+1)<='F') || (hexString.charAt(i+1)>='a' && hexString.charAt(i+1)<='f')){ // 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节 bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character .digit(hexString.charAt(i+1), 16)); } else return null; } return bytes; }
3.获取控件
4.编写处理程序
5.测试
补充
让输入的内容默认显示在左上角
android:gravity="top"