IllegalBlockingModeException using sockets - java

I'm trying to write a chat server and client that uses sockets. Connecting the client works properly and I get the correct output from the server:
Listening on port 8000
Got connection from Socket[addr=/127.0.0.1,port=50628,localport=8000]
But when I send something from the client I get IllegalBlockingModeException. Here's what I have:
public void listen()
{
try {
// Open a non-blocking socket channel
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
// Get the socket and bind it
ServerSocket ss = ssc.socket();
InetSocketAddress isa = new InetSocketAddress(this.getServerName(), this.getServerPort());
ss.bind(isa);
// Create the selector
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Listening on port " + this.getServerPort());
while (true)
{
// Wait for at least one channel to be selected
if (selector.select() == 0)
continue;
// Iterate the key set and dispatch messages
Set keys = selector.selectedKeys();
Iterator it = keys.iterator();
while (it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
if (key.isAcceptable()) {
Socket s = ss.accept();
System.out.println("Got connection from " + s);
SocketChannel sc = s.getChannel();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
else if (key.isReadable()) {
SocketChannel sc = null;
try {
sc = (SocketChannel)key.channel();
String message = processInput(sc);
if (message == null) {
key.cancel();
Socket s = null;
try {
s = sc.socket();
System.out.println("Closing connection to " +s);
s.close();
} catch( IOException ie ) {
System.err.println("Error closing socket " + s + ": " + ie);
}
}
else {
String response = getListener().process(sc, message);
ObjectOutputStream oos = new ObjectOutputStream(Channels.newOutputStream(sc));
//ObjectOutputStream oos = new ObjectOutputStream(sc.socket().getOutputStream());
oos.writeObject(response + "\n");
oos.close();
}
}
catch(IOException ie) {
key.cancel();
try {
sc.close();
} catch(IOException ie2) {
System.out.println(ie2);
}
System.out.println("Closed " + sc);
}
}
}
keys.clear();
}
}
catch (IOException ex) {
System.out.println(ex);
System.exit(1);
}
}
private String processInput( SocketChannel sc ) throws IOException {
buffer.clear();
sc.read( buffer );
buffer.flip();
if (buffer.limit()==0) {
return null;
}
return decoder.decode(buffer).toString();
}
Here's the stack trace:
java.nio.channels.SocketChannel[connected local=/127.0.0.1:8000 remote=/127.0.0.1:50656]
Exception in thread "main" java.nio.channels.IllegalBlockingModeException
at java.nio.channels.Channels.writeFully(Channels.java:97)
at java.nio.channels.Channels.access$000(Channels.java:61)
at java.nio.channels.Channels$1.write(Channels.java:174)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1870)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1779)
at java.io.ObjectOutputStream.<init>(ObjectOutputStream.java:247)
at ChatServer$Server.listen(ChatServer.java:171)
at ChatServer.run(ChatServer.java:231)
at ChatServer.main(ChatServer.java:247)
Java Result: 1
Does anybody know how to solve this?

You can't use Channels.newXXXStream() on a channel in non-blocking mode. See the Javadoc.

Ok, I managed to put it to work. Here's how:
String response = getListener().process(sc, message) + "\n";
ByteBuffer bb = ByteBuffer.wrap(response.getBytes("utf-8"));
sc.write(bb);
Instead of using an OutputStream, write directly to the SocketChannel.

Related

Java SocketChannel cannot send data to ServerSocketChannel

