java SocketChannel套接字未阅读数据

nc1teljy  于 2023-09-29  发布在  Java
关注(0)|答案(2)|浏览(108)

这是我的代码。从TestServer,我尝试通过输出流发送数据,并从测试客户端接收数据。我使用SocketChannel是因为我需要客户端同时监听3个端口。目前,我只想从一个套接字读取。但是,它似乎没有从服务器接收任何数据。对于KBThread的run方法,如果我取消注解nodata println,它将反复执行。
TestServer.java

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class TestServer extends JPanel implements KeyListener, MouseListener, MouseMotionListener {

    private final int MAX_CLIENTS = 8;

    JPanel listenerPanel = new JPanel();
    JFrame listenerFrame = new JFrame();

    static DataOutputStream kbOut;
    static DataOutputStream mOut;
    static Socket dataSocket;

    public TestServer() {
        this.setFocusable(true);
        listenerPanel.addKeyListener(this);
        listenerPanel.addMouseMotionListener(this);

        listenerFrame.add(listenerPanel);
        listenerFrame.setSize(1376,808); // 10 more x, 40 more y.
        listenerFrame.setVisible(true);
        listenerFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        listenerPanel.requestFocusInWindow();

    }

    public static void main(String[] args) {

        new TestServer().startServer();
    }

    public void startServer() {

        final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(MAX_CLIENTS);

        Runnable serverTask = () -> {
            try {
                ServerSocket serverSocket = new ServerSocket(1111);
                System.out.println("Waiting for clients.");
                while (true) {
                    Socket clientSocket = serverSocket.accept();
                    clientProcessingPool.submit(new ClientTask(clientSocket));
                }
            } catch (IOException ex) {
                System.err.println("Error with client socket.");
            }
        };

        Thread serverThread = new Thread(serverTask);
        serverThread.start();
    }

    private class ClientTask implements Runnable {
        private final Socket clientSocket;

        private ClientTask(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {

            try {
                String clientIP = clientSocket.getInetAddress().getHostAddress();
                System.out.println("Client connected from " + clientIP);

                Socket kbSocket = new Socket(clientIP, 1112);
                System.out.println("Keyboard socket connected to " + clientIP);
                kbOut = new DataOutputStream(kbSocket.getOutputStream());

                Socket mSocket = new Socket(clientIP, 1113);
                System.out.println("Mouse socket connected to " + clientIP);
                mOut = new DataOutputStream(mSocket.getOutputStream());

                //new TestServer().startKBServer(clientIP);
                //new TestServer().startMServer(clientIP);

                try {
                    clientSocket.close();
                } catch (IOException ex) {
                }
            } catch (IOException ex) {
                Logger.getLogger(TestServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void startKBServer(String clientAddress) {

        Runnable kbTask = () -> {
            try {
                Socket kbSocket = new Socket(clientAddress, 1112);
                System.out.println("Keyboard socket connected to " + clientAddress);
                new KBTask(kbSocket);

            } catch (IOException ex) {
                System.out.println("Error Calling Back " + clientAddress);
            }
        };

        Thread kbThread = new Thread(kbTask);
        kbThread.start();
    }

    private class KBTask implements Runnable {
        private final Socket kbSocket;

        private KBTask(Socket kbSocket) {
            this.kbSocket = kbSocket;
        }

        @Override
        public void run() {
            try {
                kbOut = new DataOutputStream(kbSocket.getOutputStream());
            } catch (IOException ex) {
                Logger.getLogger(TestServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    @Override
    public void keyPressed(KeyEvent ke) {
        try {
            int key = ke.getKeyCode();

            System.out.println("Key Pressed: " + key);

            kbOut.writeInt(key);
            kbOut.flush();

        } catch (IOException ex) {
            System.out.println("Error writing key data to server");
        }
    }

    @Override
    public void keyReleased(KeyEvent ke) {
        try {
            int key = ke.getKeyCode();

            System.out.println("Key Pressed: " + -key);

            kbOut.writeInt(-key);
            kbOut.flush();

        } catch (IOException ex) {
            System.out.println("Error writing -key data to server");
        }
    }

        @Override
    public void mouseMoved(MouseEvent me) {
        try {
            int mouseX = me.getX();
            int mouseY = me.getY();

            if (mOut != null) {
                mOut.writeInt(mouseX);
                mOut.writeInt(mouseY);
                mOut.flush();
                System.out.println("Mouse Moved To: " + mouseX + "," + mouseY);
            }

        } catch (IOException | NullPointerException ex) {
            System.out.println("Error writing mouse data to server");
        }
    }

    @Override
    public void mouseClicked(MouseEvent me) {

    }

    @Override
    public void mousePressed(MouseEvent me) {

    }

    @Override
    public void mouseReleased(MouseEvent me) {

    }

    @Override
    public void mouseEntered(MouseEvent me) {

    }

    @Override
    public void mouseExited(MouseEvent me) {

    }

    @Override
    public void mouseDragged(MouseEvent me) {

    }

    @Override
    public void keyTyped(KeyEvent ke) {

    }
}

TestClient.java

import java.awt.AWTException;
import java.awt.Robot;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestClient {

    private final static String SERVER_IP = "192.168.0.50";

    JPanel clientPanel = new JPanel();
    JFrame clientFrame = new JFrame();

    public void setupGUI() {

        clientFrame.add(clientPanel);
        clientFrame.setSize(200,200);
        clientFrame.setVisible(true);
        clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        clientPanel.requestFocusInWindow();
    }

    public static void main(String[] args) {

        try {
            new TestClient().setupGUI();

            Robot keyRobot = new Robot();

            Socket firstSocket = new Socket(SERVER_IP, 1111);
            System.out.println("Connected to Commander. Address sent. Waiting for callback.");
            firstSocket.close();

            Selector selector = Selector.open();

            int ports[] = new int[] { 1112, 1113 };

            for (int port : ports) {
                ServerSocketChannel serverChannel = ServerSocketChannel.open();
                serverChannel.configureBlocking(false);
                serverChannel.socket().bind(new InetSocketAddress(port));
                serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            }

            while (true) {
                // After the 2 accept methods fire, it stops here and program doesnt continue.
                selector.select();
                Set setKeys = selector.selectedKeys();
                Iterator selectedKeys = setKeys.iterator();

                while (selectedKeys.hasNext()) {
                    SelectionKey selectedKey = (SelectionKey) selectedKeys.next();
                    if (selectedKey.isAcceptable()) {
                        SocketChannel socketChannel = ((ServerSocketChannel) selectedKey.channel()).accept();
                        socketChannel.configureBlocking(false);

                        switch (socketChannel.socket().getLocalPort()) {
                            case 1112:
                                System.out.println("Keyboard socket open.");
                                Runnable kbr = new KBThread(socketChannel.socket());
                                new Thread(kbr).start();
                                break;

                            case 1113:
                                System.out.println("Mouse socket open.");
                                break;
                        }
                    }
                    selectedKeys.remove();
                }

            }

            } catch (ConnectException ece) {
            System.out.println("Failed to connect to server: " + SERVER_IP);
        } catch (IOException | AWTException eio) {
            Logger.getLogger(TestClient.class.getName()).log(Level.SEVERE, null, eio);
        }
    }

    private static class KBThread implements Runnable {
        private final Socket kbSocket;
        private int dataID = 0;

        private KBThread(Socket kbSocket) {
            this.kbSocket = kbSocket;
        }

        @Override
        public void run() {

            try {
                DataInputStream kbDis = new DataInputStream(kbSocket.getInputStream());
                while (true) {
                    try {

                        if (kbDis.available() > 0) {
                            dataID = kbDis.readInt();
                            System.out.println(dataID);
                        }
                        //else System.out.println("noData");
                    } catch (IOException ex) {
                        Logger.getLogger(TestClient.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(TestClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
dba5bblo

dba5bblo1#

这不是IO多路复用的工作方式。
一旦一个连接被接受并标记为非阻塞,就用OP_READ将它添加到同一个选择器中。检查循环中的可读事件,从套接字读取。你不需要穿线。
或者,如果你想使用线程,不要将接受的客户端连接设置为非阻塞,只需在专用线程中对其进行常规读取。

编辑0:

我能提供的最好的建议是阅读一些优秀的Java NIO教程。互联网上有很多,但你可以从这里开始:

31moq8wy

31moq8wy2#

没有足够的代表评论,所以张贴作为答案。我不是Maven,但我相信你将不得不在套接字输出流上使用PrintWriter来来回传递文本。这里thisClient是一个套接字。

writer = new PrintWriter(thisClient.getOutputStream());
System.out.println("Transmitting");
writer.println(msg);
writer.flush();

相关问题