gpt4 book ai didi

Java SocketChannel 无法正确接收传入数据

转载 作者:行者123 更新时间:2023-12-01 16:37:30 25 4
gpt4 key购买 nike

我正在编写一个聊天室服务器,它从聊天客户端获取消息并将该消息广播给所有用户。这是《Java 网络编程简介:Java 7 兼容》一书中的一个练习,我正在自学 Java 网络基础知识。我按照书中代码的示例为聊天室编写了一个 GUI 前端并实现了服务器后端。然而,当我用聊天客户端测试代码时,服务器似乎无法接收客户端的数据。我不明白为什么。聊天室(这里是为了测试目的而在命令行模式下编写的)和客户端的代码如下。谢谢。

// code for the server backend, problem seems to be lie in here.


/**
* The multiecho server itself
*/
package channelEchoServer;

import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class MultiEchoServerNIO {
private static ServerSocketChannel serverSocketChannel;
private static final int PORT = 1234;
private static Selector selector;
private static Vector<SocketChannel> socketChannelVec;
private static Vector<ChatUser> allUsers;
public static final int CAPACITY = 20;
public static final int BUFFER_SIZE = 2048;
public static final String NEW_LINE = System.lineSeparator();

public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocket = serverSocketChannel.socket();
InetSocketAddress netAddress = new InetSocketAddress(PORT);
serverSocket.bind(netAddress);
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}
catch (IOException ioEx) {
ioEx.printStackTrace();
System.exit(1);
}
socketChannelVec = new Vector<>(CAPACITY);
allUsers = new Vector<>(CAPACITY);
System.out.println("Server is opened ...");
processConnections();
}

