(1)访问网络必须添加权限,访问网络必须添加权限,访问网络必须添加权限,重要的事情说三遍。
(2)简述
UDP协议是面向报文的,简单地说,利用UDP访问网络的步骤就是“寄快递”:通过DatagramPacket(快件)把数据和地址打包,然后用DatagramSocket(你)进行数据报的收发,至于中途是怎么传送,那就是快递员的事了,不归我们管(也因此,UCP的传输是不可靠的,可能会出现丢包的情况,跟某些快递简直一毛一样)。
InetAddress:记录访问的host等信息。
DatagramPacket:包装数据和访问地址,相当于一个快件。
DatagramSocket:用于发送和接收数据报,相当于快件的寄件人和收件人。
(3)简单示例
String serverIp = "111.111.111.11"; // 访问主机ip InetAddress address = InetAddress.getByName(serverIp); DatagramSocket socket = new DatagramSocket(8888); // 根据需要可在实例化时指定端口号 // 网络操作不能在UI线程进行 new Thread() { @Override public void run() { try { // 发送数据 String msg = "hello"; byte[] msgBytes = msg.getBytes(); DatagramPacket packet = new DatagramPacket(msgBytes, msgBytes.length, mAddress, mPort); mSocket.send(packet); // 接收数据 byte[] returnMsgBytes = new byte[1024]; DatagramPacket returnPacket = new DatagramPacket(returnMsgBytes, returnMsgBytes.length, mAddress, mPort); // receive()方法是阻塞的,会一直等待接收到包 mSocket.receive(returnPacket); String serverMsg = new String(returnPacket.getData(), 0, returnMsgBytes.length); Log.d("test", serverMsg); } catch (IOException e) { e.printStackTrace(); } } }.start();从例子里我们可以看到,使用UDP就是打包数据、收发数据包这两步。
2. TCP(1)还是权限,别忘了
(2)简述
与UDP不同,TCP是面向连接的,通过Socket对象创建连接,拿到一个输入流和一个输出流,然后再关闭连接前,可以一直发送与接收数据。
过程类似打电话,首先你得输入对方的电话号码(访问地址),然后拨通电话(创建连接通道),然后你说话(发送数据),或者听对方说话(接收数据),最后挂断电话(关闭连接)。
TCP创建连接时会经过三次握手,而断开连接时经过四次挥手。
(3)简单示例
try { // 创建连接 Socket socket = new Socket("111.111.111.11", 8888); // 访问地址111.111.111.11:8888 // 拿到输入流(电话听筒)、输出流(电话话筒) InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)); // 接收数据 new Thread() { @Override public void run() { try { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }.start(); // 发送数据 String line = "test"; bw.write(line); bw.newLine(); bw.flush(); } catch (IOException e) { e.printStackTrace(); }可以看到,与UDP不同,TCP是创建连接后,在断开连接前都可以直接通过输入输出流传输数据,不需要另外将数据打包。
(4)在安卓中应用
Activity:
public class TCPActivity extends AppCompatActivity { // 发送消息的按钮 private Button mSendBtn; // 输入框 private EditText mMsgEt; // 显示消息内容的文本框 private TextView mContentTv; private TCPClientBiz mBiz = new TCPClientBiz(); private boolean isConnected = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initEvent(); mBiz.connect(new TCPClientBiz.OnConnectedListener() { @Override public void onSucceed() { // 连接成功 isConnected = true; } }); } private void initView() { mSendBtn = findViewById(R.id.send_btn); mMsgEt = findViewById(R.id.msg_et); mContentTv = findViewById(R.id.content_tv); } private void initEvent() { mSendBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { final String msg = mMsgEt.getText().toString().trim(); if (!msg.isEmpty()) { if (isConnected) { mMsgEt.setText(""); // 发送消息 mBiz.send(msg); } } } }); // 接收服务器的消息 mBiz.setOnReceivedListener(new TCPClientBiz.OnReceivedListener() { @Override public void onReceived(String serverMsg) { mContentTv.append(formatMsg(serverMsg)); } @Override public void onError(Exception e) { Toast.makeText(TCPActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } private String formatMsg(String msg) { return msg + "\n"; } }业务类:
public class TCPClientBiz { private InputStream inputStream; private OutputStream outputStream; private Handler handler = new Handler(Looper.getMainLooper()); // 异步连接,所以需要一个回调,告知已经连接成功 public void connect(final OnConnectedListener onConnectedListener) { new Thread() { @Override public void run() { try { Socket socket = new Socket("169.254.165.37", 9999); inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); onConnectedListener.onSucceed(); while (true) { // 不断接收服务器消息 receive(); } } catch (IOException e) { e.printStackTrace(); } } }.start(); } private void receive() { try { BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); final String line; if ((line = br.readLine()) != null) { handler.post(new Runnable() { @Override public void run() { if (onReceivedListener != null) { onReceivedListener.onReceived(line); } } }); } } catch (final IOException e) { handler.post(new Runnable() { @Override public void run() { if (onReceivedListener != null) { onReceivedListener.onError(e); } } }); } } public void send(final String msg) { new Thread() { @Override public void run() { try { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)); bw.write(msg); bw.newLine(); bw.flush(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } private OnReceivedListener onReceivedListener; public void setOnReceivedListener(OnReceivedListener onReceivedListener) { this.onReceivedListener = onReceivedListener; } // 接收消息接口 public interface OnReceivedListener { void onReceived(String serverMsg); void onError(Exception e); } // 连接成功接口 public interface OnConnectedListener { void onSucceed(); } }