I am trying to write a simple client/server in Java using NIO and Selectors. The server is very easy and it's the most typical implementation that you can find everywhere. Here's the code of the server (look at the start() method):
public final class MyServer {
private int port;
private String address;
public MyServer(String address, int port) {
this.address = address;
this.port = port;
}
public void start() throws IOException {
try {
Selector selector = Selector.open();
ServerSocketChannel socket = ServerSocketChannel.open();
InetSocketAddress addr = new InetSocketAddress(address, port);
socket.bind(addr);
socket.configureBlocking(false);
boolean isAlive = true;
SelectionKey selectKy = socket.register(selector, SelectionKey.OP_ACCEPT, null);
while (isAlive) {
selector.select();
Set<SelectionKey> keysList = selector.selectedKeys();
Iterator<SelectionKey> keys = keysList.iterator();
while (keys.hasNext()) {
SelectionKey theKey = keys.next();
if (theKey.isAcceptable()) {
SocketChannel clientSocket = socket.accept();
clientSocket.configureBlocking(false);
clientSocket.register(selector, SelectionKey.OP_READ);
}
if (theKey.isReadable()) {
SocketChannel clientSocket = (SocketChannel) theKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(9000);
clientSocket.read(buffer);
String result = new String(buffer.array()).trim();
System.out.println(" > SERVER: Request from " + clientSocket.getLocalAddress() + " [ toValidate = " + result + " ], sending tokens...");
//Now I send to the client a list
buffer.flip();
for (int i = 0; i < 5; ++i)
buffer.put((byte) getRandom(1, 10));
clientSocket.write(buffer);
buffer.clear();
System.out.println(" > SERVER: Response successfully sent");
}
keys.remove();
}
}
} catch (Exception e) {
System.out.println("[ SERVER ALERT: " + e.getMessage() + " ]");
}
}
}
As you can see, the code is pretty basic. Inside the if (theKey.isReadable()) I try to read a small string from the client, I print it to the console, then I flip the buffer and I send some data back to the client.
Here we have the client that sadly has a problem I cannot find:
public void something() throws IOException, InterruptedException {
ByteBuffer buffer = ByteBuffer.allocate(9000);
//Note that mRequests is a List of strings
try (SocketChannel client = SocketChannel.open(new InetSocketAddress(authIPAddr, authPort));) {
//For each transaction in mRequests, get the tokens from the server and verify them
for (String s : mRequests) {
//Write the string to the buffer and send the string
buffer.put(s.getBytes());
client.write(buffer);
buffer.rewind();
//Get response from the server
client.read(buffer);
buffer.clear();
Thread.sleep(1000);
}
}
}
The problem is exactly here:
buffer.put(s.getBytes());
client.write(buffer);
buffer.rewind();
I can say that the problem is there because the server should print
SERVER: Request from /127.0.0.1:2323 [ toValidate = {some_value} ], sending
tokens...
but instead it prints
SERVER: Request from /127.0.0.1:2323 [ toValidate = ], sending
tokens...
and from this I guess that data arent sent to the server. How can I solve this?

why is this Java Proxy Server very slow?