private static void processConnections () {
do {
try {
int numKeys = selector.select();
System.out.println(numKeys + " keys selected.");
if (numKeys > 0) {
Set eventKeys = selector.selectedKeys();
Iterator keyCycler = eventKeys.iterator();
while (keyCycler.hasNext()) {
SelectionKey key = (SelectionKey)keyCycler.next();
int keyOps = key.readyOps();
if ((keyOps & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
acceptConnection(key);
continue;
}
if ((keyOps & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
acceptData(key);
}
}
}
}
catch (IOException ioEx) {
ioEx.printStackTrace();
System.exit(1);
}
} while (true);
}
private static void acceptConnection (SelectionKey key) throws IOException {
SocketChannel socketChannel;
Socket socket;

socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socket = socketChannel.socket();
System.out.println("Connection on " + socket + ".");
socketChannel.register(selector, SelectionKey.OP_READ);
socketChannelVec.add(socketChannel);
selector.selectedKeys().remove(key);
}
private static void acceptData (SelectionKey key) throws IOException {
SocketChannel socketChannel;
Socket socket;

ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
socketChannel = (SocketChannel) key.channel();
buffer.clear();
int numBytes = socketChannel.read(buffer);
socket = socketChannel.socket();
if (numBytes == -1) {
key.cancel();
closeSocket(socket);
}
else {
String chatName = null;
byte[] byteArray = buffer.array();
if (byteArray[0] == '#')
announceNewUser(socketChannel, buffer);
else {
for (ChatUser chatUser : allUsers)
if (chatUser.getUserSocketChannel().equals(socketChannel))
chatName = chatUser.getChatName();
broadcastMessage(chatName, buffer);
}
}
}

private static void closeSocket (Socket socket) {
try {
if (socket != null)
socket.close();
}
catch (IOException ioEx) {
System.out.println("Unable to close socket!");
}
}
public static void announceNewUser (SocketChannel userSocketChannel, ByteBuffer buffer) {
ChatUser chatUser;
byte[] byteArray = buffer.array();
int messageSize = buffer.position();
String chatName = new String(byteArray, 1, messageSize);
if (chatName.indexOf("\n") >= 0)
chatName = chatName.substring(0, chatName.indexOf("\n"));
chatUser = new ChatUser(userSocketChannel, chatName);
allUsers.add(chatUser);
if (!socketChannelVec.remove(userSocketChannel)) {
System.out.println("Can't find user!");
return;
} // we should save userSocketChannel in a chatUser instance before deleting it.
chatName = chatUser.getChatName();
System.out.println(chatName + " entered the chat room at " + new Date() + "." + NEW_LINE);
String welcomeMessage = "Welcome " + chatName + "!" + NEW_LINE;
byte[] bytes = welcomeMessage.getBytes();
buffer.clear();
for (int i = 0; i < welcomeMessage.length(); i++)
buffer.put(bytes[i]);
buffer.flip();
try {
chatUser.getUserSocketChannel().write(buffer);
}
catch (IOException ioEx) {
ioEx.printStackTrace();
}
}
public static void announceExit (String name) {
System.out.println(name + " left chat room at " + new Date() + "." + NEW_LINE);
for (ChatUser chatUser : allUsers) {
if (chatUser.getChatName().equals(name))
allUsers.remove(chatUser);
}
}
public static void broadcastMessage (String chatName, ByteBuffer buffer) {
String messagePrefix = chatName + ": ";
byte[] messagePrefixBytes = messagePrefix.getBytes();
final byte[] CR = NEW_LINE.getBytes();

try {
int messageSize = buffer.position();
byte[] messageBytes = buffer.array();
byte[] messageBytesCopy = new byte[messageSize];

String userMessage = new String(messageBytes, 0, messageSize);
if (userMessage.equals("Bye"))
announceExit(chatName);

for (int i = 0; i < messageSize; i++)
messageBytesCopy[i] = messageBytes[i];
buffer.clear();
buffer.put(messagePrefixBytes);
for (int i = 0; i < messageSize; i++)
buffer.put(messageBytesCopy[i]);
buffer.put(CR);
SocketChannel chatSocketChannel;
for (ChatUser chatUser : allUsers) {
chatSocketChannel = chatUser.getUserSocketChannel();
buffer.flip();
chatSocketChannel.write(buffer);
}
}
catch (IOException ioEx) {
ioEx.printStackTrace();
}
}
}

class ChatUser {
private SocketChannel userSocketChannel;
private String chatName;

public ChatUser (SocketChannel userSocketChannel, String chatName) {
this.userSocketChannel = userSocketChannel;
this.chatName = chatName;
}

public SocketChannel getUserSocketChannel () {
return userSocketChannel;
}
public String getChatName () {
return chatName;
}
}

// Code for a chat client for testing purpose
package multithreadEchoChatroomClientGUI;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class MultithreadEchoChatroomClient1 {
private static Socket socket;
private static InetAddress host;
private static String address;
public static final int PORT = 1234;

public static void main(String[] args) {

address = JOptionPane.showInputDialog("Enter the host name or IP address:");
try {
host = InetAddress.getByName(address);
}
catch (UnknownHostException uhEx) {
JOptionPane.showMessageDialog(null, "Unknown Host!", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
try {
socket = new Socket(host, PORT);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(null, ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}

SwingUtilities.invokeLater(new Runnable () {
public void run () {
ClientFrame client = new ClientFrame(host, socket, address);
client.setTitle("Chat");
client.setSize(400, 500);
client.setVisible(true);
new Thread(client).start();
}
});
}
}

class ClientFrame extends JFrame implements Runnable {
private InetAddress host;
private String address;
private Socket socket;
private Scanner input;
private PrintWriter output;
private JMenuItem connect;
private JTextArea serverResponseArea;
private JTextArea messageArea;
private JTextField messageFiled;
private JButton sendButton;
private String serverResponse;
private String clientName;

public ClientFrame (InetAddress host, Socket socket, String address) {
this.host = host;
this.socket = socket;
this.address = address;

initFrame();
}

public void run () {

try {
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot create input or output stream!", "Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}

do {
clientName = JOptionPane.showInputDialog("What nickname would you like to use in the chatroom?");
} while (clientName == null);
output.println("#" + clientName);
do {
serverResponse = input.nextLine();
serverResponseArea.append(serverResponse + "\n");
} while (socket.isClosed() != true);
}

private final void closeSocket () {
try {
socket.close();
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot disconnect from chatroom!", "Error", JOptionPane.ERROR_MESSAGE);
}
}

private void initFrame () {
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);

JScrollPane responsePanel = createResponsePanel();
add(responsePanel, BorderLayout.NORTH);

JPanel messagePanel = createMessagePanel();
add(messagePanel, BorderLayout.CENTER);

//JPanel textPanel = createTextPanel();
//add(textPanel, BorderLayout.SOUTH);

addWindowListener(new WindowAdapter () {
@Override
public void windowClosing (WindowEvent we) {
if (!socket.isClosed())
closeSocket();
System.exit(0);
}
});
}

private JMenuBar createMenuBar () {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Operations");
connect = new JMenuItem("Connect");
connect.setEnabled(false);
connect.addActionListener(new ActionListener () {
@Override
public void actionPerformed (ActionEvent event) {
try {
host = InetAddress.getByName(address);
}
catch (UnknownHostException uhEx) {
JOptionPane.showMessageDialog(null, "Unknown Host!", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
try {
socket = new Socket(host, MultithreadEchoChatroomClient1.PORT);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(null, ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
try {
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(ClientFrame.this, "Cannot create input or output stream!", "Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}
output.println("#" + clientName);
serverResponse = input.nextLine();
serverResponseArea.append(serverResponse + "\n");
}
});
JMenuItem quit = new JMenuItem("Quit");
quit.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
if (!socket.isClosed())
closeSocket();
System.exit(0);
}
});
menu.add(connect);
menu.add(quit);
menuBar.add(menu);

return menuBar;
}

private JScrollPane createResponsePanel () {
serverResponseArea = new JTextArea(20, 35);
serverResponseArea.setEditable(false);
serverResponseArea.setLineWrap(true);
serverResponseArea.setWrapStyleWord(true);
serverResponseArea.setMargin(new Insets(5, 5, 5, 5));

JScrollPane scrlPane = new JScrollPane(serverResponseArea);
scrlPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 20));
scrlPane.setBackground(Color.yellow);

return scrlPane;
}

private JPanel createMessagePanel () {
JPanel msgPanel = new JPanel();

msgPanel.setBorder(BorderFactory.createEmptyBorder(20,10, 10, 20));
msgPanel.setBackground(Color.blue);
msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.LINE_AXIS));
JScrollPane srlPanel = createMessageTextPanel();
msgPanel.add(srlPanel);

JButton sdButton = createSendButton();
msgPanel.add(sdButton);

return msgPanel;
}

private JScrollPane createMessageTextPanel () {
messageArea = new JTextArea(10, 35);
//messageArea.setEditable(false);
messageArea.setLineWrap(true);
messageArea.setWrapStyleWord(true);
messageArea.setMargin(new Insets(5, 5, 5, 5));
JScrollPane mtPanel = new JScrollPane(messageArea);

return mtPanel;
}

private JButton createSendButton () {
JButton button = new JButton("Send");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
String message;

message = messageArea.getText();
System.out.println(message);
output.println(message);
if (message.equals("Bye")) {
closeSocket();
connect.setEnabled(true);
}
messageArea.setText("");
//serverResponse = input.nextLine();
//serverResponseArea.append(serverResponse + "\n");
}
});
return button;
}
}

再次感谢您不辞辛劳地阅读大量代码并提出建议!

最佳答案

问题按照@user207421解决。我应该在方法 acceptData(SelectedKey key)else {} block 中放置一个 remove() 操作,以便旧 key 关联socketChannel 将从所选键集中删除,以便能够检测到新传入的键。

我不知道我对user207421的解决方案的理解是否正确,但它暂时解决了问题。如果大家有其他想法,请分享您的观点。

再次感谢您,用户207421。并感谢所有访问者对这篇文章的关注。

关于Java SocketChannel 无法正确接收传入数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61928658/

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