目的:使用单线程重复发送消息给服务器端。程序清单:
1,ServerTest.java  服务器端
2,SendThread.java  客户端发送线程
3,Client.java      客户端封装类
4,MainClient.java  客户端主程序代码
服务器端:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServerTest { private ServerSocket serverSocket;
private Socket socket; public ServerTest() {
try {
serverSocket = new ServerSocket(31313);
socket = null;
} catch(IOException ioe) {
ioe.printStackTrace();
}
} private void start() { try { System.out.println("Server start..."); while(true) { socket = serverSocket.accept(); if (socket != null) { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Object obj = null; while ((obj = ois.readObject()) != null) {
System.out.println("Context: " + obj.toString());
}
}
} } catch (Exception e) {
e.printStackTrace();
}
} /**
 * @param args
 */
public static void main(String[] args) { ServerTest serverTest = new ServerTest();
serverTest.start();
}}客户端发送线程:
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class SendThread extends Thread { private ObjectOutputStream oos;
private Serializable message; public SendThread(ObjectOutputStream oos) {
this.oos = oos;
} public void setMessage(Serializable message) {
this.message = message;
} public void run() { while(true) {
if (this.message != null) {
synchronized(this.message) {
try {
oos.writeObject(this.message);
oos.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
this.message = null;
}
}
}
}
}
}客户端封装类:
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;import client.thread.SendThread;public class Client { private Socket socket;
private SendThread sendThread;
private ObjectOutputStream oos; public Client() { try { InetAddress inetAddress = InetAddress.getLocalHost();
socket = new Socket("127.0.0.1", 31313, inetAddress, 51515);
oos = new ObjectOutputStream(socket.getOutputStream());
sendThread = new SendThread(oos);
sendThread.start(); } catch (UnknownHostException uhe) {
uhe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} public void send(Serializable message) {
System.out.println("send message...");
this.sendThread.setMessage(message);
}
}客户端主程序:
import bean.TestBean;
import client.Client;public class MainClient { public static void main(String[] args) { Client client = new Client(); for (int i = 0; i < 5; i++) {

client.send(new TestBean());// try {
// client.send(new TestBean());
// Thread.sleep(10000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
}
}问题:在客户端主程序中如果不使用sleep方法的话,服务器端只打印一次消息。如果客户端主程序使用了sleep方法(注释部分代码)的话,服务器端可以打印5次消息。不知道是不是由于将消息发送放在一个线程里面,才产生了这种效果,还望各位指教。先谢谢了。

解决方案 »

  1.   

    Client client = new Client();这个代码在for循环的外面,所以只会有一个发送消息的客户端线程,如果没有调用sleep,发送消息线程会连续收到5个改变message的方法调用,因此在while循环里最有可能的情况就是只看到最后一次设置的message的值,所以发一次.
    而如果sleep一下的话,会保证每一次while发送完消息,将消息清空后,主线程睡醒后再次修改message的值,触发线程再次发消息.
      

  2.   

    for (int i = 0; i < 5; i++) {       
           client.send(new TestBean());
    }
    你在这个循环里执行的语句是不断的改变client里面的线程对象的message属性
    而这个线程对象里面监听message属性改变就会发送信息并重新赋值为null但是你这里运行的是主线程和client里面的线程对象是两个线程。
    对于cpu来说main线程执行 i=0~5这5次循环是瞬间,
    在这时间片里面client里面的SendThread线程对象很少能有机会获得执行时间。
    也就是说等你main做完了5次循环,SendThread才会执行,监听message属性的改变并向服务器端发送请求。
    如果你在循环中每次赋值main线程都小sleep下,sendThread就会拿到时间片去执行,判断出message改变并发送请求,就能成功发送5次。
      

  3.   

    可以改变一下程序的实现,如果想用单线程的话,就不需要启动新的线程来发送消息.直接在for循环里发送就好了.将client.send(new TestBean());修改成直接发送消息的函数.
      

  4.   

    如果一个连接连续发送数据的话,那在发送前双方得协定一个传输协议,里面至少有包头和包体,包头中至少含有指令、状态,以及包体数据的长度。如果不知道每一个数据包的长度,客户端连续发过来的话,那在服务端根本就不知道是一个包的数据,还是多个包的数据。有时候是这样,但是大多数的情况不是这样,而且很复杂,否则也不会有 java.util.concurrent 并发包的出现了。