I need a Java Proxy Server that let me connect to [localhost:9318] through [localhost:9418], like:
[my browser] -> [localhost:9418] -> [localhost:9318]
for that I tried this code:
http://www.java2s.com/Code/Java/Network-Protocol/Asimpleproxyserver.htm
package com.example.proxyserver;
import java.io.*;
import java.net.*;
public class App {
public static void main(String[] args) throws IOException {
try {
String host = "localhost";
int remoteport = 9318;
int localport = 9418;
// Print a start-up message
System.out.println("Starting proxy for " + host + ":" + remoteport + " on port " + localport);
// And start running the server
runServer(host, remoteport, localport); // never returns
} catch (Exception e) {
System.err.println(e);
}
}
/**
* runs a single-threaded proxy server on the specified local port. It never
* returns.
*/
public static void runServer(String host, int remoteport, int localport) throws IOException {
// Create a ServerSocket to listen for connections with
ServerSocket ss = new ServerSocket(localport);
final byte[] request = new byte[1024];
byte[] reply = new byte[4096];
while (true) {
Socket client = null, server = null;
try {
// Wait for a connection on the local port
client = ss.accept();
final InputStream streamFromClient = client.getInputStream();
final OutputStream streamToClient = client.getOutputStream();
// Make a connection to the real server.
// If we cannot connect to the server, send an error to the
// client, disconnect, and continue waiting for connections.
try {
server = new Socket(host, remoteport);
} catch (IOException e) {
PrintWriter out = new PrintWriter(streamToClient);
out.print("Proxy server cannot connect to " + host + ":" + remoteport + ":\n" + e + "\n");
out.flush();
client.close();
continue;
}
// Get server streams.
final InputStream streamFromServer = server.getInputStream();
final OutputStream streamToServer = server.getOutputStream();
// a thread to read the client's requests and pass them
// to the server. A separate thread for asynchronous.
Thread t = new Thread() {
public void run() {
int bytesRead;
try {
while ((bytesRead = streamFromClient.read(request)) != -1) {
streamToServer.write(request, 0, bytesRead);
streamToServer.flush();
}
} catch (IOException e) {
}
// the client closed the connection to us, so close our
// connection to the server.
try {
streamToServer.close();
} catch (IOException e) {
}
}
};
// Start the client-to-server request thread running
t.start();
// Read the server's responses
// and pass them back to the client.
int bytesRead;
try {
while ((bytesRead = streamFromServer.read(reply)) != -1) {
streamToClient.write(reply, 0, bytesRead);
streamToClient.flush();
}
} catch (IOException e) {
}
// The server closed its connection to us, so we close our
// connection to our client.
streamToClient.close();
} catch (IOException e) {
System.err.println(e);
} finally {
try {
if (server != null)
server.close();
if (client != null)
client.close();
}
catch (IOException e) {
}
}
}
}
}
This code works but it is very slow.
Do you know what do I need to do in order to increase the speed?
Or maybe do you know about another Java Proxy Server code that be fast?
Thanks!

Why is my message sent only once in Java socket server?

there is a server that is considered to server multiple clients at the same time.
So when clients connects, he is added to clients array. And when server gets the message, it is sent to all the clients.
It works perfectly when one client is connected, but when I have 2 clients at the same time, the message is sent only once, it doesn't work anymore after that. What's the problem?
Server
static DataInputStream inputStream;
static DataOutputStream outputStream;
static ServerSocket serverSocket;
static final int PORT = 3003;
static Socket someClient;
static List<Socket> clients = new ArrayList<>();
public Server()
{
start();
}
public static void main(String[] args) throws IOException
{
try{
serverSocket = new ServerSocket(PORT);
print("Server started on " + serverSocket.getInetAddress().getHostAddress());
while (true)
{
someClient = serverSocket.accept();
new Server();
}
} catch (Exception e){
e.printStackTrace();
}
}
#Override
public void run()
{
try{
clients.add(someClient);
print("Connected from " + someClient.getInetAddress().getHostAddress());
InputStream sin = someClient.getInputStream();
OutputStream sout = someClient.getOutputStream();
inputStream = new DataInputStream(sin);
outputStream = new DataOutputStream(sout);
String message;
while (true)
{
message = inputStream.readUTF();
print(message);
for (int i = 0; i < clients.size(); i++)
{
Socket client = clients.get(i);
OutputStream os = client.getOutputStream();
DataOutputStream oss = new DataOutputStream(os);
oss.writeUTF(message);
}
}
} catch (Exception e){
e.printStackTrace();
}
}
Client
socket = new Socket("0.0.0.0", 3003);
InputStream sin = socket.getInputStream();
OutputStream sout = socket.getOutputStream();
inputStream = new DataInputStream(sin);
outputStream = new DataOutputStream(sout);
sendButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(key != null && key.length() == 16)
{
Date date = new Date();
String msg = ">> " + nickname + ": " + messageField.getText()+" | " + date.getHours()+":"+date.getMinutes()+"\n";
try {
outputStream.writeUTF(Encrypt.AESEncrypt(key, msg));
} catch (IOException e1) {
e1.printStackTrace();
}
messageField.setText("");
}
else if(key == null)
JOptionPane.showMessageDialog(J_Frame, "Your key field is empty");
else if(key.length() != 16)
JOptionPane.showMessageDialog(J_Frame, "Key's length should be 16 symbols");
}
});
while (true)
{
String message;
message = inputStream.readUTF();
append("\n" + Encrypt.AESDecrypt(key, message));
}
} catch (Exception e1) {
clear();
append(">> Unable to connect to the server.");
hideButtons();
}
Every time a client connects to your server, it replaces the previous connection:
while (true)
{
someClient = serverSocket.accept();
...
}
someClient is static:
static Socket someClient;
which means it is shared by all threads.
Also, access to it is not synchronized in any way, which means changes to its value are not guaranteed to be visible to other threads.
As Peter Lawrey pointed out in the comments, the streams also need to be non-static:
static DataInputStream inputStream;
static DataOutputStream outputStream;
actually, the fact that you are always reading from the "latest" inputStream may be the main cause of the behavior you are describing.
outputStream seems to be unused, so it might be best to remove it.
In addition to that, OutputStreams may need to be flushed in order to actually send data.

