Socket编程,单线程重复消息发送的问题

luo2pei4 2010-06-13 11:25:52
目的:使用单线程重复发送消息给服务器端。

程序清单:
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次消息。不知道是不是由于将消息发送放在一个线程里面,才产生了这种效果,还望各位指教。先谢谢了。
...全文
466 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
daimojingdeyu 2010-06-13
  • 打赏
  • 举报
回复
Client client = new Client();这个代码在for循环的外面,所以只会有一个发送消息的客户端线程,如果没有调用sleep,发送消息线程会连续收到5个改变message的方法调用,因此在while循环里最有可能的情况就是只看到最后一次设置的message的值,所以发一次.
而如果sleep一下的话,会保证每一次while发送完消息,将消息清空后,主线程睡醒后再次修改message的值,触发线程再次发消息.
hyaccp 2010-06-13
  • 打赏
  • 举报
回复
我不懂线程,出来顶下!
  • 打赏
  • 举报
回复
如果一个连接连续发送数据的话,那在发送前双方得协定一个传输协议,里面至少有包头和包体,包头中至少含有指令、状态,以及包体数据的长度。

如果不知道每一个数据包的长度,客户端连续发过来的话,那在服务端根本就不知道是一个包的数据,还是多个包的数据。


[Quote=引用 7 楼 yangjunsoft 的回复:]
线程这东西啊,无非就几个方法套路。。。
[/Quote]

有时候是这样,但是大多数的情况不是这样,而且很复杂,否则也不会有 java.util.concurrent 并发包的出现了。
yangjunsoft 2010-06-13
  • 打赏
  • 举报
回复
线程这东西啊,无非就几个方法套路。。。
daimojingdeyu 2010-06-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 luo2pei4321 的回复:]
TO:戴墨镜的鱼
谢谢你的回答。按你的意思的,每次发送消息都要启动一个线程。但是假设连续发送10000次消息的话,很快就会出现内存溢出的情况。我之所以想用单线程来发送消息也正是出于这方面的考虑。不知道有没有好的方法能避免这个问题。
[/Quote]
可以改变一下程序的实现,如果想用单线程的话,就不需要启动新的线程来发送消息.直接在for循环里发送就好了.将client.send(new TestBean());修改成直接发送消息的函数.
lacus87 2010-06-13
  • 打赏
  • 举报
回复
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次。


liuzhengkang 2010-06-13
  • 打赏
  • 举报
回复
既然你的客户端都有:发送线程,为什么你的服务端就不启动一个:接收线程呢。。
这样的话,只要你的客户端保持着长连接的话,发送多少次都没关系啊。
luo2pei4 2010-06-13
  • 打赏
  • 举报
回复
TO:戴墨镜的鱼
谢谢你的回答。按你的意思的,每次发送消息都要启动一个线程。但是假设连续发送10000次消息的话,很快就会出现内存溢出的情况。我之所以想用单线程来发送消息也正是出于这方面的考虑。不知道有没有好的方法能避免这个问题。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