Android : 保持套接字打开以从服务器读取消息
Android : Keep socket open to read message from server
我正在开发一个 Android 应用程序
- 首先,我必须通过 TCP 套接字连接到硬件服务器
- 连接后,我必须发送 *99*1## 到服务器,然后服务器将响应 "*#*1##*#*1##"
- 然后,我需要让这个套接字保持活动状态并读取传入的消息
- 在这之后,服务器可以时不时地向我发送消息。但是,消息何时发送或消息长度未确定。
- 每条消息都会以'##'结尾,例如*1*1*18##、*1*0*19##、*1*1*#4*11##等。
- 客户端(本应用)收到消息后,会通知activity更新UI。
因此,我创建了一个线程子类来执行此操作
public class ServerThread extends Thread {
public interface OnReadListener {
public void onRead(ServerThread serverThread, String response);
}
Socket socket;
String address;
int port;
OnReadListener listener = null;
public ServerThread(String address, int port) {
this.address = address;
this.port = port;
}
@Override
public void run() {
try {
socket = new Socket(InetAddress.getByName(address), port);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
PrintWriter writer = new PrintWriter(bw, true);
writer.println("*99*1##");
writer.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while (!socket.isConnected() && !Thread.currentThread().isInterrupted()) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setListener(OnReadListener listener) {
this.listener = listener;
}
}
而在 activity 中,我是这样做的
public class MainActivity extends Activity {
ServerThread st = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
@Override
public void onResume() {
startMonitoring();
super.onResume();
}
@Override
public void onPause() {
stopMonitoring();
super.onPause();
}
private void startMonitoring() {
stopMonitoring();
st = new ServerThread(SERVER_IP_ADDRESS, SERVER_PORT);
st.setListener(new OnReadListener{
@Override
public void onRead(ServerThread serverThread, String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// update UI or do something with response
}
})
}
});
st.start();
}
private void stopMonitoring() {
if (st != null) {
st.stop();
st = null;
}
}
}
开始这个activity后,我发现
- 消息“*99*1##”已发送到服务器,我可以从服务器硬件上看到此消息。
- 但是,我只从服务器'*#*1##*#*1##'得到第一行响应
- 在那之后,套接字仍然连接(未打印堆栈跟踪)但我再也没有从服务器收到任何进一步的消息。监听器永远不会被调用。
我不知道该怎么做。欢迎任何建议。
一些您可能需要知道的注意事项
我不确定 BufferReader 是否是我需要的正确对象。因为当它读取失败时,它将return null 并且循环将保持运行。我可能需要一些可以冻结等待输入的线程的对象。该对象可以等待输入,因为服务器可能会在几秒、几分钟、几小时或更长时间内发送消息。收到消息后,继续执行代码并进入下一轮循环。
(我是全职iOS Dev,不太熟悉Java)
最终编辑
仔细检查代码后,我发现了我犯的愚蠢错误
writer.println("*99*1##")
基本上,println 将发送“*99*1##”,然后是 newline。但是我的硬件服务器不喜欢这样,所以它终止了连接。这就是为什么我从 BufferReader 的 readLine() 中得到 null 的原因。
我改成
后
writer.print("*99*1##")
服务器收到“*99*1##”并保持连接。然后,我可以像 EJP 再次建议的那样循环读取响应
String line;
while ((line = br.readLine()) != null) {
if (listener != null) {
listener.onRead(this, line);
}
}
if (listener != null) {
listener.onTerminated(this);
}
试试这个
while (isRunning) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
注意:isRunning 是一个布尔变量,用于控制您的线程生命周期。每当您想停止此线程时,请设置 isRunning = false
并在您的连接上调用 close()
。
如果您想创建一个 TCP 服务器,您应该使用 ServerSocket
而不是 Socket
。这是关于 socket
的 java 文档,但 android 使用相同的 http://docs.oracle.com/javase/tutorial/networking/sockets/
while (!socket.isConnected() ...
问题就在这里。无论如何,测试是没有意义的,因为它永远不会为假,但否定它意味着受控块永远不会执行。只需删除 isConnected()
测试。
when it failed to read, it will return null and the loop will keep running.
因为你没有正确处理那个案例。如果 line
为空,则必须退出循环并关闭连接。通常的写法是:
String line;
while ((line = reader.readLine()) != null)
{
// ...
}
你在循环中的睡眠简直就是浪费时间。
我正在开发一个 Android 应用程序
- 首先,我必须通过 TCP 套接字连接到硬件服务器
- 连接后,我必须发送 *99*1## 到服务器,然后服务器将响应 "*#*1##*#*1##"
- 然后,我需要让这个套接字保持活动状态并读取传入的消息
- 在这之后,服务器可以时不时地向我发送消息。但是,消息何时发送或消息长度未确定。
- 每条消息都会以'##'结尾,例如*1*1*18##、*1*0*19##、*1*1*#4*11##等。
- 客户端(本应用)收到消息后,会通知activity更新UI。
因此,我创建了一个线程子类来执行此操作
public class ServerThread extends Thread {
public interface OnReadListener {
public void onRead(ServerThread serverThread, String response);
}
Socket socket;
String address;
int port;
OnReadListener listener = null;
public ServerThread(String address, int port) {
this.address = address;
this.port = port;
}
@Override
public void run() {
try {
socket = new Socket(InetAddress.getByName(address), port);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
PrintWriter writer = new PrintWriter(bw, true);
writer.println("*99*1##");
writer.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while (!socket.isConnected() && !Thread.currentThread().isInterrupted()) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setListener(OnReadListener listener) {
this.listener = listener;
}
}
而在 activity 中,我是这样做的
public class MainActivity extends Activity {
ServerThread st = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
@Override
public void onResume() {
startMonitoring();
super.onResume();
}
@Override
public void onPause() {
stopMonitoring();
super.onPause();
}
private void startMonitoring() {
stopMonitoring();
st = new ServerThread(SERVER_IP_ADDRESS, SERVER_PORT);
st.setListener(new OnReadListener{
@Override
public void onRead(ServerThread serverThread, String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// update UI or do something with response
}
})
}
});
st.start();
}
private void stopMonitoring() {
if (st != null) {
st.stop();
st = null;
}
}
}
开始这个activity后,我发现
- 消息“*99*1##”已发送到服务器,我可以从服务器硬件上看到此消息。
- 但是,我只从服务器'*#*1##*#*1##'得到第一行响应
- 在那之后,套接字仍然连接(未打印堆栈跟踪)但我再也没有从服务器收到任何进一步的消息。监听器永远不会被调用。
我不知道该怎么做。欢迎任何建议。
一些您可能需要知道的注意事项
我不确定 BufferReader 是否是我需要的正确对象。因为当它读取失败时,它将return null 并且循环将保持运行。我可能需要一些可以冻结等待输入的线程的对象。该对象可以等待输入,因为服务器可能会在几秒、几分钟、几小时或更长时间内发送消息。收到消息后,继续执行代码并进入下一轮循环。
(我是全职iOS Dev,不太熟悉Java)
最终编辑
仔细检查代码后,我发现了我犯的愚蠢错误
writer.println("*99*1##")
基本上,println 将发送“*99*1##”,然后是 newline。但是我的硬件服务器不喜欢这样,所以它终止了连接。这就是为什么我从 BufferReader 的 readLine() 中得到 null 的原因。
我改成
后writer.print("*99*1##")
服务器收到“*99*1##”并保持连接。然后,我可以像 EJP 再次建议的那样循环读取响应
String line;
while ((line = br.readLine()) != null) {
if (listener != null) {
listener.onRead(this, line);
}
}
if (listener != null) {
listener.onTerminated(this);
}
试试这个
while (isRunning) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
注意:isRunning 是一个布尔变量,用于控制您的线程生命周期。每当您想停止此线程时,请设置 isRunning = false
并在您的连接上调用 close()
。
如果您想创建一个 TCP 服务器,您应该使用 ServerSocket
而不是 Socket
。这是关于 socket
的 java 文档,但 android 使用相同的 http://docs.oracle.com/javase/tutorial/networking/sockets/
while (!socket.isConnected() ...
问题就在这里。无论如何,测试是没有意义的,因为它永远不会为假,但否定它意味着受控块永远不会执行。只需删除 isConnected()
测试。
when it failed to read, it will return null and the loop will keep running.
因为你没有正确处理那个案例。如果 line
为空,则必须退出循环并关闭连接。通常的写法是:
String line;
while ((line = reader.readLine()) != null)
{
// ...
}
你在循环中的睡眠简直就是浪费时间。