gpt4 book ai didi

java - SocketChannel 套接字不读取数据

转载 作者:行者123 更新时间:2023-11-30 03:25:57 27 4
gpt4 key购买 nike

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

测试服务器.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);
}
}
}
}

最佳答案

这不是 IO 多路复用的工作方式。

首先,不要从 selectedKeys 中删除 - 在接受两个连接后,没有任何内容可供选择,因此主线程中的循环会阻塞,并且如果有新连接到达,则会发生事件不再接受它们了。 - 这是错误的,我对 Java 迭代器感到困惑,已经很长时间了......

然后,一旦连接被接受并标记为非阻塞,就使用 OP_READ 将其添加到同一选择器中。检查循环中的可读事件,从套接字读取。为此,您不需要线程。

或者,如果您想使用线程,请不要将接受的客户端连接设置为非阻塞,只需在专用线程中定期读取它。

编辑0:

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

关于java - SocketChannel 套接字不读取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30222302/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com