2010-05-12 31 views
7

Tôi viết một tập Client/Server của chương trìnhNghe cho TCP và UDP yêu cầu trên cùng một cổng

Tùy thuộc vào hoạt động theo yêu cầu của khách hàng, tôi sử dụng làm giao thức TCP hoặc yêu cầu UDP.

Thực hiện phía máy khách là thẳng về phía trước, vì tôi có thể dễ dàng mở kết nối với bất kỳ giao thức nào và gửi yêu cầu đến phía máy chủ.

Ở phía máy chủ, mặt khác, tôi muốn nghe cả hai đối với kết nối UDP và TCP trên cùng một cổng. Hơn nữa, tôi thích các máy chủ để mở thread mới cho mỗi yêu cầu kết nối.

tôi đã áp dụng phương pháp này được giải thích trong: link text

tôi đã mở rộng mẫu mã này bằng cách tạo chủ đề mới cho mỗi giao thức TCP/UDP yêu cầu.

Điều này hoạt động chính xác nếu tôi chỉ sử dụng TCP, nhưng nó không thành công khi tôi cố gắng thực hiện các ràng buộc UDP.

Vui lòng cho tôi bất kỳ đề xuất nào để tôi có thể sửa lỗi này.

tnx

Đây là Bộ luật Server:

public class Server { 
public static void main(String args[]) { 
    try { 
     int port = 4444; 
     if (args.length > 0) 
      port = Integer.parseInt(args[0]); 

     SocketAddress localport = new InetSocketAddress(port); 

     // Create and bind a tcp channel to listen for connections on. 
     ServerSocketChannel tcpserver = ServerSocketChannel.open(); 
     tcpserver.socket().bind(localport); 

     // Also create and bind a DatagramChannel to listen on. 
     DatagramChannel udpserver = DatagramChannel.open(); 
     udpserver.socket().bind(localport); 

     // Specify non-blocking mode for both channels, since our 
     // Selector object will be doing the blocking for us. 
     tcpserver.configureBlocking(false); 
     udpserver.configureBlocking(false); 

     // The Selector object is what allows us to block while waiting 
     // for activity on either of the two channels. 
     Selector selector = Selector.open(); 

     tcpserver.register(selector, SelectionKey.OP_ACCEPT); 
     udpserver.register(selector, SelectionKey.OP_READ); 

     System.out.println("Server Sterted on port: " + port + "!"); 

     //Load Map 
     Utils.LoadMap("mapa"); 
     System.out.println("Server map ... LOADED!"); 

     // Now loop forever, processing client connections 
     while(true) { 
      try { 
       selector.select(); 
       Set<SelectionKey> keys = selector.selectedKeys(); 

       // Iterate through the Set of keys. 
       for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext();) { 
        SelectionKey key = i.next(); 
        i.remove(); 

        Channel c = key.channel(); 

        if (key.isAcceptable() && c == tcpserver) { 
         new TCPThread(tcpserver.accept().socket()).start(); 
        } else if (key.isReadable() && c == udpserver) { 
         new UDPThread(udpserver.socket()).start(); 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
     System.err.println(e); 
     System.exit(1); 
    } 
} 

}

Mã UDPThread:

public class UDPThread extends Thread { 
private DatagramSocket socket = null; 

public UDPThread(DatagramSocket socket) { 
    super("UDPThread"); 
    this.socket = socket; 
} 

@Override 
public void run() { 
    byte[] buffer = new byte[2048]; 
    try {   
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     socket.receive(packet); 

     String inputLine = new String(buffer); 
     String outputLine = Utils.processCommand(inputLine.trim()); 

     DatagramPacket reply = new DatagramPacket(outputLine.getBytes(), outputLine.getBytes().length, 
                packet.getAddress(), packet.getPort()); 
     socket.send(reply); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    socket.close(); 
} 

}

tôi nhận được:

Exception in thread "UDPThread" java.nio.channels.IllegalBlockingModeException 
at sun.nio.ch.DatagramSocketAdaptor.receive(Unknown Source) 
at server.UDPThread.run(UDPThread.java:25) 

10x

+0

Không thế nào? Bạn có thêm thông tin, chẳng hạn như thông báo lỗi hoặc mã mẫu không? –

+0

Vui lòng giải thích chi tiết hơn về "nó không thành công". – BalusC

Trả lời

0

AFAIK, bạn sẽ có thể nghe cho cả các kết nối TCP và UDP thông điệp trên cùng một cổng. Nó sẽ giúp nếu bạn đăng mã UDP của bạn, và ngoại lệ + stacktrace mà bạn đang nhìn thấy.

3

Nó sẽ hoạt động. Một trong những vấn đề với mã này, có vẻ như, là kích thước ByteBuffer được thiết lập là 0, có nghĩa là datagram được loại bỏ (như nó đề cập trong các ý kiến). Nếu bạn cần nhận bất kỳ thông tin nào trên UDP và bạn đang ở trên một mạng đáng tin cậy, bạn có thể thiết lập kích thước khá lớn và nhận các gói dữ liệu lớn được tạo thành từ nhiều gói. Nếu không, trên một mạng không đáng tin cậy, hãy đặt nó thành kích thước MTU. Hãy chắc chắn rằng bạn lật() các ByteBuffer sau khi nhận được bất cứ điều gì trong đó.

Ngoài ra, tạo chủ đề mới cho mỗi yêu cầu là một ý tưởng tồi, tạo chuỗi 'phiên' cho từng IP khác nhau mà bạn nhận được trong HashMap hoặc một cái gì đó, sau đó thực hiện guarded block trên đối tượng phiên. Thức dậy chủ đề ngủ trên đối tượng đó khi bạn nhận được tin nhắn sau khi chuyển thông tin mới. Mã chọn bạn có được thiết kế để tránh việc tạo các chủ đề theo cách này bằng cách.

Chỉnh sửa: dựa trên mã trên, bạn tạo kênh datagram và sau đó sử dụng socket để nhận datagram trực tiếp? Điều đó không có ý nghĩa. Chỉ sử dụng các phương thức kênh sau khi liên kết kênh. Ngoài ra, không làm điều này trong một chủ đề riêng biệt. Mã của bạn không an toàn chỉ và sẽ tự khởi động. Đưa thông tin đã nhận ra cho chuỗi 'phiên' riêng biệt như đã đề cập trước đó.Bộ chọn được thiết kế để cho bạn biết những kênh nào có thể đọc được mà không bị chặn (mặc dù chặn bị vô hiệu hóa, vì vậy nó sẽ cho bạn biết những kênh nào có dữ liệu được đọc).

+0

Tôi có thể thấy điểm của bạn với việc sử dụng chuỗi phiên, tôi đồng ý với bạn nhưng với mục đích của tôi, tốt nhất là tạo một chuỗi cho mỗi kết nối. cho ByteBuffer, tôi không sử dụng nó có vẻ như bạn không thấy mã mà tôi đã tải lên, chỉ cần liên kết. tnx – msaveski

+0

Ổ cắm UDP không có kết nối. Chỉ có các cổng TCP làm. Chủ đề chỉ giữ nguyên quá trình xử lý khỏi chuỗi chọn chính. Dù sao, đây là cách Apache MINA hoạt động :) –

+0

Aham, nếu tôi hiểu bạn đúng bạn nói không có điểm trong việc tạo chuỗi UDP mới, mà là để nhận thông tin trong lớp máy chủ và tiếp tục xử lý nó trong một chủ đề mới ? BTW, có cách nào thanh lịch hơn để làm điều tương tự, lắng nghe cả yêu cầu tcp và udp không? – msaveski

0

Bạn không thể sử dụng DatagramSocket.receive() ở chế độ không chặn. Bạn phải sử dụng phương thức read() hoặc trực tiếp DatagramChannel của mình.

Các vấn đề liên quan