使用服务器套接字通道创建聊天

时间:2015-12-13 01:01:29

标签: sockets

我正在与ServerSocketChannel创建聊天并维护客户端 - 服务器之间的通信。 服务器从客户端接收消息并向每个客户端广播。 我试图向服务器发送消息,一切都很好,但当我尝试从服务器向客户端发送消息时,消息无法到达。它仅在我关闭套接字时提供。 (就像它被缓冲了一样)

这是我的服务器代码:

static public void main( String args[] ) throws Exception {
// Parse port from command line
int port = Integer.parseInt( args[0] );

try {
  // Instead of creating a ServerSocket, create a ServerSocketChannel
  ServerSocketChannel ssc = ServerSocketChannel.open();

  // Set it to non-blocking, so we can use select
  ssc.configureBlocking( false );

  // Get the Socket connected to this channel, and bind it to the
  // listening port
  ServerSocket ss = ssc.socket();
  InetSocketAddress isa = new InetSocketAddress( port );
  ss.bind( isa );

  // Create a new Selector for selecting
  Selector selector = Selector.open();

  // Register the ServerSocketChannel, so we can listen for incoming
  // connections
  ssc.register( selector, SelectionKey.OP_ACCEPT );
  System.out.println( "Listening on port "+port );

  while (true) {
    // See if we've had any activity -- either an incoming connection,
    // or incoming data on an existing connection
    int num = selector.select();

    // If we don't have any activity, loop around and wait again
    if (num == 0) {
      continue;
    }

    // Get the keys corresponding to the activity that has been
    // detected, and process them one by one
    Set<SelectionKey> keys = selector.selectedKeys();
    Iterator<SelectionKey> it = keys.iterator();
    while (it.hasNext()) {
      // Get a key representing one of bits of I/O activity
      SelectionKey key = it.next();

      // What kind of activity is it?
      if ((key.readyOps() & SelectionKey.OP_ACCEPT) ==
        SelectionKey.OP_ACCEPT) {

        // It's an incoming connection.  Register this socket with
        // the Selector so we can listen for input on it
        Socket s = ss.accept();
        clientList.add(new Client(s));
        System.out.println( "Got connection from "+s );

        // Make sure to make it non-blocking, so we can use a selector
        // on it.
        SocketChannel sc = s.getChannel();
        sc.configureBlocking( false );

        // Register it with the selector, for reading
        sc.register( selector, SelectionKey.OP_READ );

      } else if ((key.readyOps() & SelectionKey.OP_READ) ==
        SelectionKey.OP_READ) {

        SocketChannel sc = null;

        try {

          // It's incoming data on a connection -- process it
          sc = (SocketChannel)key.channel();
          boolean ok = processInput( sc );

          /* HERE, TRYING TO SEND A TEST MESSAGE BACK */
          ByteBuffer bf = ByteBuffer.allocate(48);
          bf.clear();
          bf.put("testmessage".getBytes());
          sc.write(bf);

          // If the connection is dead, remove it from the selector
          // and close it
          if (!ok) {
            key.cancel();

            Socket s = null;
            try {
              s = sc.socket();
              System.out.println( "Closing connection to "+s );
              s.close();
            } catch( IOException ie ) {
              System.err.println( "Error closing socket "+s+": "+ie );
            }
          }

        } catch( IOException ie ) {

          // On exception, remove this channel from the selector
          key.cancel();

          try {
            sc.close();
          } catch( IOException ie2 ) { System.out.println( ie2 ); }

          System.out.println( "Closed "+sc );
          ie.printStackTrace();
        }
      }
    }

    // We remove the selected keys, because we've dealt with them.
    keys.clear();
  }
} catch( IOException ie ) {
  System.err.println( ie );
}
 }

在服务器上,请注意以下行:

ByteBuffer bf = ByteBuffer.allocate(48);
bf.clear();
bf.put("testmessage".getBytes());
sc.write(bf);

这是我试着回答的地方。

客户端通过以下方法接收消息:

// Main method for incoming
public void run() throws IOException {
    while(true) {
        InputStream is = con.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String answer = br.readLine();
        printMessage(answer);
    }
}

此致 佩德罗

1 个答案:

答案 0 :(得分:1)

这里有几个问题。

  • 你正在读行,但你不是在写行。发送时添加行终止符。
  • 您需要立即关闭频道,从read()获得-1。在那之后你几乎肯定无法发送它。
  • 您不需要取消密钥或关闭频道的套接字。关闭频道会做到这一切。
  • 当您从readLine()获取null时,您的客户端读取循环需要中断。