Android Socket connection to bitcoin node

I can't get a response from a bitcoin node using a simple java socket on android. I send a version message and wait for a response, but nothing is returned. The code is fairly simple:
private void connect(Peer peer) {
Log.i(App.TAG, "connect to: " + peer.ip + ":8333");
InetSocketAddress address = new InetSocketAddress(peer.ip, 8333);
Socket socket = new Socket();
try {
socket.connect(address, 10000);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
VersionMessage versionMessage = new VersionMessage();
writeMessage(versionMessage, out);
readMessage(in);
Log.i(App.TAG, "Shutting down....");
out.close();
in.close();
socket.close();
} catch (IOException e) {
Log.i(App.TAG, "Socket failed to conenct");
}
}
private void writeMessage(BaseMessage message, OutputStream out) {
Log.i(App.TAG, "writeMessage: " + message.getCommandName());
byte[] header = message.getHeader();
byte[] payload = message.getPayload();
try {
Log.i(App.TAG, "header: " + Util.bytesToHexString(header));
Log.i(App.TAG, "payload: " + Util.bytesToHexString(payload));
out.write(header);
out.write(payload);
} catch (IOException e) {
Log.i(App.TAG, "Failed to write message");
}
}
private void readMessage(InputStream in) throws IOException {
Log.i(App.TAG, "readMessage");
while (true) {
int b = in.read();
Log.i(App.TAG, "read: " + b);
if (b == -1) {
Log.i(App.TAG, "END OF CONNECTION!");
break;
}
response.add(b);
}
}
The logs from the app are as follows:
connect to: 52.88.14.46:8333
writeMessage: version
header: f9beb4d976657273696f6e00000000006100000061000000
payload: 7c9c000001000000000000005a73788200000000524543495049454e54204950000000000000000000000000000053454e44455220495000000000000000000000000000000000006237646465346163626f657463686169000000000000000000
readMessage
read: -1
END OF CONNECTION!
Shutting down....
Here is a link to the project: https://github.com/boetchain/android-bitcoin-node
The checkSum field is mandatory and fellow nodes will just ignore incoming messages without a valid checksum.

Java nio udp broadcast

