今天跟大家聊聊我这几天搞的 * 实践,踩不少坑,也学到不少东西,赶紧记录下来,免得以后又忘。
我以为 `*` 就是简简单单的接收数据,结果一上手,发现事情没那么简单。
我尝试用最基本的方式接收数据:
byte[] buffer = new byte[1024];
int bytesReceived = *(buffer);
心想,这不就完事吗?结果发现,`bytesReceived` 的值有时候是 0, 纳闷,明明服务端发数据! 后来查资料才知道,对于 UDP 这种 socket,`bytesReceived` 返回 0 可能表示接收到一个空的帧。也就是说,服务端可能发一个内容为空的数据包。
后来我还遇到一个更头疼的问题,就是 `*` 会阻塞。啥意思?就是如果没有数据可读,程序会一直卡在那里,直到有数据到来,或者超时。这可不行!我的程序不能一直等着,得干点别的事情。
于是我开始研究怎么设置超时。看下文档,发现可以用 `*` 属性来设置超时时间:
* = 5000; // 设置超时时间为 5 秒
设置完超时之后,如果 5 秒内没有收到数据,`*` 就会抛出一个异常。这样,我就可以在 `try...catch` 块中处理超时的情况。
try
int bytesReceived = *(buffer);
// 处理接收到的数据
catch (SocketException ex)
if (* == *)
// 处理超时
*("接收数据超时!");
else
// 处理其他 Socket 异常
*("Socket 异常:" + *);
搞定超时,我又开始考虑怎么更高效地接收数据。每次都创建一个 1024 字节的缓冲区,感觉有点浪费。如果服务端每次只发几个字节,那岂不是浪费大量的内存?
于是我开始尝试动态调整缓冲区的大小。先用一个小的缓冲区接收数据,如果数据超过缓冲区的大小,就重新分配一个更大的缓冲区。
byte[] buffer = new byte[16]; // 初始缓冲区大小
int bytesReceived = *(buffer);
if (bytesReceived == *)
// 可能有更多的数据
byte[] newBuffer = new byte[* 2]; // 扩大缓冲区
*(buffer, newBuffer, *); // 复制数据
buffer = newBuffer;
bytesReceived += *(buffer, bytesReceived, * - bytesReceived, *); // 接收剩余的数据
这只是一个简单的示例,实际应用中还需要考虑更多的情况,比如最大缓冲区大小,以及如何避免无限循环。
我还遇到一个问题,就是怎么判断连接是否断开。如果客户端突然断开连接,`*` 会抛出一个异常,但是这个异常的具体类型是什么?我查一下资料,发现可以用 `*` 来判断连接是否被重置。
try
int bytesReceived = *(buffer);
// 处理接收到的数据
catch (SocketException ex)
if (* == *)
// 连接被重置,表示客户端断开连接
*("客户端断开连接!");
else
// 处理其他 Socket 异常
*("Socket 异常:" + *);
这回 `*` 实践,我主要搞清楚以下几个问题:
- `*` 的返回值表示接收到的字节数,如果是 UDP socket,返回 0 可能表示接收到一个空帧。
- `*` 默认是阻塞的,可以通过 `*` 属性设置超时时间。
- 可以动态调整缓冲区的大小,以提高内存利用率。
- 可以用 `*` 来判断连接是否被重置。
虽然只是简单的几个问题,但是解决起来还是挺费劲的。希望我的实践记录能够帮助到大家,少踩一些坑。