我正在做一个练习,需要使用Java非阻塞IO
制作一个服务器-客户端聊天程序。目前,程序的工作方式很简单:当客户端向服务器发送消息时,服务器(已经跟踪所有客户端)会将消息回显给所有客户端。
这是我的部分服务器端代码:
public static ByteBuffer str_to_bb(String msg) {
try {
return encoder.encode(CharBuffer.wrap(msg));
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
private static void broadcastMessage(String nickname, String message) {
System.out.println(">clientSocketChannels size " + clientSocketChannels.size());
Iterator clientSocketChannelsIterator = clientSocketChannels.iterator();
while (clientSocketChannelsIterator.hasNext()) {
SocketChannel sc = (SocketChannel) clientSocketChannelsIterator.next();
try {
ByteBuffer bb = str_to_bb(message);
System.out.println("bufferRemaining: " + bb.remaining()); // returns 2048
int writeResult = sc.write(bb);
System.out.println("writeResult: " + writeResult); // returns 2048
} catch (IOException e) {
e.printStackTrace();
}
}
}
以下是我的客户端代码:
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* Created by ThaiSon on 7/6/2015.
*/
public class ChatRoomClientGUI {
private JTextArea textAreaMessages;
private JTextField textFieldMessage;
private JButton buttonSendMsg;
private JPanel jPanel1;
private JLabel txtFieldInfo;
private static InetAddress inetAddress;
private static final int PORT = 1234;
private static Socket socket = null;
private static Scanner input = null;
private static PrintWriter output = null;
private static ChatRoomClientGUI singleton;
public ChatRoomClientGUI() {
singleton = this;
buttonSendMsg.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if (e.getButton() == MouseEvent.BUTTON1) {
String message = textFieldMessage.getText();
output.println(message);
textFieldMessage.setText("");
}
}
});
}
public static void main(String[] args) {
JFrame promptFrame = new JFrame();
Object nickname = JOptionPane.showInputDialog(promptFrame, "Enter your nickname:");
promptFrame.dispose();
JFrame frame = new JFrame("ChatRoomClientGUI");
frame.setContentPane(new ChatRoomClientGUI().jPanel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
System.out.println("> Client with nickname " + nickname);
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
accessServer(nickname.toString());
}
private static void accessServer(String nickname) {
try {
socket = new Socket(inetAddress, PORT);
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
output.println(nickname); // Register nickname with the server
//TODO update the txtFieldInfo content
// Create a new thread to listen to InputStream event
InputStreamEvent inputStreamEvent = new InputStreamEvent(socket);
inputStreamEvent.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleInputStream(){
String response = input.nextLine();
System.out.println("TODO " + response);
singleton.textAreaMessages.append(response + "\n");
}
static class InputStreamEvent extends Thread{
Socket socket;
public InputStreamEvent(Socket socket){
this.socket = socket;
}
public void run(){
try {
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[2048];
int read;
while (true){
if(inputStream.available() > 0){
handleInputStream();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我现在面临的问题是,当我使用客户端(与旧的多线程服务器
合作得很好)向服务器发送消息时,客户端只返回它发送的第一条消息。服务器的所有下一个响应都是空的(服务器确实发回了,但只有一条空消息)。
所以我的调试尝试包括:
希望你们能帮我。
我提到了EJP在这个链接上解释的代码JavaNIO服务器/客户端聊天应用程序-仅通过关闭套接字发送数据
它解决了我的问题。使用此代码
import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.Scanner;
import java.nio.channels.SelectionKey;
import java.net.InetSocketAddress;
public class Client {
public static void main(String args[]) {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
Scanner scanner = new Scanner(System.in);
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
boolean isConnected = socketChannel.connect(new InetSocketAddress("localhost", 5000));
if(isConnected) {
System.out.println("Connected, de-registering OP_CONNECT");
}
new Thread(new Runnable(){
private SocketChannel socketChannel;
private Selector selector;
public Runnable init(SocketChannel socketChannel, Selector selector) {
this.socketChannel = socketChannel;
this.selector = selector;
return this;
}
public void run() {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
while(!Thread.interrupted()) {
int keys = selector.select();
if(keys > 0) {
for(SelectionKey key : selector.selectedKeys()) {
if(key.isConnectable()) {
boolean finishConnectResult = socketChannel.finishConnect();
socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
System.out.println("Finished Connect : " + finishConnectResult);
}
if(key.isReadable()) {
int bytesRead = 0;
while((bytesRead = socketChannel.read(buf)) > 0) {
buf.flip();
while(buf.hasRemaining()) {
System.out.print((char)buf.get());
}
buf.clear();
}
if(bytesRead == -1) {
key.channel().close();
}
}
}
}
Thread.sleep(10);
}
} catch(IOException e) {
e.printStackTrace();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}.init(socketChannel, selector)).start();
while(true) {
while(scanner.hasNextLine()) {
buf.clear();
buf.put(scanner.nextLine().getBytes());
buf.flip();
socketChannel.write(buf);
buf.flip();
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
<代码>
我设置这个标志键时出错了。兴趣(SelectionKey.OP_READ);)
而不是下面。使用这个
socketChannel。寄存器(this.selector、SelectionKey.OP|u WRITE、SelectionKey.OP|u READ)
>
这是:
if(inputStream.available() > 0){
摆脱这个测试。有了它,你的客户正在抽CPU。如果没有它,它将按照上帝的意愿在readLine()
中阻塞。
您确定您的服务器仍然在发送带有行终止符的行吗?如果不是,readLine()
将永远阻止查找一个,直到流结束或出现异常。
我正在开发一个具有多个客户端的标准java RMI服务器。这些客户机有一个菜单,在那里他们可以调用服务器为他们做各种事情。 一种方法涉及一个队列,他们可以在其中将作业发送到队列并等待它得到处理。RMI服务器自动为所有客户端处理线程,但当涉及到此方法和队列时,我如何阻止此请求,例如: 首先调用客户端1,然后再调用客户端2(此处客户端1应首先从服务器接收消息,客户端2应等待服务器处理客户端1请求所需的
我已经使用java nio创建了一个客户端-服务器应用程序,它工作正常,但我的问题是,当服务器有许多连接到服务器的客户端时,服务器会响应错误的客户端,而不是请求客户端。例如,如果客户端A请求第一个人的信息,服务器将第一个人的信息返回给客户端B而不是客户端A。我已经尝试同步对象,但仍然无法正常工作,可能是什么问题。这是我的服务器示例代码
[服务器]:
我想在一些计算机之间建立点对点连接,这样用户就可以在没有外部服务器的情况下聊天和交换文件。我最初的想法如下: 我在服务器上制作了一个中央服务器插座,所有应用程序都可以连接到该插座。此ServerSocket跟踪已连接的套接字(客户端),并将新连接的客户端的IP和端口提供给所有其他客户端。每个客户端都会创建一个新的ServerSocket,所有客户端都可以连接到它。 换句话说:每个客户端都有一个Se
我已经看到了很多与我试图做的事情有关的问题,但我还没有找到任何解决方案。 我尝试编写两个套接字程序(一个客户端和一个服务器),以便服务器能够向客户端发送任何类型的文件(按字节)。我不确定如何构建/协调以下内容: > (在服务器中)读取语句从文件中获取数据(我使用fread()) (在服务器中)将数据发送到客户端的write语句(我使用的是write()) (在客户端)读取语句从服务器接收数据(我使
但还是没用。有什么帮助吗