这是我的代码。从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);
}
}
}
}
2条答案
按热度按时间dba5bblo1#
这不是IO多路复用的工作方式。
一旦一个连接被接受并标记为非阻塞,就用
OP_READ
将它添加到同一个选择器中。检查循环中的可读事件,从套接字读取。你不需要穿线。或者,如果你想使用线程,不要将接受的客户端连接设置为非阻塞,只需在专用线程中对其进行常规读取。
编辑0:
我能提供的最好的建议是阅读一些优秀的Java NIO教程。互联网上有很多,但你可以从这里开始:
31moq8wy2#
没有足够的代表评论,所以张贴作为答案。我不是Maven,但我相信你将不得不在套接字输出流上使用PrintWriter来来回传递文本。这里thisClient是一个套接字。