在客户端socket中,我写了一个线程来连续读取socket的inputStream。这里我使用了一个while循环来无限读取。但是它需要更多的 CPU;因此可以减少CPU。请添加您的建议。还可以为 inputStream 添加侦听器。
线程代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
if(!message.equals("EmptyString")) {
process(message);
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
}
}
}
SocketClient.java
public class SocketClient{
private volatile boolean isConnected;
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
if (builder.length() == 0)
return "EmptyString";
return builder.toString();
} catch (IOException e) {
return "EmptyString";
} finally {
try {
if(reader != null)
reader.close();
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
}
}
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException interruptedException) {
shutdown = true;
}
}
}
我要在这里批评整个班级。您的具体问题的答案将会出现。
public class SocketClient{
private volatile boolean isConnected;
你不需要这个。socket == null
也一样。
private int port;
private int retryCount;
private long startTime;
private String hostName;
private DataInputStream input;
private DataOutputStream output;
private Socket socket;
public SocketClient(int port, String hostname) throws IOException {
this.port = port;
this.hostName = hostname;
establishConnection();
}
public void shutdown() {
try {
shutdown = true;
input.close();
output.close();
socket.close();
您不需要所有这些关闭,而且无论如何您都以错误的顺序执行它们。output.close()
就足够了,无论如何它肯定应该是第一个。
} catch (Exception e) {
logger.debug("Exception in shutdown:" + e.getMessage());
}
}
public String getMessage() {
BufferedReader reader = null;
本BufferedReader
应该是一个实例变量,而不是一个局部变量。它被缓冲了。如果将其设为局部变量,则会丢失数据。
try {
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new
InputStreamReader(tcpSocket.getInputStream()));
do {
builder.append(reader.readLine());
} while((reader.ready()));
你不需要这一切。如果消息是一行,你只需要return reader.readLine()
,你需要调用者检查它是否为空,如果是,关闭套接字,停止读取等。如果消息超过一行,这是一种误用of ready()
:它当然不是消息结束的指示符。这似乎从你的问题下评论说,你不应该甚至有方法:只需要直接连接插座输入流的XML解析器,让它做阅读。
if (builder.length() == 0)
return "EmptyString";
不要这样做。返回""
或为空。不要为你的应用程序编造新的魔法字符串来解码。
return builder.toString();
} catch (IOException e) {
return "EmptyString";
同上。
} finally {
try {
if(reader != null)
reader.close();
你应该不会在这里结束的读者。关闭它将关闭套接字,因此您永远不会收到另一条消息。
} catch(IOException e) {
logger.error("unable to close reader");
}
}
}
private void establishConnection() {
retryCount = 1;
startTime = System.currentTimeMillis();
while (!shutdown) {
try {
if(!isConnected) {
socket = new Socket(hostName,port);
socket.setKeepAlive(true);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
isConnected = true;
shutdown = true;
你为什么要shutdown
来true
这里?什么都没有关闭。这是一个全新的插座。
}
} catch (Exception exception) {
isConnected = false;
sleepFewSeconds();
reconnectSocket();
}
练习不好。Socket.connect()
,由 内部调用new Socket(...)
,已经重试,而且您应该区分连接失败异常,而不是对它们都采用相同的策略。例如,“连接超时”已经阻塞了大约一分钟:您不需要再次睡眠;并且“连接被拒绝”意味着没有任何东西在听,所以重试是完全没有意义的。
private void reconnectSocket() {
long endTime = startTime + 120000L;
if(!(System.currentTimeMillis() < endTime)) {
shutdown = true;
}
}
private void sleepFewSeconds() {
try {
TimeUnit.MILLISECONDS.sleep(20);
这不是“几秒钟”。它是 20毫秒,这对于网络编程中至少两个数量级的 magnite 来说是不够的,当然应该有任何睡眠。
} catch (InterruptedException interruptedException) {
shutdown = true;
shutdown
似乎永远不会是假的。我怀疑您是否考虑过它的真正含义,我怀疑您是否真的需要它。
至于你的调用代码:
public void run() {
while (!shutdown) {
try {
if(socketClient != null) {
如果socketClient
为空,则此循环将无意义地旋转。这个方法肯定应该构造套接字客户端吗?
String message = socketClient.getMessage();
logger.info ("Message size:" + message.length ());
在这里,您无法检查 null 并且无法正确响应,这将关闭套接字并退出循环。相反,您将在这里获得 NPE。
if(!message.equals("EmptyString")) {
process(message);
看上面。不要给自己发送特殊的短信。如果对等方需要在某一天发送该消息会发生什么?
}
}
} catch (Exception exception) {
logger.info("Unable to read the socket message" +exception);
不可接受。这个捕获在循环内部,它基本上忽略了异常。结果是,同样,这个循环将在任何异常上无意义地旋转。您调用的方法应该声明为 throw IOException
,这就是您应该在这里捕获的全部内容。目前你甚至会旋转NullPointerException
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句