I try to implement a UDP client server detection via broadcast. The idea is the following: I have a server, which is bound to port 12344 and a client which is bound to port 12345. Now, the client sends a broadcast package to 255.255.255.255 12344. The server should reply to this package with a other package to IPClient:12345.
The implementation uses Java nio.
The problem is, that on windows, the server gets the packages but cannot(?) send an answer (I don't see the answer in wireshark).
I have the following example code:
Client
public final class ASyncUDPClient {
public static void main(String[] args) throws IOException {
InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
System.out.println(hostAddress);
// Create a non-blocking socket channel
DatagramChannel channel = DatagramChannel.open();
channel.socket().setBroadcast(true);
channel.socket().bind(new InetSocketAddress(getAddress(), 12345));
channel.configureBlocking(false);
// Kick off connection establishment
channel.connect(hostAddress);
ByteBuffer buffer = getBuffer();
Selector selector = Selector.open();
channel.write(buffer);
System.out.println("data send");
channel.register(selector, SelectionKey.OP_READ);
while (true) {
final int select = selector.select();
System.out.println("select " + select);
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
System.out.println("key selected");
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
System.out.println("read");
} else if (key.isWritable()) {
System.out.println("write");
}
}
}
}
private static ByteBuffer getBuffer() throws CharacterCodingException {
return Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("1234"));
}
private static InetAddress getAddress() throws SocketException {
final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface networkInterfaceToUse = null;
while (networkInterfaces.hasMoreElements()) {
final NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.getDisplayName().contains("Virtual")) continue;
if (networkInterface.isVirtual()) continue;
if (networkInterface.isLoopback()) continue;
if (!networkInterface.isUp()) continue;
networkInterfaceToUse = networkInterface;
System.out.println(networkInterfaceToUse);
}
return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}
}
Server example
public class ASyncUDPSvr {
static int BUF_SZ = 1024;
static int port = 12344;
static public void main(String[] args) {
ASyncUDPSvr svr = new ASyncUDPSvr();
svr.process();
}
private static InetAddress getAddress() throws SocketException {
final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface networkInterfaceToUse = null;
while (networkInterfaces.hasMoreElements()) {
final NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.getDisplayName().contains("Virtual")) continue;
if (networkInterface.isVirtual()) continue;
if (networkInterface.isLoopback()) continue;
if (!networkInterface.isUp()) continue;
networkInterfaceToUse = networkInterface;
System.out.println(networkInterfaceToUse);
}
return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}
private void process() {
try {
Selector selector = Selector.open();
DatagramChannel channel = DatagramChannel.open();
InetSocketAddress isa = new InetSocketAddress(getAddress(), port);
channel.socket().bind(isa);
channel.configureBlocking(false);
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
clientKey.attach(new Con());
while (true) {
try {
selector.select();
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
try {
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
read(key);
key.interestOps(SelectionKey.OP_WRITE);
} else if (key.isWritable()) {
write(key);
key.interestOps(SelectionKey.OP_READ);
}
} catch (IOException e) {
System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
} catch (IOException e) {
System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
} catch (IOException e) {
System.err.println("network error: " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
private void read(SelectionKey key) throws IOException {
DatagramChannel chan = (DatagramChannel) key.channel();
Con con = (Con) key.attachment();
con.sa = chan.receive(con.req);
System.out.println("sender address: " + con.sa + "rcv: " + new String(con.req.array(), "UTF-8"));
con.resp = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("send string"));
}
private void write(SelectionKey key) throws IOException {
DatagramChannel chan = (DatagramChannel) key.channel();
Con con = (Con) key.attachment();
System.out.println("sending data: " + new String(con.resp.array(), "UTF-8") + " to " + con.sa);
chan.send(con.resp, con.sa);
System.out.println("data send");
}
class Con {
ByteBuffer req;
ByteBuffer resp;
SocketAddress sa;
public Con() {
req = ByteBuffer.allocate(BUF_SZ);
}
}
}
InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
// ...
channel.connect(hostAddress);
The problem is here. You can't connect to the broadcast address, and in any case it doesn't make sense. The broadcast address isn't sending to you, you are sending to it. The server is sending to you from its own bind-address. Just remove this line. You will have to use DatagramChannel.send() rather than write(), as you are unconnected.
The accepted answer is not true. You can "connect" the channel to the broadcast address when you first set:
channel.socket().setBroadcast(true);
Of course UDP is a connectionless protocol, but a "connected" DatagramChannel has some benefits, one of them is the ability to use the write(ByteBuffer[]) method.

Categories

Resources