我在Java中编写了一个简单的应用程序,其中有两个节点,每个节点都有一个ServerSocket,可以打开一个端口来监听传入的连接。节点每个运行两个线程,通过在发送第一个消息时创建的持久TCP套接字向另一个节点发送1000条消息。但是,节点不会收到所有1000条消息。一个人可能会收到850而另一个人只收到650.这个数字往往会在多次运行中保持不变。
发送代码如下:
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
PrintWriter printwr = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
如果我使用,性能似乎有所改善 buffwr = new BufferedWriter(printwr) 同样使用 buffwr.write(...)代替 printwr.print(...),虽然它似乎不是一个完整的解决方案数据丢失。没有例外表明数据包未被传递,因此根据发件人的说法,它们都已成功发送。
在接收端,接受的连接如下处理:
BufferedReader inbuff = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
while(running) {
String rcvedln = inbuff.readLine();
if(rcvedln != null) {
count++;
System.out.println(count);
}
}
读者和作者的使用方式是否存在导致问题的问题?感谢。
答案 0 :(得分:4)
SendMsg()
每次调用都会创建一个新套接字,因此您不使用持久TCP连接。该方法也没有关闭套接字,因此你有很多开放的集合。您可能正在达到进程可以建立的连接数限制(当对象被垃圾回收时,套接字可能无法关闭)。
最后,正如kd304指出的那样,PrintWriter
的Javadoc说明了autoFlush
构造函数的PrintWriter
参数:“如果为true,则println,printf或format方法将刷新输出缓冲区“。您的代码没有调用执行刷新的方法。
试试这个:
public class MessageSender implements Closeable {
private final Socket socket;
private final PrintWriter writer;
public MessageSender(String dest, int port) {
socket = new Socket(dest, port);
writer = new PrintWriter(socket.getOutputStream(), true);
}
public void sendMessage(Message message) {
try {
writer.println(message.toString());
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
@Override
public void close() throws IOException {
writer.close();
socket.close();
}
注意我修改了代码,以便sendMessage()
调用Message.toString()
来获取格式化的消息。 sendMessage()
引用Message
中的字段以格式化邮件似乎不正确。您可以在toString()
专门为此目的创建一个方法,而不是使用Message
。
这是服务器端代码:
public class Server implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService executor;
private volatile boolean running = true;
public Server(int port, ExecutorService executor) throws IOException {
serverSocket = new ServerSocket(port);
this.executor = executor;
}
@Override
public void run() throws IOExeption {
while (running) {
Socket socket = serverSocket.accept();
executor.execute(new ConnectionHandler(socket));
}
}
public boolean stop(long timeout, TimeUnit unit) {
running = false;
executor.shutdown();
return executor.awaitTermination(timeout, unit);
}
}
您可以使用Executors
创建ExecutorService
来运行任务。请注意,ConnectionHandler需要关闭它给出的套接字。
答案 1 :(得分:1)
您是否关闭PrintWriter以刷新流?
} finally {
printwr.close();
sendsock.close();
}
答案 2 :(得分:0)
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
printrw声明并存储在函数外部,因此一旦设置完成,就不需要sentock或重新初始化printrw。在实际的应用程序中,我正在为HashMap中的每个连接存储PrintWriter,并在SendMsg(...)函数的开头检索它。
由于连接是持久的,每次接受一个连接时,一个新线程就是午餐,它运行一个while循环来连续检查数据。这些线程和连接仅在应用程序终止后关闭。除了我之前的问题,还有更有效的方法吗?
早些时候,我实现了这个没有“\ n”的代码,而是使用了println(...)而我仍然遇到了一些没有收到消息的问题,所以我不确定导致问题的是什么。消息的发送方式如下:
public class SendPortal2 implements Runnable {
String dest = null;
SendPortal2 (String dest) {
this.dest = dest;
}
public void run() {
for(int i=1; i<1000; i+=2) {
Message myMsg = new Message("Message", Main.myaddy + " " + String.valueOf(i));
Main.myCommMgr.SendMsg(dest, myMsg);
}
}
}
有两个这样的线程正在运行。当我刚刚再次运行代码时,一方获得了999个数据包,而另一方只获得了500个,这让我相信有时整个线程的数据可能被阻止。这可能吗?
感谢您的回复!
答案 3 :(得分:0)
如果我将一个Thread.sleep(2)放在调用SendMsg函数的for循环中,则会正确接收更多消息,但它并不总是1000.系统的资源是否可能被两个线程占用连续循环运行?