Java:多线程&;UDP套接字编程
我不熟悉Java中的多线程和套接字编程。我想知道实现两个线程的最佳方式是什么——一个用于接收套接字,另一个用于发送套接字。如果我想做的事情听起来很荒谬,请告诉我原因!这段代码主要是从Sun的在线教程中得到启发的。我想使用多播套接字,这样我就可以使用多播组Java:多线程&;UDP套接字编程,java,multithreading,sockets,udp,Java,Multithreading,Sockets,Udp,我不熟悉Java中的多线程和套接字编程。我想知道实现两个线程的最佳方式是什么——一个用于接收套接字,另一个用于发送套接字。如果我想做的事情听起来很荒谬,请告诉我原因!这段代码主要是从Sun的在线教程中得到启发的。我想使用多播套接字,这样我就可以使用多播组 class Server extends Thread { static protected MulticastSocket socket = null; protected BufferedReader in = null;
class Server extends Thread
{
static protected MulticastSocket socket = null;
protected BufferedReader in = null;
public InetAddress group;
private static class Receive implements Runnable
{
public void run()
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
socket.receive(pkt);
String received = new String(pkt.getData(),0,pkt.getLength());
System.out.println("From server@" + received);
Thread.sleep(1000);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
}
public Server() throws IOException
{
super("server");
socket = new MulticastSocket(4446);
group = InetAddress.getByName("239.231.12.3");
socket.joinGroup(group);
}
public void run()
{
while(1>0)
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
//String msg = reader.readLine();
String pid = ManagementFactory.getRuntimeMXBean().getName();
buf = pid.getBytes();
pkt = new DatagramPacket(buf,buf.length,group,4446);
socket.send(pkt);
Thread t = new Thread(new Receive());
t.start();
while(t.isAlive())
{
t.join(1000);
}
sleep(1);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
//socket.close();
}
public static void main(String[] args) throws IOException
{
new Server().start();
//System.out.println("Hello");
}
}
想要在应用程序中创建线程并不荒谬!您不需要确切的2个线程,但我认为您讨论的是实现Runnable接口的2个类 自Java1.5以来,线程API变得更好了,您不再需要再处理Java.lang.Thread了。您只需创建一个并向其提交可运行实例
这本书使用了这个确切的问题——创建一个线程套接字服务器——并对代码进行了多次迭代,以展示实现这一点的最佳方法。查看免费的样本章节,这是伟大的。我不会在这里复制/粘贴代码,但请具体查看清单6.8。首先要做的是:您的类应该以大写字母开头: 类名应为名词,大小写应与单词的第一个字母混合 每个内部单词都大写。尝试 保持你的类名简单明了 描写的使用完整的词避免 首字母缩略词和缩写词(除非 缩略语的使用更为广泛 而不是长格式,例如URL或 HTML) 秒: 尝试将代码分解为连贯的部分,并围绕您正在处理的一些常见功能组织它们。。。可能是围绕您正在编程的功能或模型 服务器的(基本)模型是它唯一做的事情是接收套接字连接。。。服务器依赖于处理程序来处理这些连接,仅此而已。如果您尝试构建该模型,它将如下所示:
class Server{
private final ServerSocket serverSocket;
private final ExecutorService pool;
public Server(int port, int poolSize) throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void serve() {
try {
while(true) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// receive the datagram packets
}
}
第三:我建议您查看一些现有示例
- 多线程客户端/服务器应用程序:
- 道格·李:
(感谢约翰)
(仍然找不到确切的例子,但它就在那里的某个地方……如果你有勇气的话,看看他的档案)李> - 实践示例中的并发性:
- Java并发教程:
好的,拉维,你的代码有一些大问题和一些小问题:
Receive
类是您的客户机。。。您应该将其作为一个单独的程序(具有自己的主类)取出,并同时运行服务器和多个客户端。从服务器上为您发送的每个新UDP包生成一个新的“客户端线程”是一个令人不安的想法(大问题)循环中运行接收代码(小问题),例如:
ExecutorService
不太有用否则你的方法是正确的。。。但我仍然建议您查看一些示例。2个线程就可以了。一个读者一个作家。请记住,对于UDP,您不应该产生新的处理程序线程(除非您所做的工作需要很长时间),我建议将传入消息抛出到处理队列中。发送也一样,有一个发送线程阻止UDP发送的传入队列。Eclipse的历史记录即使在一天之前也能正常工作,这是一件好事:)多亏了这一点,我能够为Ravi和Lirik提供一个关于泄漏的工作示例和答案 首先,让我声明,我不知道是什么导致了这次泄漏,但如果我将其保留足够长的时间,它将在出现OutOfMemoryError时失败 其次,我留下了为Ravi注释的工作代码,作为我的UDP服务器的一个基本工作示例。超时时间是用来测试我的防火墙会杀死接收器端多长时间(30秒)。只要把游泳池里的东西移走,你就可以走了 下面是我的示例线程化UDP服务器的一个工作但泄漏的版本
public class TestServer {
private static Integer TIMEOUT = 30;
private final static int MAX_BUFFER_SIZE = 8192;
private final static int MAX_LISTENER_THREADS = 5;
private final static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSSZ");
private int mPort;
private DatagramSocket mSocket;
// You can remove this for a working version
private ExecutorService mPool;
public TestServer(int port) {
mPort = port;
try {
mSocket = new DatagramSocket(mPort);
mSocket.setReceiveBufferSize(MAX_BUFFER_SIZE);
mSocket.setSendBufferSize(MAX_BUFFER_SIZE);
mSocket.setSoTimeout(0);
// You can uncomment this for a working version
//for (int i = 0; i < MAX_LISTENER_THREADS; i++) {
// new Thread(new Listener(mSocket)).start();
//}
// You can remove this for a working version
mPool = Executors.newFixedThreadPool(MAX_LISTENER_THREADS);
} catch (IOException e) {
e.printStackTrace();
}
}
// You can remove this for a working version
public void start() {
try {
try {
while (true) {
mPool.execute(new Listener(mSocket));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
mPool.shutdown();
}
}
private class Listener implements Runnable {
private final DatagramSocket socket;
public Listener(DatagramSocket serverSocket) {
socket = serverSocket;
}
private String readLn(DatagramPacket packet) throws IOException {
socket.receive(packet);
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(packet.getData())), MAX_BUFFER_SIZE).readLine();
}
private void writeLn(DatagramPacket packet, String string) throws IOException {
packet.setData(string.concat("\r\n").getBytes());
socket.send(packet);
}
@Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
String s;
while (true) {
try {
packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
s = readLn(packet);
System.out.println(DateFormat.format(new Date()) + " Received: " + s);
Thread.sleep(TIMEOUT * 1000);
writeLn(packet, s);
System.out.println(DateFormat.format(new Date()) + " Sent: " + s);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
if (args.length == 1) {
try {
TIMEOUT = Integer.parseInt(args[0]);
} catch (Exception e) {
TIMEOUT = 30;
}
}
System.out.println(DateFormat.format(new Date()) + " Timeout: " + TIMEOUT);
//new TestServer(4444);
new TestServer(4444).start();
}
}
公共类TestServer{
私有静态整数超时=30;
私有最终静态int MAX_BUFFER_SIZE=8192;
私有最终静态int MAX_LISTENER_THREADS=5;
私有最终静态SimpleDataFormat DateFormat=新SimpleDataFormat(“yyyy-dd-MM HH:MM:ss.SSSZ”);
私人进口;
私有DatagramSocket-mSocket;
//您可以为工作版本删除此项
私人服务mPool;
公共测试服务器(int端口){
mPort=端口;
试一试{
mSocket=新的DatagramSocket(mPort);
mSocket.setReceiveBufferSize(最大缓冲区大小);
mSocket.setSendBufferSize(最大缓冲区大小);
mSocket.setSoTimeout(0);
//您可以取消对工作版本的注释
//对于(int i=0;ipublic class TestServer {
private static Integer TIMEOUT = 30;
private final static int MAX_BUFFER_SIZE = 8192;
private final static int MAX_LISTENER_THREADS = 5;
private final static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSSZ");
private int mPort;
private DatagramSocket mSocket;
// You can remove this for a working version
private ExecutorService mPool;
public TestServer(int port) {
mPort = port;
try {
mSocket = new DatagramSocket(mPort);
mSocket.setReceiveBufferSize(MAX_BUFFER_SIZE);
mSocket.setSendBufferSize(MAX_BUFFER_SIZE);
mSocket.setSoTimeout(0);
// You can uncomment this for a working version
//for (int i = 0; i < MAX_LISTENER_THREADS; i++) {
// new Thread(new Listener(mSocket)).start();
//}
// You can remove this for a working version
mPool = Executors.newFixedThreadPool(MAX_LISTENER_THREADS);
} catch (IOException e) {
e.printStackTrace();
}
}
// You can remove this for a working version
public void start() {
try {
try {
while (true) {
mPool.execute(new Listener(mSocket));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
mPool.shutdown();
}
}
private class Listener implements Runnable {
private final DatagramSocket socket;
public Listener(DatagramSocket serverSocket) {
socket = serverSocket;
}
private String readLn(DatagramPacket packet) throws IOException {
socket.receive(packet);
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(packet.getData())), MAX_BUFFER_SIZE).readLine();
}
private void writeLn(DatagramPacket packet, String string) throws IOException {
packet.setData(string.concat("\r\n").getBytes());
socket.send(packet);
}
@Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
String s;
while (true) {
try {
packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
s = readLn(packet);
System.out.println(DateFormat.format(new Date()) + " Received: " + s);
Thread.sleep(TIMEOUT * 1000);
writeLn(packet, s);
System.out.println(DateFormat.format(new Date()) + " Sent: " + s);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
if (args.length == 1) {
try {
TIMEOUT = Integer.parseInt(args[0]);
} catch (Exception e) {
TIMEOUT = 30;
}
}
System.out.println(DateFormat.format(new Date()) + " Timeout: " + TIMEOUT);
//new TestServer(4444);
new TestServer(4444).start();
}
}