Android socket使用中需要注意的两点事项

本文深入解析Android中Socket的使用技巧,对比Java Socket的区别,重点介绍数据接收逻辑与对端关闭监测,提供实用代码示例,帮助开发者理解如何高效处理二进制与文本数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android socket 使用过程中跟 JAVA socket 基本相同,不过还是略有区别,在使用过程中有两点需要注意:

  1. 接收数据的逻辑
    简单的接收逻辑都是读取字符流,while循环按行读取字符串:
	private static void startRecive(Socket client) {
		try {
			log("startRecive");
			InputStream ins = client.getInputStream();
			InputStreamReader insr = new InputStreamReader(client.getInputStream());
			BufferedReader reader = new BufferedReader(insr);
			String str;
			while((str = reader.readLine()) != null) {
				log(str);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			client.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		log("Client Exit");
	}

如果需要直接接收二进制内容(比如传输二进制文件),使用如下方式:

	private static void startRecive(final Socket client) {
		reciveThread = new Thread() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					log("startRecive");
					InputStream ins = client.getInputStream();
					byte[] bytes = new byte[1024];
					while(ins.read(bytes) != -1) {
						log(new String(bytes));
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		reciveThread.start();
	}

需要注意的地方是,一般情况下(socket为阻塞模式)连接成功不断开,while条件中的 read 或 readLine 在收不到数据的时候是阻塞状态,也就是如果需要保持连接多次发送信息,需要自己对每次发送的信息设置间隔符号(按行发送的末尾添加\r\n),并在while(read)读到之后下一次循环之前判断并处理,例如下面:

	reciveThread = new Thread() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					log("startRecive");
					InputStream ins = client.getInputStream();
					byte[] bytes = new byte[1024];
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					int size = -1;
					while((size=ins.read(bytes)) != -1) { // 收不到数据的时候回block在read
						// 接收到消息之后判断间隔符,并在下一次while之前处理数据
						if(size > 0 && bytes[size-1] == 0x24 /* $的ascii码值 */) {
							baso.write(bytes, 0, size-1);
							handleData(baos.toByteArray());
							continue;
						}
						baos.write(bytes);
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
  1. 对端关闭退出的监测逻辑:
    一般情况下,当对端的socket关闭退出或进程意外终止,本端接收逻辑会捕获到SocketException(继承自IOException),根据测试这里的情况Android与JAVA略有区别:
  • java
    直接关闭对端程序,本端有日志:
java.net.SocketException: Connection reset
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at java.net.SocketInputStream.read(Unknown Source)
	at MainServer.startRecive(MainServer.java:50)
	at MainServer.access$0(MainServer.java:45)
	at MainServer$1.run(MainServer.java:34)

对应代码:

	private static void startRecive(Socket client) {
		try {
			log("startRecive");
			InputStream ins = client.getInputStream();
			byte[] bytes = new byte[1024];
			while(ins.read(bytes) != -1) {  //此处抛出异常
				log(new String(bytes));
			}
			log("Recive exit!");

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

当对端执行 socket.shutdownOutput() 或 socket.close() 时,本端有输出:

Recive exit!
  • Android
    直接关闭对端应用(在【应用管理】中直接杀死应用,或在【最近任务】中清除应用),或对端应用执行 socket.shutdownOutput() 或 socket.close() ,本端应用有日志:
01-01 04:18:36.287 14529 14551 D MainServer: recive exit!

综上,在 JAVA 中对端进程强制终止时,本端会捕获到SocketException, 在Android 中对端应用程序被强制终止时,本端不会捕获到SocketException,而是会read()到 -1,并退出阻塞读状态;

在 JAVA 和 Android 中对端 socket 执行 shutdownOutput 或 close 时,本端都会read()到 -1,并退出阻塞读状态;

针对如上情况,可以在 Receive线程的while和catch流程之后,增加对端 socket 关闭或退出后的处理逻辑,如下例:

	private static void startRecive(Socket conn) {
		try {
			log("startRecive");
			InputStream ins = conn.getInputStream();
			InputStreamReader insr = new InputStreamReader(client.getInputStream());
			BufferedReader reader = new BufferedReader(insr);
			String str;
			while(ins.read(bytes) != -1) {  //此处抛出异常
				log(new String(bytes));
			}
			log("Recive exit!");  // 对端关闭退出
		} catch (IOException e) { // 其他连接异常
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally { // 
			try {
				// 当前是服务端,关闭对应客户端的socket实例
				conn.shutDownInputStream();
				conn.shutDownOutStream();
				conn.close();
				// 当前是客户端,关闭当前socket实例
				// socket.shutDownInputStream();
				// socket.shutDownOutStream();
				// socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			log("Client Exit");
		}		
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值